blob: 73d88e26c9875db4572fa85a1e8fa3fe705530a3 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/payments/content/android_payment_app_factory.h"
#include <memory>
#include <utility>
#include "base/containers/contains.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/test/gmock_callback_support.h"
#include "components/payments/content/android_app_communication.h"
#include "components/payments/content/android_app_communication_test_support.h"
#include "components/payments/content/mock_android_app_communication.h"
#include "components/payments/content/mock_payment_app_factory_delegate.h"
#include "components/payments/content/payment_app_factory.h"
#include "components/payments/content/payment_request_spec.h"
#include "components/payments/content/web_payments_web_data_service.h"
#include "components/payments/core/android_app_description.h"
#include "components/webauthn/core/browser/internal_authenticator.h"
#include "content/public/browser/web_contents.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"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
class BrowserContext;
} // namespace content
namespace payments {
namespace {
using base::test::RunOnceCallback;
// The scaffolding for testing the Android payment app factory.
class AndroidPaymentAppFactoryTest : public testing::Test {
public:
AndroidPaymentAppFactoryTest()
: mock_communication_(
std::make_unique<MockAndroidAppCommunication>(&context_)),
factory_(mock_communication_->GetWeakPtr()) {
auto method_data = mojom::PaymentMethodData::New();
method_data->supported_method = "https://play.google.com/billing";
method_data->stringified_data = "{}";
delegate_ = std::make_unique<MockPaymentAppFactoryDelegate>(
web_contents_factory_.CreateWebContents(&context_),
std::move(method_data));
}
protected:
content::BrowserTaskEnvironment task_environment_;
content::TestBrowserContext context_;
content::TestWebContentsFactory web_contents_factory_;
std::unique_ptr<MockPaymentAppFactoryDelegate> delegate_;
std::unique_ptr<MockAndroidAppCommunication> mock_communication_;
AndroidPaymentAppFactory factory_;
};
// This is a regression test for crbug.com/1414738. A mismatch in early-return
// checks could result in calling IsReadyToPay with a null RenderFrameHost in a
// loop - however the first call would end up deleting |this| and cause a UAF.
TEST_F(AndroidPaymentAppFactoryTest, NullRenderFrameHost) {
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(
base::test::RunOnceCallbackRepeatedly<0>("com.example.app"));
// In order to reach the problematic code, we need a null RenderFrameHost and
// also to be in off the record mode.
EXPECT_CALL(*delegate_, GetInitiatorRenderFrameHost)
.WillRepeatedly(testing::Return(nullptr));
delegate_->set_is_off_the_record();
// Return an app with multiple activities. This causes multiple iterations
// when looping over `single_activity_apps` - the UAF would trigger on the
// second iteration.
EXPECT_CALL(*mock_communication_, GetAppDescriptions)
.WillRepeatedly(
[](const std::string& twa_package_name,
MockAndroidAppCommunication::GetAppDescriptionsCallback callback) {
std::vector<std::unique_ptr<AndroidAppDescription>> apps;
apps.emplace_back(std::make_unique<AndroidAppDescription>());
apps.back()->package = "com.example.app";
apps.back()->service_names.push_back("com.example.app.Service");
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.example.app.Activity";
apps.back()->activities.back()->default_payment_method =
"https://play.google.com/billing";
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.example.app.Activity2";
apps.back()->activities.back()->default_payment_method =
"https://play.google.com/billing";
std::move(callback).Run(std::nullopt, std::move(apps));
});
// Now trigger app finding. This should near immediately bail in
// AppFinder::OnGetAppDescriptions and not make it to IsReadyToPay.
factory_.Create(delegate_->GetWeakPtr());
}
// This test class uses a deeper integration into the underlying app support,
// and as such some tests may only run on certain platforms (e.g., ChromeOS).
class AndroidPaymentAppFactoryIntegrationTest : public testing::Test {
public:
AndroidPaymentAppFactoryIntegrationTest()
: support_(AndroidAppCommunicationTestSupport::Create()),
factory_(GetCommunication(support_->context())) {
auto method_data = mojom::PaymentMethodData::New();
method_data->supported_method = "https://play.google.com/billing";
method_data->stringified_data = "{}";
delegate_ = std::make_unique<MockPaymentAppFactoryDelegate>(
web_contents_factory_.CreateWebContents(support_->context()),
std::move(method_data));
EXPECT_CALL(*delegate_, GetInitiatorRenderFrameHost())
.WillRepeatedly(testing::Return(
delegate_->GetWebContents()->GetPrimaryMainFrame()));
}
std::unique_ptr<AndroidAppCommunicationTestSupport> support_;
content::TestWebContentsFactory web_contents_factory_;
std::unique_ptr<MockPaymentAppFactoryDelegate> delegate_;
AndroidPaymentAppFactory factory_;
private:
// Returns the Android app communication that can be used in unit tests.
static base::WeakPtr<AndroidAppCommunication> GetCommunication(
content::BrowserContext* context) {
base::WeakPtr<AndroidAppCommunication> communication =
AndroidAppCommunication::GetForBrowserContext(context);
communication->SetForTesting();
return communication;
}
};
// The payment app factory should return an error if it's unable to invoke
// Android payment apps on a platform that supports such apps, e.g, when ARC is
// disabled on Chrome OS, Lacros cannot connect to payment app instance.
TEST_F(AndroidPaymentAppFactoryIntegrationTest,
FactoryReturnsErrorWithoutPaymentAppInstance) {
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(
base::test::RunOnceCallbackRepeatedly<0>("com.example.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(
support_->GetNoInstanceExpectedErrorString(),
AppCreationFailureReason::UNKNOWN))
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
EXPECT_CALL(*delegate_, OnPaymentAppCreated(testing::_)).Times(0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId()).Times(0);
support_->ExpectNoListOfPaymentAppsQuery();
support_->ExpectNoIsReadyToPayQuery();
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// The payment app factory should not return any errors when there're no Android
// payment apps available.
TEST_F(AndroidPaymentAppFactoryIntegrationTest, NoErrorsWhenNoApps) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(
base::test::RunOnceCallbackRepeatedly<0>("com.example.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(testing::_, testing::_))
.Times(0);
EXPECT_CALL(*delegate_, OnPaymentAppCreated(testing::_)).Times(0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId()).Times(0);
support_->ExpectQueryListOfPaymentAppsAndRespond({});
support_->ExpectNoIsReadyToPayQuery();
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// The |arg| is of type std::unique_ptr<PaymentApp>.
MATCHER_P3(PaymentAppMatches, type, package, method, "") {
return arg->type() == type && arg->GetId() == package &&
base::Contains(arg->GetAppMethodNames(), method);
}
// The payment app factory should return the TWA payment app when running in TWA
// mode, even when it does not have an IS_READY_TO_PAY service.
TEST_F(AndroidPaymentAppFactoryIntegrationTest,
FindAppsThatDoNotHaveReadyToPayService) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(
base::test::RunOnceCallbackRepeatedly<0>("com.example.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(testing::_, testing::_))
.Times(0);
EXPECT_CALL(*delegate_,
OnPaymentAppCreated(PaymentAppMatches(
PaymentApp::Type::NATIVE_MOBILE_APP, "com.example.app",
"https://play.google.com/billing")))
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId())
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
// This app does not have an IS_READY_TO_PAY service.
std::vector<std::unique_ptr<AndroidAppDescription>> apps;
apps.emplace_back(std::make_unique<AndroidAppDescription>());
apps.back()->package = "com.example.app";
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.example.app.Activity";
apps.back()->activities.back()->default_payment_method =
"https://play.google.com/billing";
support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
// There is no IS_READY_TO_PAY service to invoke.
support_->ExpectNoIsReadyToPayQuery();
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// The payment app factory should return one payment app and should not query
// the IS_READY_TO_PAY service, because of being off the record.
TEST_F(AndroidPaymentAppFactoryIntegrationTest,
DoNotQueryReadyToPaySericeWhenOffTheRecord) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
// Simulate being off the record.
delegate_->set_is_off_the_record();
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(
base::test::RunOnceCallbackRepeatedly<0>("com.example.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(testing::_, testing::_))
.Times(0);
EXPECT_CALL(*delegate_,
OnPaymentAppCreated(PaymentAppMatches(
PaymentApp::Type::NATIVE_MOBILE_APP, "com.example.app",
"https://play.google.com/billing")))
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId())
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
std::vector<std::unique_ptr<AndroidAppDescription>> apps;
apps.emplace_back(std::make_unique<AndroidAppDescription>());
apps.back()->package = "com.example.app";
apps.back()->service_names.push_back("com.example.app.Service");
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.example.app.Activity";
apps.back()->activities.back()->default_payment_method =
"https://play.google.com/billing";
support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
// The IS_READY_TO_PAY service should not be invoked when off the record.
support_->ExpectNoIsReadyToPayQuery();
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// The payment app factory should return the TWA payment app that returns true
// from IS_READY_TO_PAY service when running in TWA mode.
TEST_F(AndroidPaymentAppFactoryIntegrationTest,
FindTheTwaPaymentAppThatIsReadyToPayInTwaMode) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(base::test::RunOnceCallbackRepeatedly<0>("com.twa.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(testing::_, testing::_))
.Times(0);
EXPECT_CALL(*delegate_,
OnPaymentAppCreated(PaymentAppMatches(
PaymentApp::Type::NATIVE_MOBILE_APP, "com.twa.app",
"https://play.google.com/billing")))
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId())
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
std::vector<std::unique_ptr<AndroidAppDescription>> apps;
apps.emplace_back(std::make_unique<AndroidAppDescription>());
apps.back()->package = "com.twa.app";
apps.back()->service_names.push_back("com.twa.app.Service");
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.twa.app.Activity";
apps.back()->activities.back()->default_payment_method =
"https://play.google.com/billing";
support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
support_->ExpectQueryIsReadyToPayAndRespond(/*is_ready_to_pay=*/true);
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// The payment app factory should return no payment apps when IS_READY_TO_PAY
// service returns false.
TEST_F(AndroidPaymentAppFactoryIntegrationTest,
IgnoreAppsThatAreNotReadyToPay) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(
base::test::RunOnceCallbackRepeatedly<0>("com.example.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(testing::_, testing::_))
.Times(0);
EXPECT_CALL(*delegate_, OnPaymentAppCreated(testing::_)).Times(0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId()).Times(0);
std::vector<std::unique_ptr<AndroidAppDescription>> apps;
apps.emplace_back(std::make_unique<AndroidAppDescription>());
apps.back()->package = "com.example.app";
apps.back()->service_names.push_back("com.example.app.Service");
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.example.app.Activity";
apps.back()->activities.back()->default_payment_method =
"https://play.google.com/billing";
support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
support_->ExpectQueryIsReadyToPayAndRespond(/*is_ready_to_pay=*/false);
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// The payment app factory should return the correct TWA payment app out of two
// installed payment apps, when running in TWA mode.
TEST_F(AndroidPaymentAppFactoryIntegrationTest, FindTheCorrectTwaAppInTwaMode) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(
base::test::RunOnceCallbackRepeatedly<0>("com.correct-twa.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(testing::_, testing::_))
.Times(0);
EXPECT_CALL(*delegate_,
OnPaymentAppCreated(PaymentAppMatches(
PaymentApp::Type::NATIVE_MOBILE_APP, "com.correct-twa.app",
"https://play.google.com/billing")))
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
EXPECT_CALL(*delegate_,
OnPaymentAppCreated(PaymentAppMatches(
PaymentApp::Type::NATIVE_MOBILE_APP, "com.different.app",
"https://play.google.com/billing")))
.Times(0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId())
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
std::vector<std::unique_ptr<AndroidAppDescription>> apps;
apps.emplace_back(std::make_unique<AndroidAppDescription>());
apps.back()->package = "com.correct-twa.app";
apps.back()->service_names.push_back("com.correct-twa.app.Service");
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.correct-twa.app.Activity";
apps.back()->activities.back()->default_payment_method =
"https://play.google.com/billing";
apps.emplace_back(std::make_unique<AndroidAppDescription>());
apps.back()->package = "com.different.app";
apps.back()->service_names.push_back("com.different.app.Service");
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.different.app.Activity";
apps.back()->activities.back()->default_payment_method =
"https://play.google.com/billing";
support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
support_->ExpectQueryIsReadyToPayAndRespond(/*is_ready_to_pay=*/true);
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// The payment app factory does not return non-TWA payment apps when running in
// TWA mode.
TEST_F(AndroidPaymentAppFactoryIntegrationTest, IgnoreNonTwaAppsInTwaMode) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(base::test::RunOnceCallbackRepeatedly<0>("com.twa.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(testing::_, testing::_))
.Times(0);
EXPECT_CALL(*delegate_, OnPaymentAppCreated(testing::_)).Times(0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId()).Times(0);
std::vector<std::unique_ptr<AndroidAppDescription>> apps;
apps.emplace_back(std::make_unique<AndroidAppDescription>());
apps.back()->package = "com.non-twa.app";
apps.back()->service_names.push_back("com.non-twa.app.Service");
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.non-twa.app.Activity";
apps.back()->activities.back()->default_payment_method =
"https://play.google.com/billing";
support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
support_->ExpectNoIsReadyToPayQuery();
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// The payment app factory does not return any payment apps when not running
// inside of TWA.
TEST_F(AndroidPaymentAppFactoryIntegrationTest,
DoNotLookForAppsWhenOutsideOfTwaMode) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(base::test::RunOnceCallbackRepeatedly<0>(""));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(testing::_, testing::_))
.Times(0);
EXPECT_CALL(*delegate_, OnPaymentAppCreated(testing::_)).Times(0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId()).Times(0);
support_->ExpectNoListOfPaymentAppsQuery();
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// The Android payment app factory works only with TWA specific payment methods.
TEST_F(AndroidPaymentAppFactoryIntegrationTest,
DoNotLookForAppsForNonTwaMethod) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
// "https://example.test" is not a TWA specific payment method.
auto method_data = mojom::PaymentMethodData::New();
method_data->supported_method = "https://example.test";
method_data->stringified_data = "{}";
delegate_->SetRequestedPaymentMethod(std::move(method_data));
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(
base::test::RunOnceCallbackRepeatedly<0>("com.example.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(testing::_, testing::_))
.Times(0);
EXPECT_CALL(*delegate_, OnPaymentAppCreated(testing::_)).Times(0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId()).Times(0);
support_->ExpectNoListOfPaymentAppsQuery();
support_->ExpectNoIsReadyToPayQuery();
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// If the TWA supports a non-TWA-specific payment method, then it should be
// ignored.
TEST_F(AndroidPaymentAppFactoryIntegrationTest, IgnoreNonTwaMethodInTheTwa) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(base::test::RunOnceCallbackRepeatedly<0>("com.twa.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(testing::_, testing::_))
.Times(0);
EXPECT_CALL(*delegate_, OnPaymentAppCreated(testing::_)).Times(0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId()).Times(0);
std::vector<std::unique_ptr<AndroidAppDescription>> apps;
apps.emplace_back(std::make_unique<AndroidAppDescription>());
apps.back()->package = "com.twa.app";
apps.back()->service_names.push_back("com.twa.app.Service");
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.twa.app.Activity";
apps.back()->activities.back()->default_payment_method =
"https://example.test";
support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
support_->ExpectNoIsReadyToPayQuery();
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// If the TWA supports both a TWA-specific and a non-TWA-specific payment
// method, then only the TWA-specific payment method activity should be
// returned.
TEST_F(AndroidPaymentAppFactoryIntegrationTest,
FindOnlyActivitiesWithTwaSpecificMethodName) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(base::test::RunOnceCallbackRepeatedly<0>("com.twa.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_, OnPaymentAppCreationError(testing::_, testing::_))
.Times(0);
EXPECT_CALL(*delegate_,
OnPaymentAppCreated(PaymentAppMatches(
PaymentApp::Type::NATIVE_MOBILE_APP, "com.twa.app",
"https://play.google.com/billing")))
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
EXPECT_CALL(*delegate_, OnPaymentAppCreated(PaymentAppMatches(
PaymentApp::Type::NATIVE_MOBILE_APP,
"com.twa.app", "https://example.test")))
.Times(0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId())
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
std::vector<std::unique_ptr<AndroidAppDescription>> apps;
apps.emplace_back(std::make_unique<AndroidAppDescription>());
apps.back()->package = "com.twa.app";
apps.back()->service_names.push_back("com.twa.app.Service");
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.twa.app.ActivityOne";
apps.back()->activities.back()->default_payment_method =
"https://play.google.com/billing";
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.twa.app.ActivityTwo";
apps.back()->activities.back()->default_payment_method =
"https://example.test";
support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
support_->ExpectQueryIsReadyToPayAndRespond(/*is_ready_to_pay=*/true);
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
// At most one IS_READY_TO_PAY service is allowed in an Android payment app.
TEST_F(AndroidPaymentAppFactoryIntegrationTest,
ReturnErrorWhenMoreThanOneServiceInApp) {
// Enable invoking Android payment apps on those platforms that support it.
auto scoped_initialization_ = support_->CreateScopedInitialization();
EXPECT_CALL(*delegate_, GetTwaPackageName)
.WillRepeatedly(
base::test::RunOnceCallbackRepeatedly<0>("com.example.app"));
base::RunLoop runloop;
EXPECT_CALL(*delegate_, OnDoneCreatingPaymentApps()).WillOnce([&runloop] {
runloop.Quit();
});
EXPECT_CALL(*delegate_,
OnPaymentAppCreationError(
"Found more than one IS_READY_TO_PAY service, but "
"at most one service is supported.",
AppCreationFailureReason::UNKNOWN))
.Times(support_->AreAndroidAppsSupportedOnThisPlatform() ? 1 : 0);
EXPECT_CALL(*delegate_, OnPaymentAppCreated(testing::_)).Times(0);
EXPECT_CALL(*delegate_, GetChromeOSTWAInstanceId()).Times(0);
std::vector<std::unique_ptr<AndroidAppDescription>> apps;
apps.emplace_back(std::make_unique<AndroidAppDescription>());
apps.back()->package = "com.example.app";
// Two IS_READY_TO_PAY services:
apps.back()->service_names.push_back("com.example.app.ServiceOne");
apps.back()->service_names.push_back("com.example.app.ServiceTwo");
apps.back()->activities.emplace_back(
std::make_unique<AndroidActivityDescription>());
apps.back()->activities.back()->name = "com.example.app.Activity";
apps.back()->activities.back()->default_payment_method =
"https://play.google.com/billing";
support_->ExpectQueryListOfPaymentAppsAndRespond(std::move(apps));
support_->ExpectNoIsReadyToPayQuery();
factory_.Create(delegate_->GetWeakPtr());
runloop.Run();
}
} // namespace
} // namespace payments