Add end-to-end browser tests for PluginVm setup flow

Adds end-to-end setup flow browser tests.
This CL also adds DCHECKs that check that UI related calls made in the
UI thread.

Test: browser_tests --gtest_filter="PluginVm*"
Bug: 920988
Change-Id: Ia3ae225f44f05cde4468b72f49a7ecbaa250c42c
Reviewed-on: https://chromium-review.googlesource.com/c/1494881
Commit-Queue: Olya Kalitova <okalitova@chromium.org>
Reviewed-by: Igor <igorcov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#637253}
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.cc b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.cc
index fc072af..e37149a 100644
--- a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.cc
+++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/generated_resources.h"
+#include "content/public/browser/browser_thread.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/text/bytes_formatting.h"
@@ -158,15 +159,13 @@
                    GetLayoutManager()->GetPreferredHeightForWidth(this, width));
 }
 
-PluginVmLauncherView::~PluginVmLauncherView() {
-  plugin_vm_image_manager_->RemoveObserver();
-  g_plugin_vm_launcher_view = nullptr;
+void PluginVmLauncherView::OnDownloadStarted() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 }
 
-void PluginVmLauncherView::OnDownloadStarted() {}
-
 void PluginVmLauncherView::OnDownloadProgressUpdated(uint64_t bytes_downloaded,
                                                      int64_t content_length) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK_EQ(state_, State::DOWNLOADING);
 
   base::Optional<double> fraction_complete =
@@ -178,6 +177,7 @@
 }
 
 void PluginVmLauncherView::OnDownloadCompleted() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK_EQ(state_, State::DOWNLOADING);
 
   plugin_vm_image_manager_->StartUnzipping();
@@ -185,9 +185,12 @@
   OnStateUpdated();
 }
 
-void PluginVmLauncherView::OnDownloadCancelled() {}
+void PluginVmLauncherView::OnDownloadCancelled() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+}
 
 void PluginVmLauncherView::OnDownloadFailed() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   state_ = State::ERROR;
   OnStateUpdated();
 }
@@ -195,6 +198,7 @@
 void PluginVmLauncherView::OnUnzippingProgressUpdated(
     int64_t bytes_unzipped,
     int64_t plugin_vm_image_size) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK_EQ(state_, State::UNZIPPING);
   base::Optional<double> fraction_complete =
       GetFractionComplete(bytes_unzipped, plugin_vm_image_size);
@@ -205,21 +209,18 @@
 }
 
 void PluginVmLauncherView::OnUnzipped() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK_EQ(state_, State::UNZIPPING);
   state_ = State::FINISHED;
   OnStateUpdated();
 }
 
 void PluginVmLauncherView::OnUnzippingFailed() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   state_ = State::ERROR;
   OnStateUpdated();
 }
 
-plugin_vm::PluginVmImageManager*
-PluginVmLauncherView::GetPluginVmImageManagerForTesting() {
-  return plugin_vm_image_manager_;
-}
-
 base::string16 PluginVmLauncherView::GetBigMessage() {
   switch (state_) {
     case State::START_DOWNLOADING:
@@ -234,10 +235,30 @@
   }
 }
 
+PluginVmLauncherView::~PluginVmLauncherView() {
+  plugin_vm_image_manager_->RemoveObserver();
+  g_plugin_vm_launcher_view = nullptr;
+}
+
 void PluginVmLauncherView::AddedToWidget() {
   StartPluginVmImageDownload();
 }
 
+void PluginVmLauncherView::OnStateUpdated() {
+  DialogModelChanged();
+  SetBigMessageLabel();
+  SetMessageLabel();
+  SetBigImage();
+
+  const bool progress_bar_visible =
+      state_ == State::DOWNLOADING || state_ == State::UNZIPPING;
+  progress_bar_->SetVisible(progress_bar_visible);
+  // Values outside the range [0,1] display an infinite loading animation.
+  progress_bar_->SetValue(-1);
+
+  GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
+}
+
 base::string16 PluginVmLauncherView::GetMessage() const {
   switch (state_) {
     case State::START_DOWNLOADING:
@@ -278,21 +299,6 @@
           IDR_PLUGIN_VM_LAUNCHER));
 }
 
