Skip to content

Commit 096a12c

Browse files
Mehmet GercekerAutomatedTester
authored andcommitted
Adds rewrite rules clear api.
Fixes content type for request/response intercept and adds doc links for writing intercept code. Adds comments clarifying intercept client test coverage. Augments human test for url rewrite and adds clear portion. Adds test for response intercept. Adds bootstrap script to download tools to test with. Refactors human tests so browser session are cleaned up when tests fail and tests run with chromium. Adds server start script for travis. Changes .travis.yml to use provided scripts and also run headless chrome. Updates .travis.yml not to skip all tests. Updates .travis.yml not to skip all tests. Removes all but Python 2.7 for testing purposes. Removes redundant argument from .travis.yml. Updates webdriver tests to use chrome with the proxy. (FF does not work with actual tests) Updates tests to be functional tests. (uses proper assertions) Removes redundant lines from the remote tests. Reduces tests to human tests only for testing. Fixes Chromium binary location setting. Tweaks .travis.yml Tweaking server start scripts. Adding jdk version for proper functionality of Se server. Sets oracle jdk8 as default. Tweaks .travis.yml and bootstrap.sh Adds Linux binaries. Reverting to chrome stable for testing. Adding dist spec for google-chrome-stable installation. Adds chrome no sandbox option. Now all tests can run on Travis.
1 parent 19663c9 commit 096a12c

File tree

7 files changed

+159
-53
lines changed

7 files changed

+159
-53
lines changed

.travis.yml

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
language: python
2+
3+
jdk:
4+
- oraclejdk8
5+
6+
addons:
7+
apt:
8+
packages:
9+
- oracle-java8-installer
10+
- oracle-java8-set-default
11+
- google-chrome-stable
12+
213
sudo: false
314
python:
415
- 2.6
@@ -7,10 +18,12 @@ python:
718
- 3.4
819
- 3.5
920
before_script:
10-
- curl -l -L -O https://github.com/lightbody/browsermob-proxy/releases/download/browsermob-proxy-2.1.0-beta-6/browsermob-proxy-2.1.0-beta-6-bin.zip
11-
- unzip browsermob-proxy-2.1.0-beta-6-bin.zip
12-
- sh browsermob-proxy-2.1.0-beta-6/bin/browsermob-proxy --port=9090 &
21+
- export DISPLAY=:99.0
22+
- sh -e /etc/init.d/xvfb start
23+
- ./bootstrap.sh
24+
- ./start-servers.sh
1325
- sleep 5
1426
install: pip install pytest selenium
15-
script: python setup.py develop && py.test -m "not human" test
27+
script: python setup.py develop && py.test test
1628
sudo: false
29+
dist: trusty

bootstrap.sh

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env bash
2+
if [ "$(uname)" == "Darwin" ]; then
3+
echo "We're on a MAC!"
4+
chromeDriver="chromedriver_mac64.zip"
5+
geckoDriverVersion="v0.13.0"
6+
geckoDriver="geckodriver-$geckoDriverVersion-macos.tar.gz"
7+
else
8+
echo "We're not on a MAC!"
9+
chromeDriver="chromedriver_linux64.zip"
10+
geckoDriverVersion="v0.14.0"
11+
geckoDriver="geckodriver-$geckoDriverVersion-linux64.tar.gz"
12+
fi
13+
rm -rf tools
14+
mkdir -p tools && \
15+
cd tools && \
16+
wget https://github.com/lightbody/browsermob-proxy/releases/download/browsermob-proxy-2.1.4/browsermob-proxy-2.1.4-bin.zip && \
17+
unzip -o browsermob-proxy-2.1.4-bin.zip && \
18+
rm -rf browsermob-proxy*.zip* && \
19+
wget http://selenium-release.storage.googleapis.com/3.0/selenium-server-standalone-3.0.1.jar && \
20+
wget https://github.com/mozilla/geckodriver/releases/download/${geckoDriverVersion}/${geckoDriver} && \
21+
tar zxf ${geckoDriver} && \
22+
rm -rf ${geckoDriver}* && \
23+
wget https://chromedriver.storage.googleapis.com/2.27/${chromeDriver} && \
24+
unzip ${chromeDriver} && \
25+
rm -rf ${chromeDriver}* && \
26+
cd ..

