summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorelizavetai@chromium.org <elizavetai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-21 21:43:59 +0000
committerelizavetai@chromium.org <elizavetai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-07-21 21:43:59 +0000
commit4d1b6920f31b3d19ed54e01593304be8e5d1a7be (patch)
tree9d56d6edc1cf716dfc635288e11444ccab8856a5
parentb22de071523b8ebc09837f5a5b1662708ced71f1 (diff)
downloadchromium_src-4d1b6920f31b3d19ed54e01593304be8e5d1a7be.zip
chromium_src-4d1b6920f31b3d19ed54e01593304be8e5d1a7be.tar.gz
chromium_src-4d1b6920f31b3d19ed54e01593304be8e5d1a7be.tar.bz2
Taking screenshots while running a test
Adds a class ScreenshotTester, which now adds an opportunity to take a screenshot while running a test and then save it to a directory specified by some switch. it is now fully included in LoginUIVisible test. Taking screenshots also requires waiting until all the animation finishes loading. To handle with it, a class AnimationDelayHandler is implemented (in LoginUIVisible). To turn taking screenshots on, switch --enable-test-screenshots should be used. To specify the directory where all the screenshots will be stored, use --screenshot-dest=value, where value is the full path to the directory. It is planned that working with this class will have two modes: taking a new screenshot and saving it, and taking a screenshot and comparing it with the previously stored one. Now only the first mode is implemented, and running it also requires a switch --update-golden-screenshots. Pixel output is usually off in the tests, so before taking screenshots switches --enable-pixel-output-in-tests and --ui-enable-impl-side-painting should be also used. BUG=395653 Review URL: https://codereview.chromium.org/405093003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284504 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/chromeos/login/login_ui_browsertest.cc140
-rw-r--r--chrome/browser/chromeos/login/screenshot_tester.cc103
-rw-r--r--chrome/browser/chromeos/login/screenshot_tester.h67
-rw-r--r--chrome/chrome_tests.gypi2
-rw-r--r--chromeos/chromeos_switches.cc7
-rw-r--r--chromeos/chromeos_switches.h4
6 files changed, 321 insertions, 2 deletions
diff --git a/chrome/browser/chromeos/login/login_ui_browsertest.cc b/chrome/browser/chromeos/login/login_ui_browsertest.cc
index 4f545ed..29bf936 100644
--- a/chrome/browser/chromeos/login/login_ui_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_browsertest.cc
@@ -2,12 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/command_line.h"
#include "base/prefs/pref_service.h"
+#include "base/timer/timer.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/login/login_manager_test.h"
+#include "chrome/browser/chromeos/login/screenshot_tester.h"
#include "chrome/browser/chromeos/login/startup_utils.h"
#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
+#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
#include "chrome/common/pref_names.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "ui/compositor/compositor_switches.h"
namespace chromeos {
@@ -16,12 +27,136 @@ namespace {
const char kTestUser1[] = "test-user1@gmail.com";
const char kTestUser2[] = "test-user2@gmail.com";
+// A class that provides a way to wait until all the animation
+// has loaded and is properly shown on the screen.
+class AnimationDelayHandler : public content::NotificationObserver {
+ public:
+ AnimationDelayHandler();
+
+ // Should be run as early as possible on order not to miss notifications.
+ // It seems though that it can't be moved to constructor(?).
+ void Initialize();
+
+ // Override from content::NotificationObserver.
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ // This method checks if animation is loaded, and, if not,
+ // waits until it is loaded and properly shown on the screen.
+ void WaitUntilAnimationLoads();
+
+ private:
+ void InitializeForWaiting(const base::Closure& quitter);
+
+ // It turns out that it takes some more time for the animation
+ // to finish loading even after all the notifications have been sent.
+ // That happens due to some properties of compositor.
+ // This method should be used after getting all the necessary notifications
+ // to wait for the actual load of animation.
+ void SynchronizeAnimationLoadWithCompositor();
+
+ // This method exists only because of the current implementation of
+ // SynchronizeAnimationLoadWithCompositor.
+ void HandleAnimationLoad();
+
+ // Returns true if, according to the notificatons received, animation has
+ // finished loading by now.
+ bool IsAnimationLoaded();
+
+ base::OneShotTimer<AnimationDelayHandler> timer_;
+ bool waiter_loop_is_on_;
+ bool login_or_lock_webui_visible_;
+ base::Closure animation_waiter_quitter_;
+ content::NotificationRegistrar registrar_;
+};
+
} // anonymous namespace
+AnimationDelayHandler::AnimationDelayHandler()
+ : waiter_loop_is_on_(false), login_or_lock_webui_visible_(false) {
+}
+
+void AnimationDelayHandler::Initialize() {
+ waiter_loop_is_on_ = false;
+ registrar_.Add(this,
+ chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+ content::NotificationService::AllSources());
+}
+
+bool AnimationDelayHandler::IsAnimationLoaded() {
+ return login_or_lock_webui_visible_;
+}
+
+void AnimationDelayHandler::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ if (chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE == type) {
+ login_or_lock_webui_visible_ = true;
+ registrar_.Remove(this,
+ chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
+ content::NotificationService::AllSources());
+ }
+ if (waiter_loop_is_on_ && IsAnimationLoaded()) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE, animation_waiter_quitter_);
+ }
+}
+
+void AnimationDelayHandler::InitializeForWaiting(const base::Closure& quitter) {
+ waiter_loop_is_on_ = true;
+ animation_waiter_quitter_ = quitter;
+}
+
+void AnimationDelayHandler::HandleAnimationLoad() {
+ timer_.Stop();
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE, animation_waiter_quitter_);
+}
+
+// Current implementation is a mockup.
+// It simply waits for 5 seconds, assuming that this time is enough for
+// animation to load completely.
+// TODO(elizavetai): Replace this temporary hack with getting a
+// valid notification from compositor.
+void AnimationDelayHandler::SynchronizeAnimationLoadWithCompositor() {
+ base::RunLoop waiter;
+ animation_waiter_quitter_ = waiter.QuitClosure();
+ timer_.Start(FROM_HERE,
+ base::TimeDelta::FromSeconds(5),
+ this,
+ &AnimationDelayHandler::HandleAnimationLoad);
+ waiter.Run();
+}
+
+void AnimationDelayHandler::WaitUntilAnimationLoads() {
+ if (!IsAnimationLoaded()) {
+ base::RunLoop animation_waiter;
+ InitializeForWaiting(animation_waiter.QuitClosure());
+ animation_waiter.Run();
+ }
+ SynchronizeAnimationLoadWithCompositor();
+}
+
class LoginUITest : public chromeos::LoginManagerTest {
public:
+ bool enable_test_screenshots_;
LoginUITest() : LoginManagerTest(false) {}
virtual ~LoginUITest() {}
+ virtual void SetUpOnMainThread() OVERRIDE {
+ enable_test_screenshots_ = screenshot_tester.TryInitialize();
+ if (enable_test_screenshots_) {
+ animation_delay_handler.Initialize();
+ } else {
+ LOG(WARNING) << "Screenshots will not be taken";
+ }
+ LoginManagerTest::SetUpOnMainThread();
+ }
+
+ protected:
+ AnimationDelayHandler animation_delay_handler;
+ ScreenshotTester screenshot_tester;
};
IN_PROC_BROWSER_TEST_F(LoginUITest, PRE_LoginUIVisible) {
@@ -41,11 +176,14 @@ IN_PROC_BROWSER_TEST_F(LoginUITest, LoginUIVisible) {
".user.emailAddress == '" + std::string(kTestUser1) + "'");
JSExpect("document.querySelectorAll('.pod:not(#user-pod-template)')[1]"
".user.emailAddress == '" + std::string(kTestUser2) + "'");
+ if (enable_test_screenshots_) {
+ animation_delay_handler.WaitUntilAnimationLoads();
+ screenshot_tester.Run("LoginUITest-LoginUIVisible");
+ }
}
IN_PROC_BROWSER_TEST_F(LoginUITest, PRE_InterruptedAutoStartEnrollment) {
StartupUtils::MarkOobeCompleted();
-
PrefService* prefs = g_browser_process->local_state();
prefs->SetBoolean(prefs::kDeviceEnrollmentAutoStart, true);
}
diff --git a/chrome/browser/chromeos/login/screenshot_tester.cc b/chrome/browser/chromeos/login/screenshot_tester.cc
new file mode 100644
index 0000000..683f987
--- /dev/null
+++ b/chrome/browser/chromeos/login/screenshot_tester.cc
@@ -0,0 +1,103 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/login/screenshot_tester.h"
+
+#include "ash/shell.h"
+#include "base/base_export.h"
+#include "base/bind_internal.h"
+#include "base/command_line.h"
+#include "base/memory/weak_ptr.h"
+#include "base/prefs/pref_service.h"
+#include "base/run_loop.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/common/pref_names.h"
+#include "chromeos/chromeos_switches.h"
+#include "content/public/browser/browser_thread.h"
+#include "ui/compositor/compositor_switches.h"
+#include "ui/gfx/image/image.h"
+#include "ui/snapshot/snapshot.h"
+
+namespace chromeos {
+
+ScreenshotTester::ScreenshotTester() : weak_factory_(this) {
+}
+
+ScreenshotTester::~ScreenshotTester() {
+}
+
+bool ScreenshotTester::TryInitialize() {
+ CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (!command_line.HasSwitch(switches::kEnableScreenshotTesting))
+ return false;
+ if (!command_line.HasSwitch(::switches::kEnablePixelOutputInTests) ||
+ !command_line.HasSwitch(::switches::kUIEnableImplSidePainting)) {
+ // TODO(elizavetai): make turning on --enable-pixel-output-in-tests
+ // and --ui-enable-impl-side-painting automatical.
+ LOG(ERROR) << "--enable-pixel-output-in-tests and "
+ << "--ui-enable-impl-side-painting are required to take "
+ << "screenshots";
+ return false;
+ }
+ if (!command_line.HasSwitch(switches::kScreenshotDestinationDir)) {
+ LOG(ERROR) << "No destination for screenshots specified";
+ return false;
+ }
+ screenshot_dest_ = command_line.GetSwitchValuePath(
+ chromeos::switches::kScreenshotDestinationDir);
+ return true;
+}
+
+void ScreenshotTester::Run(const std::string& file_name) {
+ TakeScreenshot();
+ PNGFile current_screenshot = screenshot_;
+ UpdateGoldenScreenshot(file_name, current_screenshot);
+}
+
+void ScreenshotTester::UpdateGoldenScreenshot(const std::string& file_name,
+ PNGFile png_data) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ if (!png_data) {
+ LOG(ERROR) << "Can't take a screenshot";
+ return;
+ }
+ base::FilePath golden_screenshot_path =
+ screenshot_dest_.AppendASCII(file_name + ".png");
+ if (!base::CreateDirectory(golden_screenshot_path.DirName())) {
+ LOG(ERROR) << "Can't create a directory ";
+ return;
+ }
+ if (static_cast<size_t>(
+ base::WriteFile(golden_screenshot_path,
+ reinterpret_cast<char*>(&(png_data->data()[0])),
+ png_data->size())) != png_data->size()) {
+ LOG(ERROR) << "Can't save screenshot";
+ }
+ VLOG(0) << "Golden screenshot updated successfully";
+}
+
+void ScreenshotTester::ReturnScreenshot(PNGFile png_data) {
+ // TODO(elizavetai): rewrite this function so that TakeScreenshot
+ // could return a |PNGFile| -- current screenshot.
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ screenshot_ = png_data;
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE, run_loop_quitter_);
+}
+
+void ScreenshotTester::TakeScreenshot() {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ aura::Window* primary_window = ash::Shell::GetPrimaryRootWindow();
+ gfx::Rect rect = primary_window->bounds();
+ ui::GrabWindowSnapshotAsync(primary_window,
+ rect,
+ content::BrowserThread::GetBlockingPool(),
+ base::Bind(&ScreenshotTester::ReturnScreenshot,
+ weak_factory_.GetWeakPtr()));
+ base::RunLoop run_loop;
+ run_loop_quitter_ = run_loop.QuitClosure();
+ run_loop.Run();
+}
+
+} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screenshot_tester.h b/chrome/browser/chromeos/login/screenshot_tester.h
new file mode 100644
index 0000000..5a1d052
--- /dev/null
+++ b/chrome/browser/chromeos/login/screenshot_tester.h
@@ -0,0 +1,67 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREENSHOT_TESTER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENSHOT_TESTER_H_
+
+#include "base/base_export.h"
+#include "base/bind_internal.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/weak_ptr.h"
+#include "base/run_loop.h"
+
+namespace chromeos {
+
+// A class that allows taking, saving and comparing screnshots while
+// running tests.
+class ScreenshotTester {
+ public:
+ ScreenshotTester();
+ virtual ~ScreenshotTester();
+
+ // Returns true if the screenshots should be taken and will be taken,
+ // false otherwise. Also gets all the information from the command line
+ // swithes.
+ bool TryInitialize();
+
+ // Does all the work that has been stated through switches:
+ // updates golden screenshot or takes a new screenshot and compares it
+ // with the golden one (this part is not implemented yet).
+ void Run(const std::string& file_name);
+
+ private:
+ typedef scoped_refptr<base::RefCountedBytes> PNGFile;
+
+ // Takes a screenshot and puts it to |screenshot_| field.
+ void TakeScreenshot();
+
+ // Saves |png_data| as a new golden screenshot for this test.
+ void UpdateGoldenScreenshot(const std::string& file_name, PNGFile png_data);
+
+ // Saves |png_data| as a current screenshot.
+ void ReturnScreenshot(PNGFile png_data);
+
+ // Path to the directory for golden screenshots.
+ base::FilePath screenshot_dest_;
+
+ // |run_loop_| and |run_loop_quitter_| are used to synchronize
+ // with ui::GrabWindowSnapshotAsync.
+ base::RunLoop run_loop_;
+ base::Closure run_loop_quitter_;
+
+ // Current screenshot.
+ PNGFile screenshot_;
+
+ // Is true when we running updating golden screenshots mode.
+ bool update_golden_screenshot_;
+ base::WeakPtrFactory<ScreenshotTester> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenshotTester);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENSHOT_TESTER_H_
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 0baab89..a9f6a3f 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -285,6 +285,8 @@
'browser/chromeos/login/login_manager_test.h',
'browser/chromeos/login/login_ui_browsertest.cc',
'browser/chromeos/login/oobe_browsertest.cc',
+ 'browser/chromeos/login/screenshot_tester.h',
+ 'browser/chromeos/login/screenshot_tester.cc',
'browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc',
'browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.cc',
'browser/chromeos/login/users/wallpaper/wallpaper_manager_test_utils.h',
diff --git a/chromeos/chromeos_switches.cc b/chromeos/chromeos_switches.cc
index 96667d2..52b60a0 100644
--- a/chromeos/chromeos_switches.cc
+++ b/chromeos/chromeos_switches.cc
@@ -96,6 +96,9 @@ const char kEnableNetworkPortalNotification[] =
// Enables activation of voice search by saying 'Ok Google'.
const char kEnableOkGoogleVoiceSearch[] = "enable-ok-google-voice-search";
+// Enables using screenshots in tests.
+const char kEnableScreenshotTesting[] = "enable-screenshot-testing";
+
// Enables touchpad three-finger-click as middle button.
const char kEnableTouchpadThreeFingerClick[]
= "enable-touchpad-three-finger-click";
@@ -236,6 +239,10 @@ const char kEnableFirstRunUITransitions[] = "enable-first-run-ui-transitions";
// Forces first-run UI to be shown for every login.
const char kForceFirstRunUI[] = "force-first-run-ui";
+// Turns on screenshot testing and specifies the directory where the
+// golden screenshots are stored.
+const char kScreenshotDestinationDir[] = "screenshot-destination-dir";
+
// Enables testing for auto update UI.
const char kTestAutoUpdateUI[] = "test-auto-update-ui";
diff --git a/chromeos/chromeos_switches.h b/chromeos/chromeos_switches.h
index e31aac7..b7bc3b3 100644
--- a/chromeos/chromeos_switches.h
+++ b/chromeos/chromeos_switches.h
@@ -45,13 +45,13 @@ CHROMEOS_EXPORT extern const char kEnableConsumerManagement[];
CHROMEOS_EXPORT extern const char kEnableEmbeddedSignin[];
CHROMEOS_EXPORT extern const char kEnableExtensionAssetsSharing[];
CHROMEOS_EXPORT extern const char kEnableFileManagerMTP[];
-CHROMEOS_EXPORT extern const char kEnableVideoPlayerChromecastSupport[];
CHROMEOS_EXPORT extern const char kEnableFirstRunUITransitions[];
CHROMEOS_EXPORT extern const char kEnableKioskMode[];
CHROMEOS_EXPORT extern const char kEnableNetworkPortalNotification[];
CHROMEOS_EXPORT extern const char kEnableOkGoogleVoiceSearch[];
CHROMEOS_EXPORT extern const char kEnableRequestTabletSite[];
CHROMEOS_EXPORT extern const char kEnableTouchpadThreeFingerClick[];
+CHROMEOS_EXPORT extern const char kEnableVideoPlayerChromecastSupport[];
CHROMEOS_EXPORT extern const char kEnterpriseEnableForcedReEnrollment[];
CHROMEOS_EXPORT extern const char kEnterpriseEnrollmentInitialModulus[];
CHROMEOS_EXPORT extern const char kEnterpriseEnrollmentModulusLimit[];
@@ -80,6 +80,8 @@ CHROMEOS_EXPORT extern const char kShowHostPairingDemo[];
CHROMEOS_EXPORT extern const char kSmsTestMessages[];
CHROMEOS_EXPORT extern const char kStubCrosSettings[];
CHROMEOS_EXPORT extern const char kTestAutoUpdateUI[];
+CHROMEOS_EXPORT extern const char kEnableScreenshotTesting[];
+CHROMEOS_EXPORT extern const char kScreenshotDestinationDir[];
} // namespace switches
} // namespace chromeos