-void PluginVmLauncherView::OnStateUpdated() {
-  DialogModelChanged();
-  SetBigMessageLabel();
-  SetMessageLabel();
-  SetBigImage();
-
-  const bool progress_bar_visible =
-      state_ == State::DOWNLOADING || state_ == State::UNZIPPING;
-  progress_bar_->SetVisible(progress_bar_visible);
-  // Values outside the range [0,1] display an infinite loading animation.
-  progress_bar_->SetValue(-1);
-
-  GetWidget()->SetSize(GetWidget()->non_client_view()->GetPreferredSize());
-}
-
 void PluginVmLauncherView::StartPluginVmImageDownload() {
   plugin_vm_image_manager_->SetObserver(this);
   plugin_vm_image_manager_->StartDownload();
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.h b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.h
index f8b8cc7..bda4520 100644
--- a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.h
+++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.h
@@ -47,24 +47,9 @@
   void OnUnzippingFailed() override;
 
   // Public for testing purposes.
-  plugin_vm::PluginVmImageManager* GetPluginVmImageManagerForTesting();
   base::string16 GetBigMessage();
 
  protected:
-  // views::BubbleDialogDelegateView implementation.
-  void AddedToWidget() override;
-
- private:
-  ~PluginVmLauncherView() override;
-
-  base::string16 GetMessage() const;
-  void SetBigMessageLabel();
-  void SetMessageLabel();
-  void SetBigImage();
-  void OnStateUpdated();
-
-  void StartPluginVmImageDownload();
-
   enum class State {
     START_DOWNLOADING,  // PluginVm image downloading should be started.
     DOWNLOADING,        // PluginVm image downloading is in progress.
@@ -74,6 +59,20 @@
   };
 
   State state_ = State::START_DOWNLOADING;
+
+  ~PluginVmLauncherView() override;
+  virtual void OnStateUpdated();
+  // views::BubbleDialogDelegateView implementation.
+  void AddedToWidget() override;
+
+ private:
+  base::string16 GetMessage() const;
+  void SetBigMessageLabel();
+  void SetMessageLabel();
+  void SetBigImage();
+
+  void StartPluginVmImageDownload();
+
   plugin_vm::PluginVmImageManager* plugin_vm_image_manager_ = nullptr;
   views::Label* big_message_label_ = nullptr;
   views::Label* message_label_ = nullptr;
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc
index fa6442f..d11e36f 100644
--- a/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc
+++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view_browsertest.cc
@@ -4,26 +4,100 @@
 
 #include "chrome/browser/ui/views/plugin_vm/plugin_vm_launcher_view.h"
 
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/download/public/background_service/download_metadata.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/scoped_user_pref_update.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/window/dialog_client_view.h"
 
+namespace {
+
+const char kZipFile[] = "/downloads/a_zip_file.zip";
+const char kZippedFile[] = "a_file.txt";
+const char kZipFileHash[] =
+    "bb077522e6c6fec07cf863ca44d5701935c4bc36ed12ef154f4cc22df70aec18";
+const char kNonMatchingHash[] =
+    "842841a4c75a55ad050d686f4ea5f77e83ae059877fe9b6946aa63d3d057ed32";
+const char kJpgFile[] = "/downloads/image.jpg";
+const char kJpgFileHash[] =
+    "01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b";
+
+}  // namespace
+
+class PluginVmLauncherViewForTesting : public PluginVmLauncherView {
+ public:
+  explicit PluginVmLauncherViewForTesting(Profile* profile)
+      : PluginVmLauncherView(profile) {}
+
+  void AddSetupIsFinishedCallbackForTesting(base::RepeatingClosure callback) {
+    setup_is_finished_callback_for_testing_ = callback;
+  }
+
+ private:
+  base::RepeatingClosure setup_is_finished_callback_for_testing_;
+
+  void OnStateUpdated() override {
+    PluginVmLauncherView::OnStateUpdated();
+
+    if (state_ == State::FINISHED || state_ == State::ERROR) {
+      if (setup_is_finished_callback_for_testing_)
+        setup_is_finished_callback_for_testing_.Run();
+    }
+  }
+};
+
 class PluginVmLauncherViewBrowserTest : public DialogBrowserTest {
  public:
+  class SetupObserver {
+   public:
+    void OnSetupFinished() {
+      if (closure_) {
+        base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+                                                      std::move(closure_));
+      }
+    }
+
+    void WaitForSetupToFinish() {
+      base::RunLoop run_loop;
+      closure_ = run_loop.QuitClosure();
+      run_loop.Run();
+    }
+
+   private:
+    base::OnceClosure closure_;
+  };
+
   PluginVmLauncherViewBrowserTest() {}
 
   void SetUp() override { DialogBrowserTest::SetUp(); }
 
+  void SetUpOnMainThread() override {
+    embedded_test_server()->ServeFilesFromSourceDirectory("chrome/test/data");
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+
   // DialogBrowserTest:
   void ShowUi(const std::string& name) override {
-    view_ = new PluginVmLauncherView(browser()->profile());
+    view_ = new PluginVmLauncherViewForTesting(browser()->profile());
+    setup_observer_ = new SetupObserver();
+    view_->AddSetupIsFinishedCallbackForTesting(base::BindRepeating(
+        &SetupObserver::OnSetupFinished, base::Unretained(setup_observer_)));
     views::DialogDelegate::CreateDialogWidget(view_, nullptr, nullptr);
   }
 
+ protected:
+  PluginVmLauncherViewForTesting* view_;
+  SetupObserver* setup_observer_;
+
   bool HasAcceptButton() {
     return view_->GetDialogClientView()->ok_button() != nullptr;
   }
@@ -32,14 +106,6 @@
     return view_->GetDialogClientView()->cancel_button() != nullptr;
   }
 
-  void CheckSetupIsInProgress() {
-    EXPECT_TRUE(HasCancelButton());
-    EXPECT_FALSE(HasAcceptButton());
-    EXPECT_EQ(view_->GetBigMessage(),
-              l10n_util::GetStringUTF16(
-                  IDS_PLUGIN_VM_LAUNCHER_ENVIRONMENT_SETTING_TITLE));
-  }
-
   void CheckSetupFailed() {
     EXPECT_TRUE(HasAcceptButton());
     EXPECT_TRUE(HasCancelButton());
@@ -47,19 +113,45 @@
               l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_RETRY_BUTTON));
     EXPECT_EQ(view_->GetBigMessage(),
               l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_ERROR_TITLE));