browsermobproxy/client.py

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ def __init__(self, url, params=None, options=None):
3434
jcontent = json.loads(content)
3535
except Exception as e:
3636
raise Exception("Could not read Browsermob-Proxy json\n"
37-
"Another server running on this port?\n%s..."%content[:512])
37+
"Another server running on this port?\n%s..." % content[:512])
3838
self.port = jcontent['port']
3939
url_parts = self.host.split(":")
4040
self.proxy = url_parts[1][2:] + ":" + str(self.port)
@@ -103,7 +103,6 @@ def har(self):
103103

104104
return r.json()
105105

106-
107106
def new_har(self, ref=None, options=None, title=None):
108107
"""
109108
This sets a new HAR to be recorded
@@ -199,24 +198,30 @@ def headers(self, headers):
199198

200199
def response_interceptor(self, js):
201200
"""
202-
Executes the javascript against each response
203-
204-
:param str js: the javascript to execute
201+
Executes the java/js code against each response
202+
`HttpRequest request <https://netty.io/4.1/api/io/netty/handler/codec/http/HttpRequest.html>`_,
203+
`HttpMessageContents contents <https://raw.githubusercontent.com/lightbody/browsermob-proxy/master/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageContents.java>`_,
204+
`HttpMessageInfo messageInfo <https://raw.githubusercontent.com/lightbody/browsermob-proxy/master/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageInfo.java>`_
205+
are available objects to interact with.
206+
:param str js: the js/java code to execute
205207
"""
206208
r = requests.post(url='%s/proxy/%s/filter/response' % (self.host, self.port),
207-
data=js,
208-
headers={'content-type': 'application/json'})
209+
data=js,
210+
headers={'content-type': 'text/plain'})
209211
return r.status_code
210212

211213
def request_interceptor(self, js):
212214
"""
213-
Executes the javascript against each request
214-
215-
:param str js: the javascript to execute
215+
Executes the java/js code against each response
216+
`HttpRequest request <https://netty.io/4.1/api/io/netty/handler/codec/http/HttpRequest.html>`_,
217+
`HttpMessageContents contents <https://raw.githubusercontent.com/lightbody/browsermob-proxy/master/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageContents.java>`_,
218+
`HttpMessageInfo messageInfo <https://raw.githubusercontent.com/lightbody/browsermob-proxy/master/browsermob-core/src/main/java/net/lightbody/bmp/util/HttpMessageInfo.java>`_
219+
are available objects to interact with.
220+
:param str js: the js/java code to execute
216221
"""
217222
r = requests.post(url='%s/proxy/%s/filter/request' % (self.host, self.port),
218-
data=js,
219-
headers={'content-type': 'application/json'})
223+
data=js,
224+
headers={'content-type': 'text/plain'})
220225
return r.status_code
221226

222227
LIMITS = {
@@ -295,7 +300,7 @@ def remap_hosts(self, address=None, ip_address=None, hostmap=None):
295300
hostmap[address] = ip_address
296301

297302
r = requests.post('%s/proxy/%s/hosts' % (self.host, self.port),
298-
json.dumps(hostmap),
303+
json.dumps(hostmap),
299304
headers={'content-type': 'application/json'})
300305
return r.status_code
301306

@@ -308,7 +313,7 @@ def wait_for_traffic_to_stop(self, quiet_period, timeout):
308313
:param int timeout: max number of milliseconds to wait
309314
"""
310315
r = requests.put('%s/proxy/%s/wait' % (self.host, self.port),
311-
{'quietPeriodInMs': quiet_period, 'timeoutInMs': timeout})
316+
{'quietPeriodInMs': quiet_period, 'timeoutInMs': timeout})
312317
return r.status_code
313318

314319
def clear_dns_cache(self):
@@ -334,12 +339,21 @@ def rewrite_url(self, match, replace):
334339
params)
335340
return r.status_code
336341

342+
def clear_all_rewrite_url_rules(self):
343+
"""
344+
Clears all URL rewrite rules
345+
:return: status code
346+
"""
347+
348+
r = requests.delete('%s/proxy/%s/rewrite' % (self.host, self.port))
349+
return r.status_code
350+
337351
def retry(self, retry_count):
338352
"""
339353
Retries. No idea what its used for, but its in the API...
340354
341355
:param int retry_count: the number of retries
342356
"""
343357
r = requests.put('%s/proxy/%s/retry' % (self.host, self.port),
344-
{'retrycount': retry_count})
358+
{'retrycount': retry_count})
345359
return r.status_code

