chromium/chrome/browser/ash/file_manager/file_tasks_notifier_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 "chrome/browser/ash/file_manager/file_tasks_notifier.h"

#include <memory>
#include <string>
#include <utility>

#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/scoped_observation.h"
#include "base/test/bind.h"
#include "chrome/browser/ash/file_manager/file_tasks_observer.h"
#include "chrome/browser/ash/file_manager/path_util.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/ash/components/drivefs/mojom/drivefs.mojom-test-utils.h"
#include "chromeos/ash/components/drivefs/mojom/drivefs.mojom.h"
#include "components/drive/file_errors.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/fake_download_item.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "storage/browser/file_system/external_mount_points.h"
#include "storage/browser/file_system/file_system_url.h"
#include "storage/common/file_system/file_system_types.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "ui/shell_dialogs/selected_file_info.h"

namespace file_manager {
namespace file_tasks {
namespace {

using testing::_;

storage::FileSystemURL CreateFileSystemUrl(
    const base::FilePath& path,
    storage::FileSystemType type = storage::kFileSystemTypeLocal) {
  return storage::FileSystemURL::CreateForTest({}, {}, {}, "", type, path, "",
                                               {});
}

ui::SelectedFileInfo CreateSelectedFileInfo(
    const base::FilePath& path,
    const base::FilePath& local_path = {}) {
  return ui::SelectedFileInfo(path, local_path);
}

class FakeDriveFs : public drivefs::mojom::DriveFsInterceptorForTesting {
 public:
  DriveFs* GetForwardingInterface() override {
    NOTREACHED_IN_MIGRATION();
    return nullptr;
  }

  void GetMetadata(const base::FilePath& path,
                   GetMetadataCallback callback) override {
    if (path.value().find("offline") != std::string::npos) {
      auto metadata = drivefs::mojom::FileMetadata::New();
      metadata->available_offline = path.value() == "available_offline";
      metadata->capabilities = drivefs::mojom::Capabilities::New();
      std::move(callback).Run(drive::FILE_ERROR_OK, std::move(metadata));
      return;
    }
    if (path.value() == "not_found") {
      std::move(callback).Run(drive::FILE_ERROR_NOT_FOUND, nullptr);
      return;
    }
    if (path.value() == "error") {
      std::move(callback).Run(drive::FILE_ERROR_SERVICE_UNAVAILABLE, nullptr);
      return;
    }
    ADD_FAILURE() << "Unexpected DriveFS metadata request for " << path;
    std::move(callback).Run(drive::FILE_ERROR_INVALID_URL, nullptr);
  }
};

class MockFileTasksObserver : public file_tasks::FileTasksObserver {
 public:
  explicit MockFileTasksObserver(FileTasksNotifier* notifier) {
    observation_.Observe(notifier);
  }

  MOCK_METHOD2(OnFilesOpenedImpl,
               void(const base::FilePath& path, OpenType open_type));

  void OnFilesOpened(const std::vector<FileOpenEvent>& opens) override {
    ASSERT_TRUE(!opens.empty());
    for (auto& open : opens) {
      OnFilesOpenedImpl(open.path, open.open_type);
    }
  }

 private:
  base::ScopedObservation<file_tasks::FileTasksNotifier,
                          file_tasks::FileTasksObserver>
      observation_{this};
};

class FileTasksNotifierForTest : public FileTasksNotifier {
 public:
  FileTasksNotifierForTest(Profile* profile,
                           mojo::PendingRemote<drivefs::mojom::DriveFs> drivefs)
      : FileTasksNotifier(profile), drivefs_(std::move(drivefs)) {}

  drivefs::mojom::DriveFs* GetDriveFsInterface() override {
    return drivefs_.get();
  }

  bool GetRelativeDrivePath(const base::FilePath& path,
                            base::FilePath* drive_relative_path) override {
    *drive_relative_path = path.BaseName();
    return true;
  }

  bool IsOffline() override { return is_offline_; }

  void set_is_offline(bool is_offline) { is_offline_ = is_offline; }

