Commit da7e1a15 authored by leon.han's avatar leon.han Committed by Commit bot

[DeviceService] Create end-to-end browsertest for BatteryMonitor

This CL is to confirm that in a real browser environment javascript
battery APIs(navigator.getBattery and its event listener) CAN eventually
succeed in connecting to Device Service to receive battery status change
notifications correctly.

BUG=717379
TEST=content_browsertests

Review-Url: https://codereview.chromium.org/2882633002
Cr-Commit-Position: refs/heads/master@{#473432}
parent 6b0a3020
// Copyright 2017 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 <utility>
#include "base/bind.h"
#include "base/macros.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/device/public/interfaces/battery_monitor.mojom.h"
#include "services/device/public/interfaces/constants.mojom.h"
#include "services/service_manager/public/cpp/service_context.h"
namespace content {
namespace {
class MockBatteryMonitor : public device::mojom::BatteryMonitor {
public:
MockBatteryMonitor() : binding_(this) {}
~MockBatteryMonitor() override = default;
void Bind(const service_manager::BindSourceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle handle) {
DCHECK(!binding_.is_bound());
binding_.Bind(device::mojom::BatteryMonitorRequest(std::move(handle)));
}
void DidChange(const device::mojom::BatteryStatus& battery_status) {
status_ = battery_status;
status_to_report_ = true;
if (!callback_.is_null())
ReportStatus();
}
private:
// mojom::BatteryMonitor methods:
void QueryNextStatus(const QueryNextStatusCallback& callback) override {
if (!callback_.is_null()) {
DVLOG(1) << "Overlapped call to QueryNextStatus!";
binding_.Close();
return;
}
callback_ = callback;
if (status_to_report_)
ReportStatus();
}
void ReportStatus() {
callback_.Run(status_.Clone());
callback_.Reset();
status_to_report_ = false;
}
QueryNextStatusCallback callback_;
device::mojom::BatteryStatus status_;
bool status_to_report_ = false;
mojo::Binding<device::mojom::BatteryMonitor> binding_;
DISALLOW_COPY_AND_ASSIGN(MockBatteryMonitor);
};
class BatteryMonitorTest : public ContentBrowserTest {
public:
BatteryMonitorTest() = default;
void SetUpOnMainThread() override {
mock_battery_monitor_ = base::MakeUnique<MockBatteryMonitor>();
// Because Device Service also runs in this process(browser process), here
// we can directly set our binder to intercept interface requests against
// it.
service_manager::ServiceContext::SetGlobalBinderForTesting(
device::mojom::kServiceName, device::mojom::BatteryMonitor::Name_,
base::Bind(&MockBatteryMonitor::Bind,
base::Unretained(mock_battery_monitor_.get())));
}
protected:
MockBatteryMonitor* mock_battery_monitor() {
return mock_battery_monitor_.get();
}
private:
std::unique_ptr<MockBatteryMonitor> mock_battery_monitor_;
DISALLOW_COPY_AND_ASSIGN(BatteryMonitorTest);
};
IN_PROC_BROWSER_TEST_F(BatteryMonitorTest, NavigatorGetBatteryInfo) {
// From JavaScript request a promise for the battery status information and
// once it resolves check the values and navigate to #pass.
device::mojom::BatteryStatus status;
status.charging = true;
status.charging_time = 100;
status.discharging_time = std::numeric_limits<double>::infinity();
status.level = 0.5;
mock_battery_monitor()->DidChange(status);
GURL test_url = GetTestUrl("battery_monitor",
"battery_status_promise_resolution_test.html");
NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 2);
EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
}
IN_PROC_BROWSER_TEST_F(BatteryMonitorTest, NavigatorGetBatteryListenChange) {
// From JavaScript request a promise for the battery status information.
// Once it resolves add an event listener for battery level change. Set
// battery level to 0.6 and invoke update. Check that the event listener
// is invoked with the correct value for level and navigate to #pass.
device::mojom::BatteryStatus status;
mock_battery_monitor()->DidChange(status);
TestNavigationObserver same_tab_observer(shell()->web_contents(), 2);
GURL test_url =
GetTestUrl("battery_monitor", "battery_status_event_listener_test.html");
shell()->LoadURL(test_url);
same_tab_observer.Wait();
EXPECT_EQ("resolved", shell()->web_contents()->GetLastCommittedURL().ref());
TestNavigationObserver same_tab_observer2(shell()->web_contents(), 1);
status.level = 0.6;
mock_battery_monitor()->DidChange(status);
same_tab_observer2.Wait();
EXPECT_EQ("pass", shell()->web_contents()->GetLastCommittedURL().ref());
}
} // namespace
} // namespace content
...@@ -600,6 +600,7 @@ test("content_browsertests") { ...@@ -600,6 +600,7 @@ test("content_browsertests") {
"../browser/accessibility/snapshot_ax_tree_browsertest.cc", "../browser/accessibility/snapshot_ax_tree_browsertest.cc",
"../browser/accessibility/touch_accessibility_aura_browsertest.cc", "../browser/accessibility/touch_accessibility_aura_browsertest.cc",
"../browser/background_sync/background_sync_browsertest.cc", "../browser/background_sync/background_sync_browsertest.cc",
"../browser/battery_monitor_browsertest.cc",
"../browser/blob_storage/blob_storage_browsertest.cc", "../browser/blob_storage/blob_storage_browsertest.cc",
"../browser/blob_storage/blob_url_browsertest.cc", "../browser/blob_storage/blob_url_browsertest.cc",
"../browser/bookmarklet_browsertest.cc", "../browser/bookmarklet_browsertest.cc",
......
<html>
<head>
<title>Battery Status API test : event listener</title>
<script type="text/javascript">
function testBattery() {
navigator.getBattery().then(
function(battery) {
battery.addEventListener('levelchange', onLevelChange);
document.location = '#resolved';
}, fail());
}
function onLevelChange() {
if (this.level == 0.6)
pass();
else
fail();
}
function pass() {
document.getElementById('status').innerHTML = 'PASS';
document.location = '#pass';
}
function fail() {
document.location = '#fail';
}
</script>
</head>
<body onLoad="testBattery()">
<div id="status">FAIL</div>
</body>
</html>
<html>
<body>
<head>
<meta name="description" content="Test for Battery Status API"/>
<title>Battery Status API</title>
</head>
<body>
<table>
<tr>
<td>Battery Status API</td>
<td width="250px"></td>
</tr>
<tr>
<td colspan="2">
<hr>
</td>
</tr>
<tr>
<td>charging</td>
<td id="charging"></td>
</tr>
<tr>
<td>chargingTime</td>
<td id="chargingTime"></td>
</tr>
<tr>
<td>dischargingTime</td>
<td id="dischargingTime"></td>
</tr>
<tr>
<td>battery level</td>
<td id="level"></td>
</tr>
<tr>
<td colspan="2">
<hr>
</td>
</tr>
<tr>
<td>promise status</td>
<td id="promiseStatus"></td>
</tr>
<tr>
<td>number of updates</td>
<td id="numberUpdates"></td>
</tr>
</table>
<script>
var numberUpdates = 0;
var battery;
function batterySuccess(batteryManager) {
battery = batteryManager;
document.getElementById("promiseStatus").innerHTML = "success";
updateBatteryInformation();
battery.addEventListener('chargingchange', updateBatteryInformation);
battery.addEventListener('chargingtimechange', updateBatteryInformation);
battery.addEventListener('dischargingtimechange', updateBatteryInformation);
battery.addEventListener('levelchange', updateBatteryInformation);
}
function batteryFailure() {
document.getElementById("promiseStatus").innerHTML = "failed";
}
function ConvertToHMS(durationInSeconds) {
if (!isFinite(durationInSeconds)) return "";
var hours = Math.floor(durationInSeconds / 3600);
var seconds = durationInSeconds % 60;
var minutes = Math.floor((durationInSeconds - hours * 3600 - seconds) / 60);
return " (" + hours + "h:" + minutes + "m:" + seconds + "s)";
}
function updateBatteryInformation() {
document.getElementById("charging").innerHTML = battery.charging;
document.getElementById("chargingTime").innerHTML = battery.chargingTime + ConvertToHMS(battery.chargingTime);
document.getElementById("dischargingTime").innerHTML = battery.dischargingTime + ConvertToHMS(battery.dischargingTime);
document.getElementById("level").innerHTML = battery.level;
numberUpdates++;
document.getElementById("numberUpdates").innerHTML = numberUpdates;
}
document.getElementById("promiseStatus").innerHTML = "pending";
document.getElementById("numberUpdates").innerHTML = numberUpdates;
navigator.getBattery().then(batterySuccess, batteryFailure);
</script>
</body>
</html>
\ No newline at end of file
<html>
<head>
<title>Battery Status API test : promise resolution</title>
<script type="text/javascript">
function checkBatteryInfo(battery) {
return battery.charging &&
battery.chargingTime == 100 &&
battery.dischargingTime == Infinity &&
battery.level == 0.5;
}
function testBattery() {
navigator.getBattery().then(
function(battery) {
if (checkBatteryInfo(battery))
pass();
else
fail();
}, fail());
}
function pass() {
document.getElementById('status').innerHTML = 'PASS';
document.location = '#pass';
}
function fail() {
document.location = '#fail';
}
</script>
</head>
<body onLoad="testBattery()">
<div id="status">FAIL</div>
</body>
</html>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment