1 // Copyright 2017 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.
4
5 #include <utility>
6
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/macros.h"
10 #include "content/browser/renderer_host/render_process_host_impl.h"
11 #include "content/public/browser/web_contents.h"
12 #include "content/public/test/browser_test.h"
13 #include "content/public/test/browser_test_utils.h"
14 #include "content/public/test/content_browser_test.h"
15 #include "content/public/test/content_browser_test_utils.h"
16 #include "content/public/test/test_navigation_observer.h"
17 #include "content/public/test/test_utils.h"
18 #include "content/shell/browser/shell.h"
19 #include "mojo/public/cpp/bindings/pending_receiver.h"
20 #include "mojo/public/cpp/bindings/receiver.h"
21 #include "services/device/public/mojom/battery_monitor.mojom.h"
22 #include "services/device/public/mojom/battery_status.mojom.h"
23
24 namespace content {
25
26 namespace {
27
28 class MockBatteryMonitor : public device::mojom::BatteryMonitor {
29 public:
30 MockBatteryMonitor() = default;
31 ~MockBatteryMonitor() override = default;
32
Bind(mojo::PendingReceiver<device::mojom::BatteryMonitor> receiver)33 void Bind(mojo::PendingReceiver<device::mojom::BatteryMonitor> receiver) {
34 DCHECK(!receiver_.is_bound());
35 receiver_.Bind(std::move(receiver));
36 }
37
DidChange(const device::mojom::BatteryStatus & battery_status)38 void DidChange(const device::mojom::BatteryStatus& battery_status) {
39 status_ = battery_status;
40 status_to_report_ = true;
41
42 if (!callback_.is_null())
43 ReportStatus();
44 }
45
46 private:
47 // mojom::BatteryMonitor methods:
QueryNextStatus(QueryNextStatusCallback callback)48 void QueryNextStatus(QueryNextStatusCallback callback) override {
49 if (!callback_.is_null()) {
50 DVLOG(1) << "Overlapped call to QueryNextStatus!";
51 receiver_.reset();
52 return;
53 }
54 callback_ = std::move(callback);
55
56 if (status_to_report_)
57 ReportStatus();
58 }
59
ReportStatus()60 void ReportStatus() {
61 std::move(callback_).Run(status_.Clone());
62 status_to_report_ = false;
63 }
64
65 QueryNextStatusCallback callback_;
66 device::mojom::BatteryStatus status_;
67 bool status_to_report_ = false;
68 mojo::Receiver<device::mojom::BatteryMonitor> receiver_{this};
69
70 DISALLOW_COPY_AND_ASSIGN(MockBatteryMonitor);
71 };
72
73 class BatteryMonitorTest : public ContentBrowserTest {
74 public:
BatteryMonitorTest()75 BatteryMonitorTest() {
76 mock_battery_monitor_ = std::make_unique<MockBatteryMonitor>();
77 // Because Device Service also runs in this process(browser process), here
78 // we can directly set our binder to intercept interface requests against
79 // it.
80 RenderProcessHostImpl::OverrideBatteryMonitorBinderForTesting(
81 base::BindRepeating(&MockBatteryMonitor::Bind,
82 base::Unretained(mock_battery_monitor_.get())));
83 }
84
~BatteryMonitorTest()85 ~BatteryMonitorTest() override {
86 RenderProcessHostImpl::OverrideBatteryMonitorBinderForTesting(
87 base::NullCallback());
88 }
89
90 protected:
mock_battery_monitor()91 MockBatteryMonitor* mock_battery_monitor() {
92 return mock_battery_monitor_.get();
93 }
94
95 private:
96 std::unique_ptr<MockBatteryMonitor> mock_battery_monitor_;
97
98 DISALLOW_COPY_AND_ASSIGN(BatteryMonitorTest);
99 };
100
IN_PROC_BROWSER_TEST_F(BatteryMonitorTest,NavigatorGetBatteryInfo)101 IN_PROC_BROWSER_TEST_F(BatteryMonitorTest, NavigatorGetBatteryInfo) {
102 // From JavaScript request a promise for the battery status information and
103 // once it resolves check the values and navigate to #pass.
104 device::mojom::BatteryStatus status;
105 status.charging = true;
106 status.charging_time = 100;
107 status.discharging_time = std::numeric_limits<double>::infinity();
108 status.level = 0.5;
109 mock_battery_monitor()->DidChange(status);
110
111 GURL test_url = GetTestUrl("battery_monitor",
112 "battery_status_promise_resolution_test.html");
113 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
114 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
115 }
116
IN_PROC_BROWSER_TEST_F(BatteryMonitorTest,NavigatorGetBatteryListenChange)117 IN_PROC_BROWSER_TEST_F(BatteryMonitorTest, NavigatorGetBatteryListenChange) {
118 // From JavaScript request a promise for the battery status information.
119 // Once it resolves add an event listener for battery level change. Set
120 // battery level to 0.6 and invoke update. Check that the event listener
121 // is invoked with the correct value for level and navigate to #pass.
122 device::mojom::BatteryStatus status;
123 mock_battery_monitor()->DidChange(status);
124
125 TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
126 GURL test_url =
127 GetTestUrl("battery_monitor", "battery_status_event_listener_test.html");
128 shell()->LoadURL(test_url);
129 same_tab_observer.Wait();
130 EXPECT_EQ("resolved", shell()->web_contents()->GetLastCommittedURL().ref());
131
132 TestNavigationObserver same_tab_observer2(shell()->web_contents(), 1);
133 status.level = 0.6;
134 mock_battery_monitor()->DidChange(status);
135 same_tab_observer2.Wait();
136 EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
137 }
138
139 } // namespace
140
141 } // namespace content
142