 private:
  const mojo::Remote<drivefs::mojom::DriveFs> drivefs_;
  bool is_offline_ = false;
};

class FileTasksNotifierTest : public testing::Test {
 protected:
  FileTasksNotifierTest() = default;

  void SetUp() override {
    // crbug.com/1301822 Revoke external file systems before use.
    auto* mount_points = storage::ExternalMountPoints::GetSystemInstance();
    mount_points->RevokeAllFileSystems();

    profile_ = std::make_unique<TestingProfile>();
    notifier_ = std::make_unique<FileTasksNotifierForTest>(
        profile_.get(), drivefs_receiver_.BindNewPipeAndPassRemote());
    observation_ = std::make_unique<MockFileTasksObserver>(notifier_.get());

    my_files_ = util::GetMyFilesFolderForProfile(profile_.get());
    ASSERT_TRUE(base::CreateDirectory(my_files_));
    base::WriteFile(my_files_.Append("file"), "data");
    ASSERT_TRUE(mount_points->RegisterFileSystem(
        "downloads", storage::kFileSystemTypeLocal, {}, my_files_));
    ASSERT_TRUE(mount_points->RegisterFileSystem(
        "drivefs", storage::kFileSystemTypeDriveFs, {},
        base::FilePath("/media/fuse/drivefs")));
    ASSERT_TRUE(mount_points->RegisterFileSystem(
        "arc-documents-provider", storage::kFileSystemTypeArcDocumentsProvider,
        {}, base::FilePath("/special/arc-documents-provider")));
  }

  void TearDown() override {
    auto* mount_points = storage::ExternalMountPoints::GetSystemInstance();
    mount_points->RevokeFileSystem("downloads");
    mount_points->RevokeFileSystem("drivefs");
    mount_points->RevokeFileSystem("arc-documents-provider");

    observation_.reset();
    notifier_.reset();
    profile_.reset();
  }

  Profile& profile() { return *profile_; }
  MockFileTasksObserver& observer() { return *observation_; }
  FileTasksNotifierForTest& notifier() { return *notifier_; }

  download::DownloadItem* CreateCompletedDownloadItem(
      const base::FilePath& path) {
    download_item_ = std::make_unique<content::FakeDownloadItem>();
    download_item_->SetTargetFilePath(path);
    download_item_->SetState(download::DownloadItem::DownloadState::COMPLETE);
    return download_item_.get();
  }

  const base::FilePath& my_files() { return my_files_; }

