Add Network Conditions Override Manager and tests
BUG=https://code.google.com/p/chromedriver/issues/detail?id=984
Review URL: https://codereview.chromium.org/883083002
Cr-Commit-Position: refs/heads/master@{#319668}
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 4960e11..5f164b34 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1143,6 +1143,8 @@
'test/chromedriver/chrome/mobile_emulation_override_manager.h',
'test/chromedriver/chrome/navigation_tracker.cc',
'test/chromedriver/chrome/navigation_tracker.h',
+ 'test/chromedriver/chrome/network_conditions_override_manager.cc',
+ 'test/chromedriver/chrome/network_conditions_override_manager.h',
'test/chromedriver/chrome/status.cc',
'test/chromedriver/chrome/status.h',
'test/chromedriver/chrome/ui_events.cc',
@@ -1256,6 +1258,9 @@
'test/chromedriver/chrome/javascript_dialog_manager_unittest.cc',
'test/chromedriver/chrome/mobile_emulation_override_manager_unittest.cc',
'test/chromedriver/chrome/navigation_tracker_unittest.cc',
+ 'test/chromedriver/chrome/network_conditions_override_manager_unittest.cc',
+ 'test/chromedriver/chrome/recorder_devtools_client.cc',
+ 'test/chromedriver/chrome/recorder_devtools_client.h',
'test/chromedriver/chrome/status_unittest.cc',
'test/chromedriver/chrome/stub_chrome.cc',
'test/chromedriver/chrome/stub_chrome.h',
diff --git a/chrome/test/chromedriver/chrome/geolocation_override_manager_unittest.cc b/chrome/test/chromedriver/chrome/geolocation_override_manager_unittest.cc
index 955ced7..574d861a 100644
--- a/chrome/test/chromedriver/chrome/geolocation_override_manager_unittest.cc
+++ b/chrome/test/chromedriver/chrome/geolocation_override_manager_unittest.cc
@@ -2,57 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/geolocation_override_manager.h"
#include "chrome/test/chromedriver/chrome/geoposition.h"
+#include "chrome/test/chromedriver/chrome/recorder_devtools_client.h"
#include "chrome/test/chromedriver/chrome/status.h"
-#include "chrome/test/chromedriver/chrome/stub_devtools_client.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-struct Command {
- Command() {}
- Command(const std::string& method, const base::DictionaryValue& params)
- : method(method) {
- this->params.MergeDictionary(¶ms);
- }
- Command(const Command& command) {
- *this = command;
- }
- Command& operator=(const Command& command) {
- method = command.method;
- params.Clear();
- params.MergeDictionary(&command.params);
- return *this;
- }
- ~Command() {}
-
- std::string method;
- base::DictionaryValue params;
-};
-
-class RecorderDevToolsClient : public StubDevToolsClient {
- public:
- RecorderDevToolsClient() {}
- ~RecorderDevToolsClient() override {}
-
- // Overridden from StubDevToolsClient:
- Status SendCommandAndGetResult(
- const std::string& method,
- const base::DictionaryValue& params,
- scoped_ptr<base::DictionaryValue>* result) override {
- commands_.push_back(Command(method, params));
- return Status(kOk);
- }
-
- std::vector<Command> commands_;
-};
-
void AssertGeolocationCommand(const Command& command,
const Geoposition& geoposition) {
ASSERT_EQ("Page.setGeolocationOverride", command.method);
diff --git a/chrome/test/chromedriver/chrome/javascript_dialog_manager_unittest.cc b/chrome/test/chromedriver/chrome/javascript_dialog_manager_unittest.cc
index a016511..8b2c6b5 100644
--- a/chrome/test/chromedriver/chrome/javascript_dialog_manager_unittest.cc
+++ b/chrome/test/chromedriver/chrome/javascript_dialog_manager_unittest.cc
@@ -8,8 +8,8 @@
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/javascript_dialog_manager.h"
+#include "chrome/test/chromedriver/chrome/recorder_devtools_client.h"
#include "chrome/test/chromedriver/chrome/status.h"
-#include "chrome/test/chromedriver/chrome/stub_devtools_client.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(JavaScriptDialogManager, NoDialog) {
@@ -22,30 +22,6 @@
ASSERT_EQ(kNoAlertOpen, manager.HandleDialog(false, NULL).code());
}
-namespace {
-
-class RecorderDevToolsClient : public StubDevToolsClient {
- public:
- RecorderDevToolsClient() {}
- ~RecorderDevToolsClient() override {}
-
- // Overridden from StubDevToolsClient:
- Status SendCommandAndGetResult(
- const std::string& method,
- const base::DictionaryValue& params,
- scoped_ptr<base::DictionaryValue>* result) override {
- method_ = method;
- params_.Clear();
- params_.MergeDictionary(¶ms);
- return Status(kOk);
- }
-
- std::string method_;
- base::DictionaryValue params_;
-};
-
-} // namespace
-
TEST(JavaScriptDialogManager, HandleDialogPassesParams) {
RecorderDevToolsClient client;
JavaScriptDialogManager manager(&client);
@@ -57,9 +33,9 @@
std::string given_text("text");
ASSERT_EQ(kOk, manager.HandleDialog(false, &given_text).code());
std::string text;
- client.params_.GetString("promptText", &text);
+ ASSERT_TRUE(client.commands_[0].params.GetString("promptText", &text));
ASSERT_EQ(given_text, text);
- ASSERT_TRUE(client.params_.HasKey("accept"));
+ ASSERT_TRUE(client.commands_[0].params.HasKey("accept"));
}
TEST(JavaScriptDialogManager, HandleDialogNullPrompt) {
@@ -71,8 +47,8 @@
kOk,
manager.OnEvent(&client, "Page.javascriptDialogOpening", params).code());
ASSERT_EQ(kOk, manager.HandleDialog(false, NULL).code());
- ASSERT_FALSE(client.params_.HasKey("promptText"));
- ASSERT_TRUE(client.params_.HasKey("accept"));
+ ASSERT_FALSE(client.commands_[0].params.HasKey("promptText"));
+ ASSERT_TRUE(client.commands_[0].params.HasKey("accept"));
}
TEST(JavaScriptDialogManager, ReconnectClearsStateAndSendsEnable) {
@@ -88,7 +64,7 @@
ASSERT_EQ(kOk, manager.GetDialogMessage(&message).code());
ASSERT_TRUE(manager.OnConnected(&client).IsOk());
- ASSERT_EQ("Page.enable", client.method_);
+ ASSERT_EQ("Page.enable", client.commands_[0].method);
ASSERT_FALSE(manager.IsDialogOpen());
ASSERT_EQ(kNoAlertOpen, manager.GetDialogMessage(&message).code());
ASSERT_EQ(kNoAlertOpen, manager.HandleDialog(false, NULL).code());
diff --git a/chrome/test/chromedriver/chrome/mobile_emulation_override_manager_unittest.cc b/chrome/test/chromedriver/chrome/mobile_emulation_override_manager_unittest.cc
index 099442f..c8cf20c 100644
--- a/chrome/test/chromedriver/chrome/mobile_emulation_override_manager_unittest.cc
+++ b/chrome/test/chromedriver/chrome/mobile_emulation_override_manager_unittest.cc
@@ -2,59 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <string>
-#include <vector>
-
-#include "base/compiler_specific.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/device_metrics.h"
#include "chrome/test/chromedriver/chrome/mobile_emulation_override_manager.h"
+#include "chrome/test/chromedriver/chrome/recorder_devtools_client.h"
#include "chrome/test/chromedriver/chrome/status.h"
-#include "chrome/test/chromedriver/chrome/stub_devtools_client.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
-struct Command {
- Command() {}
- Command(const std::string& method, const base::DictionaryValue& params)
- : method(method) {
- this->params.MergeDictionary(¶ms);
- }
- Command(const Command& command) {
- *this = command;
- }
- Command& operator=(const Command& command) {
- method = command.method;
- params.Clear();
- params.MergeDictionary(&command.params);
- return *this;
- }
- ~Command() {}
-
- std::string method;
- base::DictionaryValue params;
-};
-
-class RecorderDevToolsClient : public StubDevToolsClient {
- public:
- RecorderDevToolsClient() {}
- ~RecorderDevToolsClient() override {}
-
- // Overridden from StubDevToolsClient:
- Status SendCommandAndGetResult(
- const std::string& method,
- const base::DictionaryValue& params,
- scoped_ptr<base::DictionaryValue>* result) override {
- commands_.push_back(Command(method, params));
- return Status(kOk);
- }
-
- std::vector<Command> commands_;
-};
-
void AssertDeviceMetricsCommand(const Command& command,
- const DeviceMetrics& device_metrics) {
+ const DeviceMetrics& device_metrics) {
ASSERT_EQ("Page.setDeviceMetricsOverride", command.method);
int width, height;
double device_scale_factor, font_scale_factor;
diff --git a/chrome/test/chromedriver/chrome/network_conditions.h b/chrome/test/chromedriver/chrome/network_conditions.h
new file mode 100644
index 0000000..2233655
--- /dev/null
+++ b/chrome/test/chromedriver/chrome/network_conditions.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2015 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_TEST_CHROMEDRIVER_CHROME_NETWORK_CONDITIONS_H_
+#define CHROME_TEST_CHROMEDRIVER_CHROME_NETWORK_CONDITIONS_H_
+
+struct NetworkConditions {
+ bool offline;
+ double latency;
+ double download_throughput;
+ double upload_throughput;
+};
+
+#endif // CHROME_TEST_CHROMEDRIVER_CHROME_NETWORK_CONDITIONS_H_
diff --git a/chrome/test/chromedriver/chrome/network_conditions_override_manager.cc b/chrome/test/chromedriver/chrome/network_conditions_override_manager.cc
new file mode 100644
index 0000000..18c9018
--- /dev/null
+++ b/chrome/test/chromedriver/chrome/network_conditions_override_manager.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2015 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/test/chromedriver/chrome/network_conditions_override_manager.h"
+
+#include "base/values.h"
+#include "chrome/test/chromedriver/chrome/devtools_client.h"
+#include "chrome/test/chromedriver/chrome/network_conditions.h"
+#include "chrome/test/chromedriver/chrome/status.h"
+
+NetworkConditionsOverrideManager::NetworkConditionsOverrideManager(
+ DevToolsClient* client)
+ : client_(client),
+ overridden_network_conditions_(NULL) {
+ client_->AddListener(this);
+}
+
+NetworkConditionsOverrideManager::~NetworkConditionsOverrideManager() {
+}
+
+Status NetworkConditionsOverrideManager::OverrideNetworkConditions(
+ const NetworkConditions& network_conditions) {
+ Status status = ApplyOverride(&network_conditions);
+ if (status.IsOk())
+ overridden_network_conditions_ = &network_conditions;
+ return status;
+}
+
+Status NetworkConditionsOverrideManager::OnConnected(DevToolsClient* client) {
+ return ApplyOverrideIfNeeded();
+}
+
+Status NetworkConditionsOverrideManager::OnEvent(
+ DevToolsClient* client,
+ const std::string& method,
+ const base::DictionaryValue& params) {
+ if (method == "Page.frameNavigated") {
+ const base::Value* unused_value;
+ if (!params.Get("frame.parentId", &unused_value))
+ return ApplyOverrideIfNeeded();
+ }
+ return Status(kOk);
+}
+
+Status NetworkConditionsOverrideManager::ApplyOverrideIfNeeded() {
+ if (overridden_network_conditions_)
+ return ApplyOverride(overridden_network_conditions_);
+ return Status(kOk);
+}
+
+Status NetworkConditionsOverrideManager::ApplyOverride(
+ const NetworkConditions* network_conditions) {
+ base::DictionaryValue params, empty_params;
+ params.SetBoolean("offline", network_conditions->offline);
+ params.SetDouble("latency", network_conditions->latency);
+ params.SetDouble("downloadThroughput",
+ network_conditions->download_throughput);
+ params.SetDouble("uploadThroughput", network_conditions->upload_throughput);
+
+ Status status = client_->SendCommand("Network.enable", empty_params);
+ if (status.IsError())
+ return status;
+
+ scoped_ptr<base::DictionaryValue> result;
+ bool can = false;
+ status = client_->SendCommandAndGetResult(
+ "Network.canEmulateNetworkConditions", empty_params, &result);
+ if (status.IsError() || !result->GetBoolean("result", &can))
+ return Status(kUnknownError,
+ "unable to detect if chrome can emulate network conditions", status);
+ if (!can)
+ return Status(kUnknownError, "Cannot emulate network conditions");
+
+ return client_->SendCommand("Network.emulateNetworkConditions", params);
+}
diff --git a/chrome/test/chromedriver/chrome/network_conditions_override_manager.h b/chrome/test/chromedriver/chrome/network_conditions_override_manager.h
new file mode 100644
index 0000000..2f55a3ba
--- /dev/null
+++ b/chrome/test/chromedriver/chrome/network_conditions_override_manager.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2015 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_TEST_CHROMEDRIVER_CHROME_NETWORK_CONDITIONS_OVERRIDE_MANAGER_H_
+#define CHROME_TEST_CHROMEDRIVER_CHROME_NETWORK_CONDITIONS_OVERRIDE_MANAGER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+class DevToolsClient;
+struct NetworkConditions;
+class Status;
+
+// Overrides the network conditions, if requested, for the duration of the
+// given |DevToolsClient|'s lifetime.
+class NetworkConditionsOverrideManager : public DevToolsEventListener {
+ public:
+ explicit NetworkConditionsOverrideManager(DevToolsClient* client);
+ ~NetworkConditionsOverrideManager() override;
+
+ Status OverrideNetworkConditions(const NetworkConditions& network_conditions);
+
+ // Overridden from DevToolsEventListener:
+ Status OnConnected(DevToolsClient* client) override;
+ Status OnEvent(DevToolsClient* client,
+ const std::string& method,
+ const base::DictionaryValue& params) override;
+
+ private:
+ Status ApplyOverrideIfNeeded();
+ Status ApplyOverride(const NetworkConditions* network_conditions);
+
+ DevToolsClient* client_;
+ const NetworkConditions* overridden_network_conditions_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkConditionsOverrideManager);
+};
+
+#endif // CHROME_TEST_CHROMEDRIVER_CHROME_NETWORK_CONDITIONS_OVERRIDE_MANAGER_H_
diff --git a/chrome/test/chromedriver/chrome/network_conditions_override_manager_unittest.cc b/chrome/test/chromedriver/chrome/network_conditions_override_manager_unittest.cc
new file mode 100644
index 0000000..85171b0
--- /dev/null
+++ b/chrome/test/chromedriver/chrome/network_conditions_override_manager_unittest.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2015 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 "base/values.h"
+#include "chrome/test/chromedriver/chrome/network_conditions.h"
+#include "chrome/test/chromedriver/chrome/network_conditions_override_manager.h"
+#include "chrome/test/chromedriver/chrome/recorder_devtools_client.h"
+#include "chrome/test/chromedriver/chrome/status.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+void AssertNetworkConditionsCommand(
+ const Command& command,
+ const NetworkConditions& network_conditions) {
+ ASSERT_EQ("Network.emulateNetworkConditions", command.method);
+ bool offline;
+ double latency, download_throughput, upload_throughput;
+ ASSERT_TRUE(command.params.GetBoolean("offline", &offline));
+ ASSERT_TRUE(command.params.GetDouble("latency", &latency));
+ ASSERT_TRUE(command.params.GetDouble("downloadThroughput",
+ &download_throughput));
+ ASSERT_TRUE(command.params.GetDouble("uploadThroughput",
+ &upload_throughput));
+ ASSERT_EQ(network_conditions.offline, offline);
+ ASSERT_EQ(network_conditions.latency, latency);
+ ASSERT_EQ(network_conditions.download_throughput, download_throughput);
+ ASSERT_EQ(network_conditions.upload_throughput, upload_throughput);
+}
+
+} // namespace
+
+TEST(NetworkConditionsOverrideManager, OverrideSendsCommand) {
+ RecorderDevToolsClient client;
+ NetworkConditionsOverrideManager manager(&client);
+ NetworkConditions network_conditions = {false, 100, 750*1024, 750*1024};
+ manager.OverrideNetworkConditions(network_conditions);
+ ASSERT_EQ(3u, client.commands_.size());
+ ASSERT_NO_FATAL_FAILURE(
+ AssertNetworkConditionsCommand(client.commands_[2], network_conditions));
+
+ network_conditions.latency = 200;
+ manager.OverrideNetworkConditions(network_conditions);
+ ASSERT_EQ(6u, client.commands_.size());
+ ASSERT_NO_FATAL_FAILURE(
+ AssertNetworkConditionsCommand(client.commands_[5], network_conditions));
+}
+
+TEST(NetworkConditionsOverrideManager, SendsCommandOnConnect) {
+ RecorderDevToolsClient client;
+ NetworkConditionsOverrideManager manager(&client);
+ ASSERT_EQ(0u, client.commands_.size());
+ ASSERT_EQ(kOk, manager.OnConnected(&client).code());
+
+ NetworkConditions network_conditions = {false, 100, 750*1024, 750*1024};
+ manager.OverrideNetworkConditions(network_conditions);
+ ASSERT_EQ(3u, client.commands_.size());
+ ASSERT_EQ(kOk, manager.OnConnected(&client).code());
+ ASSERT_EQ(6u, client.commands_.size());
+ ASSERT_NO_FATAL_FAILURE(
+ AssertNetworkConditionsCommand(client.commands_[5], network_conditions));
+}
+
+TEST(NetworkConditionsOverrideManager, SendsCommandOnNavigation) {
+ RecorderDevToolsClient client;
+ NetworkConditionsOverrideManager manager(&client);
+ base::DictionaryValue main_frame_params;
+ ASSERT_EQ(kOk,
+ manager.OnEvent(&client, "Page.frameNavigated", main_frame_params)
+ .code());
+ ASSERT_EQ(0u, client.commands_.size());
+
+ NetworkConditions network_conditions = {false, 100, 750*1024, 750*1024};
+ manager.OverrideNetworkConditions(network_conditions);
+ ASSERT_EQ(3u, client.commands_.size());
+ ASSERT_EQ(kOk,
+ manager.OnEvent(&client, "Page.frameNavigated", main_frame_params)
+ .code());
+ ASSERT_EQ(6u, client.commands_.size());
+ ASSERT_NO_FATAL_FAILURE(
+ AssertNetworkConditionsCommand(client.commands_[2], network_conditions));
+
+ base::DictionaryValue sub_frame_params;
+ sub_frame_params.SetString("frame.parentId", "id");
+ ASSERT_EQ(
+ kOk,
+ manager.OnEvent(&client, "Page.frameNavigated", sub_frame_params).code());
+ ASSERT_EQ(6u, client.commands_.size());
+ ASSERT_NO_FATAL_FAILURE(
+ AssertNetworkConditionsCommand(client.commands_[5], network_conditions));
+}
diff --git a/chrome/test/chromedriver/chrome/recorder_devtools_client.cc b/chrome/test/chromedriver/chrome/recorder_devtools_client.cc
new file mode 100644
index 0000000..2a7b0bd
--- /dev/null
+++ b/chrome/test/chromedriver/chrome/recorder_devtools_client.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2015 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/test/chromedriver/chrome/recorder_devtools_client.h"
+#include "chrome/test/chromedriver/chrome/status.h"
+
+RecorderDevToolsClient::RecorderDevToolsClient() {}
+
+RecorderDevToolsClient::~RecorderDevToolsClient() {}
+
+Status RecorderDevToolsClient::SendCommandAndGetResult(
+ const std::string& method,
+ const base::DictionaryValue& params,
+ scoped_ptr<base::DictionaryValue>* result) {
+ commands_.push_back(Command(method, params));
+
+ // For any tests that directly call SendCommandAndGetResults, we'll just
+ // always return { "result": true }. Currently only used when testing
+ // "canEmulateNetworkConditions".
+ (*result).reset(new base::DictionaryValue);
+ (*result)->SetBoolean("result", true);
+ return Status(kOk);
+}
diff --git a/chrome/test/chromedriver/chrome/recorder_devtools_client.h b/chrome/test/chromedriver/chrome/recorder_devtools_client.h
new file mode 100644
index 0000000..f7e49d2
--- /dev/null
+++ b/chrome/test/chromedriver/chrome/recorder_devtools_client.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2015 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_TEST_CHROMEDRIVER_CHROME_RECORDER_DEVTOOLS_CLIENT_H_
+#define CHROME_TEST_CHROMEDRIVER_CHROME_RECORDER_DEVTOOLS_CLIENT_H_
+
+#include <vector>
+
+#include "base/values.h"
+#include "chrome/test/chromedriver/chrome/stub_devtools_client.h"
+
+namespace base {
+class DictionaryValue;
+}
+
+class Status;
+
+struct Command {
+ Command() {}
+ Command(const std::string& method, const base::DictionaryValue& params)
+ : method(method) {
+ this->params.MergeDictionary(¶ms);
+ }
+ Command(const Command& command) {
+ *this = command;
+ }
+ Command& operator=(const Command& command) {
+ method = command.method;
+ params.Clear();
+ params.MergeDictionary(&command.params);
+ return *this;
+ }
+ ~Command() {}
+
+ std::string method;
+ base::DictionaryValue params;
+};
+
+class RecorderDevToolsClient : public StubDevToolsClient {
+ public:
+ RecorderDevToolsClient();
+ ~RecorderDevToolsClient() override;
+
+ // Overridden from StubDevToolsClient:
+ Status SendCommandAndGetResult(
+ const std::string& method,
+ const base::DictionaryValue& params,
+ scoped_ptr<base::DictionaryValue>* result) override;
+
+ std::vector<Command> commands_;
+};
+
+#endif // CHROME_TEST_CHROMEDRIVER_CHROME_RECORDER_DEVTOOLS_CLIENT_H_
diff --git a/chrome/test/chromedriver/chrome/stub_web_view.cc b/chrome/test/chromedriver/chrome/stub_web_view.cc
index 8ba6c7c5..12c6eeea 100644
--- a/chrome/test/chromedriver/chrome/stub_web_view.cc
+++ b/chrome/test/chromedriver/chrome/stub_web_view.cc
@@ -121,6 +121,11 @@
return Status(kOk);
}
+Status StubWebView::OverrideNetworkConditions(
+ const NetworkConditions& network_conditions) {
+ return Status(kOk);
+}
+
Status StubWebView::CaptureScreenshot(std::string* screenshot) {
return Status(kOk);
}
diff --git a/chrome/test/chromedriver/chrome/stub_web_view.h b/chrome/test/chromedriver/chrome/stub_web_view.h
index 0f59e6d6a..4b23879e 100644
--- a/chrome/test/chromedriver/chrome/stub_web_view.h
+++ b/chrome/test/chromedriver/chrome/stub_web_view.h
@@ -60,6 +60,8 @@
bool* is_pending) override;
JavaScriptDialogManager* GetJavaScriptDialogManager() override;
Status OverrideGeolocation(const Geoposition& geoposition) override;
+ Status OverrideNetworkConditions(
+ const NetworkConditions& network_conditions) override;
Status CaptureScreenshot(std::string* screenshot) override;
Status SetFileInputFiles(const std::string& frame,
const base::DictionaryValue& element,
diff --git a/chrome/test/chromedriver/chrome/web_view.h b/chrome/test/chromedriver/chrome/web_view.h
index 718900e..47c0cca7 100644
--- a/chrome/test/chromedriver/chrome/web_view.h
+++ b/chrome/test/chromedriver/chrome/web_view.h
@@ -24,6 +24,7 @@
class JavaScriptDialogManager;
struct KeyEvent;
struct MouseEvent;
+struct NetworkConditions;
struct TouchEvent;
class Status;
@@ -144,6 +145,10 @@
// Overrides normal geolocation with a given geoposition.
virtual Status OverrideGeolocation(const Geoposition& geoposition) = 0;
+ // Overrides normal network conditions with given conditions.
+ virtual Status OverrideNetworkConditions(
+ const NetworkConditions& network_conditions) = 0;
+
// Captures the visible portions of the web view as a base64-encoded PNG.
virtual Status CaptureScreenshot(std::string* screenshot) = 0;
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.cc b/chrome/test/chromedriver/chrome/web_view_impl.cc
index d703b4e3..712a36cd 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.cc
+++ b/chrome/test/chromedriver/chrome/web_view_impl.cc
@@ -24,6 +24,7 @@
#include "chrome/test/chromedriver/chrome/js.h"
#include "chrome/test/chromedriver/chrome/mobile_emulation_override_manager.h"
#include "chrome/test/chromedriver/chrome/navigation_tracker.h"
+#include "chrome/test/chromedriver/chrome/network_conditions_override_manager.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/chrome/ui_events.h"
@@ -127,6 +128,8 @@
new MobileEmulationOverrideManager(client.get(), device_metrics)),
geolocation_override_manager_(
new GeolocationOverrideManager(client.get())),
+ network_conditions_override_manager_(
+ new NetworkConditionsOverrideManager(client.get())),
heap_snapshot_taker_(new HeapSnapshotTaker(client.get())),
debugger_(new DebuggerTracker(client.get())),
client_(client.release()) {}
@@ -410,6 +413,12 @@
return geolocation_override_manager_->OverrideGeolocation(geoposition);
}
+Status WebViewImpl::OverrideNetworkConditions(
+ const NetworkConditions& network_conditions) {
+ return network_conditions_override_manager_->OverrideNetworkConditions(
+ network_conditions);
+}
+
Status WebViewImpl::CaptureScreenshot(std::string* screenshot) {
base::DictionaryValue params;
scoped_ptr<base::DictionaryValue> result;
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.h b/chrome/test/chromedriver/chrome/web_view_impl.h
index 19660dc..9fcadaf 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.h
+++ b/chrome/test/chromedriver/chrome/web_view_impl.h
@@ -27,6 +27,7 @@
class FrameTracker;
class GeolocationOverrideManager;
class MobileEmulationOverrideManager;
+class NetworkConditionsOverrideManager;
class HeapSnapshotTaker;
struct KeyEvent;
struct MouseEvent;
@@ -87,6 +88,8 @@
bool* is_pending) override;
JavaScriptDialogManager* GetJavaScriptDialogManager() override;
Status OverrideGeolocation(const Geoposition& geoposition) override;
+ Status OverrideNetworkConditions(
+ const NetworkConditions& network_conditions) override;
Status CaptureScreenshot(std::string* screenshot) override;
Status SetFileInputFiles(const std::string& frame,
const base::DictionaryValue& element,
@@ -117,6 +120,8 @@
scoped_ptr<JavaScriptDialogManager> dialog_manager_;
scoped_ptr<MobileEmulationOverrideManager> mobile_emulation_override_manager_;
scoped_ptr<GeolocationOverrideManager> geolocation_override_manager_;
+ scoped_ptr<NetworkConditionsOverrideManager>
+ network_conditions_override_manager_;
scoped_ptr<HeapSnapshotTaker> heap_snapshot_taker_;
scoped_ptr<DebuggerTracker> debugger_;
scoped_ptr<DevToolsClient> client_;
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py
index a4389f97..3700a73a 100644
--- a/chrome/test/chromedriver/client/chromedriver.py
+++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -357,3 +357,26 @@
def SetAutoReporting(self, enabled):
self.ExecuteCommand(Command.SET_AUTO_REPORTING, {'enabled': enabled})
+
+ def SetNetworkConditions(self, latency, download_throughput,
+ upload_throughput):
+ # Until http://crbug.com/456324 is resolved, we'll always set 'offline' to
+ # False, as going "offline" will sever Chromedriver's connection to Chrome.
+ params = {
+ 'network_conditions': {
+ 'offline': False,
+ 'latency': latency,
+ 'download_throughput': download_throughput,
+ 'upload_throughput': upload_throughput
+ }
+ }
+ self.ExecuteCommand(Command.SET_NETWORK_CONDITIONS, params)
+
+ def GetNetworkConditions(self):
+ conditions = self.ExecuteCommand(Command.GET_NETWORK_CONDITIONS)
+ return {
+ 'latency': conditions['latency'],
+ 'download_throughput': conditions['download_throughput'],
+ 'upload_throughput': conditions['upload_throughput'],
+ 'offline': conditions['offline']
+ }
diff --git a/chrome/test/chromedriver/client/command_executor.py b/chrome/test/chromedriver/client/command_executor.py
index 4b59881..f3d6465 100644
--- a/chrome/test/chromedriver/client/command_executor.py
+++ b/chrome/test/chromedriver/client/command_executor.py
@@ -95,6 +95,10 @@
EXECUTE_SQL = (_Method.POST, '/session/:sessionId/execute_sql')
GET_LOCATION = (_Method.GET, '/session/:sessionId/location')
SET_LOCATION = (_Method.POST, '/session/:sessionId/location')
+ GET_NETWORK_CONDITIONS = (
+ _Method.GET, '/session/:sessionId/chromium/network_conditions')
+ SET_NETWORK_CONDITIONS = (
+ _Method.POST, '/session/:sessionId/chromium/network_conditions')
GET_STATUS = (_Method.GET, '/session/:sessionId/application_cache/status')
IS_BROWSER_ONLINE = (_Method.GET, '/session/:sessionId/browser_connection')
SET_BROWSER_ONLINE = (_Method.POST, '/session/:sessionId/browser_connection')
diff --git a/chrome/test/chromedriver/server/http_handler.cc b/chrome/test/chromedriver/server/http_handler.cc
index 6e452fe..3ae9299 100644
--- a/chrome/test/chromedriver/server/http_handler.cc
+++ b/chrome/test/chromedriver/server/http_handler.cc
@@ -370,6 +370,16 @@
kPost,
"session/:sessionId/location",
WrapToCommand("SetGeolocation", base::Bind(&ExecuteSetLocation))),
+ CommandMapping(
+ kGet,
+ "session/:sessionId/chromium/network_conditions",
+ WrapToCommand("GetNetworkConditions",
+ base::Bind(&ExecuteGetNetworkConditions))),
+ CommandMapping(
+ kPost,
+ "session/:sessionId/chromium/network_conditions",
+ WrapToCommand("SetNetworkConditions",
+ base::Bind(&ExecuteSetNetworkConditions))),
CommandMapping(kGet,
"session/:sessionId/application_cache/status",
base::Bind(&ExecuteGetStatus)),
diff --git a/chrome/test/chromedriver/session.h b/chrome/test/chromedriver/session.h
index 2df16d7..fa0a82d 100644
--- a/chrome/test/chromedriver/session.h
+++ b/chrome/test/chromedriver/session.h
@@ -16,6 +16,7 @@
#include "chrome/test/chromedriver/basic_types.h"
#include "chrome/test/chromedriver/chrome/device_metrics.h"
#include "chrome/test/chromedriver/chrome/geoposition.h"
+#include "chrome/test/chromedriver/chrome/network_conditions.h"
#include "chrome/test/chromedriver/command_listener.h"
namespace base {
@@ -72,6 +73,7 @@
scoped_ptr<std::string> prompt_text;
scoped_ptr<Geoposition> overridden_geoposition;
scoped_ptr<DeviceMetrics> overridden_device_metrics;
+ scoped_ptr<NetworkConditions> overridden_network_conditions;
// Logs that populate from DevTools events.
ScopedVector<WebDriverLog> devtools_logs;
scoped_ptr<WebDriverLog> driver_log;
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index 9af15c3a..b403124 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -356,6 +356,20 @@
return status;
}
+ if (session->overridden_network_conditions) {
+ WebView* web_view;
+ status = session->chrome->GetWebViewById(web_view_id, &web_view);
+ if (status.IsError())
+ return status;
+ status = web_view->ConnectIfNecessary();
+ if (status.IsError())
+ return status;
+ status = web_view->OverrideNetworkConditions(
+ *session->overridden_network_conditions);
+ if (status.IsError())
+ return status;
+ }
+
session->window = web_view_id;
session->SwitchToTopFrame();
session->mouse_position = WebPoint(0, 0);
@@ -456,6 +470,29 @@
return Status(kOk);
}
+Status ExecuteGetNetworkConditions(
+ Session* session,
+ const base::DictionaryValue& params,
+ scoped_ptr<base::Value>* value) {
+ if (!session->overridden_network_conditions) {
+ return Status(kUnknownError,
+ "network conditions must be set before it can be retrieved");
+ }
+ base::DictionaryValue conditions;
+ conditions.SetBoolean("offline",
+ session->overridden_network_conditions->offline);
+ conditions.SetInteger("latency",
+ session->overridden_network_conditions->latency);
+ conditions.SetInteger(
+ "download_throughput",
+ session->overridden_network_conditions->download_throughput);
+ conditions.SetInteger(
+ "upload_throughput",
+ session->overridden_network_conditions->upload_throughput);
+ value->reset(conditions.DeepCopy());
+ return Status(kOk);
+}
+
Status ExecuteGetWindowPosition(
Session* session,
const base::DictionaryValue& params,
diff --git a/chrome/test/chromedriver/session_commands.h b/chrome/test/chromedriver/session_commands.h
index c30ceff..204e3ee 100644
--- a/chrome/test/chromedriver/session_commands.h
+++ b/chrome/test/chromedriver/session_commands.h
@@ -118,6 +118,11 @@
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value);
+Status ExecuteGetNetworkConditions(
+ Session* session,
+ const base::DictionaryValue& params,
+ scoped_ptr<base::Value>* value);
+
Status ExecuteGetWindowPosition(
Session* session,
const base::DictionaryValue& params,
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index a56389d..556227a4 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -50,6 +50,8 @@
# This test is flaky since it uses setTimeout.
# Re-enable once crbug.com/177511 is fixed and we can remove setTimeout.
'ChromeDriverTest.testAlert',
+ # Enable per-browser when http://crbug.com/456324 is fixed.
+ 'ChromeDriverTest.testEmulateNetworkConditionsOffline',
]
_VERSION_SPECIFIC_FILTER = {}
@@ -787,6 +789,47 @@
lots_of_data = self._driver.ExecuteScript(script)
self.assertEquals('0'.zfill(int(10e6)), lots_of_data)
+ def testEmulateNetworkConditions(self):
+ # DSL: 2Mbps throughput, 5ms RTT
+ latency = 5
+ throughput = 2048 * 1024
+ self._driver.SetNetworkConditions(latency, throughput, throughput)
+
+ network = self._driver.GetNetworkConditions()
+ self.assertEquals(latency, network['latency']);
+ self.assertEquals(throughput, network['download_throughput']);
+ self.assertEquals(throughput, network['upload_throughput']);
+
+ def testEmulateNetworkConditionsOffline(self):
+ self._driver.SetNetworkConditions(5, 2048, 2048, offline=True)
+ self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html'))
+ self.assertIn('is not available', self._driver.GetTitle())
+
+ def testEmulateNetworkConditionsSpeed(self):
+ # Warm up the browser.
+ self._http_server.SetDataForPath(
+ '/', "<html><body>blank</body></html>")
+ self._driver.Load(self._http_server.GetUrl() + '/')
+
+ # DSL: 2Mbps throughput, 5ms RTT
+ latency = 5
+ throughput_kbps = 2048
+ throughput = throughput_kbps * 1024
+ self._driver.SetNetworkConditions(latency, throughput, throughput)
+
+ _32_bytes = " 0 1 2 3 4 5 6 7 8 9 A B C D E F"
+ _1_megabyte = _32_bytes * 32768
+ self._http_server.SetDataForPath(
+ '/1MB',
+ "<html><body>%s</body></html>" % _1_megabyte)
+ start = time.time()
+ self._driver.Load(self._http_server.GetUrl() + '/1MB')
+ finish = time.time()
+ duration = finish - start
+ actual_throughput_kbps = 1024 / duration
+ self.assertLessEqual(actual_throughput_kbps, throughput_kbps * 1.5)
+ self.assertGreaterEqual(actual_throughput_kbps, throughput_kbps / 1.5)
+
def testShadowDomFindElementWithSlashDeep(self):
"""Checks that chromedriver can find elements in a shadow DOM using /deep/
css selectors."""
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index 9a3c405..70273317 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -869,6 +869,53 @@
return status;
}
+Status ExecuteSetNetworkConditions(
+ Session* session,
+ WebView* web_view,
+ const base::DictionaryValue& params,
+ scoped_ptr<base::Value>* value) {
+ const base::DictionaryValue* conditions = NULL;
+ NetworkConditions network_conditions;
+ // |latency| is required.
+ if (!params.GetDictionary("network_conditions", &conditions) ||
+ !conditions->GetDouble("latency", &network_conditions.latency))
+ return Status(kUnknownError, "missing or invalid 'network_conditions'");
+
+ // Either |throughput| or the pair |download_throughput| and
+ // |upload_throughput| is required.
+ if (conditions->HasKey("throughput")) {
+ if (!conditions->GetDouble("throughput",
+ &network_conditions.download_throughput))
+ return Status(kUnknownError, "invalid 'throughput'");
+ conditions->GetDouble("throughput", &network_conditions.upload_throughput);
+ } else if (conditions->HasKey("download_throughput") &&
+ conditions->HasKey("upload_throughput")) {
+ if (!conditions->GetDouble("download_throughput",
+ &network_conditions.download_throughput) ||
+ !conditions->GetDouble("upload_throughput",
+ &network_conditions.upload_throughput))
+ return Status(kUnknownError,
+ "invalid 'download_throughput' or 'upload_throughput'");
+ } else {
+ return Status(kUnknownError,
+ "invalid 'network_conditions' is missing 'throughput' or "
+ "'download_throughput'/'upload_throughput' pair");
+ }
+
+ // |offline| is optional.
+ if (conditions->HasKey("offline")) {
+ if (!conditions->GetBoolean("offline", &network_conditions.offline))
+ return Status(kUnknownError, "invalid 'offline'");
+ } else {
+ network_conditions.offline = false;
+ }
+
+ session->overridden_network_conditions.reset(
+ new NetworkConditions(network_conditions));
+ return web_view->OverrideNetworkConditions(
+ *session->overridden_network_conditions);
+}
+
Status ExecuteTakeHeapSnapshot(
Session* session,
WebView* web_view,
diff --git a/chrome/test/chromedriver/window_commands.h b/chrome/test/chromedriver/window_commands.h
index 612906e..67d9ff88 100644
--- a/chrome/test/chromedriver/window_commands.h
+++ b/chrome/test/chromedriver/window_commands.h
@@ -290,6 +290,12 @@
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value);
+Status ExecuteSetNetworkConditions(
+ Session* session,
+ WebView* web_view,
+ const base::DictionaryValue& params,
+ scoped_ptr<base::Value>* value);
+
Status ExecuteTakeHeapSnapshot(
Session* session,
WebView* web_view,