summaryrefslogtreecommitdiffstats
path: root/content/shell/browser/webkit_test_controller.h
blob: 47012ed834da1534d9d9ca9e7d7fa537b30337f5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// Copyright 2013 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 CONTENT_SHELL_BROWSER_WEBKIT_TEST_CONTROLLER_H_
#define CONTENT_SHELL_BROWSER_WEBKIT_TEST_CONTROLLER_H_

#include <ostream>
#include <string>

#include "base/cancelable_callback.h"
#include "base/files/file_path.h"
#include "base/synchronization/lock.h"
#include "base/threading/non_thread_safe.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/shell/common/leak_detection_result.h"
#include "ui/gfx/size.h"
#include "webkit/common/webpreferences.h"

#if defined(OS_ANDROID)
#include "base/threading/thread_restrictions.h"
#endif

class SkBitmap;

namespace content {

class Shell;

#if defined(OS_ANDROID)
// Android uses a nested message loop for running layout tests because the
// default message loop, provided by the system, does not offer a blocking
// Run() method. The loop itself, implemented as NestedMessagePumpAndroid,
// uses a base::WaitableEvent allowing it to sleep until more events arrive.
class ScopedAllowWaitForAndroidLayoutTests {
 private:
  base::ThreadRestrictions::ScopedAllowWait wait;
};
#endif

class WebKitTestResultPrinter {
 public:
  WebKitTestResultPrinter(std::ostream* output, std::ostream* error);
  ~WebKitTestResultPrinter();

  void reset() {
    state_ = DURING_TEST;
  }
  bool output_finished() const { return state_ == AFTER_TEST; }
  void set_capture_text_only(bool capture_text_only) {
    capture_text_only_ = capture_text_only;
  }

  void set_encode_binary_data(bool encode_binary_data) {
    encode_binary_data_ = encode_binary_data;
  }

  void PrintTextHeader();
  void PrintTextBlock(const std::string& block);
  void PrintTextFooter();

  void PrintImageHeader(const std::string& actual_hash,
                        const std::string& expected_hash);
  void PrintImageBlock(const std::vector<unsigned char>& png_image);
  void PrintImageFooter();

  void PrintAudioHeader();
  void PrintAudioBlock(const std::vector<unsigned char>& audio_data);
  void PrintAudioFooter();

  void AddMessage(const std::string& message);
  void AddMessageRaw(const std::string& message);
  void AddErrorMessage(const std::string& message);

  void CloseStderr();

 private:
  void PrintEncodedBinaryData(const std::vector<unsigned char>& data);

  enum State {
    DURING_TEST,
    IN_TEXT_BLOCK,
    IN_AUDIO_BLOCK,
    IN_IMAGE_BLOCK,
    AFTER_TEST
  };
  State state_;

  bool capture_text_only_;
  bool encode_binary_data_;

  std::ostream* output_;
  std::ostream* error_;

  DISALLOW_COPY_AND_ASSIGN(WebKitTestResultPrinter);
};

class WebKitTestController : public base::NonThreadSafe,
                             public WebContentsObserver,
                             public NotificationObserver,
                             public GpuDataManagerObserver {
 public:
  static WebKitTestController* Get();

  WebKitTestController();
  virtual ~WebKitTestController();

  // True if the controller is ready for testing.
  bool PrepareForLayoutTest(const GURL& test_url,
                            const base::FilePath& current_working_directory,
                            bool enable_pixel_dumping,
                            const std::string& expected_pixel_hash);
  // True if the controller was reset successfully.
  bool ResetAfterLayoutTest();

  void SetTempPath(const base::FilePath& temp_path);
  void RendererUnresponsive();
  void WorkerCrashed();
  void OverrideWebkitPrefs(WebPreferences* prefs);
  void OpenURL(const GURL& url);
  void TestFinishedInSecondaryWindow();
  bool IsMainWindow(WebContents* web_contents) const;

  WebKitTestResultPrinter* printer() { return printer_.get(); }
  void set_printer(WebKitTestResultPrinter* printer) {
    printer_.reset(printer);
  }

  // WebContentsObserver implementation.
  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
  virtual void PluginCrashed(const base::FilePath& plugin_path,
                             base::ProcessId plugin_pid) OVERRIDE;
  virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE;
  virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
  virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;

  // NotificationObserver implementation.
  virtual void Observe(int type,
                       const NotificationSource& source,
                       const NotificationDetails& details) OVERRIDE;

  // GpuDataManagerObserver implementation.
  virtual void OnGpuProcessCrashed(base::TerminationStatus exit_code) OVERRIDE;

 private:
  enum TestPhase {
    BETWEEN_TESTS,
    DURING_TEST,
    CLEAN_UP
  };

  static WebKitTestController* instance_;

  void DiscardMainWindow();
  void SendTestConfiguration();

  // Message handlers.
  void OnAudioDump(const std::vector<unsigned char>& audio_dump);
  void OnImageDump(const std::string& actual_pixel_hash, const SkBitmap& image);
  void OnTextDump(const std::string& dump);
  void OnPrintMessage(const std::string& message);
  void OnOverridePreferences(const WebPreferences& prefs);
  void OnTestFinished();
  void OnClearDevToolsLocalStorage();
  void OnShowDevTools(const std::string& settings);
  void OnCloseDevTools();
  void OnGoToOffset(int offset);
  void OnReload();
  void OnLoadURLForFrame(const GURL& url, const std::string& frame_name);
  void OnCaptureSessionHistory();
  void OnCloseRemainingWindows();
  void OnResetDone();
  void OnLeakDetectionDone(const content::LeakDetectionResult& result);

  scoped_ptr<WebKitTestResultPrinter> printer_;

  base::FilePath current_working_directory_;
  base::FilePath temp_path_;

  Shell* main_window_;

  // The PID of the render process of the render view host of main_window_.
  int current_pid_;

  // True if we should set the test configuration to the next RenderViewHost
  // created.
  bool send_configuration_to_next_host_;

  // What phase of running an individual test we are currently in.
  TestPhase test_phase_;

  // True if the currently running test is a compositing test.
  bool is_compositing_test_;

  // Per test config.
  bool enable_pixel_dumping_;
  std::string expected_pixel_hash_;
  gfx::Size initial_size_;
  GURL test_url_;

  // True if the WebPreferences of newly created RenderViewHost should be
  // overridden with prefs_.
  bool should_override_prefs_;
  WebPreferences prefs_;

  NotificationRegistrar registrar_;

  const bool is_leak_detection_enabled_;

#if defined(OS_ANDROID)
  // Because of the nested message pump implementation, Android needs to allow
  // waiting on the UI thread while layout tests are being ran.
  ScopedAllowWaitForAndroidLayoutTests reduced_restrictions_;
#endif

  DISALLOW_COPY_AND_ASSIGN(WebKitTestController);
};

}  // namespace content

#endif  // CONTENT_SHELL_BROWSER_WEBKIT_TEST_CONTROLLER_H_