start-servers.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
TOOLS=$(pwd)/tools
3+
cd $TOOLS/browsermob-proxy-2.1.4/bin/ && \
4+
./browsermob-proxy --port 9090 & \
5+
cd $TOOLS && \
6+
java -Dwebdriver.chrome.driver=chromedriver -Dwebdriver.gecko.driver=geckodriver -jar selenium-server-standalone-3.0.1.jar &

test/test_client.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,8 @@ def test_close(self):
167167
def test_response_interceptor_with_parsing_js(self):
168168
"""
169169
/proxy/:port/interceptor/response
170+
This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS
171+
Code only gets validated if the filter/interceptor is used.
170172
"""
171173
js = 'alert("foo")'
172174
status_code = self.client.response_interceptor(js)
@@ -175,6 +177,8 @@ def test_response_interceptor_with_parsing_js(self):
175177
def test_response_interceptor_with_invalid_js(self):
176178
"""
177179
/proxy/:port/interceptor/response
180+
This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS
181+
Code only gets validated if the filter/interceptor is used.
178182
"""
179183
js = 'alert("foo"'
180184
status_code = self.client.response_interceptor(js)
@@ -183,6 +187,8 @@ def test_response_interceptor_with_invalid_js(self):
183187
def test_request_interceptor_with_parsing_js(self):
184188
"""
185189
/proxy/:port/interceptor/request
190+
This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS
191+
Code only gets validated if the filter/interceptor is used.
186192
"""
187193
js = 'alert("foo")'
188194
status_code = self.client.request_interceptor(js)
@@ -191,6 +197,8 @@ def test_request_interceptor_with_parsing_js(self):
191197
def test_request_interceptor_with_invalid_js(self):
192198
"""
193199
/proxy/:port/interceptor/request
200+
This test is only checking very basic syntax rules. The snippet needs to be JAVA/JS
201+
Code only gets validated if the filter/interceptor is used.
194202
"""
195203
js = 'alert("foo"'
196204
status_code = self.client.request_interceptor(js)

test/test_remote.py

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,55 @@
1+
from os import environ
2+
13
from selenium import webdriver
24
import selenium.webdriver.common.desired_capabilities
35
import os
46
import sys
5-
import time
67
import pytest
78

9+
810
def setup_module(module):
911
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
1012

13+
1114
class TestRemote(object):
1215
def setup_method(self, method):
1316
from browsermobproxy.client import Client
1417
self.client = Client("localhost:9090")
18+
chrome_binary = environ.get("CHROME_BIN", None)
19+
self.desired_caps = selenium.webdriver.common.desired_capabilities.DesiredCapabilities.CHROME
20+
if chrome_binary is not None:
21+
self.desired_caps.update({
22+
"chromeOptions": {
23+
"binary": chrome_binary,
24+
"args": ['no-sandbox']
25+
}
26+
})
27+
self.driver = webdriver.Remote(
28+
desired_capabilities=self.desired_caps,
29+
proxy=self.client)
1530

1631
def teardown_method(self, method):
1732
self.client.close()
33+
self.driver.quit()
1834

1935
@pytest.mark.human
20-
def test_i_want_my_remote(self):
21-
driver = webdriver.Remote(desired_capabilities=selenium.webdriver.common.desired_capabilities.DesiredCapabilities.FIREFOX,
22-
proxy=self.client)
36+
def test_set_clear_url_rewrite_rule(self):
37+
targetURL = "https://www.saucelabs.com/versions.js"
38+
assert 200 == self.client.rewrite_url(
39+
"https://www.saucelabs.com/versions.+", "https://www.saucelabs.com/versions.json"
40+
)
41+
self.driver.get(targetURL)
42+
assert "Sauce Connect" in self.driver.page_source
43+
assert self.client.clear_all_rewrite_url_rules() == 200
44+
self.driver.get(targetURL)
45+
assert "Sauce Connect" not in self.driver.page_source
2346

