summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRodney Dawes <rodney.dawes@canonical.com>2016-01-13 11:56:09 -0500
committerRodney Dawes <rodney.dawes@canonical.com>2016-01-13 11:56:09 -0500
commita67cfcc43c36ca090e3e4032573cfac1783bd485 (patch)
treece5b4ae9d54f85b29653be54549db90ffdfb41ec
parent76328f2a1afeed98415ed3dc285632ff249b9f3b (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.cpp23
-rw-r--r--tests/auto/purchasing/ubuntu/tst_qinappstore_ubuntu.cpp86
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)