chromium/chrome/browser/ui/ash/assistant/assistant_browsertest.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 "ash/public/cpp/test/app_list_test_api.h"
#include "base/command_line.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_run_loop_timeout.h"
#include "base/time/time.h"
#include "chrome/browser/ui/ash/assistant/assistant_test_mixin.h"
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "chromeos/ash/components/assistant/test_support/expect_utils.h"
#include "chromeos/ash/components/audio/cras_audio_handler.h"
#include "chromeos/ash/services/assistant/public/cpp/features.h"
#include "chromeos/ash/services/assistant/public/cpp/switches.h"
#include "chromeos/ash/services/assistant/service.h"
#include "chromeos/dbus/power_manager/backlight.pb.h"
#include "content/public/test/browser_test.h"
#include "sandbox/policy/switches.h"

namespace ash::assistant {

namespace {

using test::ExpectResult;

// Please remember to set auth token when running in |kProxy| mode.
constexpr auto kMode = FakeS3Mode::kReplay;
// Update this when you introduce breaking changes to existing tests.
constexpr int kVersion = 1;

constexpr int kStartBrightnessPercent = 50;

inline constexpr char kDlcInstallResultHistogram[] =
    "Assistant.Libassistant.DlcInstallResult";

inline constexpr char kDlcLoadStatusHistogram[] =
    "Assistant.Libassistant.DlcLoadStatus";

// Ensures that |value_| is within the range {min_, max_}. If it isn't, this
// will print a nice error message.
#define EXPECT_WITHIN_RANGE(min_, value_, max_)                \
  ({                                                           \
    EXPECT_TRUE(min_ <= value_ && value_ <= max_)              \
        << "Expected " << value_ << " to be within the range " \
        << "{" << min_ << ", " << max_ << "}.";                \
  })

}  // namespace

// All tests are disabled because LibAssistant V2 binary does not run on Linux
// bot. To run the tests on gLinux, please add
// `--gtest_also_run_disabled_tests`.
class DISABLED_AssistantBrowserTest : public MixinBasedInProcessBrowserTest,
                                      public testing::WithParamInterface<bool> {
 public:
  DISABLED_AssistantBrowserTest() {
    // Do not log to file in test. Otherwise multiple tests may create/delete
    // the log file at the same time. See http://crbug.com/1307868.
    base::CommandLine::ForCurrentProcess()->AppendSwitch(
        switches::kDisableLibAssistantLogfile);

    // In browser tests, the fake_s3_server uses gRPC framework, which is not
    // allowed in the sandbox by default. Instead of enabling and setting up the
    // gRPC policy, we do not enable sandbox in the tests.
    base::CommandLine::ForCurrentProcess()->AppendSwitch(
        sandbox::policy::switches::kNoSandbox);
  }

  DISABLED_AssistantBrowserTest(const DISABLED_AssistantBrowserTest&) = delete;
  DISABLED_AssistantBrowserTest& operator=(
      const DISABLED_AssistantBrowserTest&) = delete;

  ~DISABLED_AssistantBrowserTest() override = default;

  AssistantTestMixin* tester() { return &tester_; }

  void ShowAssistantUi() {
    if (!tester()->IsVisible())
      tester()->PressAssistantKey();

    // Make sure that the app list bubble finished showing.
    AppListTestApi().WaitForBubbleWindow(
        /*wait_for_opening_animation=*/false);
  }

  void CloseAssistantUi() {
    if (tester()->IsVisible())
      tester()->PressAssistantKey();
  }

  void InitializeBrightness() {
    auto* power_manager = chromeos::PowerManagerClient::Get();
    power_manager::SetBacklightBrightnessRequest request;
    request.set_percent(kStartBrightnessPercent);
    request.set_transition(
        power_manager::SetBacklightBrightnessRequest_Transition_INSTANT);
    request.set_cause(
        power_manager::SetBacklightBrightnessRequest_Cause_USER_REQUEST);
    chromeos::PowerManagerClient::Get()->SetScreenBrightness(request);

    // Wait for the initial value to settle.
    ExpectResult(
        true, base::BindLambdaForTesting([&]() {
          constexpr double kEpsilon = 0.1;
          auto current_brightness = tester()->SyncCall(base::BindOnce(
              &chromeos::PowerManagerClient::GetScreenBrightnessPercent,
              base::Unretained(power_manager)));
          return current_brightness &&
                 std::abs(kStartBrightnessPercent -
                          current_brightness.value()) < kEpsilon;
        }));
  }

  void ExpectBrightnessUp() {
    auto* power_manager = chromeos::PowerManagerClient::Get();
    // Check the brightness changes
    ExpectResult(
        true, base::BindLambdaForTesting([&]() {
          constexpr double kEpsilon = 1;
          auto current_brightness = tester()->SyncCall(base::BindOnce(
              &chromeos::PowerManagerClient::GetScreenBrightnessPercent,
              base::Unretained(power_manager)));

          return current_brightness && (current_brightness.value() -
                                        kStartBrightnessPercent) > kEpsilon;
        }));
  }

  void ExpectBrightnessDown() {
    auto* power_manager = chromeos::PowerManagerClient::Get();
    // Check the brightness changes
    ExpectResult(
        true, base::BindLambdaForTesting([&]() {
          constexpr double kEpsilon = 1;
          auto current_brightness = tester()->SyncCall(base::BindOnce(
              &chromeos::PowerManagerClient::GetScreenBrightnessPercent,
              base::Unretained(power_manager)));

          return current_brightness && (kStartBrightnessPercent -
                                        current_brightness.value()) > kEpsilon;
        }));
  }

  base::HistogramTester* histogram_tester() { return &histogram_tester_; }

 private:
  base::HistogramTester histogram_tester_;
  AssistantTestMixin tester_{&mixin_host_, this, embedded_test_server(), kMode,
                             kVersion};
};

IN_PROC_BROWSER_TEST_F(DISABLED_AssistantBrowserTest,
                       ShouldOpenAssistantUiWhenPressingAssistantKey) {
  tester()->StartAssistantAndWaitForReady();

  tester()->PressAssistantKey();

  // Make sure that the app list bubble finished showing (the app list view gets
  // created asynchronously).
  AppListTestApi().WaitForBubbleWindow(
      /*wait_for_opening_animation=*/false);

  EXPECT_TRUE(tester()->IsVisible());
  histogram_tester()->ExpectTotalCount(kDlcInstallResultHistogram, 1);
  histogram_tester()->ExpectTotalCount(kDlcLoadStatusHistogram, 1);
}

IN_PROC_BROWSER_TEST_F(DISABLED_AssistantBrowserTest,
                       ShouldDisplayTextResponse) {
  tester()->StartAssistantAndWaitForReady();

  ShowAssistantUi();

  tester()->SendTextQuery("test");
  tester()->ExpectAnyOfTheseTextResponses({
      "No one told me there would be a test",
      "You're coming in loud and clear",
      "debug OK",
      "I can assure you, this thing's on",
      "Is this thing on?",
  });
}

IN_PROC_BROWSER_TEST_F(DISABLED_AssistantBrowserTest,
                       ShouldDisplayTextResponseWithTwoContiniousQueries) {
  tester()->StartAssistantAndWaitForReady();

  ShowAssistantUi();

  tester()->SendTextQuery("phone");
  tester()->SendTextQuery("test");
  tester()->ExpectAnyOfTheseTextResponses({
      "No one told me there would be a test",
      "You're coming in loud and clear",
      "debug OK",
      "I can assure you, this thing's on",
      "Is this thing on?",
  });
}

IN_PROC_BROWSER_TEST_F(DISABLED_AssistantBrowserTest,
                       ShouldDisplayCardResponse) {
  tester()->StartAssistantAndWaitForReady();

  ShowAssistantUi();

  ASSERT_TRUE(tester()->IsVisible());

  tester()->SendTextQuery("What is the highest mountain in the world?");
  tester()->ExpectCardResponse("Mount Everest");
}

IN_PROC_BROWSER_TEST_F(DISABLED_AssistantBrowserTest, ShouldTurnUpVolume) {
  tester()->StartAssistantAndWaitForReady();

  ShowAssistantUi();

  ASSERT_TRUE(tester()->IsVisible());

  auto* cras = CrasAudioHandler::Get();
  constexpr int kStartVolumePercent = 50;
  cras->SetOutputVolumePercent(kStartVolumePercent);
  EXPECT_EQ(kStartVolumePercent, cras->GetOutputVolumePercent());

  tester()->SendTextQuery("turn up volume");

  ExpectResult(true, base::BindRepeating(
                         [](CrasAudioHandler* cras) {
                           return cras->GetOutputVolumePercent() >
                                  kStartVolumePercent;
                         },
                         cras));
}

IN_PROC_BROWSER_TEST_F(DISABLED_AssistantBrowserTest, ShouldTurnDownVolume) {
  tester()->StartAssistantAndWaitForReady();

  ShowAssistantUi();

  ASSERT_TRUE(tester()->IsVisible());

  auto* cras = CrasAudioHandler::Get();
  constexpr int kStartVolumePercent = 50;
  cras->SetOutputVolumePercent(kStartVolumePercent);
  EXPECT_EQ(kStartVolumePercent, cras->GetOutputVolumePercent());

  tester()->SendTextQuery("turn down volume");

  ExpectResult(true, base::BindRepeating(
                         [](CrasAudioHandler* cras) {
                           return cras->GetOutputVolumePercent() <
                                  kStartVolumePercent;
                         },
                         cras));
}

IN_PROC_BROWSER_TEST_F(DISABLED_AssistantBrowserTest, ShouldTurnUpBrightness) {
  tester()->StartAssistantAndWaitForReady();

  ShowAssistantUi();

  ASSERT_TRUE(tester()->IsVisible());

  InitializeBrightness();

  tester()->SendTextQuery("turn up brightness");

  ExpectBrightnessUp();
}

IN_PROC_BROWSER_TEST_F(DISABLED_AssistantBrowserTest,
                       ShouldTurnDownBrightness) {
  tester()->StartAssistantAndWaitForReady();

  ShowAssistantUi();

  ASSERT_TRUE(tester()->IsVisible());

  InitializeBrightness();

  tester()->SendTextQuery("turn down brightness");

  ExpectBrightnessDown();
}

IN_PROC_BROWSER_TEST_F(DISABLED_AssistantBrowserTest,
                       ShouldPuntWhenChangingUnsupportedSetting) {
  tester()->StartAssistantAndWaitForReady();

  ShowAssistantUi();

  ASSERT_TRUE(tester()->IsVisible());

  tester()->SendTextQuery("enable night mode");

  tester()->ExpectTextResponse("Night Mode isn't available on your device");
}

// TODO(crbug.com/40142964): Disabled because it's flaky.
IN_PROC_BROWSER_TEST_F(DISABLED_AssistantBrowserTest,
                       ShouldShowSingleErrorOnNetworkDown) {
  tester()->StartAssistantAndWaitForReady();

  ShowAssistantUi();

  ASSERT_TRUE(tester()->IsVisible());

  tester()->DisableFakeS3Server();

  base::RunLoop().RunUntilIdle();

  tester()->SendTextQuery("Is this thing on?");

  tester()->ExpectErrorResponse(
      "Something went wrong. Try again in a few seconds");

  // Make sure no further changes happen to the view hierarchy.
  tester()->ExpectNoChange(base::Seconds(1));

  // This is necessary to prevent a UserInitiatedVoicelessActivity from
  // blocking test harness teardown while we wait on assistant to finish
  // the interaction.
  CloseAssistantUi();
}

}  // namespace ash::assistant