 private:
  content::BrowserTaskEnvironment task_environment_;
  FakeDriveFs fake_drivefs_;
  mojo::Receiver<drivefs::mojom::DriveFs> drivefs_receiver_{&fake_drivefs_};
  std::unique_ptr<TestingProfile> profile_;
  std::unique_ptr<FileTasksNotifierForTest> notifier_;
  std::unique_ptr<MockFileTasksObserver> observation_;
  std::unique_ptr<content::FakeDownloadItem> download_item_;
  base::FilePath my_files_;
};

TEST_F(FileTasksNotifierTest, FileTask_Local) {
  base::FilePath path = my_files().Append("file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kLaunch));
  notifier().NotifyFileTasks({CreateFileSystemUrl(path)});
}

TEST_F(FileTasksNotifierTest, FileTask_DriveFs) {
  base::FilePath path("/media/fuse/drivefs-abcedf/root/file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kLaunch));
  notifier().NotifyFileTasks(
      {CreateFileSystemUrl(path, storage::kFileSystemTypeDriveFs)});
}

TEST_F(FileTasksNotifierTest, FileTask_Arc) {
  base::FilePath path("/run/arc/sdcard/write/emulated/0/file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kLaunch));
  notifier().NotifyFileTasks({CreateFileSystemUrl(path)});
}

TEST_F(FileTasksNotifierTest, FileTask_Crostini) {
  base::FilePath path("/media/fuse/crostini-abcdef/file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kLaunch));
  notifier().NotifyFileTasks({CreateFileSystemUrl(path)});
}

TEST_F(FileTasksNotifierTest, FileTask_UnknownPath) {
  base::FilePath path("/some/other/path");
  EXPECT_CALL(observer(), OnFilesOpenedImpl(_, _)).Times(0);
  notifier().NotifyFileTasks({CreateFileSystemUrl(path)});
}

TEST_F(FileTasksNotifierTest, FileTask_RemovableMedia) {
  base::FilePath path("/media/removable/device/file");
  EXPECT_CALL(observer(), OnFilesOpenedImpl(_, _)).Times(0);
  notifier().NotifyFileTasks({CreateFileSystemUrl(path)});
}

TEST_F(FileTasksNotifierTest, FileTask_ArcDocumentsProvider) {
  base::FilePath path("/special/arc-documents-provider/root/file");
  EXPECT_CALL(observer(), OnFilesOpenedImpl(_, _)).Times(0);
  notifier().NotifyFileTasks({CreateFileSystemUrl(
      path, storage::kFileSystemTypeArcDocumentsProvider)});
}

TEST_F(FileTasksNotifierTest, FileTask_Multiple) {
  base::FilePath local_path = my_files().Append("file");
  base::FilePath drivefs_path("/media/fuse/drivefs-abcedf/root/file");
  base::FilePath arc_path("/run/arc/sdcard/write/emulated/0/file");
  base::FilePath crostini_path("/media/fuse/crostini-abcdef/file");
  base::FilePath unknown_path("/some/other/path");
  base::FilePath removable_path("/media/removable/device/file");
  base::FilePath arc_documents_provider_path(
      "/special/arc-documents-provider/root/file");
  EXPECT_CALL(
      observer(),
      OnFilesOpenedImpl(local_path, FileTasksObserver::OpenType::kLaunch));
  EXPECT_CALL(
      observer(),
      OnFilesOpenedImpl(drivefs_path, FileTasksObserver::OpenType::kLaunch));
  EXPECT_CALL(observer(), OnFilesOpenedImpl(
                              arc_path, FileTasksObserver::OpenType::kLaunch));
  EXPECT_CALL(
      observer(),
      OnFilesOpenedImpl(crostini_path, FileTasksObserver::OpenType::kLaunch));
  notifier().NotifyFileTasks({
      CreateFileSystemUrl(local_path),
      CreateFileSystemUrl(drivefs_path, storage::kFileSystemTypeDriveFs),
      CreateFileSystemUrl(arc_path),
      CreateFileSystemUrl(crostini_path),
      CreateFileSystemUrl(unknown_path),
      CreateFileSystemUrl(removable_path),
      CreateFileSystemUrl(arc_documents_provider_path),
  });
}

TEST_F(FileTasksNotifierTest, DialogSelection_Local) {
  base::FilePath path = my_files().Append("file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kOpen));
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, true);

  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kSaveAs));
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, false);
}

TEST_F(FileTasksNotifierTest, DialogSelection_DriveFs) {
  base::FilePath path("/media/fuse/drivefs-abcdef/root/file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kOpen));
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, true);

  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kSaveAs));
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, false);
}

TEST_F(FileTasksNotifierTest, DialogSelection_Arc) {
  base::FilePath path("/run/arc/sdcard/write/emulated/0/file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kOpen));
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, true);

  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kSaveAs));
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, false);
}

TEST_F(FileTasksNotifierTest, DialogSelection_Crostini) {
  base::FilePath path("/media/fuse/crostini-abcdef/file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kOpen));
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, true);

  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kSaveAs));
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, false);
}

TEST_F(FileTasksNotifierTest, DialogSelection_UnknownPath) {
  base::FilePath path("/some/other/path");
  EXPECT_CALL(observer(), OnFilesOpenedImpl(_, _)).Times(0);
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, true);
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, false);
}

TEST_F(FileTasksNotifierTest, DialogSelection_RemovableMedia) {
  base::FilePath path("/media/removable/device/file");
  EXPECT_CALL(observer(), OnFilesOpenedImpl(_, _)).Times(0);
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, true);
  notifier().NotifyFileDialogSelection({CreateSelectedFileInfo(path)}, false);
}

