chromium/chromeos/ash/services/cellular_setup/cellular_setup_service_unittest.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <memory>
#include <optional>
#include <utility>

#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "chromeos/ash/services/cellular_setup/cellular_setup_impl.h"
#include "chromeos/ash/services/cellular_setup/public/cpp/fake_activation_delegate.h"
#include "chromeos/ash/services/cellular_setup/public/cpp/fake_carrier_portal_handler.h"
#include "chromeos/ash/services/cellular_setup/public/cpp/fake_cellular_setup.h"
#include "chromeos/ash/services/cellular_setup/public/mojom/cellular_setup.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash::cellular_setup {

namespace {

using CarrierPortalHandlerPair =
    std::pair<mojo::Remote<mojom::CarrierPortalHandler>,
              FakeCarrierPortalHandler*>;

const char kTestPaymentUrl[] = "testPaymentUrl";
const char kTestPaymentPostData[] = "testPaymentPostData";
const char kTestCarrier[] = "testCarrier";
const char kTestMeid[] = "testMeid";
const char kTestImei[] = "testImei";
const char kTestMdn[] = "testMdn";

}  // namespace

class CellularSetupServiceTest : public testing::Test {
 public:
  CellularSetupServiceTest(const CellularSetupServiceTest&) = delete;
  CellularSetupServiceTest& operator=(const CellularSetupServiceTest&) = delete;

 protected:
  CellularSetupServiceTest() = default;
  ~CellularSetupServiceTest() override = default;

  // testing::Test:
  void SetUp() override {
    service_ = std::make_unique<FakeCellularSetup>();
    service_->BindReceiver(cellular_setup_remote_.BindNewPipeAndPassReceiver());
    cellular_setup_remote_.FlushForTesting();
  }

  // Calls StartActivation() and returns the fake CarrierPortalHandler and its
  // associated mojo::Remote<>.
  CarrierPortalHandlerPair CallStartActivation(
      FakeActivationDelegate* fake_activation_delegate) {
    std::vector<std::unique_ptr<FakeCellularSetup::StartActivationInvocation>>&
        start_activation_invocations =
            fake_cellular_setup()->start_activation_invocations();
    size_t num_args_before_call = start_activation_invocations.size();
    base::RunLoop run_loop;

    // Make StartActivation() call and propagate it to the service.
    cellular_setup_remote_->StartActivation(
        fake_activation_delegate->GenerateRemote(),
        base::BindOnce(&CellularSetupServiceTest::OnStartActivationResult,
                       base::Unretained(this), run_loop.QuitClosure()));
    cellular_setup_remote_.FlushForTesting();

    // Verify that the call was made successfully.
    EXPECT_EQ(num_args_before_call + 1u, start_activation_invocations.size());

    // Execute the callback and retrieve the returned CarrierPortalHandler.
    FakeCarrierPortalHandler* fake_carrier_portal_observer =
        start_activation_invocations.back()->ExecuteCallback();
    run_loop.RunUntilIdle();

    EXPECT_TRUE(last_carrier_portal_observer_);
    CarrierPortalHandlerPair observer_pair = std::make_pair(
        std::move(last_carrier_portal_observer_), fake_carrier_portal_observer);
    last_carrier_portal_observer_.reset();

    return observer_pair;
  }

  // Calls OnActivationStarted() for the provided ActivationDelegate, passing
  // test metadata to represent the device. |fake_activation_delegate| must
  // correspond to the delegate provided to the most recent call to
  // CallStartActivation().
  void NotifyLastDelegateThatActivationStarted(
      FakeActivationDelegate* fake_activation_delegate) {
    const std::vector<mojom::CellularMetadataPtr>& cellular_metadata_list =
        fake_activation_delegate->cellular_metadata_list();
    size_t num_elements_before_call = cellular_metadata_list.size();

    GetLastActivationDelegate()->OnActivationStarted(
        mojom::CellularMetadata::New(GURL(kTestPaymentUrl),
                                     kTestPaymentPostData, kTestCarrier,
                                     kTestMeid, kTestImei, kTestMdn));
    GetLastActivationDelegate().FlushForTesting();

    ASSERT_EQ(num_elements_before_call + 1u, cellular_metadata_list.size());
    EXPECT_EQ(GURL(kTestPaymentUrl),
              cellular_metadata_list.back()->payment_url);
    EXPECT_EQ(kTestCarrier, cellular_metadata_list.back()->carrier);
    EXPECT_EQ(kTestMeid, cellular_metadata_list.back()->meid);
    EXPECT_EQ(kTestImei, cellular_metadata_list.back()->imei);
    EXPECT_EQ(kTestMdn, cellular_metadata_list.back()->mdn);
  }

