Commit 0d53d7a9 authored by srawlins's avatar srawlins Committed by Commit bot

Add Network Presets to Network Throttling feature

BUG=

Review URL: https://codereview.chromium.org/1004843002

Cr-Commit-Position: refs/heads/master@{#320987}
parent 9349a45e
......@@ -1147,8 +1147,12 @@
'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.cc',
'test/chromedriver/chrome/network_conditions.h',
'test/chromedriver/chrome/network_conditions_override_manager.cc',
'test/chromedriver/chrome/network_conditions_override_manager.h',
'test/chromedriver/chrome/network_list.cc',
'test/chromedriver/chrome/network_list.h',
'test/chromedriver/chrome/status.cc',
'test/chromedriver/chrome/status.h',
'test/chromedriver/chrome/ui_events.cc',
......
// Copyright 2014 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.h"
#include "base/json/json_reader.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/network_list.h"
#include "chrome/test/chromedriver/chrome/status.h"
NetworkConditions::NetworkConditions() {}
NetworkConditions::NetworkConditions(
bool offline, double latency, double download_throughput,
double upload_throughput)
: offline(offline),
latency(latency),
download_throughput(download_throughput),
upload_throughput(upload_throughput) {}
NetworkConditions::~NetworkConditions() {}
Status FindPresetNetwork(std::string network_name,
NetworkConditions* network_conditions) {
base::JSONReader json_reader(base::JSON_ALLOW_TRAILING_COMMAS);
scoped_ptr<base::Value> networks_value;
networks_value.reset(json_reader.ReadToValue(kNetworks));
if (!networks_value.get())
return Status(kUnknownError,
"could not parse network list because " +
json_reader.GetErrorMessage());
base::ListValue* networks;
if (!networks_value->GetAsList(&networks))
return Status(kUnknownError, "malformed networks list");
for (base::ListValue::iterator it = networks->begin();
it != networks->end();
++it) {
base::DictionaryValue* network = NULL;
if (!(*it)->GetAsDictionary(&network)) {
return Status(kUnknownError,
"malformed network in list: should be a dictionary");
}
if (network == NULL)
continue;
std::string title;
if (!network->GetString("title", &title)) {
return Status(kUnknownError,
"malformed network title: should be a string");
}
if (title != network_name)
continue;
if (!network->GetDouble("latency", &network_conditions->latency)) {
return Status(kUnknownError,
"malformed network latency: should be a double");
}
// Preset list maintains a single "throughput" attribute for each network,
// so we use that value for both |download_throughput| and
// |upload_throughput| in the NetworkConditions (as does Chrome).
if (!network->GetDouble("throughput",
&network_conditions->download_throughput) ||
!network->GetDouble("throughput",
&network_conditions->upload_throughput)) {
return Status(kUnknownError,
"malformed network throughput: should be a double");
}
// The throughputs of the network presets are listed in kbps, but must be
// supplied to the OverrideNetworkConditions command as bps.
network_conditions->download_throughput *= 1024;
network_conditions->upload_throughput *= 1024;
// |offline| is always false for now.
network_conditions->offline = false;
return Status(kOk);
}
return Status(kUnknownError, "must be a valid network");
}
......@@ -5,11 +5,24 @@
#ifndef CHROME_TEST_CHROMEDRIVER_CHROME_NETWORK_CONDITIONS_H_
#define CHROME_TEST_CHROMEDRIVER_CHROME_NETWORK_CONDITIONS_H_
#include <string>
#include "base/memory/scoped_ptr.h"
class Status;
struct NetworkConditions {
NetworkConditions();
NetworkConditions(bool offline, double latency,
double download_throughput, double upload_throughput);
~NetworkConditions();
bool offline;
double latency;
double download_throughput;
double upload_throughput;
};
Status FindPresetNetwork(
std::string network_name,
NetworkConditions* network_conditions);
#endif // CHROME_TEST_CHROMEDRIVER_CHROME_NETWORK_CONDITIONS_H_
// Copyright 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.
// This file was generated at (2015-03-12 15:00:42.307998) by running:
// chrome/test/chromedriver/embed_networks_in_cpp.py --directory
// chrome/test/chromedriver/chrome/
// third_party/WebKit/Source/devtools/front_end/toolbox/OverridesUI.js
#include "chrome/test/chromedriver/chrome/network_list.h"
const char kNetworks[] =
"[{\"id\": \"offline\", \"title\": \"Offline\", \"throughput\": 0, "
"\"latency\": 0},{\"id\": \"gprs\", \"title\": \"GPRS\", \"throughput\": "
"50, \"latency\": 500},{\"id\": \"edge\", \"title\": \"Regular 2G\", "
"\"throughput\": 250, \"latency\": 300},{\"id\": \"2g+\", \"title\": "
"\"Good 2G\", \"throughput\": 450, \"latency\": 150},{\"id\": \"3g\", "
"\"title\": \"Regular 3G\", \"throughput\": 750, \"latency\": "
"100},{\"id\": \"3g+\", \"title\": \"Good 3G\", \"throughput\": 1536.0, "
"\"latency\": 40},{\"id\": \"4g\", \"title\": \"Regular 4G\", "
"\"throughput\": 4096.0, \"latency\": 20},{\"id\": \"dsl\", \"title\": "
"\"DSL\", \"throughput\": 2048.0, \"latency\": 5},{\"id\": \"wifi\", "
"\"title\": \"WiFi\", \"throughput\": 30720.0, \"latency\": 2},{\"id\": "
"\"online\", \"title\": \"No throttling\", \"throughput\": -1, "
"\"latency\": 0}]";
// Copyright 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.
// This file was generated at (2015-03-12 15:00:42.307998) by running:
// chrome/test/chromedriver/embed_networks_in_cpp.py --directory
// chrome/test/chromedriver/chrome/
// third_party/WebKit/Source/devtools/front_end/toolbox/OverridesUI.js
#ifndef CHROME_TEST_CHROMEDRIVER_CHROME_NETWORK_LIST_H_
#define CHROME_TEST_CHROMEDRIVER_CHROME_NETWORK_LIST_H_
extern const char kNetworks[];
#endif // CHROME_TEST_CHROMEDRIVER_CHROME_NETWORK_LIST_H_
......@@ -372,6 +372,10 @@ class ChromeDriver(object):
}
self.ExecuteCommand(Command.SET_NETWORK_CONDITIONS, params)
def SetNetworkConditionsName(self, network_name):
self.ExecuteCommand(
Command.SET_NETWORK_CONDITIONS, {'network_name': network_name})
def GetNetworkConditions(self):
conditions = self.ExecuteCommand(Command.GET_NETWORK_CONDITIONS)
return {
......
#!/usr/bin/env python
# Copyright 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.
"""Embeds standalone JavaScript snippets in C++ code.
The script requires the devtools/front_end/toolbox/OverridesUI.js file from
WebKit that lists the preset network conditions to be passed in as the only
argument. The list of network conditions will be written to a C-style string to
be parsed with JSONReader.
"""
import optparse
import os
import re
import subprocess
import sys
import cpp_source
UNLIMITED_THROUGHPUT = ('WebInspector.OverridesSupport'
'.NetworkThroughputUnlimitedValue')
def quotizeKeys(s, keys):
"""Returns the string s with each instance of each key wrapped in quotes.
Args:
s: a string containing keys that need to be wrapped in quotes.
keys: an iterable of keys to be wrapped in quotes in the string.
"""
for key in keys:
s = re.sub('%s: ' % key, '"%s": ' % key, s)
return s
def evaluateMultiplications(s):
"""Returns the string s with each bare multiplication evaluated.
Since the source is JavaScript, which includes bare arithmetic, and the
output must be JSON format, we must evaluate all expressions.
Args:
s: a string containing bare multiplications that need to be evaluated.
"""
def evaluateBinaryMultiplication(match):
return str(float(match.group(1)) * float(match.group(2)))
return re.sub('([0-9\.]+) \* ([0-9\.]+)', evaluateBinaryMultiplication, s)
def main():
parser = optparse.OptionParser()
parser.add_option(
'', '--directory', type='string', default='.',
help='Path to directory where the cc/h files should be created')
options, args = parser.parse_args()
networks = '['
file_name = args[0]
inside_list = False
with open(file_name, 'r') as f:
for line in f:
if not inside_list:
if 'WebInspector.OverridesUI._networkConditionsPresets = [' in line:
inside_list = True
else:
if line.strip() == '];':
inside_list = False
continue
line = line.replace(UNLIMITED_THROUGHPUT, "-1")
networks += line.strip()
output_dir = 'chrome/test/chromedriver/chrome'
networks += ']'
networks = quotizeKeys(networks, ['id', 'title', 'throughput', 'latency'])
networks = evaluateMultiplications(networks)
cpp_source.WriteSource('network_list',
output_dir,
options.directory, {'kNetworks': networks})
clang_format = ['clang-format', '-i']
subprocess.Popen(clang_format + ['%s/network_list.cc' % output_dir])
subprocess.Popen(clang_format + ['%s/network_list.h' % output_dir])
if __name__ == '__main__':
sys.exit(main())
......@@ -54,6 +54,7 @@ _NEGATIVE_FILTER = [
'ChromeDriverTest.testEmulateNetworkConditionsOffline',
# This test is too flaky on the bots, but seems to run perfectly fine
# on developer workstations.
'ChromeDriverTest.testEmulateNetworkConditionsNameSpeed',
'ChromeDriverTest.testEmulateNetworkConditionsSpeed',
]
......@@ -161,6 +162,7 @@ _ANDROID_NEGATIVE_FILTER['chromedriver_webview_shell'] = (
'ChromeDriverTest.testShadowDom*',
# WebView doesn't support emulating network conditions.
'ChromeDriverTest.testEmulateNetworkConditions',
'ChromeDriverTest.testEmulateNetworkConditionsNameSpeed',
'ChromeDriverTest.testEmulateNetworkConditionsOffline',
'ChromeDriverTest.testEmulateNetworkConditionsSpeed',
]
......@@ -806,6 +808,19 @@ class ChromeDriverTest(ChromeDriverBaseTest):
self.assertEquals(latency, network['latency']);
self.assertEquals(throughput, network['download_throughput']);
self.assertEquals(throughput, network['upload_throughput']);
self.assertEquals(False, network['offline']);
def testEmulateNetworkConditionsName(self):
# DSL: 2Mbps throughput, 5ms RTT
#latency = 5
#throughput = 2048 * 1024
self._driver.SetNetworkConditionsName('DSL')
network = self._driver.GetNetworkConditions()
self.assertEquals(5, network['latency']);
self.assertEquals(2048*1024, network['download_throughput']);
self.assertEquals(2048*1024, network['upload_throughput']);
self.assertEquals(False, network['offline']);
def testEmulateNetworkConditionsSpeed(self):
# Warm up the browser.
......@@ -832,6 +847,30 @@ class ChromeDriverTest(ChromeDriverBaseTest):
self.assertLessEqual(actual_throughput_kbps, throughput_kbps * 1.5)
self.assertGreaterEqual(actual_throughput_kbps, throughput_kbps / 1.5)
def testEmulateNetworkConditionsNameSpeed(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
throughput_kbps = 2048
throughput = throughput_kbps * 1024
self._driver.SetNetworkConditionsName('DSL')
_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 testEmulateNetworkConditionsOffline(self):
self._driver.SetNetworkConditions(5, 2048, 2048, offline=True)
self._driver.Load(self.GetHttpUrlForFile('/chromedriver/page_test.html'))
......
......@@ -21,6 +21,7 @@
#include "chrome/test/chromedriver/chrome/geoposition.h"
#include "chrome/test/chromedriver/chrome/javascript_dialog_manager.h"
#include "chrome/test/chromedriver/chrome/js.h"
#include "chrome/test/chromedriver/chrome/network_conditions.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/chrome/ui_events.h"
#include "chrome/test/chromedriver/chrome/web_view.h"
......@@ -874,44 +875,57 @@ Status ExecuteSetNetworkConditions(
WebView* web_view,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
std::string network_name;
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))
scoped_ptr<NetworkConditions> network_conditions(new NetworkConditions());
if (params.GetString("network_name", &network_name)) {
// Get conditions from preset list.
Status status = FindPresetNetwork(network_name, network_conditions.get());
if (status.IsError())
return status;
} else if (params.GetDictionary("network_conditions", &conditions)) {
// |latency| is required.
if (!conditions->GetDouble("latency", &network_conditions->latency))
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");
}
"invalid 'network_conditions' is missing 'latency'");
// 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'");
// |offline| is optional.
if (conditions->HasKey("offline")) {
if (!conditions->GetBoolean("offline", &network_conditions->offline))
return Status(kUnknownError, "invalid 'offline'");
} else {
network_conditions->offline = false;
}
} else {
network_conditions.offline = false;
return Status(kUnknownError,
"either 'network_conditions' or 'network_name' must be "
"supplied");
}
session->overridden_network_conditions.reset(
new NetworkConditions(network_conditions));
network_conditions.release());
return web_view->OverrideNetworkConditions(
*session->overridden_network_conditions);
}
......
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