chromium/chrome/browser/ash/crosapi/payment_app_instance_ash_unittest.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/crosapi/payment_app_instance_ash.h"

#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "ash/components/arc/test/arc_payment_app_bridge_test_support.h"
#include "ash/public/cpp/external_arc/overlay/test/test_arc_overlay_manager.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "base/unguessable_token.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/components/payments/mojom/payment_app.mojom.h"
#include "chromeos/components/payments/mojom/payment_app_types.mojom-forward.h"
#include "components/payments/core/android_app_description.h"
#include "components/services/app_service/public/cpp/instance_registry.h"
#include "components/services/app_service/public/cpp/instance_update.h"
#include "content/public/browser/web_contents.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"

namespace payments {
namespace {

class PaymentAppInstanceAshTest : public testing::Test {
 public:
  void SetUp() override {
    payment_app_instance_ash_ =
        std::make_unique<crosapi::PaymentAppInstanceAsh>();
    payment_app_instance_ash_->BindReceiver(
        payment_app_instance_remote_.BindNewPipeAndPassReceiver());
    scoped_set_instance_ = support_.CreateScopedSetInstance();
    payment_app_instance_ash_->SetPaymentAppServiceForTesting(
        arc::ArcPaymentAppBridge::GetForBrowserContextForTesting(
            support_.context()));
    payment_app_instance_ash_->SetInstanceRegistryForTesting(
        &instance_registry_);
  }
  base::UnguessableToken CreateTWAInstance() {
    aura::Window window(nullptr);
    window.Init(ui::LAYER_NOT_DRAWN);
    instance_registry_.CreateOrUpdateInstance(
        apps::InstanceParams("twa_app_id", &window));
    base::UnguessableToken twa_instance_id;
    instance_registry_.ForInstancesWithWindow(
        &window, [&twa_instance_id](const apps::InstanceUpdate& update) {
          twa_instance_id = update.InstanceId();
        });
    return twa_instance_id;
  }

