| // Copyright 2017 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.h" | 
 |  | 
 | #include "base/json/json_reader.h" | 
 | #include "base/strings/string_number_conversions.h" | 
 | #include "base/test/gmock_callback_support.h" | 
 | #include "chrome/browser/ash/smb_client/smb_service_test_base.h" | 
 | #include "chrome/common/pref_names.h" | 
 | #include "components/prefs/pref_service.h" | 
 | #include "storage/browser/file_system/external_mount_points.h" | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | namespace ash::smb_client { | 
 |  | 
 | namespace { | 
 |  | 
 | inline constexpr char kTestUser[] = "foobar"; | 
 | inline constexpr char kTestPassword[] = "my_secret_password"; | 
 | inline constexpr char kTestDomain[] = "EXAMPLE.COM"; | 
 | inline constexpr char kSharePath2[] = "\\\\server2\\second_share"; | 
 | inline constexpr char kShareUrl[] = "smb://server/foobar"; | 
 | inline constexpr char kInvalidShareUrl[] = "smb://server"; | 
 | inline constexpr char kMountPath2[] = "/share/mount/second_path"; | 
 |  | 
 | }  // namespace | 
 |  | 
 | class SmbServiceWithSmbfsTest : public SmbServiceBaseTest {}; | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, InvalidUrls) { | 
 |   CreateService(profile()); | 
 |  | 
 |   ExpectInvalidUrl(""); | 
 |   ExpectInvalidUrl("foo"); | 
 |   ExpectInvalidUrl("\\foo"); | 
 |   ExpectInvalidUrl("\\\\foo"); | 
 |   ExpectInvalidUrl("\\\\foo\\"); | 
 |   ExpectInvalidUrl("file://foo/bar"); | 
 |   ExpectInvalidUrl("smb://foo"); | 
 |   ExpectInvalidUrl("smb://user@password:foo"); | 
 |   ExpectInvalidUrl("smb:\\\\foo\\bar"); | 
 |   ExpectInvalidUrl("//foo/bar"); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, InvalidSsoUrls) { | 
 |   CreateService(profile()); | 
 |  | 
 |   ExpectInvalidSsoUrl("\\\\192.168.1.1\\foo"); | 
 |   ExpectInvalidSsoUrl("\\\\[0:0:0:0:0:0:0:1]\\foo"); | 
 |   ExpectInvalidSsoUrl("\\\\[::1]\\foo"); | 
 |   ExpectInvalidSsoUrl("smb://192.168.1.1/foo"); | 
 |   ExpectInvalidSsoUrl("smb://[0:0:0:0:0:0:0:1]/foo"); | 
 |   ExpectInvalidSsoUrl("smb://[::1]/foo"); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, Mount) { | 
 |   CreateService(profile()); | 
 |   WaitForSetupComplete(); | 
 |  | 
 |   mojo::Remote<smbfs::mojom::SmbFs> smbfs_remote; | 
 |   MockSmbFsImpl smbfs_impl(smbfs_remote.BindNewPipeAndPassReceiver()); | 
 |   mojo::Remote<smbfs::mojom::SmbFsDelegate> smbfs_delegate_remote; | 
 |  | 
 |   smbfs::SmbFsHost::Delegate* smbfs_host_delegate = nullptr; | 
 |   auto mock_mounter = std::make_unique<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> { | 
 |         EXPECT_EQ(share_path, kShareUrl); | 
 |         EXPECT_EQ(options.username, kTestUser); | 
 |         EXPECT_TRUE(options.workgroup.empty()); | 
 |         EXPECT_EQ(options.password, kTestPassword); | 
 |         EXPECT_TRUE(options.allow_ntlm); | 
 |         EXPECT_FALSE(options.kerberos_options); | 
 |         smbfs_host_delegate = delegate; | 
 |         return std::move(mock_mounter); | 
 |       })); | 
 |   EXPECT_CALL(*mock_mounter, Mount(_)) | 
 |       .WillOnce( | 
 |           [this, &smbfs_host_delegate, &smbfs_remote, | 
 |            &smbfs_delegate_remote](smbfs::SmbFsMounter::DoneCallback callback) { | 
 |             std::move(callback).Run( | 
 |                 smbfs::mojom::MountError::kOk, | 
 |                 std::make_unique<smbfs::SmbFsHost>( | 
 |                     MakeMountPoint(base::FilePath(kMountPath)), | 
 |                     smbfs_host_delegate, std::move(smbfs_remote), | 
 |                     smbfs_delegate_remote.BindNewPipeAndPassReceiver())); | 
 |           }); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   smb_service->Mount( | 
 |       kDisplayName, base::FilePath(kSharePath), kTestUser, kTestPassword, | 
 |       false /* use_kerberos */, | 
 |       false /* should_open_file_manager_after_mount */, | 
 |       false /* save_credentials */, | 
 |       base::BindLambdaForTesting([&run_loop](SmbMountResult result) { | 
 |         EXPECT_EQ(SmbMountResult::kSuccess, result); | 
 |         run_loop.Quit(); | 
 |       })); | 
 |   run_loop.Run(); | 
 |  | 
 |   // Expect that the filesystem mount path is registered. | 
 |   std::vector<storage::MountPoints::MountPointInfo> mount_points; | 
 |   storage::ExternalMountPoints::GetSystemInstance()->AddMountPointInfosTo( | 
 |       &mount_points); | 
 |   bool found = false; | 
 |   for (const auto& info : mount_points) { | 
 |     if (info.path == base::FilePath(kMountPath)) { | 
 |       found = true; | 
 |       break; | 
 |     } | 
 |   } | 
 |   EXPECT_TRUE(found); | 
 |  | 
 |   // Check that the SmbFsShare can be accessed. | 
 |   const base::FilePath mount_path(kMountPath); | 
 |   SmbFsShare* share = smb_service->GetSmbFsShareForPath(mount_path); | 
 |   ASSERT_TRUE(share); | 
 |   EXPECT_EQ(share->mount_path(), mount_path); | 
 |   EXPECT_EQ(share->share_url().ToString(), kShareUrl); | 
 |  | 
 |   // Check that the share was saved. | 
 |   SmbPersistedShareRegistry registry(profile()); | 
 |   std::optional<SmbShareInfo> info = registry.Get(SmbUrl(kShareUrl)); | 
 |   ASSERT_TRUE(info); | 
 |   EXPECT_EQ(info->share_url().ToString(), kShareUrl); | 
 |   EXPECT_EQ(info->display_name(), kDisplayName); | 
 |   EXPECT_EQ(info->username(), kTestUser); | 
 |   EXPECT_TRUE(info->workgroup().empty()); | 
 |   EXPECT_FALSE(info->use_kerberos()); | 
 |  | 
 |   // Unmounting should remove the saved share. Since |save_credentials| was | 
 |   // false, there should be no request to smbfs. | 
 |   EXPECT_CALL(smbfs_impl, RemoveSavedCredentials(_)).Times(0); | 
 |   smb_service->UnmountSmbFs(base::FilePath(kMountPath)); | 
 |   info = registry.Get(SmbUrl(kShareUrl)); | 
 |   EXPECT_FALSE(info); | 
 |   EXPECT_TRUE(registry.GetAll().empty()); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, Mount_SaveCredentials) { | 
 |   CreateService(profile()); | 
 |   WaitForSetupComplete(); | 
 |  | 
 |   mojo::Remote<smbfs::mojom::SmbFs> smbfs_remote; | 
 |   MockSmbFsImpl smbfs_impl(smbfs_remote.BindNewPipeAndPassReceiver()); | 
 |   mojo::Remote<smbfs::mojom::SmbFsDelegate> smbfs_delegate_remote; | 
 |  | 
 |   smbfs::SmbFsHost::Delegate* smbfs_host_delegate = nullptr; | 
 |   auto mock_mounter = std::make_unique<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> { | 
 |         EXPECT_EQ(share_path, kShareUrl); | 
 |         EXPECT_EQ(options.username, kTestUser); | 
 |         EXPECT_TRUE(options.workgroup.empty()); | 
 |         EXPECT_EQ(options.password, kTestPassword); | 
 |         EXPECT_FALSE(options.kerberos_options); | 
 |         EXPECT_TRUE(options.save_restore_password); | 
 |         EXPECT_FALSE(options.account_hash.empty()); | 
 |         EXPECT_FALSE(options.password_salt.empty()); | 
 |         smbfs_host_delegate = delegate; | 
 |         return std::move(mock_mounter); | 
 |       })); | 
 |   EXPECT_CALL(*mock_mounter, Mount(_)) | 
 |       .WillOnce( | 
 |           [this, &smbfs_host_delegate, &smbfs_remote, | 
 |            &smbfs_delegate_remote](smbfs::SmbFsMounter::DoneCallback callback) { | 
 |             std::move(callback).Run( | 
 |                 smbfs::mojom::MountError::kOk, | 
 |                 std::make_unique<smbfs::SmbFsHost>( | 
 |                     MakeMountPoint(base::FilePath(kMountPath)), | 
 |                     smbfs_host_delegate, std::move(smbfs_remote), | 
 |                     smbfs_delegate_remote.BindNewPipeAndPassReceiver())); | 
 |           }); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   smb_service->Mount( | 
 |       kDisplayName, base::FilePath(kSharePath), kTestUser, kTestPassword, | 
 |       false /* use_kerberos */, | 
 |       false /* should_open_file_manager_after_mount */, | 
 |       true /* save_credentials */, | 
 |       base::BindLambdaForTesting([&run_loop](SmbMountResult result) { | 
 |         EXPECT_EQ(SmbMountResult::kSuccess, result); | 
 |         run_loop.Quit(); | 
 |       })); | 
 |   run_loop.Run(); | 
 |  | 
 |   // Check that the share was saved. | 
 |   SmbPersistedShareRegistry registry(profile()); | 
 |   std::optional<SmbShareInfo> info = registry.Get(SmbUrl(kShareUrl)); | 
 |   ASSERT_TRUE(info); | 
 |   EXPECT_EQ(info->share_url().ToString(), kShareUrl); | 
 |   EXPECT_EQ(info->display_name(), kDisplayName); | 
 |   EXPECT_EQ(info->username(), kTestUser); | 
 |   EXPECT_TRUE(info->workgroup().empty()); | 
 |   EXPECT_FALSE(info->use_kerberos()); | 
 |   EXPECT_FALSE(info->password_salt().empty()); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, MountPreconfigured) { | 
 |   const char kPremountPath[] = "smb://preconfigured/share"; | 
 |   const char kPreconfiguredShares[] = | 
 |       R"([{"mode":"pre_mount","share_url":"\\\\preconfigured\\share"}])"; | 
 |   auto parsed_shares = base::JSONReader::Read( | 
 |       kPreconfiguredShares, base::JSON_PARSE_CHROMIUM_EXTENSIONS); | 
 |   ASSERT_TRUE(parsed_shares); | 
 |   profile()->GetPrefs()->Set(prefs::kNetworkFileSharesPreconfiguredShares, | 
 |                              *parsed_shares); | 
 |  | 
 |   CreateService(profile()); | 
 |  | 
 |   mojo::Remote<smbfs::mojom::SmbFs> smbfs_remote; | 
 |   MockSmbFsImpl smbfs_impl(smbfs_remote.BindNewPipeAndPassReceiver()); | 
 |   mojo::Remote<smbfs::mojom::SmbFsDelegate> smbfs_delegate_remote; | 
 |  | 
 |   smbfs::SmbFsHost::Delegate* smbfs_host_delegate = nullptr; | 
 |   auto mock_mounter = std::make_unique<MockSmbFsMounter>(); | 
 |   smb_service->SetSmbFsMounterCreationCallbackForTesting( | 
 |       base::BindLambdaForTesting( | 
 |           [&mock_mounter, &smbfs_host_delegate, kPremountPath]( | 
 |               const std::string& share_path, const std::string& mount_dir_name, | 
 |               const SmbFsShare::MountOptions& options, | 
 |               smbfs::SmbFsHost::Delegate* delegate) | 
 |               -> std::unique_ptr<smbfs::SmbFsMounter> { | 
 |             EXPECT_EQ(share_path, kPremountPath); | 
 |             EXPECT_TRUE(options.username.empty()); | 
 |             EXPECT_TRUE(options.workgroup.empty()); | 
 |             EXPECT_TRUE(options.password.empty()); | 
 |             EXPECT_FALSE(options.kerberos_options); | 
 |             smbfs_host_delegate = delegate; | 
 |             return std::move(mock_mounter); | 
 |           })); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   EXPECT_CALL(*mock_mounter, Mount(_)) | 
 |       .WillOnce([this, &smbfs_host_delegate, &smbfs_remote, | 
 |                  &smbfs_delegate_remote, | 
 |                  &run_loop](smbfs::SmbFsMounter::DoneCallback callback) { | 
 |         std::move(callback).Run( | 
 |             smbfs::mojom::MountError::kOk, | 
 |             std::make_unique<smbfs::SmbFsHost>( | 
 |                 MakeMountPoint(base::FilePath(kMountPath)), smbfs_host_delegate, | 
 |                 std::move(smbfs_remote), | 
 |                 smbfs_delegate_remote.BindNewPipeAndPassReceiver())); | 
 |         run_loop.Quit(); | 
 |       }); | 
 |  | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, MountInvalidPreconfigured) { | 
 |   const char kPreconfiguredShares[] = | 
 |       R"([{"mode":"pre_mount","share_url":"\\\\preconfigured"}])"; | 
 |   auto parsed_shares = base::JSONReader::Read( | 
 |       kPreconfiguredShares, base::JSON_PARSE_CHROMIUM_EXTENSIONS); | 
 |   ASSERT_TRUE(parsed_shares); | 
 |   profile()->GetPrefs()->Set(prefs::kNetworkFileSharesPreconfiguredShares, | 
 |                              *parsed_shares); | 
 |  | 
 |   CreateService(profile()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   smb_service->SetRestoredShareMountDoneCallbackForTesting( | 
 |       base::BindLambdaForTesting([&run_loop](SmbMountResult mount_result, | 
 |                                              const base::FilePath& mount_path) { | 
 |         EXPECT_EQ(mount_result, SmbMountResult::kInvalidUrl); | 
 |         run_loop.Quit(); | 
 |       })); | 
 |  | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, MountSaved) { | 
 |   const std::vector<uint8_t> kSalt = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; | 
 |   // Save share in profile. | 
 |   { | 
 |     SmbPersistedShareRegistry registry(profile()); | 
 |     SmbShareInfo info(SmbUrl(kShareUrl), kDisplayName, kTestUser, kTestDomain, | 
 |                       false /* use_kerberos */, kSalt); | 
 |     registry.Save(info); | 
 |   } | 
 |  | 
 |   CreateService(profile()); | 
 |  | 
 |   mojo::Remote<smbfs::mojom::SmbFs> smbfs_remote; | 
 |   MockSmbFsImpl smbfs_impl(smbfs_remote.BindNewPipeAndPassReceiver()); | 
 |   mojo::Remote<smbfs::mojom::SmbFsDelegate> smbfs_delegate_remote; | 
 |  | 
 |   smbfs::SmbFsHost::Delegate* smbfs_host_delegate = nullptr; | 
 |   auto mock_mounter = std::make_unique<MockSmbFsMounter>(); | 
 |   smb_service->SetSmbFsMounterCreationCallbackForTesting( | 
 |       base::BindLambdaForTesting([&mock_mounter, &smbfs_host_delegate, kSalt]( | 
 |                                      const std::string& share_path, | 
 |                                      const std::string& mount_dir_name, | 
 |                                      const SmbFsShare::MountOptions& options, | 
 |                                      smbfs::SmbFsHost::Delegate* delegate) | 
 |                                      -> std::unique_ptr<smbfs::SmbFsMounter> { | 
 |         EXPECT_EQ(share_path, kShareUrl); | 
 |         EXPECT_EQ(options.username, kTestUser); | 
 |         EXPECT_EQ(options.workgroup, kTestDomain); | 
 |         EXPECT_TRUE(options.password.empty()); | 
 |         EXPECT_TRUE(options.allow_ntlm); | 
 |         EXPECT_FALSE(options.kerberos_options); | 
 |         EXPECT_TRUE(options.save_restore_password); | 
 |         EXPECT_FALSE(options.account_hash.empty()); | 
 |         EXPECT_EQ(options.password_salt, kSalt); | 
 |         smbfs_host_delegate = delegate; | 
 |         return std::move(mock_mounter); | 
 |       })); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   EXPECT_CALL(*mock_mounter, Mount(_)) | 
 |       .WillOnce([this, &smbfs_host_delegate, &smbfs_remote, | 
 |                  &smbfs_delegate_remote, | 
 |                  &run_loop](smbfs::SmbFsMounter::DoneCallback callback) { | 
 |         std::move(callback).Run( | 
 |             smbfs::mojom::MountError::kOk, | 
 |             std::make_unique<smbfs::SmbFsHost>( | 
 |                 MakeMountPoint(base::FilePath(kMountPath)), smbfs_host_delegate, | 
 |                 std::move(smbfs_remote), | 
 |                 smbfs_delegate_remote.BindNewPipeAndPassReceiver())); | 
 |         run_loop.Quit(); | 
 |       }); | 
 |  | 
 |   run_loop.Run(); | 
 |  | 
 |   // Unmounting should remove the saved share, and ask smbfs to remove any saved | 
 |   // credentials. | 
 |   base::RunLoop run_loop2; | 
 |   EXPECT_CALL(smbfs_impl, RemoveSavedCredentials(_)) | 
 |       .WillOnce( | 
 |           [](smbfs::mojom::SmbFs::RemoveSavedCredentialsCallback callback) { | 
 |             std::move(callback).Run(true /* success */); | 
 |           }); | 
 |   EXPECT_CALL(smbfs_impl, OnDisconnect()) | 
 |       .WillOnce(base::test::RunClosure(run_loop2.QuitClosure())); | 
 |   smb_service->UnmountSmbFs(base::FilePath(kMountPath)); | 
 |   run_loop2.Run(); | 
 |  | 
 |   SmbPersistedShareRegistry registry(profile()); | 
 |   std::optional<SmbShareInfo> info = registry.Get(SmbUrl(kShareUrl)); | 
 |   EXPECT_FALSE(info); | 
 |   EXPECT_TRUE(registry.GetAll().empty()); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, MountInvalidSaved) { | 
 |   const std::vector<uint8_t> kSalt = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; | 
 |   // Save an (invalid) share in profile. This can't occur in practice. | 
 |   { | 
 |     SmbPersistedShareRegistry registry(profile()); | 
 |     SmbShareInfo info(SmbUrl(kInvalidShareUrl), kDisplayName, kTestUser, | 
 |                       kTestDomain, /*use_kerberos=*/false, kSalt); | 
 |     registry.Save(info); | 
 |   } | 
 |  | 
 |   CreateService(profile()); | 
 |  | 
 |   base::RunLoop run_loop; | 
 |   smb_service->SetRestoredShareMountDoneCallbackForTesting( | 
 |       base::BindLambdaForTesting([&run_loop](SmbMountResult mount_result, | 
 |                                              const base::FilePath& mount_path) { | 
 |         EXPECT_EQ(mount_result, SmbMountResult::kInvalidUrl); | 
 |         run_loop.Quit(); | 
 |       })); | 
 |  | 
 |   run_loop.Run(); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, MountExcessiveShares) { | 
 |   // The maximum number of smbfs shares that can be mounted simultaneously. | 
 |   // Should match the definition in smb_service.cc. | 
 |   const size_t kMaxSmbFsShares = 16; | 
 |   CreateService(profile()); | 
 |   WaitForSetupComplete(); | 
 |  | 
 |   // Check: It is possible to mount the maximum number of shares. | 
 |   for (size_t i = 0; i < kMaxSmbFsShares; ++i) { | 
 |     const std::string share_path = | 
 |         std::string(kSharePath) + base::NumberToString(i); | 
 |     const std::string mount_path = | 
 |         std::string(kMountPath) + base::NumberToString(i); | 
 |     std::ignore = MountBasicShare(share_path, mount_path, | 
 |                                   base::BindOnce([](SmbMountResult result) { | 
 |                                     EXPECT_EQ(SmbMountResult::kSuccess, result); | 
 |                                   })); | 
 |   } | 
 |  | 
 |   // Check: After mounting the maximum number of shares, requesting to mount an | 
 |   // additional share should fail. | 
 |   const std::string share_path = | 
 |       std::string(kSharePath) + base::NumberToString(kMaxSmbFsShares); | 
 |   const std::string mount_path = | 
 |       std::string(kMountPath) + base::NumberToString(kMaxSmbFsShares); | 
 |   std::ignore = MountBasicShare( | 
 |       share_path, mount_path, base::BindOnce([](SmbMountResult result) { | 
 |         EXPECT_EQ(SmbMountResult::kTooManyOpened, result); | 
 |       })); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, GetSmbFsShareForPath) { | 
 |   CreateService(profile()); | 
 |   WaitForSetupComplete(); | 
 |  | 
 |   std::ignore = MountBasicShare(kSharePath, kMountPath, | 
 |                                 base::BindOnce([](SmbMountResult result) { | 
 |                                   EXPECT_EQ(SmbMountResult::kSuccess, result); | 
 |                                 })); | 
 |   std::ignore = MountBasicShare(kSharePath2, kMountPath2, | 
 |                                 base::BindOnce([](SmbMountResult result) { | 
 |                                   EXPECT_EQ(SmbMountResult::kSuccess, result); | 
 |                                 })); | 
 |  | 
 |   SmbFsShare* share = | 
 |       smb_service->GetSmbFsShareForPath(base::FilePath(kMountPath)); | 
 |   EXPECT_EQ(share->mount_path(), base::FilePath(kMountPath)); | 
 |   share = smb_service->GetSmbFsShareForPath( | 
 |       base::FilePath(kMountPath).Append("foo")); | 
 |   EXPECT_EQ(share->mount_path(), base::FilePath(kMountPath)); | 
 |  | 
 |   share = smb_service->GetSmbFsShareForPath(base::FilePath(kMountPath2)); | 
 |   EXPECT_EQ(share->mount_path(), base::FilePath(kMountPath2)); | 
 |   share = smb_service->GetSmbFsShareForPath( | 
 |       base::FilePath(kMountPath2).Append("bar/baz")); | 
 |   EXPECT_EQ(share->mount_path(), base::FilePath(kMountPath2)); | 
 |  | 
 |   EXPECT_FALSE( | 
 |       smb_service->GetSmbFsShareForPath(base::FilePath("/share/mount"))); | 
 |   EXPECT_FALSE(smb_service->GetSmbFsShareForPath( | 
 |       base::FilePath("/share/mount/third_path"))); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, MountDuplicate) { | 
 |   CreateService(profile()); | 
 |   WaitForSetupComplete(); | 
 |  | 
 |   std::ignore = MountBasicShare(kSharePath, kMountPath, | 
 |                                 base::BindOnce([](SmbMountResult result) { | 
 |                                   EXPECT_EQ(SmbMountResult::kSuccess, result); | 
 |                                 })); | 
 |  | 
 |   // A second mount with the same share path should fail. | 
 |   std::ignore = MountBasicShare( | 
 |       kSharePath, kMountPath2, base::BindOnce([](SmbMountResult result) { | 
 |         EXPECT_EQ(SmbMountResult::kMountExists, result); | 
 |       })); | 
 |  | 
 |   // Unmounting and mounting again should succeed. | 
 |   smb_service->UnmountSmbFs(base::FilePath(kMountPath)); | 
 |   std::ignore = MountBasicShare(kSharePath, kMountPath2, | 
 |                                 base::BindOnce([](SmbMountResult result) { | 
 |                                   EXPECT_EQ(SmbMountResult::kSuccess, result); | 
 |                                 })); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, IsAnySmbShareAdded) { | 
 |   CreateService(profile()); | 
 |   WaitForSetupComplete(); | 
 |   EXPECT_FALSE(smb_service->IsAnySmbShareConfigured()); | 
 |  | 
 |   // Add a share | 
 |   std::ignore = MountBasicShare(kSharePath, kMountPath, | 
 |                                 base::BindOnce([](SmbMountResult result) { | 
 |                                   EXPECT_EQ(SmbMountResult::kSuccess, result); | 
 |                                 })); | 
 |  | 
 |   EXPECT_TRUE(smb_service->IsAnySmbShareConfigured()); | 
 | } | 
 |  | 
 | TEST_F(SmbServiceWithSmbfsTest, IsAnySmbShareConfigured) { | 
 |   // Add a preconfigured share | 
 |   const char kPreconfiguredShares[] = | 
 |       R"([{"mode":"pre_mount","share_url":"\\\\preconfigured\\share"}])"; | 
 |   auto parsed_shares = base::JSONReader::Read( | 
 |       kPreconfiguredShares, base::JSON_PARSE_CHROMIUM_EXTENSIONS); | 
 |   ASSERT_TRUE(parsed_shares); | 
 |   profile()->GetPrefs()->Set(prefs::kNetworkFileSharesPreconfiguredShares, | 
 |                              *parsed_shares); | 
 |  | 
 |   CreateService(profile()); | 
 |   EXPECT_TRUE(smb_service->IsAnySmbShareConfigured()); | 
 | } | 
 |  | 
 | }  // namespace ash::smb_client |