|  | // 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 <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "ash/shell.h" | 
|  | #include "base/files/file_path.h" | 
|  | #include "base/files/file_util.h" | 
|  | #include "base/run_loop.h" | 
|  | #include "base/task/single_thread_task_runner.h" | 
|  | #include "base/test/bind.h" | 
|  | #include "base/test/scoped_feature_list.h" | 
|  | #include "base/threading/thread_restrictions.h" | 
|  | #include "chrome/browser/ui/browser.h" | 
|  | #include "chrome/browser/ui/browser_window.h" | 
|  | #include "chrome/test/base/chromeos/crosier/annotations.h" | 
|  | #include "chrome/test/base/chromeos/crosier/chromeos_integration_test_mixin.h" | 
|  | #include "chrome/test/base/chromeos/crosier/helper/test_sudo_helper_client.h" | 
|  | #include "chrome/test/base/in_process_browser_test.h" | 
|  | #include "chrome/test/base/mixin_based_in_process_browser_test.h" | 
|  | #include "chrome/test/base/ui_test_utils.h" | 
|  | #include "content/public/test/browser_test.h" | 
|  | #include "gpu/config/gpu_finch_features.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "third_party/skia/include/core/SkColor.h" | 
|  | #include "ui/display/manager/display_configurator.h" | 
|  | #include "ui/gfx/color_analysis.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | class ScreenshotIntegrationTest : public MixinBasedInProcessBrowserTest, | 
|  | public testing::WithParamInterface<bool> { | 
|  | public: | 
|  | ScreenshotIntegrationTest() { | 
|  | if (UseVulkan()) { | 
|  | // Check for board support because enabling the ScopedFeatureList, | 
|  | // otherwise GPU process initialization will crash before the test body. | 
|  | if (crosier::HasRequirement(crosier::Requirement::kVulkan)) { | 
|  | feature_list_.InitAndEnableFeature(features::kVulkan); | 
|  | } else { | 
|  | skip_test_ = true; | 
|  | } | 
|  | } else { | 
|  | feature_list_.InitAndDisableFeature(features::kVulkan); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool UseVulkan() { return GetParam(); } | 
|  |  | 
|  | // MixinBasedInProcessBrowserTest: | 
|  | void TearDownOnMainThread() override { | 
|  | // Clean up even if the test was skipped. | 
|  | browser()->window()->Close(); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | base::test::ScopedFeatureList feature_list_; | 
|  | bool skip_test_ = false; | 
|  | ChromeOSIntegrationTestMixin chromeos_integration_test_mixin_{&mixin_host_}; | 
|  | }; | 
|  |  | 
|  | INSTANTIATE_TEST_SUITE_P(Vulkan, ScreenshotIntegrationTest, testing::Bool()); | 
|  |  | 
|  | // TODO(b/349252684): Sometimes fails with "CRTC not found. Is the screen on?" | 
|  | // despite the code below that turns on the screen. | 
|  | IN_PROC_BROWSER_TEST_P(ScreenshotIntegrationTest, DISABLED_AverageColor) { | 
|  | if (skip_test_) { | 
|  | GTEST_SKIP() << "Skipping test because target doesn't support Vulkan."; | 
|  | } | 
|  |  | 
|  | // Ensure the display is powered on, otherwise the screenshot will fail. | 
|  | base::RunLoop run_loop; | 
|  | ash::Shell::Get()->display_configurator()->SetDisplayPower( | 
|  | chromeos::DISPLAY_POWER_ALL_ON, | 
|  | display::DisplayConfigurator::kSetDisplayPowerForceProbe, | 
|  | base::BindLambdaForTesting([&](bool success) { | 
|  | ASSERT_TRUE(success); | 
|  | run_loop.Quit(); | 
|  | })); | 
|  | run_loop.Run(); | 
|  |  | 
|  | // Maximize the browser window. | 
|  | ASSERT_TRUE(browser()); | 
|  | browser()->window()->Maximize(); | 
|  |  | 
|  | // Load a page with a solid red background. | 
|  | ASSERT_TRUE(ui_test_utils::NavigateToURL( | 
|  | browser(), GURL("data:text/html,<body bgcolor=red></body>"))); | 
|  |  | 
|  | // We don't know when the frame's pixels will be scanned out, so take | 
|  | // screenshots in a loop until we get a valid one. | 
|  | SkColor dominant_color; | 
|  | bool success = false; | 
|  | for (int i = 0; i < 10; ++i) { | 
|  | // Sleep for 1 second. | 
|  | base::RunLoop run_loop2; | 
|  | base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( | 
|  | FROM_HERE, run_loop2.QuitClosure(), base::Seconds(1)); | 
|  | run_loop2.Run(); | 
|  |  | 
|  | // Use the command-line screenshot utility to capture the screen. | 
|  | auto result = | 
|  | TestSudoHelperClient().RunCommand("screenshot /tmp/screen.png"); | 
|  | ASSERT_EQ(result.return_code, 0) << result.output; | 
|  |  | 
|  | // Load the PNG screenshot. | 
|  | base::ScopedAllowBlockingForTesting allow_blocking; | 
|  | std::optional<std::vector<uint8_t>> image_png = | 
|  | base::ReadFileToBytes(base::FilePath("/tmp/screen.png")); | 
|  | ASSERT_TRUE(image_png.has_value()); | 
|  |  | 
|  | // Compute the dominant color. | 
|  | dominant_color = color_utils::CalculateKMeanColorOfPNG(*image_png); | 
|  |  | 
|  | // If the color matches the red page background, we're done. | 
|  | if (dominant_color == SK_ColorRED) { | 
|  | success = true; | 
|  | break; | 
|  | } | 
|  |  | 
|  | // The screen may not yet have valid pixels yet. | 
|  | LOG(WARNING) << "Dominant color " << std::hex << dominant_color | 
|  | << " does not match expected " << SK_ColorRED; | 
|  | } | 
|  | EXPECT_TRUE(success) << "Final screenshot had invalid dominant color " | 
|  | << std::hex << dominant_color; | 
|  | } | 
|  |  | 
|  | }  // namespace |