TEST_F(FileTasksNotifierTest, DialogSelection_ArcDocumentsProvider) {
  base::FilePath path("/special/arc-documents-provider/root/file");
  base::FilePath local_path =
      profile().GetPath().Append("GCache/v1/files/file");
  EXPECT_CALL(observer(), OnFilesOpenedImpl(_, _)).Times(0);
  notifier().NotifyFileDialogSelection(
      {CreateSelectedFileInfo(path, local_path), CreateSelectedFileInfo(path)},
      true);
  notifier().NotifyFileDialogSelection(
      {CreateSelectedFileInfo(path, local_path), CreateSelectedFileInfo(path)},
      false);
}

TEST_F(FileTasksNotifierTest, DialogSelection_Multiple) {
  base::FilePath local_path = my_files().Append("file");
  base::FilePath drivefs_path("/media/fuse/drivefs-abcdef/root/file");
  base::FilePath arc_path("/run/arc/sdcard/write/emulated/0/file");
  base::FilePath crostini_path("/media/fuse/crostini-abcdef/file");
  base::FilePath unknown_path("/some/other/path");
  base::FilePath removable_path("/media/removable/device/file");
  base::FilePath arc_documents_provider_path(
      "/special/arc-documents-provider/root/file");
  EXPECT_CALL(observer(), OnFilesOpenedImpl(
                              local_path, FileTasksObserver::OpenType::kOpen));
  EXPECT_CALL(
      observer(),
      OnFilesOpenedImpl(drivefs_path, FileTasksObserver::OpenType::kOpen));
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(arc_path, FileTasksObserver::OpenType::kOpen));
  EXPECT_CALL(
      observer(),
      OnFilesOpenedImpl(crostini_path, FileTasksObserver::OpenType::kOpen));

  notifier().NotifyFileDialogSelection(
      {CreateSelectedFileInfo(local_path), CreateSelectedFileInfo(drivefs_path),
       CreateSelectedFileInfo(arc_path), CreateSelectedFileInfo(crostini_path),
       CreateSelectedFileInfo(unknown_path),
       CreateSelectedFileInfo(arc_documents_provider_path),
       CreateSelectedFileInfo(removable_path)},
      true);

  EXPECT_CALL(
      observer(),
      OnFilesOpenedImpl(local_path, FileTasksObserver::OpenType::kSaveAs));
  EXPECT_CALL(
      observer(),
      OnFilesOpenedImpl(drivefs_path, FileTasksObserver::OpenType::kSaveAs));
  EXPECT_CALL(observer(), OnFilesOpenedImpl(
                              arc_path, FileTasksObserver::OpenType::kSaveAs));
  EXPECT_CALL(
      observer(),
      OnFilesOpenedImpl(crostini_path, FileTasksObserver::OpenType::kSaveAs));

  notifier().NotifyFileDialogSelection(
      {CreateSelectedFileInfo(local_path), CreateSelectedFileInfo(drivefs_path),
       CreateSelectedFileInfo(arc_path), CreateSelectedFileInfo(crostini_path),
       CreateSelectedFileInfo(unknown_path),
       CreateSelectedFileInfo(arc_documents_provider_path),
       CreateSelectedFileInfo(removable_path)},
      false);
}

