Testing In-App Billing Version 3 has been made unpredictable by the fact that the Google Play app buffers data from the Google Play servers, and the buffering process is not wel
Here is my own experience purchasing an item with an app running on a Nexus 7 tablet and then detecting that purchase using the same app running on a Nexus One phone. The testing described below was performed using a test account for an app that was uploaded in draft mode (not yet published). The test account was declared on the Developer Console for the draft app, and was the main account for both test devices.
The purchase made was of a non-consumable item. The purchase was made using a variant of the IabHelper class provided with the TrivialDrive sample app. The IabHelper method invoked to make the purchase was launchPurchaseFlow().
As soon as the purchase was made, the item was added to the list of purchased items returned to that same device when IabHelper's queryInventoryAsync() method was subsequently used.
However, a separate Nexus One device owned by the same account, when started, performed a call to queryInventoryAsync() but did not receive the purchased item in the inventory of purchased items returned using that method.
If, however, the Nexus One device was used to initiate a purchase of the same item using launchPurchaseFlow(), a message was returned (in a dialog that popped up in front of the display that would have been used to make the purchase), indicating that the item cannot be purchased because it is already owned. This occurred less than 15 minutes after the purchase was initiated from the Nexus 7, showing that the data was fairly promptly available on the Google Play servers, but was not automatically available on the Nexus One, until the attempt to re-purchase the item from the Nexus One device was initiated.
Following this abortive attempt to purchase the already-owned item, the item did appear on subsequent invocations of queryInventoryAsync() on the Nexus One. This suggests that the attempt to purchase the item triggered a synchronization of the Nexus One Google Play app's buffered data with the data available on the Google Play servers. This was not triggered by queryInventoryAsync() itself.
I tested a second scenario in which, instead of making an attempt to purchase the already-owned item from the Nexus One, I deleted the cache in the Google Play app. This did not initiate an update of the data returned by queryInventoryAsync(); that data remained unchanged.
I tested a third scenario in which, instead of making an attempt to purchase the already-owned item from the Nexus One, I simply powered down the Nexus One and then powered it up again. After this, when I ran the same app and it performed a queryInventoryAsync() request, the item that was purchased from the Nexus 7 was in fact visible in the returned list of purchased items.
I conclude from the above that the Google Play app is attempting to reduce the number of round trips that it makes to the Google Play servers by buffering purchases locally and only updating itself when specific triggers occur. I have identified two triggers as being 1) an attempt to purchase an already-owned item and 2) a reboot of the device on which the Google Play app is running. In particular, queryInventoryAsync() does not initiate such an update, and so may return stale data, as described above.
Knowing the above can make testing more efficient and less confusing, because it allows one to deliberately trigger updating of the buffered data from the data that is available on the Google Play servers.