+
+    base::FilePath plugin_vm_image_dir =
+        browser()
+            ->profile()
+            ->GetPath()
+            .AppendASCII(plugin_vm::kCrosvmDir)
+            .AppendASCII(plugin_vm::kPvmDir)
+            .AppendASCII(plugin_vm::kPluginVmImageDir);
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    EXPECT_FALSE(base::DirectoryExists(plugin_vm_image_dir));
   }
 
-  void CheckSetupIsCompleted() {
+  void CheckSetupIsFinishedSuccessfully() {
     EXPECT_TRUE(HasAcceptButton());
     EXPECT_FALSE(HasCancelButton());
     EXPECT_EQ(view_->GetDialogButtonLabel(ui::DIALOG_BUTTON_OK),
               l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_LAUNCH_BUTTON));
     EXPECT_EQ(view_->GetBigMessage(),
               l10n_util::GetStringUTF16(IDS_PLUGIN_VM_LAUNCHER_FINISHED_TITLE));
+
+    base::FilePath plugin_vm_image_dir =
+        browser()
+            ->profile()
+            ->GetPath()
+            .AppendASCII(plugin_vm::kCrosvmDir)
+            .AppendASCII(plugin_vm::kPvmDir)
+            .AppendASCII(plugin_vm::kPluginVmImageDir);
+    base::ScopedAllowBlockingForTesting allow_blocking;
+    EXPECT_TRUE(base::DirectoryExists(plugin_vm_image_dir));
+    EXPECT_TRUE(base::PathExists(plugin_vm_image_dir.AppendASCII(kZippedFile)));
   }
 