TEST_F(FileTasksNotifierTest, Download_Local) {
  base::FilePath path = my_files().Append("file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kDownload));
  notifier().OnDownloadUpdated(nullptr, CreateCompletedDownloadItem(path));
}

TEST_F(FileTasksNotifierTest, Download_DriveFs) {
  base::FilePath path("/media/fuse/drivefs/root/file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kDownload));
  notifier().OnDownloadUpdated(nullptr, CreateCompletedDownloadItem(path));
}

TEST_F(FileTasksNotifierTest, Download_Arc) {
  base::FilePath path("/run/arc/sdcard/write/emulated/0/file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kDownload));
  notifier().OnDownloadUpdated(nullptr, CreateCompletedDownloadItem(path));
}

TEST_F(FileTasksNotifierTest, Download_Crostini) {
  base::FilePath path("/media/fuse/crostini-abcdef/file");
  EXPECT_CALL(observer(),
              OnFilesOpenedImpl(path, FileTasksObserver::OpenType::kDownload));
  notifier().OnDownloadUpdated(nullptr, CreateCompletedDownloadItem(path));
}

TEST_F(FileTasksNotifierTest, Download_UnknownPath) {
  base::FilePath path("/some/other/path");
  EXPECT_CALL(observer(), OnFilesOpenedImpl(_, _)).Times(0);
  notifier().OnDownloadUpdated(nullptr, CreateCompletedDownloadItem(path));
}

TEST_F(FileTasksNotifierTest, Download_RemovableMedia) {
  base::FilePath path("/media/removable/device/file");
  EXPECT_CALL(observer(), OnFilesOpenedImpl(_, _)).Times(0);
  notifier().OnDownloadUpdated(nullptr, CreateCompletedDownloadItem(path));
}

TEST_F(FileTasksNotifierTest, Download_Incomplete) {
  EXPECT_CALL(observer(), OnFilesOpenedImpl(_, _)).Times(0);
  content::FakeDownloadItem download_item;
  download_item.SetTargetFilePath(my_files().Append("file"));

  for (auto state : {download::DownloadItem::DownloadState::IN_PROGRESS,
                     download::DownloadItem::DownloadState::CANCELLED,
                     download::DownloadItem::DownloadState::INTERRUPTED}) {
    download_item.SetState(state);
    notifier().OnDownloadUpdated(nullptr, &download_item);
  }
}

TEST_F(FileTasksNotifierTest, QueryFileAvailability_NotFound) {
  base::RunLoop run_loop;
  notifier().QueryFileAvailability(
      {my_files().Append("not_found.txt")},
      base::BindLambdaForTesting(
          [&](std::vector<FileTasksNotifier::FileAvailability> results) {
            run_loop.Quit();
            ASSERT_EQ(1u, results.size());
            EXPECT_EQ(FileTasksNotifier::FileAvailability::kGone, results[0]);
          }));
  run_loop.Run();
}

TEST_F(FileTasksNotifierTest, QueryFileAvailability_FileExists) {
  base::RunLoop run_loop;
  notifier().QueryFileAvailability(
      {my_files().Append("file")},
      base::BindLambdaForTesting(
          [&](std::vector<FileTasksNotifier::FileAvailability> results) {
            run_loop.Quit();
            ASSERT_EQ(1u, results.size());
            EXPECT_EQ(FileTasksNotifier::FileAvailability::kOk, results[0]);
          }));
  run_loop.Run();
}

TEST_F(FileTasksNotifierTest, QueryFileAvailability_UnsupportedMountType) {
  base::RunLoop run_loop;
  notifier().QueryFileAvailability(
      {base::FilePath("/special/arc-documents-provider/root/file")},
      base::BindLambdaForTesting(
          [&](std::vector<FileTasksNotifier::FileAvailability> results) {
            run_loop.Quit();
            ASSERT_EQ(1u, results.size());
            EXPECT_EQ(FileTasksNotifier::FileAvailability::kGone, results[0]);
          }));
  run_loop.Run();
}

TEST_F(FileTasksNotifierTest, QueryFileAvailability_OutsideMounts) {
  base::RunLoop run_loop;
  notifier().QueryFileAvailability(
      {base::FilePath("/media/fuse/crostini-abcdef/file")},
      base::BindLambdaForTesting(
          [&](std::vector<FileTasksNotifier::FileAvailability> results) {
            run_loop.Quit();
            ASSERT_EQ(1u, results.size());
            EXPECT_EQ(FileTasksNotifier::FileAvailability::kUnknown,
                      results[0]);
          }));
  run_loop.Run();
}

TEST_F(FileTasksNotifierTest, QueryFileAvailability_DriveFsAvailableOffline) {
  base::RunLoop run_loop;
  notifier().QueryFileAvailability(
      {base::FilePath("/media/fuse/drivefs/root/available_offline")},
      base::BindLambdaForTesting(
          [&](std::vector<FileTasksNotifier::FileAvailability> results) {
            run_loop.Quit();
            ASSERT_EQ(1u, results.size());
            EXPECT_EQ(FileTasksNotifier::FileAvailability::kOk, results[0]);
          }));
  run_loop.Run();
}

TEST_F(FileTasksNotifierTest, QueryFileAvailability_DriveFsUnavailableOffline) {
  base::RunLoop run_loop;
  notifier().QueryFileAvailability(
      {base::FilePath("/media/fuse/drivefs/root/unavailable_offline")},
      base::BindLambdaForTesting(
          [&](std::vector<FileTasksNotifier::FileAvailability> results) {
            run_loop.Quit();
            ASSERT_EQ(1u, results.size());
            EXPECT_EQ(FileTasksNotifier::FileAvailability::kOk, results[0]);
          }));
  run_loop.Run();
}

TEST_F(FileTasksNotifierTest,
       QueryFileAvailability_DriveFsUnavailableOfflineWhileOffline) {
  notifier().set_is_offline(true);

  base::RunLoop run_loop;
  notifier().QueryFileAvailability(
      {base::FilePath("/media/fuse/drivefs/root/unavailable_offline")},
      base::BindLambdaForTesting(
          [&](std::vector<FileTasksNotifier::FileAvailability> results) {
            run_loop.Quit();
            ASSERT_EQ(1u, results.size());
            EXPECT_EQ(
                FileTasksNotifier::FileAvailability::kTemporarilyUnavailable,
                results[0]);
          }));
  run_loop.Run();
}

TEST_F(FileTasksNotifierTest, QueryFileAvailability_DriveFsNotFound) {
  base::RunLoop run_loop;
  notifier().QueryFileAvailability(
      {base::FilePath("/media/fuse/drivefs/root/not_found")},
      base::BindLambdaForTesting(
          [&](std::vector<FileTasksNotifier::FileAvailability> results) {
            run_loop.Quit();
            ASSERT_EQ(1u, results.size());
            EXPECT_EQ(FileTasksNotifier::FileAvailability::kGone, results[0]);
          }));
  run_loop.Run();
}

TEST_F(FileTasksNotifierTest, QueryFileAvailability_DriveFsServiceError) {
  base::RunLoop run_loop;
  notifier().QueryFileAvailability(
      {base::FilePath("/media/fuse/drivefs/root/error")},
      base::BindLambdaForTesting(
          [&](std::vector<FileTasksNotifier::FileAvailability> results) {
            run_loop.Quit();
            ASSERT_EQ(1u, results.size());
            EXPECT_EQ(FileTasksNotifier::FileAvailability::kUnknown,
                      results[0]);
          }));
  run_loop.Run();
}

TEST_F(FileTasksNotifierTest, QueryFileAvailability_Multiple) {
  notifier().set_is_offline(true);

  base::RunLoop run_loop;
  notifier().QueryFileAvailability(
      {my_files().Append("not_found"), my_files().Append("file"),
       base::FilePath("/special/arc-documents-provider/root/file"),
       base::FilePath("/media/fuse/crostini-abcdef/file"),
       base::FilePath("/media/fuse/drivefs/root/available_offline"),
       base::FilePath("/media/fuse/drivefs/root/unavailable_offline"),
       base::FilePath("/media/fuse/drivefs/root/not_found"),
       base::FilePath("/media/fuse/drivefs/root/error")},
      base::BindLambdaForTesting(
          [&](std::vector<FileTasksNotifier::FileAvailability> results) {
            run_loop.Quit();
            EXPECT_EQ((std::vector<FileTasksNotifier::FileAvailability>{
                          FileTasksNotifier::FileAvailability::kGone,
                          FileTasksNotifier::FileAvailability::kOk,
                          FileTasksNotifier::FileAvailability::kGone,
                          FileTasksNotifier::FileAvailability::kUnknown,
                          FileTasksNotifier::FileAvailability::kOk,
                          FileTasksNotifier::FileAvailability::
                              kTemporarilyUnavailable,
                          FileTasksNotifier::FileAvailability::kGone,
                          FileTasksNotifier::FileAvailability::kUnknown}),
                      results);
          }));
  run_loop.Run();
}

}  // namespace
}  // namespace file_tasks
}  // namespace file_manager