chromium/chrome/browser/ash/smb_client/smb_service_test_base.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/smb_client/smb_service_test_base.h"

#include "base/test/simple_test_tick_clock.h"
#include "chrome/browser/ash/file_manager/volume_manager.h"
#include "chrome/browser/ash/file_manager/volume_manager_factory.h"
#include "chrome/test/base/testing_browser_process.h"

namespace ash::smb_client {

namespace {

void SaveMountResult(SmbMountResult* out, SmbMountResult result) {
  *out = result;
}

// Creates a new VolumeManager for tests.
// By default, VolumeManager KeyedService is null for testing.
std::unique_ptr<KeyedService> BuildVolumeManager(
    content::BrowserContext* context) {
  return std::make_unique<file_manager::VolumeManager>(
      Profile::FromBrowserContext(context),
      nullptr /* drive_integration_service */,
      nullptr /* power_manager_client */,
      disks::DiskMountManager::GetInstance(),
      nullptr /* file_system_provider_service */,
      file_manager::VolumeManager::GetMtpStorageInfoCallback());
}

}  // namespace

// MockSmbFsMounter
MockSmbFsMounter::MockSmbFsMounter() = default;
MockSmbFsMounter::~MockSmbFsMounter() = default;

// MockSmbFsImpl
MockSmbFsImpl::MockSmbFsImpl(mojo::PendingReceiver<smbfs::mojom::SmbFs> pending)
    : receiver_(this, std::move(pending)) {
  receiver_.set_disconnect_handler(
      base::BindOnce(&MockSmbFsImpl::OnDisconnect, base::Unretained(this)));
}

MockSmbFsImpl::~MockSmbFsImpl() = default;

// SmbServiceBaseTest
SmbServiceBaseTest::TestSmbFsInstance::TestSmbFsInstance(
    mojo::PendingReceiver<smbfs::mojom::SmbFs> pending)
    : mock_smbfs(std::move(pending)) {}

SmbServiceBaseTest::TestSmbFsInstance::~TestSmbFsInstance() = default;

SmbServiceBaseTest::SmbServiceBaseTest() {
  profile_manager_ = std::make_unique<TestingProfileManager>(
      TestingBrowserProcess::GetGlobal());
  CHECK(profile_manager_->SetUp());

  {
    auto user_manager_temp = std::make_unique<FakeChromeUserManager>();

    profile_ = profile_manager_->CreateTestingProfile("[email protected]");
    user_manager_temp->AddUser(
        AccountId::FromUserEmail(profile_->GetProfileUserName()));

    // Run pending async tasks resulting from profile construction to ensure
    // these are complete before the test begins.
    base::RunLoop().RunUntilIdle();

    user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
        std::move(user_manager_temp));
  }

  SmbProviderClient::InitializeFake();
  ConciergeClient::InitializeFake(/*fake_cicerone_client=*/nullptr);

  disk_mount_manager_ = new disks::FakeDiskMountManager();
  // Takes ownership of |disk_mount_manager_|, but Shutdown() must be called.
  disks::DiskMountManager::InitializeForTesting(disk_mount_manager_);
}

SmbServiceBaseTest::~SmbServiceBaseTest() {
  // The following reset() and Shutdown() are required to override and delete
  // the global dependencies.
  smb_service.reset();
  user_manager_enabler_.reset();
  profile_manager_.reset();
  disks::DiskMountManager::Shutdown();
  SmbProviderClient::Shutdown();
}

void SmbServiceBaseTest::CreateService(TestingProfile* profile) {
  SmbService::DisableShareDiscoveryForTesting();
  file_manager::VolumeManagerFactory::GetInstance()->SetTestingFactory(
      profile, base::BindRepeating(&BuildVolumeManager));

  smb_service = std::make_unique<SmbService>(
      profile, std::make_unique<base::SimpleTestTickClock>());
}