- protected:
-  PluginVmLauncherView* view_;
+  void SetPluginVmImagePref(std::string url, std::string hash) {
+    DictionaryPrefUpdate update(browser()->profile()->GetPrefs(),
+                                plugin_vm::prefs::kPluginVmImage);
+    base::DictionaryValue* plugin_vm_image = update.Get();
+    plugin_vm_image->SetKey("url", base::Value(url));
+    plugin_vm_image->SetKey("hash", base::Value(hash));
+  }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(PluginVmLauncherViewBrowserTest);
@@ -70,65 +162,64 @@
   ShowAndVerifyUi();
 }
 
-IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest, SetupCompleted) {
-  // TODO(https://crbug.com/904852): Add a proper end-to-end test that
-  // checks that file specified by PluginVmImage user policy is being
-  // downloaded and unzipped to the specified location.
+IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest,
+                       SetupShouldFinishSuccessfully) {
+  SetPluginVmImagePref(embedded_test_server()->GetURL(kZipFile).spec(),
+                       kZipFileHash);
 
   ShowUi("default");
   EXPECT_NE(nullptr, view_);
 
-  CheckSetupIsInProgress();
+  setup_observer_->WaitForSetupToFinish();
 
-  view_->GetPluginVmImageManagerForTesting()->OnDownloadCompleted(
-      download::CompletionInfo());
-
-  CheckSetupIsInProgress();
-
-  view_->GetPluginVmImageManagerForTesting()->OnUnzipped(true /* success */);
-
-  CheckSetupIsCompleted();
-
-  view_->GetDialogClientView()->AcceptWindow();
-
-  EXPECT_TRUE(view_->GetWidget()->IsClosed());
+  CheckSetupIsFinishedSuccessfully();
 }
 
 IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest,
-                       RetryAfterDownloadFailed) {
+                       SetupShouldFailAsHashesDoNotMatch) {
+  SetPluginVmImagePref(embedded_test_server()->GetURL(kZipFile).spec(),
+                       kNonMatchingHash);
+
   ShowUi("default");
   EXPECT_NE(nullptr, view_);
 
-  CheckSetupIsInProgress();
-
-  view_->GetPluginVmImageManagerForTesting()->OnDownloadFailed();
+  setup_observer_->WaitForSetupToFinish();
 
   CheckSetupFailed();
+}
+
+IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest,
+                       SetupShouldFailAsUnzippingFails) {
+  SetPluginVmImagePref(embedded_test_server()->GetURL(kJpgFile).spec(),
+                       kJpgFileHash);
+
+  ShowUi("default");
+  EXPECT_NE(nullptr, view_);
+
+  setup_observer_->WaitForSetupToFinish();
+
+  CheckSetupFailed();
+}
+
+IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest,
+                       CouldRetryAfterFailedSetup) {
+  SetPluginVmImagePref(embedded_test_server()->GetURL(kZipFile).spec(),
+                       kNonMatchingHash);
+
+  ShowUi("default");
+  EXPECT_NE(nullptr, view_);
+
+  setup_observer_->WaitForSetupToFinish();
+
+  CheckSetupFailed();
+
+  SetPluginVmImagePref(embedded_test_server()->GetURL(kZipFile).spec(),
+                       kZipFileHash);
 
   // Retry button clicked to retry the download.
   view_->GetDialogClientView()->AcceptWindow();
 
-  CheckSetupIsInProgress();
-}
+  setup_observer_->WaitForSetupToFinish();
 
-IN_PROC_BROWSER_TEST_F(PluginVmLauncherViewBrowserTest,
-                       RetryAfterUnzippingFailed) {
-  ShowUi("default");
-  EXPECT_NE(nullptr, view_);
-
-  CheckSetupIsInProgress();
-
-  view_->GetPluginVmImageManagerForTesting()->OnDownloadCompleted(
-      download::CompletionInfo());
-
-  CheckSetupIsInProgress();
-
-  view_->GetPluginVmImageManagerForTesting()->OnUnzipped(false /* success */);
-
-  CheckSetupFailed();
-
-  // Retry button clicked to retry the download.
-  view_->GetDialogClientView()->AcceptWindow();
-
-  CheckSetupIsInProgress();
+  CheckSetupIsFinishedSuccessfully();
 }