  // Calls OnActivationFinished() for the provided ActivationDelegate, passing
  // |activation_result| to the callback. |fake_activation_delegate| must
  // correspond to the delegate provided to the most recent call to
  // CallStartActivation().
  void NotifyLastDelegateThatActivationFinished(
      mojom::ActivationResult activation_result,
      FakeActivationDelegate* fake_activation_delegate) {
    const std::vector<mojom::ActivationResult>& activation_results =
        fake_activation_delegate->activation_results();
    size_t num_results_before_call = activation_results.size();

    GetLastActivationDelegate()->OnActivationFinished(activation_result);
    GetLastActivationDelegate().FlushForTesting();

    ASSERT_EQ(num_results_before_call + 1u, activation_results.size());
    EXPECT_EQ(activation_result, activation_results.back());
  }

  // Calls OnCarrierPortalStatusChanged() for the provided
  // CarrierPortalStatusObserver and verifies that the status was received.
  void SendCarrierPortalStatusUpdate(
      mojom::CarrierPortalStatus carrier_portal_status,
      CarrierPortalHandlerPair* pair) {
    const std::vector<mojom::CarrierPortalStatus>& status_updates =
        pair->second->status_updates();
    size_t num_updates_before_call = status_updates.size();

    pair->first->OnCarrierPortalStatusChange(carrier_portal_status);
    pair->first.FlushForTesting();

    ASSERT_EQ(num_updates_before_call + 1u, status_updates.size());
    EXPECT_EQ(carrier_portal_status, status_updates.back());
  }

 private:
  void OnStartActivationResult(base::OnceClosure quit_closure,
                               mojo::PendingRemote<mojom::CarrierPortalHandler>
                                   carrier_portal_observer) {
    EXPECT_FALSE(last_carrier_portal_observer_);
    last_carrier_portal_observer_.Bind(std::move(carrier_portal_observer));
    std::move(quit_closure).Run();
  }

  FakeCellularSetup* fake_cellular_setup() { return service_.get(); }

  mojo::Remote<mojom::ActivationDelegate>& GetLastActivationDelegate() {
    return fake_cellular_setup()
        ->start_activation_invocations()
        .back()
        ->activation_delegate();
  }

  base::test::TaskEnvironment task_environment_;

  std::unique_ptr<FakeCellularSetup> service_;

  mojo::Remote<mojom::CarrierPortalHandler> last_carrier_portal_observer_;

  mojo::Remote<mojom::CellularSetup> cellular_setup_remote_;
};

TEST_F(CellularSetupServiceTest, StartActivation_Success) {
  auto fake_activation_delegate = std::make_unique<FakeActivationDelegate>();

  CarrierPortalHandlerPair pair =
      CallStartActivation(fake_activation_delegate.get());
  NotifyLastDelegateThatActivationStarted(fake_activation_delegate.get());

  SendCarrierPortalStatusUpdate(
      mojom::CarrierPortalStatus::kPortalLoadedWithoutPaidUser, &pair);
  SendCarrierPortalStatusUpdate(
      mojom::CarrierPortalStatus::kPortalLoadedAndUserCompletedPayment, &pair);

  NotifyLastDelegateThatActivationFinished(
      mojom::ActivationResult::kSuccessfullyStartedActivation,
      fake_activation_delegate.get());
}

TEST_F(CellularSetupServiceTest, StartActivation_PortalFailsToLoad) {
  auto fake_activation_delegate = std::make_unique<FakeActivationDelegate>();

  CarrierPortalHandlerPair pair =
      CallStartActivation(fake_activation_delegate.get());
  NotifyLastDelegateThatActivationStarted(fake_activation_delegate.get());

  SendCarrierPortalStatusUpdate(mojom::CarrierPortalStatus::kPortalFailedToLoad,
                                &pair);

  NotifyLastDelegateThatActivationFinished(
      mojom::ActivationResult::kFailedToActivate,
      fake_activation_delegate.get());
}

TEST_F(CellularSetupServiceTest, StartActivation_ErrorDuringPayment) {
  auto fake_activation_delegate = std::make_unique<FakeActivationDelegate>();

  CarrierPortalHandlerPair pair =
      CallStartActivation(fake_activation_delegate.get());
  NotifyLastDelegateThatActivationStarted(fake_activation_delegate.get());

  SendCarrierPortalStatusUpdate(
      mojom::CarrierPortalStatus::kPortalLoadedWithoutPaidUser, &pair);
  SendCarrierPortalStatusUpdate(
      mojom::CarrierPortalStatus::kPortalLoadedButErrorOccurredDuringPayment,
      &pair);

  NotifyLastDelegateThatActivationFinished(
      mojom::ActivationResult::kFailedToActivate,
      fake_activation_delegate.get());
}

}  // namespace ash::cellular_setup