24-
self.client.new_har("mtv")
25-
targetURL = "http://www.mtv.com"
26-
self.client.rewrite_url(".*american_flag-384x450\\.jpg", "http://www.foodsubs.com/Photos/englishmuffin.jpg")
27-
28-
driver.get(targetURL)
29-
time.sleep(5)
30-
31-
driver.quit()
47+
@pytest.mark.human
48+
def test_response_interceptor(self):
49+
content = "Response successfully intercepted"
50+
targetURL = "https://saucelabs.com/versions.json?hello"
51+
self.client.response_interceptor(
52+
"""if(messageInfo.getOriginalUrl().contains('?hello')){contents.setTextContents("%s");}""" % content
53+
)
54+
self.driver.get(targetURL)
55+
assert content in self.driver.page_source

test/test_webdriver.py

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
from os import environ
2+
13
from selenium import webdriver
24
import selenium.webdriver.common.desired_capabilities
35
from selenium.webdriver.common.proxy import Proxy
46
import os
57
import sys
68
import copy
7-
import time
89
import pytest
910

1011
def setup_module(module):
@@ -14,39 +15,28 @@ class TestWebDriver(object):
1415
def setup_method(self, method):
1516
from browsermobproxy.client import Client
1617
self.client = Client("localhost:9090")
18+
self.driver = None
1719

1820
def teardown_method(self, method):
1921
self.client.close()
22+
if self.driver is not None:
23+
self.driver.quit()
2024

2125
@pytest.mark.human
2226
def test_i_want_my_by_capability(self):
23-
capabilities = selenium.webdriver.common.desired_capabilities.DesiredCapabilities.FIREFOX
27+
capabilities = selenium.webdriver.common.desired_capabilities.DesiredCapabilities.CHROME
2428
self.client.add_to_capabilities(capabilities)
25-
driver = webdriver.Firefox(capabilities=capabilities)
26-
27-
self.client.new_har("mtv")
28-
targetURL = "http://www.mtv.com"
29-
self.client.rewrite_url(".*american_flag-384x450\\.jpg", "http://www.foodsubs.com/Photos/englishmuffin.jpg")
30-
31-
driver.get(targetURL)
32-
33-
time.sleep(5)
29+
# sets self.driver for proper clean up
30+
self._create_webdriver(capabilites=capabilities)
3431

35-
driver.quit()
32+
self._run_url_rewrite_test()
3633

3734
@pytest.mark.human
3835
def test_i_want_my_by_proxy_object(self):
39-
driver = webdriver.Firefox(proxy=self.client)
36+
self._create_webdriver(capabilites=selenium.webdriver.common.desired_capabilities.DesiredCapabilities.CHROME,
37+
proxy=self.client)
4038

41-
self.client.new_har("mtv")
42-
targetURL = "http://www.mtv.com"
43-
self.client.rewrite_url(".*american_flag-384x450\\.jpg", "http://www.foodsubs.com/Photos/englishmuffin.jpg")
44-
45-
driver.get(targetURL)
46-
47-
time.sleep(5)
48-
49-
driver.quit()
39+
self._run_url_rewrite_test()
5040

5141
def test_what_things_look_like(self):
5242
bmp_capabilities = copy.deepcopy(selenium.webdriver.common.desired_capabilities.DesiredCapabilities.FIREFOX)
@@ -58,3 +48,28 @@ def test_what_things_look_like(self):
5848
proxy.add_to_capabilities(proxy_capabilities)
5949

6050
assert bmp_capabilities == proxy_capabilities
51+
52+
def _create_webdriver(self, capabilites, proxy=None):
53+
chrome_binary = environ.get("CHROME_BIN", None)
54+
if chrome_binary is not None:
55+
capabilites.update({
56+
"chromeOptions": {
57+
"binary": chrome_binary,
58+
"args": ['no-sandbox']
59+
}
60+
})
61+
if proxy is None:
62+
self.driver = webdriver.Remote(desired_capabilities=capabilites)
63+
else:
64+
self.driver = webdriver.Remote(desired_capabilities=capabilites, proxy=proxy)
65+
66+
def _run_url_rewrite_test(self):
67+
targetURL = "https://www.saucelabs.com/versions.js"
68+
assert 200 == self.client.rewrite_url(
69+
"https://www.saucelabs.com/versions.+", "https://www.saucelabs.com/versions.json"
70+
)
71+
self.driver.get(targetURL)
72+
assert "Sauce Connect" in self.driver.page_source
73+
assert self.client.clear_all_rewrite_url_rules() == 200
74+
self.driver.get(targetURL)
75+
assert "Sauce Connect" not in self.driver.page_source

0 commit comments

Comments
 (0)