[SPC] Add SecurePaymentConfirmationAppFactory tests for handling icons
This CL adds a new test class,
SecurePaymentConfirmationAppFactoryNetworkAndIssuerIconsTest,
to secure_payment_confirmation_app_factory_unittest.cc, which
triggers creation of a SecureConfirmationPaymentApp and verifies
that the networkInfo and issuerInfo fields are correctly handled.
A future CL will add testing for the new paymentEntitiesLogos field.
Bug: 417683819
Change-Id: I33353ff94b196362fefa208c3571b3fc693f5191
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6575767
Commit-Queue: Stephen McGruer <smcgruer@chromium.org>
Reviewed-by: Slobodan Pejic <slobodan@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1467090}
diff --git a/components/payments/content/mock_payment_manifest_web_data_service.h b/components/payments/content/mock_payment_manifest_web_data_service.h
index 608d7c9..c3283eb8 100644
--- a/components/payments/content/mock_payment_manifest_web_data_service.h
+++ b/components/payments/content/mock_payment_manifest_web_data_service.h
@@ -18,6 +18,13 @@
class MockPaymentManifestWebDataService : public PaymentManifestWebDataService {
public:
MockPaymentManifestWebDataService();
+
+ MOCK_METHOD(WebDataServiceBase::Handle,
+ GetSecurePaymentConfirmationCredentials,
+ (std::vector<std::vector<uint8_t>> credential_ids,
+ const std::string& relying_party_id,
+ WebDataServiceConsumer* consumer),
+ (override));
MOCK_METHOD(void,
ClearSecurePaymentConfirmationCredentials,
(base::Time begin, base::Time end, base::OnceClosure callback),
diff --git a/components/payments/content/payment_manifest_web_data_service.h b/components/payments/content/payment_manifest_web_data_service.h
index 5ac52ee5..e731480 100644
--- a/components/payments/content/payment_manifest_web_data_service.h
+++ b/components/payments/content/payment_manifest_web_data_service.h
@@ -71,7 +71,7 @@
// `credential_ids` and returns it to the `consumer`, which must outlive the
// DB operation, because DB tasks cannot be cancelled. Please use
// `std::move()` for `credential_ids` parameter to avoid extra copies.
- WebDataServiceBase::Handle GetSecurePaymentConfirmationCredentials(
+ virtual WebDataServiceBase::Handle GetSecurePaymentConfirmationCredentials(
std::vector<std::vector<uint8_t>> credential_ids,
const std::string& relying_party_id,
WebDataServiceConsumer* consumer);
diff --git a/components/payments/content/secure_payment_confirmation_app_factory.cc b/components/payments/content/secure_payment_confirmation_app_factory.cc
index 12bfcb7dd..587905b 100644
--- a/components/payments/content/secure_payment_confirmation_app_factory.cc
+++ b/components/payments/content/secure_payment_confirmation_app_factory.cc
@@ -413,13 +413,6 @@
delegate->OnDoneCreatingPaymentApps();
}
-#if BUILDFLAG(IS_ANDROID)
-void SecurePaymentConfirmationAppFactory::SetBrowserBoundKeyStoreForTesting(
- scoped_refptr<BrowserBoundKeyStore> key_store) {
- browser_bound_key_store_for_testing_ = std::move(key_store);
-}
-#endif // BUILDFLAG(IS_ANDROID)
-
void SecurePaymentConfirmationAppFactory::OnWebDataServiceRequestDone(
WebDataServiceBase::Handle handle,
std::unique_ptr<WDTypedResult> result) {
@@ -446,6 +439,13 @@
}
}
+#if BUILDFLAG(IS_ANDROID)
+void SecurePaymentConfirmationAppFactory::SetBrowserBoundKeyStoreForTesting(
+ scoped_refptr<BrowserBoundKeyStore> key_store) {
+ browser_bound_key_store_for_testing_ = std::move(key_store);
+}
+#endif // BUILDFLAG(IS_ANDROID)
+
void SecurePaymentConfirmationAppFactory::OnGetMatchingCredentialIdsFromStore(
std::unique_ptr<Request> request,
std::string relying_party_id,
diff --git a/components/payments/content/secure_payment_confirmation_app_factory.h b/components/payments/content/secure_payment_confirmation_app_factory.h
index ec18bd4..337bd5d 100644
--- a/components/payments/content/secure_payment_confirmation_app_factory.h
+++ b/components/payments/content/secure_payment_confirmation_app_factory.h
@@ -34,6 +34,11 @@
// PaymentAppFactory:
void Create(base::WeakPtr<Delegate> delegate) override;
+ // WebDataServiceConsumer:
+ void OnWebDataServiceRequestDone(
+ WebDataServiceBase::Handle handle,
+ std::unique_ptr<WDTypedResult> result) override;
+
#if BUILDFLAG(IS_ANDROID)
void SetBrowserBoundKeyStoreForTesting(
scoped_refptr<BrowserBoundKeyStore> key_store);
@@ -42,11 +47,6 @@
private:
struct Request;
- // WebDataServiceConsumer:
- void OnWebDataServiceRequestDone(
- WebDataServiceBase::Handle handle,
- std::unique_ptr<WDTypedResult> result) override;
-
void OnIsUserVerifyingPlatformAuthenticatorAvailable(
std::unique_ptr<Request> request,
bool is_available);
diff --git a/components/payments/content/secure_payment_confirmation_app_factory_unittest.cc b/components/payments/content/secure_payment_confirmation_app_factory_unittest.cc
index 3bb0a6b..fb49fb2 100644
--- a/components/payments/content/secure_payment_confirmation_app_factory_unittest.cc
+++ b/components/payments/content/secure_payment_confirmation_app_factory_unittest.cc
@@ -18,7 +18,9 @@
#include "components/payments/content/mock_payment_manifest_web_data_service.h"
#include "components/payments/core/features.h"
#include "components/payments/core/native_error_strings.h"
+#include "components/payments/core/secure_payment_confirmation_credential.h"
#include "components/webauthn/core/browser/mock_internal_authenticator.h"
+#include "components/webdata/common/web_data_results.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_browser_context.h"
#include "content/public/test/test_web_contents_factory.h"
@@ -46,11 +48,14 @@
using ::testing::Return;
using ::testing::ReturnRef;
-static constexpr char kChallengeBase64[] = "aaaa";
-static constexpr char kCredentialIdBase64[] = "cccc";
+constexpr std::string kRpId = "rp.example";
+constexpr char kChallengeBase64[] = "aaaa";
+constexpr char kCredentialIdBase64[] = "cccc";
class SecurePaymentConfirmationAppFactoryTest : public testing::Test {
protected:
+ const GURL kInstrumentIconUrl = GURL("https://site.example/icon.png");
+
SecurePaymentConfirmationAppFactoryTest()
: os_crypt_(os_crypt_async::GetTestOSCryptAsyncForTesting(
/*is_sync_for_unittests=*/true)),
@@ -78,13 +83,14 @@
std::vector<uint8_t>(challenge_bytes_.begin(), challenge_bytes_.end());
spc_request->instrument = blink::mojom::PaymentCredentialInstrument::New();
spc_request->instrument->display_name = "1234";
- spc_request->instrument->icon = GURL("https://site.example/icon.png");
+ spc_request->instrument->icon = kInstrumentIconUrl;
spc_request->payee_origin =
url::Origin::Create(GURL("https://merchant.example"));
- spc_request->rp_id = "rp.example";
+ spc_request->rp_id = kRpId;
return spc_request;
}
+
content::BrowserTaskEnvironment task_environment_;
std::unique_ptr<os_crypt_async::OSCryptAsync> os_crypt_;
content::TestBrowserContext context_;
@@ -521,6 +527,244 @@
secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
}
+// Class wrapping tests relating to the network and issuer icons support in
+// SecurePaymentConfirmationAppFactory.
+class SecurePaymentConfirmationAppFactoryNetworkAndIssuerIconsTest
+ : public SecurePaymentConfirmationAppFactoryTest {
+ protected:
+ const GURL kIssuerIconUrl = GURL("https://issuer.example/icon.png");
+ const GURL kNetworkIconUrl = GURL("https://network.example/icon.png");
+ const WebDataServiceBase::Handle kWebDataServiceHandle = 1234;
+
+ SecurePaymentConfirmationAppFactoryNetworkAndIssuerIconsTest() {
+ // For test setup simplicity, force tests in this fixture to use the (mocked
+ // out) database storage path.
+ feature_list_.InitAndDisableFeature(
+ features::kSecurePaymentConfirmationUseCredentialStoreAPIs);
+ }
+
+ void SetUp() override {
+ SecurePaymentConfirmationAppFactoryTest::SetUp();
+
+ mock_authenticator_ =
+ std::make_unique<webauthn::MockInternalAuthenticator>(web_contents_);
+ EXPECT_CALL(*mock_authenticator_,
+ IsUserVerifyingPlatformAuthenticatorAvailable(_))
+ .WillOnce(RunOnceCallback<0>(true));
+
+ mock_service_ = base::MakeRefCounted<MockPaymentManifestWebDataService>();
+ EXPECT_CALL(*mock_service_,
+ GetSecurePaymentConfirmationCredentials(_, _, _))
+ .WillOnce(Return(kWebDataServiceHandle));
+ }
+
+ std::unique_ptr<MockPaymentAppFactoryDelegate> CreateMockDelegate(
+ mojom::PaymentMethodDataPtr method_data) {
+ auto mock_delegate = std::make_unique<MockPaymentAppFactoryDelegate>(
+ web_contents_, std::move(method_data));
+ EXPECT_CALL(*mock_delegate, CreateInternalAuthenticator())
+ .WillOnce(Return(ByMove(std::move(mock_authenticator_))));
+ EXPECT_CALL(*mock_delegate, GetPaymentManifestWebDataService())
+ .WillRepeatedly(Return(mock_service_));
+
+ return mock_delegate;
+ }
+
+ void FakeCredentialFetchedFromDatabase(std::string credential_id_bytes) {
+ std::vector<std::unique_ptr<SecurePaymentConfirmationCredential>>
+ credentials;
+ std::vector<uint8_t> credential_id(credential_id_bytes.begin(),
+ credential_id_bytes.end());
+ credentials.emplace_back(
+ std::make_unique<SecurePaymentConfirmationCredential>(
+ std::move(credential_id), kRpId,
+ /*user_id=*/std::vector<uint8_t>()));
+
+ std::unique_ptr<WDTypedResult> result = std::make_unique<WDResult<
+ std::vector<std::unique_ptr<SecurePaymentConfirmationCredential>>>>(
+ SECURE_PAYMENT_CONFIRMATION, std::move(credentials));
+
+ secure_payment_confirmation_app_factory_->OnWebDataServiceRequestDone(
+ kWebDataServiceHandle, std::move(result));
+ }
+
+ void FakeImageDownloaded(GURL image_url, bool succeeded = true) {
+ std::vector<gfx::Size> icon_sizes({{32, 32}});
+ std::vector<SkBitmap> icon_bitmaps;
+ if (succeeded) {
+ icon_bitmaps.emplace_back();
+ icon_bitmaps[0].allocN32Pixels(/*width=*/32, /*height=*/32);
+ }
+
+ ASSERT_TRUE(static_cast<content::TestWebContents*>(web_contents_.get())
+ ->TestDidDownloadImage(image_url, /*https_status_code=*/200,
+ std::move(icon_bitmaps),
+ std::move(icon_sizes)));
+ }
+
+ std::unique_ptr<webauthn::MockInternalAuthenticator> mock_authenticator_;
+ scoped_refptr<MockPaymentManifestWebDataService> mock_service_;
+ base::test::ScopedFeatureList feature_list_;
+};
+
+// Tests that when neither the network nor issuer icons are specified, they are
+// not present on the final PaymentApp.
+TEST_F(SecurePaymentConfirmationAppFactoryNetworkAndIssuerIconsTest,
+ NoIconsSpecified) {
+ auto method_data = mojom::PaymentMethodData::New();
+ method_data->supported_method = "secure-payment-confirmation";
+ method_data->secure_payment_confirmation =
+ CreateSecurePaymentConfirmationRequest();
+
+ std::unique_ptr<MockPaymentAppFactoryDelegate> mock_delegate =
+ CreateMockDelegate(std::move(method_data));
+
+ std::unique_ptr<PaymentApp> created_payment_app;
+ EXPECT_CALL(*mock_delegate, OnPaymentAppCreated(_))
+ .WillOnce(MoveArg<0>(&created_payment_app));
+
+ secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
+
+ FakeCredentialFetchedFromDatabase(credential_id_bytes_);
+ FakeImageDownloaded(kInstrumentIconUrl);
+
+ ASSERT_TRUE(created_payment_app);
+ EXPECT_FALSE(created_payment_app->issuer_bitmap());
+ EXPECT_FALSE(created_payment_app->network_bitmap());
+}
+
+TEST_F(SecurePaymentConfirmationAppFactoryNetworkAndIssuerIconsTest,
+ NetworkIcon) {
+ auto method_data = mojom::PaymentMethodData::New();
+ method_data->supported_method = "secure-payment-confirmation";
+ mojom::SecurePaymentConfirmationRequestPtr spc_request =
+ CreateSecurePaymentConfirmationRequest();
+ spc_request->network_info = mojom::NetworkOrIssuerInformation::New();
+ spc_request->network_info->name = "Network Name";
+ spc_request->network_info->icon = kNetworkIconUrl;
+ method_data->secure_payment_confirmation = std::move(spc_request);
+
+ std::unique_ptr<MockPaymentAppFactoryDelegate> mock_delegate =
+ CreateMockDelegate(std::move(method_data));
+
+ std::unique_ptr<PaymentApp> created_payment_app;
+ EXPECT_CALL(*mock_delegate, OnPaymentAppCreated(_))
+ .WillOnce(MoveArg<0>(&created_payment_app));
+
+ secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
+
+ FakeCredentialFetchedFromDatabase(credential_id_bytes_);
+ FakeImageDownloaded(kInstrumentIconUrl);
+ FakeImageDownloaded(kNetworkIconUrl);
+
+ // This payment app should have been created with a network icon but not an
+ // issuer one.
+ ASSERT_TRUE(created_payment_app);
+ EXPECT_TRUE(created_payment_app->network_bitmap());
+ EXPECT_FALSE(created_payment_app->issuer_bitmap());
+}
+
+TEST_F(SecurePaymentConfirmationAppFactoryNetworkAndIssuerIconsTest,
+ IssuerIcon) {
+ auto method_data = mojom::PaymentMethodData::New();
+ method_data->supported_method = "secure-payment-confirmation";
+ mojom::SecurePaymentConfirmationRequestPtr spc_request =
+ CreateSecurePaymentConfirmationRequest();
+ spc_request->issuer_info = mojom::NetworkOrIssuerInformation::New();
+ spc_request->issuer_info->name = "Issuer Name";
+ spc_request->issuer_info->icon = kIssuerIconUrl;
+ method_data->secure_payment_confirmation = std::move(spc_request);
+
+ std::unique_ptr<MockPaymentAppFactoryDelegate> mock_delegate =
+ CreateMockDelegate(std::move(method_data));
+
+ std::unique_ptr<PaymentApp> created_payment_app;
+ EXPECT_CALL(*mock_delegate, OnPaymentAppCreated(_))
+ .WillOnce(MoveArg<0>(&created_payment_app));
+
+ secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
+
+ FakeCredentialFetchedFromDatabase(credential_id_bytes_);
+ FakeImageDownloaded(kInstrumentIconUrl);
+ FakeImageDownloaded(kIssuerIconUrl);
+
+ // This payment app should have been created with an issuer icon but not a
+ // network one.
+ ASSERT_TRUE(created_payment_app);
+ EXPECT_FALSE(created_payment_app->network_bitmap());
+ EXPECT_TRUE(created_payment_app->issuer_bitmap());
+}
+
+TEST_F(SecurePaymentConfirmationAppFactoryNetworkAndIssuerIconsTest,
+ NetworkAndIssuerIcon) {
+ auto method_data = mojom::PaymentMethodData::New();
+ method_data->supported_method = "secure-payment-confirmation";
+ mojom::SecurePaymentConfirmationRequestPtr spc_request =
+ CreateSecurePaymentConfirmationRequest();
+ spc_request->network_info = mojom::NetworkOrIssuerInformation::New();
+ spc_request->network_info->name = "Network Name";
+ spc_request->network_info->icon = kNetworkIconUrl;
+ spc_request->issuer_info = mojom::NetworkOrIssuerInformation::New();
+ spc_request->issuer_info->name = "Issuer Name";
+ spc_request->issuer_info->icon = kIssuerIconUrl;
+ method_data->secure_payment_confirmation = std::move(spc_request);
+
+ std::unique_ptr<MockPaymentAppFactoryDelegate> mock_delegate =
+ CreateMockDelegate(std::move(method_data));
+
+ std::unique_ptr<PaymentApp> created_payment_app;
+ EXPECT_CALL(*mock_delegate, OnPaymentAppCreated(_))
+ .WillOnce(MoveArg<0>(&created_payment_app));
+
+ secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
+
+ FakeCredentialFetchedFromDatabase(credential_id_bytes_);
+ FakeImageDownloaded(kInstrumentIconUrl);
+ FakeImageDownloaded(kNetworkIconUrl);
+ FakeImageDownloaded(kIssuerIconUrl);
+
+ // This payment app should have been created with both a network and issuer
+ // icon.
+ ASSERT_TRUE(created_payment_app);
+ EXPECT_TRUE(created_payment_app->network_bitmap());
+ EXPECT_TRUE(created_payment_app->issuer_bitmap());
+}
+
+TEST_F(SecurePaymentConfirmationAppFactoryNetworkAndIssuerIconsTest,
+ NetworkAndIssuerIcon_DownloadFails) {
+ auto method_data = mojom::PaymentMethodData::New();
+ method_data->supported_method = "secure-payment-confirmation";
+ mojom::SecurePaymentConfirmationRequestPtr spc_request =
+ CreateSecurePaymentConfirmationRequest();
+ spc_request->network_info = mojom::NetworkOrIssuerInformation::New();
+ spc_request->network_info->name = "Network Name";
+ spc_request->network_info->icon = kNetworkIconUrl;
+ spc_request->issuer_info = mojom::NetworkOrIssuerInformation::New();
+ spc_request->issuer_info->name = "Issuer Name";
+ spc_request->issuer_info->icon = kIssuerIconUrl;
+ method_data->secure_payment_confirmation = std::move(spc_request);
+
+ std::unique_ptr<MockPaymentAppFactoryDelegate> mock_delegate =
+ CreateMockDelegate(std::move(method_data));
+
+ std::unique_ptr<PaymentApp> created_payment_app;
+ EXPECT_CALL(*mock_delegate, OnPaymentAppCreated(_))
+ .WillOnce(MoveArg<0>(&created_payment_app));
+
+ secure_payment_confirmation_app_factory_->Create(mock_delegate->GetWeakPtr());
+
+ FakeCredentialFetchedFromDatabase(credential_id_bytes_);
+ FakeImageDownloaded(kInstrumentIconUrl);
+ FakeImageDownloaded(kNetworkIconUrl, /*succeeded=*/false);
+ FakeImageDownloaded(kIssuerIconUrl);
+
+ // The resultant payment app should have been created with only an issuer
+ // icon.
+ ASSERT_TRUE(created_payment_app);
+ EXPECT_FALSE(created_payment_app->network_bitmap());
+ EXPECT_TRUE(created_payment_app->issuer_bitmap());
+}
+
// TODO(crbug.com/417683819): Add tests verifying that paymentEntitiesLogos is
// correctly converted into icons to be downloaded.