1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/synchronization/waitable_event.h"
7 #include "base/threading/platform_thread.h"
8 #include "content/browser/device_sensors/data_fetcher_shared_memory.h"
9 #include "content/browser/device_sensors/device_inertial_sensor_service.h"
10 #include "content/common/device_sensors/device_light_hardware_buffer.h"
11 #include "content/common/device_sensors/device_motion_hardware_buffer.h"
12 #include "content/common/device_sensors/device_orientation_hardware_buffer.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/test/content_browser_test.h"
17 #include "content/public/test/content_browser_test_utils.h"
18 #include "content/public/test/test_navigation_observer.h"
19 #include "content/public/test/test_utils.h"
20 #include "content/shell/browser/shell.h"
21 #include "content/shell/browser/shell_javascript_dialog_manager.h"
27 class FakeDataFetcher : public DataFetcherSharedMemory {
30 : started_orientation_(false, false),
31 stopped_orientation_(false, false),
32 started_motion_(false, false),
33 stopped_motion_(false, false),
34 started_light_(false, false),
35 stopped_light_(false, false),
36 sensor_data_available_(true) {}
37 virtual ~FakeDataFetcher() { }
39 virtual bool Start(ConsumerType consumer_type, void* buffer) OVERRIDE {
42 switch (consumer_type) {
43 case CONSUMER_TYPE_MOTION:
45 DeviceMotionHardwareBuffer* motion_buffer =
46 static_cast<DeviceMotionHardwareBuffer*>(buffer);
47 if (sensor_data_available_)
48 UpdateMotion(motion_buffer);
49 SetMotionBufferReady(motion_buffer);
50 started_motion_.Signal();
53 case CONSUMER_TYPE_ORIENTATION:
55 DeviceOrientationHardwareBuffer* orientation_buffer =
56 static_cast<DeviceOrientationHardwareBuffer*>(buffer);
57 if (sensor_data_available_)
58 UpdateOrientation(orientation_buffer);
59 SetOrientationBufferReady(orientation_buffer);
60 started_orientation_.Signal();
63 case CONSUMER_TYPE_LIGHT:
65 DeviceLightHardwareBuffer* light_buffer =
66 static_cast<DeviceLightHardwareBuffer*>(buffer);
67 UpdateLight(light_buffer,
68 sensor_data_available_
70 : std::numeric_limits<double>::infinity());
71 started_light_.Signal();
80 virtual bool Stop(ConsumerType consumer_type) OVERRIDE {
81 switch (consumer_type) {
82 case CONSUMER_TYPE_MOTION:
83 stopped_motion_.Signal();
85 case CONSUMER_TYPE_ORIENTATION:
86 stopped_orientation_.Signal();
88 case CONSUMER_TYPE_LIGHT:
89 stopped_light_.Signal();
97 virtual void Fetch(unsigned consumer_bitmask) OVERRIDE {
98 FAIL() << "fetch should not be called";
101 virtual FetcherType GetType() const OVERRIDE {
102 return FETCHER_TYPE_DEFAULT;
105 void SetSensorDataAvailable(bool available) {
106 sensor_data_available_ = available;
109 void SetMotionBufferReady(DeviceMotionHardwareBuffer* buffer) {
110 buffer->seqlock.WriteBegin();
111 buffer->data.allAvailableSensorsAreActive = true;
112 buffer->seqlock.WriteEnd();
115 void SetOrientationBufferReady(DeviceOrientationHardwareBuffer* buffer) {
116 buffer->seqlock.WriteBegin();
117 buffer->data.allAvailableSensorsAreActive = true;
118 buffer->seqlock.WriteEnd();
121 void UpdateMotion(DeviceMotionHardwareBuffer* buffer) {
122 buffer->seqlock.WriteBegin();
123 buffer->data.accelerationX = 1;
124 buffer->data.hasAccelerationX = true;
125 buffer->data.accelerationY = 2;
126 buffer->data.hasAccelerationY = true;
127 buffer->data.accelerationZ = 3;
128 buffer->data.hasAccelerationZ = true;
130 buffer->data.accelerationIncludingGravityX = 4;
131 buffer->data.hasAccelerationIncludingGravityX = true;
132 buffer->data.accelerationIncludingGravityY = 5;
133 buffer->data.hasAccelerationIncludingGravityY = true;
134 buffer->data.accelerationIncludingGravityZ = 6;
135 buffer->data.hasAccelerationIncludingGravityZ = true;
137 buffer->data.rotationRateAlpha = 7;
138 buffer->data.hasRotationRateAlpha = true;
139 buffer->data.rotationRateBeta = 8;
140 buffer->data.hasRotationRateBeta = true;
141 buffer->data.rotationRateGamma = 9;
142 buffer->data.hasRotationRateGamma = true;
144 buffer->data.interval = 100;
145 buffer->data.allAvailableSensorsAreActive = true;
146 buffer->seqlock.WriteEnd();
149 void UpdateOrientation(DeviceOrientationHardwareBuffer* buffer) {
150 buffer->seqlock.WriteBegin();
151 buffer->data.alpha = 1;
152 buffer->data.hasAlpha = true;
153 buffer->data.beta = 2;
154 buffer->data.hasBeta = true;
155 buffer->data.gamma = 3;
156 buffer->data.hasGamma = true;
157 buffer->data.allAvailableSensorsAreActive = true;
158 buffer->seqlock.WriteEnd();
161 void UpdateLight(DeviceLightHardwareBuffer* buffer, double lux) {
162 buffer->seqlock.WriteBegin();
163 buffer->data.value = lux;
164 buffer->seqlock.WriteEnd();
167 base::WaitableEvent started_orientation_;
168 base::WaitableEvent stopped_orientation_;
169 base::WaitableEvent started_motion_;
170 base::WaitableEvent stopped_motion_;
171 base::WaitableEvent started_light_;
172 base::WaitableEvent stopped_light_;
173 bool sensor_data_available_;
176 DISALLOW_COPY_AND_ASSIGN(FakeDataFetcher);
180 class DeviceInertialSensorBrowserTest : public ContentBrowserTest {
182 DeviceInertialSensorBrowserTest()
184 io_loop_finished_event_(false, false) {
187 virtual void SetUpOnMainThread() OVERRIDE {
188 BrowserThread::PostTask(
189 BrowserThread::IO, FROM_HERE,
190 base::Bind(&DeviceInertialSensorBrowserTest::SetUpOnIOThread, this));
191 io_loop_finished_event_.Wait();
194 void SetUpOnIOThread() {
195 fetcher_ = new FakeDataFetcher();
196 DeviceInertialSensorService::GetInstance()->
197 SetDataFetcherForTesting(fetcher_);
198 io_loop_finished_event_.Signal();
201 void DelayAndQuit(base::TimeDelta delay) {
202 base::PlatformThread::Sleep(delay);
203 base::MessageLoop::current()->QuitWhenIdle();
206 void WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta delay) {
207 ShellJavaScriptDialogManager* dialog_manager=
208 static_cast<ShellJavaScriptDialogManager*>(
209 shell()->GetJavaScriptDialogManager());
211 scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner();
212 dialog_manager->set_dialog_request_callback(
213 base::Bind(&DeviceInertialSensorBrowserTest::DelayAndQuit, this,
218 FakeDataFetcher* fetcher_;
221 base::WaitableEvent io_loop_finished_event_;
224 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, OrientationTest) {
225 // The test page will register an event handler for orientation events,
226 // expects to get an event with fake values, then removes the event
227 // handler and navigates to #pass.
228 GURL test_url = GetTestUrl("device_sensors", "device_orientation_test.html");
229 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
231 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
232 fetcher_->started_orientation_.Wait();
233 fetcher_->stopped_orientation_.Wait();
236 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, LightTest) {
237 // The test page will register an event handler for light events,
238 // expects to get an event with fake values, then removes the event
239 // handler and navigates to #pass.
240 GURL test_url = GetTestUrl("device_sensors", "device_light_test.html");
242 // TODO(riju): remove command line args when the feature goes stable.
243 if (!CommandLine::ForCurrentProcess()->HasSwitch(
244 switches::kEnableExperimentalWebPlatformFeatures)) {
245 CommandLine::ForCurrentProcess()->AppendSwitch(
246 switches::kEnableExperimentalWebPlatformFeatures);
249 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
251 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
252 fetcher_->started_light_.Wait();
253 fetcher_->stopped_light_.Wait();
256 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest, MotionTest) {
257 // The test page will register an event handler for motion events,
258 // expects to get an event with fake values, then removes the event
259 // handler and navigates to #pass.
260 GURL test_url = GetTestUrl("device_sensors", "device_motion_test.html");
261 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
263 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
264 fetcher_->started_motion_.Wait();
265 fetcher_->stopped_motion_.Wait();
268 // crbug/416406. The test is flaky.
269 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest,
270 DISABLED_LightOneOffInfintyTest) {
271 // The test page will register an event handler for light events,
272 // expects to get an event with value equal to Infinity. This tests that the
273 // one-off infinity event still propagates to window after the alert is
274 // dismissed and the callback is invoked which navigates to #pass.
275 fetcher_->SetSensorDataAvailable(false);
277 // TODO(riju): remove command line args when the feature goes stable.
278 if (!CommandLine::ForCurrentProcess()->HasSwitch(
279 switches::kEnableExperimentalWebPlatformFeatures)) {
280 CommandLine::ForCurrentProcess()->AppendSwitch(
281 switches::kEnableExperimentalWebPlatformFeatures);
284 TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
287 GetTestUrl("device_sensors", "device_light_infinity_test.html");
288 shell()->LoadURL(test_url);
290 WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta::FromMilliseconds(1000));
292 fetcher_->started_light_.Wait();
293 fetcher_->stopped_light_.Wait();
294 same_tab_observer.Wait();
295 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
298 // Flaking in the android try bot. See http://crbug.com/360578.
299 #if defined(OS_ANDROID)
300 #define MAYBE_OrientationNullTestWithAlert DISABLED_OrientationNullTestWithAlert
302 #define MAYBE_OrientationNullTestWithAlert OrientationNullTestWithAlert
304 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest,
305 MAYBE_OrientationNullTestWithAlert) {
306 // The test page will register an event handler for orientation events,
307 // expects to get an event with null values. The test raises a modal alert
308 // dialog with a delay to test that the one-off null-event still propagates
309 // to window after the alert is dismissed and the callback is invoked which
310 // navigates to #pass.
311 fetcher_->SetSensorDataAvailable(false);
312 TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
314 GURL test_url = GetTestUrl("device_sensors",
315 "device_orientation_null_test_with_alert.html");
316 shell()->LoadURL(test_url);
318 // TODO(timvolodine): investigate if it is possible to test this without
319 // delay, crbug.com/360044.
320 WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta::FromMilliseconds(1000));
322 fetcher_->started_orientation_.Wait();
323 fetcher_->stopped_orientation_.Wait();
324 same_tab_observer.Wait();
325 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
328 // Flaking in the android try bot. See http://crbug.com/360578.
329 #if defined(OS_ANDROID)
330 #define MAYBE_MotionNullTestWithAlert DISABLED_MotionNullTestWithAlert
332 #define MAYBE_MotionNullTestWithAlert MotionNullTestWithAlert
334 IN_PROC_BROWSER_TEST_F(DeviceInertialSensorBrowserTest,
335 MAYBE_MotionNullTestWithAlert) {
336 // The test page will register an event handler for motion events,
337 // expects to get an event with null values. The test raises a modal alert
338 // dialog with a delay to test that the one-off null-event still propagates
339 // to window after the alert is dismissed and the callback is invoked which
340 // navigates to #pass.
341 fetcher_->SetSensorDataAvailable(false);
342 TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
345 GetTestUrl("device_sensors", "device_motion_null_test_with_alert.html");
346 shell()->LoadURL(test_url);
348 // TODO(timvolodine): investigate if it is possible to test this without
349 // delay, crbug.com/360044.
350 WaitForAlertDialogAndQuitAfterDelay(base::TimeDelta::FromMilliseconds(1000));
352 fetcher_->started_motion_.Wait();
353 fetcher_->stopped_motion_.Wait();
354 same_tab_observer.Wait();
355 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
360 } // namespace content