 protected:
  arc::ArcPaymentAppBridgeTestSupport support_;
  mojo::Remote<chromeos::payments::mojom::PaymentAppInstance>
      payment_app_instance_remote_;
  std::unique_ptr<crosapi::PaymentAppInstanceAsh> payment_app_instance_ash_;
  std::unique_ptr<arc::ArcPaymentAppBridgeTestSupport::ScopedSetInstance>
      scoped_set_instance_;
  ash::TestArcOverlayManager overlay_manager_;
  apps::InstanceRegistry instance_registry_;
};

TEST_F(PaymentAppInstanceAshTest, IsPaymentImplemented) {
  EXPECT_CALL(*support_.instance(),
              IsPaymentImplemented(testing::_, testing::_))
      .WillOnce([](const std::string& package_name,
                   arc::ArcPaymentAppBridge::IsPaymentImplementedCallback
                       callback) {
        auto valid =
            chromeos::payments::mojom::IsPaymentImplementedValidResult::New();
        valid->activity_names.push_back("com.example.Activity");
        valid->service_names.push_back("com.example.Service");
        std::move(callback).Run(
            chromeos::payments::mojom::IsPaymentImplementedResult::NewValid(
                std::move(valid)));
      });

  base::test::TestFuture<
      chromeos::payments::mojom::IsPaymentImplementedResultPtr>
      future;
  payment_app_instance_ash_->IsPaymentImplemented("test_package_name",
                                                  future.GetCallback());

  auto is_payment_implemented_result = future.Take();
  ASSERT_TRUE(is_payment_implemented_result);
  ASSERT_FALSE(is_payment_implemented_result.is_null());
  EXPECT_FALSE(is_payment_implemented_result->is_error());
  ASSERT_TRUE(is_payment_implemented_result->is_valid());
  ASSERT_FALSE(is_payment_implemented_result->get_valid().is_null());
  EXPECT_EQ(std::vector<std::string>{"com.example.Activity"},
            is_payment_implemented_result->get_valid()->activity_names);
  EXPECT_EQ(std::vector<std::string>{"com.example.Service"},
            is_payment_implemented_result->get_valid()->service_names);
}

TEST_F(PaymentAppInstanceAshTest, IsPaymentImplementedError) {
  EXPECT_CALL(*support_.instance(),
              IsPaymentImplemented(testing::_, testing::_))
      .WillOnce([&](const std::string& package_name,
                    crosapi::PaymentAppInstanceAsh::IsPaymentImplementedCallback
                        callback) {
        std::move(callback).Run(
            chromeos::payments::mojom::IsPaymentImplementedResult::NewError(
                "Error message."));
      });

  base::test::TestFuture<
      chromeos::payments::mojom::IsPaymentImplementedResultPtr>
      future;
  payment_app_instance_ash_->IsPaymentImplemented("test_package_name",
                                                  future.GetCallback());

  auto is_payment_implemented_result = future.Take();
  ASSERT_TRUE(is_payment_implemented_result);
  ASSERT_FALSE(is_payment_implemented_result.is_null());
  EXPECT_FALSE(is_payment_implemented_result->is_valid());
  ASSERT_TRUE(is_payment_implemented_result->is_error());
  EXPECT_EQ("Error message.", is_payment_implemented_result->get_error());
}

TEST_F(PaymentAppInstanceAshTest, IsReadyToPay) {
  EXPECT_CALL(*support_.instance(), IsReadyToPay(testing::_, testing::_))
      .WillOnce(
          [](chromeos::payments::mojom::PaymentParametersPtr parameters,
             crosapi::PaymentAppInstanceAsh::IsReadyToPayCallback callback) {
            std::move(callback).Run(
                chromeos::payments::mojom::IsReadyToPayResult::NewResponse(
                    true));
          });

  base::test::TestFuture<chromeos::payments::mojom::IsReadyToPayResultPtr>
      future;
  payment_app_instance_ash_->IsReadyToPay(
      chromeos::payments::mojom::PaymentParameters::New(),
      future.GetCallback());

  auto is_ready_to_pay_result = future.Take();
  ASSERT_TRUE(is_ready_to_pay_result);
  ASSERT_FALSE(is_ready_to_pay_result.is_null());
  EXPECT_FALSE(is_ready_to_pay_result->is_error());
  ASSERT_TRUE(is_ready_to_pay_result->is_response());
  EXPECT_TRUE(is_ready_to_pay_result->get_response());
}

TEST_F(PaymentAppInstanceAshTest, IsNotReadyToPay) {
  EXPECT_CALL(*support_.instance(), IsReadyToPay(testing::_, testing::_))
      .WillOnce(
          [](chromeos::payments::mojom::PaymentParametersPtr parameters,
             crosapi::PaymentAppInstanceAsh::IsReadyToPayCallback callback) {
            std::move(callback).Run(
                chromeos::payments::mojom::IsReadyToPayResult::NewResponse(
                    false));
          });

  base::test::TestFuture<chromeos::payments::mojom::IsReadyToPayResultPtr>
      future;
  payment_app_instance_ash_->IsReadyToPay(
      chromeos::payments::mojom::PaymentParameters::New(),
      future.GetCallback());

  auto is_ready_to_pay_result = future.Take();
  ASSERT_TRUE(is_ready_to_pay_result);
  ASSERT_FALSE(is_ready_to_pay_result.is_null());
  EXPECT_FALSE(is_ready_to_pay_result->is_error());
  ASSERT_TRUE(is_ready_to_pay_result->is_response());
  EXPECT_FALSE(is_ready_to_pay_result->get_response());
}

TEST_F(PaymentAppInstanceAshTest, InvokePaymentAppNoToken) {
  base::test::TestFuture<chromeos::payments::mojom::InvokePaymentAppResultPtr>
      future;
  payment_app_instance_ash_->InvokePaymentApp(
      chromeos::payments::mojom::PaymentParameters::New(),
      future.GetCallback());

  auto invoke_payment_app_result = future.Take();
  ASSERT_TRUE(invoke_payment_app_result);
  ASSERT_FALSE(invoke_payment_app_result.is_null());
  EXPECT_FALSE(invoke_payment_app_result->is_valid());
  ASSERT_TRUE(invoke_payment_app_result->is_error());
  EXPECT_EQ("Unable to invoke Android apps.",
            invoke_payment_app_result->get_error());
}

TEST_F(PaymentAppInstanceAshTest, InvokePaymentAppResultOK) {
  EXPECT_CALL(*support_.instance(), InvokePaymentApp(testing::_, testing::_))
      .WillOnce([](chromeos::payments::mojom::PaymentParametersPtr parameters,
                   crosapi::PaymentAppInstanceAsh::InvokePaymentAppCallback
                       callback) {
        auto valid =
            chromeos::payments::mojom::InvokePaymentAppValidResult::New();
        valid->is_activity_result_ok = true;
        valid->stringified_details = "{}";
        std::move(callback).Run(
            chromeos::payments::mojom::InvokePaymentAppResult::NewValid(
                std::move(valid)));
      });

  auto params = chromeos::payments::mojom::PaymentParameters::New();
  params->request_token = "Abc";
  params->twa_instance_identifier = CreateTWAInstance();

  base::test::TestFuture<chromeos::payments::mojom::InvokePaymentAppResultPtr>
      future;
  payment_app_instance_ash_->InvokePaymentApp(std::move(params),
                                              future.GetCallback());

  auto invoke_payment_app_result = future.Take();
  ASSERT_TRUE(invoke_payment_app_result);
  ASSERT_FALSE(invoke_payment_app_result.is_null());
  EXPECT_FALSE(invoke_payment_app_result->is_error());
  ASSERT_TRUE(invoke_payment_app_result->is_valid());
  ASSERT_FALSE(invoke_payment_app_result->get_valid().is_null());
  EXPECT_TRUE(invoke_payment_app_result->get_valid()->is_activity_result_ok);
  EXPECT_EQ("{}", invoke_payment_app_result->get_valid()->stringified_details);
}

TEST_F(PaymentAppInstanceAshTest, InvokePaymentAppError) {
  EXPECT_CALL(*support_.instance(), InvokePaymentApp(testing::_, testing::_))
      .WillOnce([](chromeos::payments::mojom::PaymentParametersPtr parameters,
                   crosapi::PaymentAppInstanceAsh::InvokePaymentAppCallback
                       callback) {
        std::move(callback).Run(
            chromeos::payments::mojom::InvokePaymentAppResult::NewError(
                "Error message."));
      });

  auto params = chromeos::payments::mojom::PaymentParameters::New();
  params->request_token = "Abc";
  params->twa_instance_identifier = CreateTWAInstance();

  base::test::TestFuture<chromeos::payments::mojom::InvokePaymentAppResultPtr>
      future;
  payment_app_instance_ash_->InvokePaymentApp(std::move(params),
                                              future.GetCallback());

  auto invoke_payment_app_result = future.Take();
  ASSERT_TRUE(invoke_payment_app_result);
  ASSERT_FALSE(invoke_payment_app_result.is_null());
  EXPECT_FALSE(invoke_payment_app_result->is_valid());
  ASSERT_TRUE(invoke_payment_app_result->is_error());
  EXPECT_EQ("Error message.", invoke_payment_app_result->get_error());
}

TEST_F(PaymentAppInstanceAshTest, AbortPaymentAppOK) {
  EXPECT_CALL(*support_.instance(), AbortPaymentApp(testing::_, testing::_))
      .WillOnce(
          [](const std::string& request_token,
             crosapi::PaymentAppInstanceAsh::AbortPaymentAppCallback callback) {
            std::move(callback).Run(true);
          });

  base::test::TestFuture<bool> future;
  payment_app_instance_ash_->AbortPaymentApp("some token",
                                             future.GetCallback());

  auto abort_app_result = future.Take();
  ASSERT_TRUE(abort_app_result);
}

}  // namespace
}  // namespace payments