diff options
| author | Rodney Dawes <rodney.dawes@canonical.com> | 2016-01-13 11:56:09 -0500 |
|---|---|---|
| committer | Rodney Dawes <rodney.dawes@canonical.com> | 2016-01-13 11:56:09 -0500 |
| commit | a67cfcc43c36ca090e3e4032573cfac1783bd485 (patch) | |
| tree | ce5b4ae9d54f85b29653be54549db90ffdfb41ec | |
| parent | 76328f2a1afeed98415ed3dc285632ff249b9f3b (diff) | |
Handle return to UNKNOWN state in libpay observer.libpaybackend
This is how libpay notifies of an error to the observer. We handle this by
notifying that the purchase failed. This also cleans up the code to use a
switch statement instead of ifs, with a critical log message for unexpected
status transitions.
Signed-off-by: Rodney Dawes <rodney.dawes@canonical.com>
| -rw-r--r-- | src/purchasing/inapppurchase/ubuntu/qubuntuinapppurchasebackend.cpp | 23 | ||||
| -rw-r--r-- | tests/auto/purchasing/ubuntu/tst_qinappstore_ubuntu.cpp | 86 |
2 files changed, 98 insertions, 11 deletions
diff --git a/src/purchasing/inapppurchase/ubuntu/qubuntuinapppurchasebackend.cpp b/src/purchasing/inapppurchase/ubuntu/qubuntuinapppurchasebackend.cpp index cc3c556..a879e77 100644 --- a/src/purchasing/inapppurchase/ubuntu/qubuntuinapppurchasebackend.cpp +++ b/src/purchasing/inapppurchase/ubuntu/qubuntuinapppurchasebackend.cpp @@ -208,19 +208,22 @@ void QUbuntuInAppPurchaseBackend::itemObserver(const QString &sku, if (prev == PAY_PACKAGE_ITEM_STATUS_PURCHASING) { - if ((status == PAY_PACKAGE_ITEM_STATUS_APPROVED) || - (status == PAY_PACKAGE_ITEM_STATUS_PURCHASED)) - { - auto item = pay_package_get_item(m_package.data(), qUtf8Printable(sku)); + auto item = pay_package_get_item(m_package.data(), qUtf8Printable(sku)); + + switch (status) { + case PAY_PACKAGE_ITEM_STATUS_APPROVED: + case PAY_PACKAGE_ITEM_STATUS_PURCHASED: emitTransactionReadyForItem(item, QInAppTransaction::PurchaseApproved); - pay_item_unref(item); - } - else if (status == PAY_PACKAGE_ITEM_STATUS_NOT_PURCHASED) - { - auto item = pay_package_get_item(m_package.data(), qUtf8Printable(sku)); + break; + case PAY_PACKAGE_ITEM_STATUS_NOT_PURCHASED: + case PAY_PACKAGE_ITEM_STATUS_UNKNOWN: emitTransactionReadyForItem(item, QInAppTransaction::PurchaseFailed); - pay_item_unref(item); + break; + default: + qCritical() << "Unexpected status transition to:" << status; + break; } + pay_item_unref(item); } m_statuses[sku] = status; diff --git a/tests/auto/purchasing/ubuntu/tst_qinappstore_ubuntu.cpp b/tests/auto/purchasing/ubuntu/tst_qinappstore_ubuntu.cpp index 6eae435..adf6cee 100644 --- a/tests/auto/purchasing/ubuntu/tst_qinappstore_ubuntu.cpp +++ b/tests/auto/purchasing/ubuntu/tst_qinappstore_ubuntu.cpp @@ -71,6 +71,8 @@ private slots: void registeredProducts(); void restorePurchases(); void successfulPurchase(); + void purchaseCancelled(); + void purchaseAccessDenied(); private: @@ -91,7 +93,9 @@ private: QMap<QString,IAP> m_iaps { { "sword", { 0, 0, 0, "available", "$1", QInAppProduct::Consumable, "sword", "Sword", "A Sword." } }, { "shield", { 1000, 0, 100, "approved", "$1", QInAppProduct::Unlockable, "shield", "Shield", "A Shield." } }, - { "amulet", { 1000, 1010, 101, "purchased", "$1", QInAppProduct::Unlockable, "amulet", "Amulet", "An Amulet." } } + { "amulet", { 1000, 1010, 101, "purchased", "$1", QInAppProduct::Unlockable, "amulet", "Amulet", "An Amulet." } }, + { "cancel", { 0, 0, 0, "available", "$0", QInAppProduct::Unlockable, "cancel", "Cancel", "For testing cancelling of purchase." } }, + { "denied", { 0, 0, 0, "available", "$0", QInAppProduct::Unlockable, "denied", "Denied", "For testing access denied by trust store." } } }; void verifyProduct(const QInAppProduct *product, const IAP item) { @@ -333,6 +337,86 @@ void tst_QInAppStore::successfulPurchase() QCOMPARE(finalizedSku, sku); } +void tst_QInAppStore::purchaseCancelled() +{ + // SETUP + + StoreMock mock (PACKAGE_S, storeItems()); + + // instantiate a store with the registered products + QInAppStore store(this); + for (const auto &item : m_iaps) + store.registerProduct(item.type, item.sku); + + // Set our expectations. + + const int expectedRegistered = 0; + const int expectedUnknown = 0; + const int expectedReady = 1; + const auto sku = QString::fromUtf8("cancel"); + const auto expectedTimeStamp = QDateTime::currentDateTime(); + + // TEST: PURCHASE + + QSignalSpy registered (&store, SIGNAL(productRegistered(QInAppProduct *))); + QSignalSpy unknown (&store, SIGNAL(productUnknown(QInAppProduct::ProductType,QString))); + QSignalSpy ready (&store, SIGNAL(transactionReady(QInAppTransaction *))); + + auto product = store.registeredProduct(sku); + QVERIFY(product != nullptr); + product->purchase(); + + QTRY_COMPARE (ready.length(), expectedReady); + QCOMPARE (registered.length(), expectedRegistered); + QCOMPARE (unknown.length(), expectedUnknown); + auto transaction = ready.at(0).at(0).value<QInAppTransaction *>(); + QVERIFY (transaction->errorString().isEmpty()); + QCOMPARE (transaction->failureReason(), QInAppTransaction::NoFailure); + QVERIFY (transaction->orderId() != 0); + verifyProduct(transaction->product(), m_iaps[sku]); + QCOMPARE (transaction->status(), QInAppTransaction::PurchaseFailed); +} + +void tst_QInAppStore::purchaseAccessDenied() +{ + // SETUP + + StoreMock mock (PACKAGE_S, storeItems()); + + // instantiate a store with the registered products + QInAppStore store(this); + for (const auto &item : m_iaps) + store.registerProduct(item.type, item.sku); + + // Set our expectations. + + const int expectedRegistered = 0; + const int expectedUnknown = 0; + const int expectedReady = 1; + const auto sku = QString::fromUtf8("denied"); + const auto expectedTimeStamp = QDateTime::currentDateTime(); + + // TEST: PURCHASE + + QSignalSpy registered (&store, SIGNAL(productRegistered(QInAppProduct *))); + QSignalSpy unknown (&store, SIGNAL(productUnknown(QInAppProduct::ProductType,QString))); + QSignalSpy ready (&store, SIGNAL(transactionReady(QInAppTransaction *))); + + auto product = store.registeredProduct(sku); + QVERIFY(product != nullptr); + product->purchase(); + + QTRY_COMPARE (ready.length(), expectedReady); + QCOMPARE (registered.length(), expectedRegistered); + QCOMPARE (unknown.length(), expectedUnknown); + auto transaction = ready.at(0).at(0).value<QInAppTransaction *>(); + QVERIFY (transaction->errorString().isEmpty()); + QCOMPARE (transaction->failureReason(), QInAppTransaction::NoFailure); + QVERIFY (transaction->orderId() != 0); + verifyProduct(transaction->product(), m_iaps[sku]); + QCOMPARE (transaction->status(), QInAppTransaction::PurchaseFailed); +} + QTEST_GUILESS_MAIN(tst_QInAppStore) |