void SmbServiceBaseTest::ExpectInvalidUrl(const std::string& url) {
  SmbMountResult result = SmbMountResult::kSuccess;
  smb_service->Mount(
      "" /* display_name */, base::FilePath(url), "" /* username */,
      "" /* password */, false /* use_kerberos */,
      false /* should_open_file_manager_after_mount */,
      false /* save_credentials */, base::BindOnce(&SaveMountResult, &result));
  EXPECT_EQ(result, SmbMountResult::kInvalidUrl);
}

void SmbServiceBaseTest::ExpectInvalidSsoUrl(const std::string& url) {
  SmbMountResult result = SmbMountResult::kSuccess;
  smb_service->Mount(
      "" /* display_name */, base::FilePath(url), "" /* username */,
      "" /* password */, true /* use_kerberos */,
      false /* should_open_file_manager_after_mount */,
      false /* save_credentials */, base::BindOnce(&SaveMountResult, &result));
  EXPECT_EQ(result, SmbMountResult::kInvalidSsoUrl);
}

void SmbServiceBaseTest::WaitForSetupComplete() {
  {
    base::RunLoop run_loop;
    smb_service->OnSetupCompleteForTesting(run_loop.QuitClosure());
    run_loop.Run();
  }
  {
    // Share gathering needs to complete at least once before a share can be
    // mounted.
    base::RunLoop run_loop;
    smb_service->GatherSharesInNetwork(
        base::DoNothing(),
        base::BindLambdaForTesting(
            [&run_loop](const std::vector<SmbUrl>& shares_gathered, bool done) {
              if (done) {
                run_loop.Quit();
              }
            }));
    run_loop.Run();
  }
}

std::unique_ptr<disks::MountPoint> SmbServiceBaseTest::MakeMountPoint(
    const base::FilePath& path) {
  return std::make_unique<disks::MountPoint>(path, disk_mount_manager_);
}

std::unique_ptr<SmbServiceBaseTest::TestSmbFsInstance>
SmbServiceBaseTest::MountBasicShare(const std::string& share_path,
                                    const std::string& mount_path,
                                    SmbService::MountResponse callback) {
  mojo::Remote<smbfs::mojom::SmbFs> smbfs_remote;
  auto instance = std::make_unique<TestSmbFsInstance>(
      smbfs_remote.BindNewPipeAndPassReceiver());

  smbfs::SmbFsHost::Delegate* smbfs_host_delegate = nullptr;
  // Use a NiceMock<> so that the ON_CALL below doesn't complain.
  auto mock_mounter = std::make_unique<NiceMock<MockSmbFsMounter>>();

  smb_service->SetSmbFsMounterCreationCallbackForTesting(
      base::BindLambdaForTesting([&mock_mounter, &smbfs_host_delegate](
                                     const std::string& share_path,
                                     const std::string& mount_dir_name,
                                     const SmbFsShare::MountOptions& options,
                                     smbfs::SmbFsHost::Delegate* delegate)
                                     -> std::unique_ptr<smbfs::SmbFsMounter> {
        smbfs_host_delegate = delegate;
        return std::move(mock_mounter);
      }));

  // Use ON_CALL instead of EXPECT_CALL because there might be a failure
  // earlier in the mount process and this won't be called.
  ON_CALL(*mock_mounter, Mount(_))
      .WillByDefault(
          [this, &smbfs_host_delegate, &smbfs_remote, &instance,
           &mount_path](smbfs::SmbFsMounter::DoneCallback mount_callback) {
            std::move(mount_callback)
                .Run(smbfs::mojom::MountError::kOk,
                     std::make_unique<smbfs::SmbFsHost>(
                         MakeMountPoint(base::FilePath(mount_path)),
                         smbfs_host_delegate, std::move(smbfs_remote),
                         instance->delegate.BindNewPipeAndPassReceiver()));
          });

  base::RunLoop run_loop;
  smb_service->Mount(
      kDisplayName, base::FilePath(share_path), "" /* username */,
      "" /* password */, false /* use_kerberos */,
      false /* should_open_file_manager_after_mount */,
      false /* save_credentials */,
      base::BindLambdaForTesting([&run_loop, &callback](SmbMountResult result) {
        std::move(callback).Run(result);
        run_loop.Quit();
      }));
  run_loop.Run();

  return instance;
}

}  // namespace ash::smb_client