From 3624bc4df003f3145d75248888bebc2181cec009 Mon Sep 17 00:00:00 2001 From: David Wick Date: Thu, 29 May 2014 15:28:30 -0700 Subject: [PATCH 1/7] added load tests and scenarios --- package.json | 3 +- tests/load/grinder.properties | 18 ++ tests/load/play | 1 + tests/load/proxy.js | 16 ++ tests/load/record | 1 + tests/load/record_filtered | 1 + tests/load/scenario-a.py | 186 ++++++++++++++ tests/load/scenario-b.py | 289 ++++++++++++++++++++++ tests/load/scenario-c.py | 442 ++++++++++++++++++++++++++++++++++ 9 files changed, 956 insertions(+), 1 deletion(-) create mode 100755 tests/load/grinder.properties create mode 100755 tests/load/play create mode 100644 tests/load/proxy.js create mode 100755 tests/load/record create mode 100755 tests/load/record_filtered create mode 100644 tests/load/scenario-a.py create mode 100644 tests/load/scenario-b.py create mode 100644 tests/load/scenario-c.py diff --git a/package.json b/package.json index 1268fcf..e7918e1 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "ejsify": "^0.1.0", "grunt-contrib-copy": "^0.5.0", "uglify-js": "^2.4.13", - "grunt-contrib-uglify": "^0.4.0" + "grunt-contrib-uglify": "^0.4.0", + "http-proxy": "0.10.3" } } diff --git a/tests/load/grinder.properties b/tests/load/grinder.properties new file mode 100755 index 0000000..24762f2 --- /dev/null +++ b/tests/load/grinder.properties @@ -0,0 +1,18 @@ +grinder.script=grinder.py + +grinder.runs=1 + +grinder.initialProcesses=1 +grinder.processes=1 +grinder.processIncrement=1 +grinder.processIncrementInterval=100000 +grinder.threads=25 + +grinder.useConsole=false +grinder.logDirectory=log +grinder.numberOfOldLogs=1 + +# randomized start 0-10 milliseconds +grinder.initialSleepTime=5000 +# variation in sleep times +grinder.sleepTimeVariation=.5 \ No newline at end of file diff --git a/tests/load/play b/tests/load/play new file mode 100755 index 0000000..db33d32 --- /dev/null +++ b/tests/load/play @@ -0,0 +1 @@ +CLASSPATH=/usr/local/bin/grinder/lib/grinder.jar java net.grinder.Grinder \ No newline at end of file diff --git a/tests/load/proxy.js b/tests/load/proxy.js new file mode 100644 index 0000000..0a07ff7 --- /dev/null +++ b/tests/load/proxy.js @@ -0,0 +1,16 @@ +'use strict'; +var httpProxy = require('http-proxy'); + +var proxyPort = 3001; + +httpProxy.createServer(function (req, res, proxy) { + var original = req.headers.host; + var isForio = /(api\.)?forio.com|localhost:9002/.test(original); + + proxy.proxyRequest(req, res, { + host: isForio ? 'localhost' : original, + port: isForio ? '8001' : /\:\d+$/.test(original) ? original.match(/\:(\d+)$/)[1] : '80' + }); +}).listen(proxyPort); + +console.log('Listening on %s', proxyPort); \ No newline at end of file diff --git a/tests/load/record b/tests/load/record new file mode 100755 index 0000000..89d6ca2 --- /dev/null +++ b/tests/load/record @@ -0,0 +1 @@ +CLASSPATH=/usr/local/bin/grinder/lib/grinder.jar java -DHTTPPlugin.additionalHeaders=XAcceptVersion net.grinder.TCPProxy -console -http > grinder.py \ No newline at end of file diff --git a/tests/load/record_filtered b/tests/load/record_filtered new file mode 100755 index 0000000..d3b5772 --- /dev/null +++ b/tests/load/record_filtered @@ -0,0 +1 @@ +node proxy.js & ./record \ No newline at end of file diff --git a/tests/load/scenario-a.py b/tests/load/scenario-a.py new file mode 100644 index 0000000..3f4f07b --- /dev/null +++ b/tests/load/scenario-a.py @@ -0,0 +1,186 @@ +# The Grinder 3.11 +# HTTP script recorded by TCPProxy at May 29, 2014 3:12:48 PM + +from net.grinder.script import Test +from net.grinder.script.Grinder import grinder +from net.grinder.plugin.http import HTTPPluginControl, HTTPRequest +from HTTPClient import NVPair +connectionDefaults = HTTPPluginControl.getConnectionDefaults() +httpUtilities = HTTPPluginControl.getHTTPUtilities() + +# To use a proxy server, uncomment the next line and set the host and port. +# connectionDefaults.setProxyServer("localhost", 8001) + +def createRequest(test, url, headers=None): + """Create an instrumented HTTPRequest.""" + request = HTTPRequest(url=url) + if headers: request.headers=headers + test.record(request, HTTPRequest.getHttpMethodFilter()) + return request + +# These definitions at the top level of the file are evaluated once, +# when the worker process is started. + +url0 = 'http://localhost:9002' + +request101 = createRequest(Test(101, 'GET /'), url0) + +request102 = createRequest(Test(102, 'GET jquery.min.js'), url0) + +request103 = createRequest(Test(103, 'GET lodash.min.js'), url0) + +request104 = createRequest(Test(104, 'GET d3.min.js'), url0) + +request105 = createRequest(Test(105, 'GET backbone.js'), url0) + +request106 = createRequest(Test(106, 'GET contour.min.js'), url0) + +request107 = createRequest(Test(107, 'GET app.js'), url0) + +request108 = createRequest(Test(108, 'GET main.css'), url0) + +request201 = createRequest(Test(201, 'GET epicenter-logo.svg'), url0) + +request301 = createRequest(Test(301, 'GET mandelbrot-logo.svg'), url0) + +request401 = createRequest(Test(401, 'GET contour-logo.svg'), url0) + +request501 = createRequest(Test(501, 'GET julia.svg'), url0) + +request601 = createRequest(Test(601, 'GET opensource-logo.svg'), url0) + +request701 = createRequest(Test(701, 'GET map.svg'), url0) + +request801 = createRequest(Test(801, 'GET logo-white.svg'), url0) + +request901 = createRequest(Test(901, 'GET logo.svg'), url0) + +request1001 = createRequest(Test(1001, 'GET book-crawl.json'), url0) + +request1101 = createRequest(Test(1101, 'GET ss-symbolicons-block.woff'), url0) + +request1102 = createRequest(Test(1102, 'GET marker-sprite-shadow.png'), url0) + + +class TestRunner: + """A TestRunner instance is created for each worker thread.""" + + # A method for each recorded page. + def page1(self): + """GET / (requests 101-108).""" + result = request101.GET('/') + self.token_family = \ + httpUtilities.valueFromBodyURI('family') # 'Open+Sans:300' + + grinder.sleep(173) + request102.GET('/vendor/jquery/dist/jquery.min.js') + + request103.GET('/vendor/lodash/dist/lodash.min.js') + + request104.GET('/vendor/d3/d3.min.js') + + request105.GET('/vendor/backbone/backbone.js') + + request106.GET('/vendor/contour/dist/contour.min.js') + + request107.GET('/scripts/app.js') + + grinder.sleep(68) + request108.GET('/styles/main.css') + + return result + + def page2(self): + """GET epicenter-logo.svg (request 201).""" + result = request201.GET('/styles/assets/logos/epicenter-logo.svg') + + return result + + def page3(self): + """GET mandelbrot-logo.svg (request 301).""" + result = request301.GET('/styles/assets/logos/mandelbrot-logo.svg') + + return result + + def page4(self): + """GET contour-logo.svg (request 401).""" + result = request401.GET('/styles/assets/logos/contour-logo.svg') + + return result + + def page5(self): + """GET julia.svg (request 501).""" + result = request501.GET('/styles/assets/logos/julia.svg') + + return result + + def page6(self): + """GET opensource-logo.svg (request 601).""" + result = request601.GET('/styles/assets/logos/opensource-logo.svg') + + return result + + def page7(self): + """GET map.svg (request 701).""" + result = request701.GET('/styles/assets/logos/map.svg') + + return result + + def page8(self): + """GET logo-white.svg (request 801).""" + result = request801.GET('/styles/assets/logo-white.svg') + + return result + + def page9(self): + """GET logo.svg (request 901).""" + result = request901.GET('/styles/assets/logo.svg') + + return result + + def page10(self): + """GET book-crawl.json (request 1001).""" + result = request1001.GET('/data/book-crawl.json') + + return result + + def page11(self): + """GET ss-symbolicons-block.woff (requests 1101-1102).""" + result = request1101.GET('/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') + + grinder.sleep(715) + request1102.GET('/styles/assets/marker-sprite-shadow.png') + + return result + + def __call__(self): + """Called for every run performed by the worker thread.""" + self.page1() # GET / (requests 101-108) + + grinder.sleep(243) + self.page2() # GET epicenter-logo.svg (request 201) + self.page3() # GET mandelbrot-logo.svg (request 301) + self.page4() # GET contour-logo.svg (request 401) + self.page5() # GET julia.svg (request 501) + self.page6() # GET opensource-logo.svg (request 601) + self.page7() # GET map.svg (request 701) + self.page8() # GET logo-white.svg (request 801) + self.page9() # GET logo.svg (request 901) + self.page10() # GET book-crawl.json (request 1001) + + grinder.sleep(149) + self.page11() # GET ss-symbolicons-block.woff (requests 1101-1102) + + +# Instrument page methods. +Test(100, 'Page 1').record(TestRunner.page1) +Test(200, 'Page 2').record(TestRunner.page2) +Test(300, 'Page 3').record(TestRunner.page3) +Test(400, 'Page 4').record(TestRunner.page4) +Test(500, 'Page 5').record(TestRunner.page5) +Test(600, 'Page 6').record(TestRunner.page6) +Test(700, 'Page 7').record(TestRunner.page7) +Test(800, 'Page 8').record(TestRunner.page8) +Test(900, 'Page 9').record(TestRunner.page9) +Test(1000, 'Page 10').record(TestRunner.page10) +Test(1100, 'Page 11').record(TestRunner.page11) diff --git a/tests/load/scenario-b.py b/tests/load/scenario-b.py new file mode 100644 index 0000000..a4330b7 --- /dev/null +++ b/tests/load/scenario-b.py @@ -0,0 +1,289 @@ +# The Grinder 3.11 +# HTTP script recorded by TCPProxy at May 29, 2014 3:14:05 PM + +from net.grinder.script import Test +from net.grinder.script.Grinder import grinder +from net.grinder.plugin.http import HTTPPluginControl, HTTPRequest +from HTTPClient import NVPair +connectionDefaults = HTTPPluginControl.getConnectionDefaults() +httpUtilities = HTTPPluginControl.getHTTPUtilities() + +# To use a proxy server, uncomment the next line and set the host and port. +# connectionDefaults.setProxyServer("localhost", 8001) + +def createRequest(test, url, headers=None): + """Create an instrumented HTTPRequest.""" + request = HTTPRequest(url=url) + if headers: request.headers=headers + test.record(request, HTTPRequest.getHttpMethodFilter()) + return request + +# These definitions at the top level of the file are evaluated once, +# when the worker process is started. + +url0 = 'http://localhost:9002' +url1 = 'http://api.forio.com:80' + +request101 = createRequest(Test(101, 'GET /'), url0) + +request102 = createRequest(Test(102, 'GET jquery.min.js'), url0) + +request103 = createRequest(Test(103, 'GET main.css'), url0) + +request104 = createRequest(Test(104, 'GET lodash.min.js'), url0) + +request105 = createRequest(Test(105, 'GET d3.min.js'), url0) + +request106 = createRequest(Test(106, 'GET backbone.js'), url0) + +request107 = createRequest(Test(107, 'GET contour.min.js'), url0) + +request108 = createRequest(Test(108, 'GET app.js'), url0) + +request201 = createRequest(Test(201, 'GET epicenter-logo.svg'), url0) + +request301 = createRequest(Test(301, 'GET mandelbrot-logo.svg'), url0) + +request401 = createRequest(Test(401, 'GET contour-logo.svg'), url0) + +request501 = createRequest(Test(501, 'GET julia.svg'), url0) + +request601 = createRequest(Test(601, 'GET opensource-logo.svg'), url0) + +request701 = createRequest(Test(701, 'GET map.svg'), url0) + +request801 = createRequest(Test(801, 'GET logo-white.svg'), url0) + +request901 = createRequest(Test(901, 'GET logo.svg'), url0) + +request1001 = createRequest(Test(1001, 'GET book-crawl.json'), url0) + +request1101 = createRequest(Test(1101, 'GET ss-symbolicons-block.woff'), url0) + +request1102 = createRequest(Test(1102, 'GET marker-sprite-shadow.png'), url0) + +request1201 = createRequest(Test(1201, 'OPTIONS run'), url1) + +request1301 = createRequest(Test(1301, 'POST run'), url1) + +request1401 = createRequest(Test(1401, 'OPTIONS e9e65040-7977-44d1-a0e4-a8f853f3a02b'), url1) + +request1501 = createRequest(Test(1501, 'POST e9e65040-7977-44d1-a0e4-a8f853f3a02b'), url1) + +request1601 = createRequest(Test(1601, 'GET sf-sightseeing.json'), url0) + +request1701 = createRequest(Test(1701, 'POST e9e65040-7977-44d1-a0e4-a8f853f3a02b'), url1) + +request1801 = createRequest(Test(1801, 'GET business-deliver.json'), url0) + +request1901 = createRequest(Test(1901, 'POST e9e65040-7977-44d1-a0e4-a8f853f3a02b'), url1) + + +class TestRunner: + """A TestRunner instance is created for each worker thread.""" + + # A method for each recorded page. + def page1(self): + """GET / (requests 101-108).""" + result = request101.GET('/') + self.token_family = \ + httpUtilities.valueFromBodyURI('family') # 'Open+Sans:300' + + grinder.sleep(51) + request102.GET('/vendor/jquery/dist/jquery.min.js') + + request103.GET('/styles/main.css') + + request104.GET('/vendor/lodash/dist/lodash.min.js') + + request105.GET('/vendor/d3/d3.min.js') + + request106.GET('/vendor/backbone/backbone.js') + + request107.GET('/vendor/contour/dist/contour.min.js') + + grinder.sleep(63) + request108.GET('/scripts/app.js') + + return result + + def page2(self): + """GET epicenter-logo.svg (request 201).""" + result = request201.GET('/styles/assets/logos/epicenter-logo.svg') + + return result + + def page3(self): + """GET mandelbrot-logo.svg (request 301).""" + result = request301.GET('/styles/assets/logos/mandelbrot-logo.svg') + + return result + + def page4(self): + """GET contour-logo.svg (request 401).""" + result = request401.GET('/styles/assets/logos/contour-logo.svg') + + return result + + def page5(self): + """GET julia.svg (request 501).""" + result = request501.GET('/styles/assets/logos/julia.svg') + + return result + + def page6(self): + """GET opensource-logo.svg (request 601).""" + result = request601.GET('/styles/assets/logos/opensource-logo.svg') + + return result + + def page7(self): + """GET map.svg (request 701).""" + result = request701.GET('/styles/assets/logos/map.svg') + + return result + + def page8(self): + """GET logo-white.svg (request 801).""" + result = request801.GET('/styles/assets/logo-white.svg') + + return result + + def page9(self): + """GET logo.svg (request 901).""" + result = request901.GET('/styles/assets/logo.svg') + + return result + + def page10(self): + """GET book-crawl.json (request 1001).""" + result = request1001.GET('/data/book-crawl.json') + + return result + + def page11(self): + """GET ss-symbolicons-block.woff (requests 1101-1102).""" + result = request1101.GET('/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') + + grinder.sleep(639) + request1102.GET('/styles/assets/marker-sprite-shadow.png') + + return result + + def page12(self): + """OPTIONS run (request 1201).""" + result = request1201.OPTIONS('/model/run', + '''0\r\n\r\n''') + + return result + + def page13(self): + """POST run (request 1301).""" + result = request1301.POST('/model/run', + '{\"account\":\"showcase\",\"project\":\"route-optimizer\",\"model\":\"TSPModel.jl\"}') + + return result + + def page14(self): + """OPTIONS e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1401).""" + result = request1401.OPTIONS('/model/operation/e9e65040-7977-44d1-a0e4-a8f853f3a02b', + '''0\r\n\r\n''') + + return result + + def page15(self): + """POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1501).""" + result = request1501.POST('/model/operation/e9e65040-7977-44d1-a0e4-a8f853f3a02b', + '{\"name\":\"solve\",\"arguments\":[[[0,2449,3433,5656,1584,2994,5198,8013,3829],[1840,0,1247,5898,2455,4450,5454,9468,5285],[3056,1441,0,6532,3671,5688,4928,14670,6522],[5415,4986,5943,0,3606,4246,2589,7557,2759],[1808,2462,3855,4495,0,2656,4050,7674,3609],[2839,4407,5192,4666,2700,0,4681,5672,2320],[5506,4923,5252,2864,3698,4589,0,9252,4454],[8086,9654,13904,8282,7947,5247,9642,0,4904],[4476,5761,6545,2673,3893,2220,4480,5374,0]]]}') + + return result + + def page16(self): + """GET sf-sightseeing.json (request 1601).""" + result = request1601.GET('/data/sf-sightseeing.json') + + return result + + def page17(self): + """POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1701).""" + result = request1701.POST('/model/operation/e9e65040-7977-44d1-a0e4-a8f853f3a02b', + '{\"name\":\"solve\",\"arguments\":[[[0,10205,6037,3696,5488,10761,4622,2329,4190],[14522,0,9107,11063,12810,12396,12936,11973,13674],[12343,4168,0,8885,10632,8712,10758,9795,11496],[3523,7369,3202,0,1789,10623,1453,4471,2426],[4713,8193,4025,2001,0,11996,1650,5844,1466],[10469,8465,9478,10670,12414,0,12088,7895,12033],[4469,8601,4434,2257,1606,11903,0,5751,2243],[2601,7957,3789,4350,6094,8238,5768,0,5714],[3518,9056,4888,3023,1278,11594,2219,5597,0]]]}') + + return result + + def page18(self): + """GET business-deliver.json (request 1801).""" + result = request1801.GET('/data/business-deliver.json') + + return result + + def page19(self): + """POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1901).""" + result = request1901.POST('/model/operation/e9e65040-7977-44d1-a0e4-a8f853f3a02b', + '{\"name\":\"solve\",\"arguments\":[[[0,11635,5399,7804,15904,5065,13521,14630,9511],[11917,0,9505,7414,3734,7516,3887,5579,2966],[5660,9744,0,7564,7766,5466,5431,7728,6181],[7877,7411,11729,0,11029,2928,8918,13041,6701],[15082,3733,7681,10826,0,9743,2966,3466,5147],[5727,7432,5471,2869,9597,0,6737,10619,4483],[13388,3773,5887,7962,3159,6776,0,4984,2597],[14253,5713,8738,12582,3756,9831,4722,0,6902],[10172,2965,5741,6258,5179,5416,2692,7016,0]]]}') + + return result + + def __call__(self): + """Called for every run performed by the worker thread.""" + self.page1() # GET / (requests 101-108) + + grinder.sleep(596) + self.page2() # GET epicenter-logo.svg (request 201) + self.page3() # GET mandelbrot-logo.svg (request 301) + self.page4() # GET contour-logo.svg (request 401) + self.page5() # GET julia.svg (request 501) + self.page6() # GET opensource-logo.svg (request 601) + self.page7() # GET map.svg (request 701) + self.page8() # GET logo-white.svg (request 801) + self.page9() # GET logo.svg (request 901) + self.page10() # GET book-crawl.json (request 1001) + + grinder.sleep(140) + self.page11() # GET ss-symbolicons-block.woff (requests 1101-1102) + + grinder.sleep(4941) + self.page12() # OPTIONS run (request 1201) + + grinder.sleep(111) + self.page13() # POST run (request 1301) + + grinder.sleep(114) + self.page14() # OPTIONS e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1401) + + grinder.sleep(124) + self.page15() # POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1501) + + grinder.sleep(38305) + self.page16() # GET sf-sightseeing.json (request 1601) + + grinder.sleep(2286) + self.page17() # POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1701) + + grinder.sleep(15556) + self.page18() # GET business-deliver.json (request 1801) + + grinder.sleep(3003) + self.page19() # POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1901) + + +# Instrument page methods. +Test(100, 'Page 1').record(TestRunner.page1) +Test(200, 'Page 2').record(TestRunner.page2) +Test(300, 'Page 3').record(TestRunner.page3) +Test(400, 'Page 4').record(TestRunner.page4) +Test(500, 'Page 5').record(TestRunner.page5) +Test(600, 'Page 6').record(TestRunner.page6) +Test(700, 'Page 7').record(TestRunner.page7) +Test(800, 'Page 8').record(TestRunner.page8) +Test(900, 'Page 9').record(TestRunner.page9) +Test(1000, 'Page 10').record(TestRunner.page10) +Test(1100, 'Page 11').record(TestRunner.page11) +Test(1200, 'Page 12').record(TestRunner.page12) +Test(1300, 'Page 13').record(TestRunner.page13) +Test(1400, 'Page 14').record(TestRunner.page14) +Test(1500, 'Page 15').record(TestRunner.page15) +Test(1600, 'Page 16').record(TestRunner.page16) +Test(1700, 'Page 17').record(TestRunner.page17) +Test(1800, 'Page 18').record(TestRunner.page18) +Test(1900, 'Page 19').record(TestRunner.page19) diff --git a/tests/load/scenario-c.py b/tests/load/scenario-c.py new file mode 100644 index 0000000..886f439 --- /dev/null +++ b/tests/load/scenario-c.py @@ -0,0 +1,442 @@ +# The Grinder 3.11 +# HTTP script recorded by TCPProxy at May 29, 2014 3:20:14 PM + +from net.grinder.script import Test +from net.grinder.script.Grinder import grinder +from net.grinder.plugin.http import HTTPPluginControl, HTTPRequest +from HTTPClient import NVPair +connectionDefaults = HTTPPluginControl.getConnectionDefaults() +httpUtilities = HTTPPluginControl.getHTTPUtilities() + +# To use a proxy server, uncomment the next line and set the host and port. +# connectionDefaults.setProxyServer("localhost", 8001) + +def createRequest(test, url, headers=None): + """Create an instrumented HTTPRequest.""" + request = HTTPRequest(url=url) + if headers: request.headers=headers + test.record(request, HTTPRequest.getHttpMethodFilter()) + return request + +# These definitions at the top level of the file are evaluated once, +# when the worker process is started. + +url0 = 'http://localhost:9002' +url1 = 'http://api.forio.com:80' + +request101 = createRequest(Test(101, 'GET /'), url0) + +request102 = createRequest(Test(102, 'GET jquery.min.js'), url0) + +request103 = createRequest(Test(103, 'GET lodash.min.js'), url0) + +request104 = createRequest(Test(104, 'GET d3.min.js'), url0) + +request105 = createRequest(Test(105, 'GET backbone.js'), url0) + +request106 = createRequest(Test(106, 'GET contour.min.js'), url0) + +request107 = createRequest(Test(107, 'GET app.js'), url0) + +request108 = createRequest(Test(108, 'GET main.css'), url0) + +request201 = createRequest(Test(201, 'GET epicenter-logo.svg'), url0) + +request301 = createRequest(Test(301, 'GET mandelbrot-logo.svg'), url0) + +request401 = createRequest(Test(401, 'GET contour-logo.svg'), url0) + +request501 = createRequest(Test(501, 'GET julia.svg'), url0) + +request601 = createRequest(Test(601, 'GET opensource-logo.svg'), url0) + +request701 = createRequest(Test(701, 'GET logo-white.svg'), url0) + +request801 = createRequest(Test(801, 'GET map.svg'), url0) + +request901 = createRequest(Test(901, 'GET logo.svg'), url0) + +request1001 = createRequest(Test(1001, 'GET book-crawl.json'), url0) + +request1101 = createRequest(Test(1101, 'GET ss-symbolicons-block.woff'), url0) + +request1102 = createRequest(Test(1102, 'GET marker-sprite-shadow.png'), url0) + +request1201 = createRequest(Test(1201, 'GET /'), url0) + +request1202 = createRequest(Test(1202, 'GET jquery.min.js'), url0) + +request1203 = createRequest(Test(1203, 'GET main.css'), url0) + +request1204 = createRequest(Test(1204, 'GET lodash.min.js'), url0) + +request1205 = createRequest(Test(1205, 'GET d3.min.js'), url0) + +request1206 = createRequest(Test(1206, 'GET backbone.js'), url0) + +request1207 = createRequest(Test(1207, 'GET contour.min.js'), url0) + +request1208 = createRequest(Test(1208, 'GET app.js'), url0) + +request1301 = createRequest(Test(1301, 'GET epicenter-logo.svg'), url0) + +request1401 = createRequest(Test(1401, 'GET mandelbrot-logo.svg'), url0) + +request1501 = createRequest(Test(1501, 'GET contour-logo.svg'), url0) + +request1601 = createRequest(Test(1601, 'GET julia.svg'), url0) + +request1701 = createRequest(Test(1701, 'GET opensource-logo.svg'), url0) + +request1801 = createRequest(Test(1801, 'GET map.svg'), url0) + +request1901 = createRequest(Test(1901, 'GET logo-white.svg'), url0) + +request2001 = createRequest(Test(2001, 'GET logo.svg'), url0) + +request2101 = createRequest(Test(2101, 'GET book-crawl.json'), url0) + +request2201 = createRequest(Test(2201, 'GET ss-symbolicons-block.woff'), url0) + +request2202 = createRequest(Test(2202, 'GET marker-sprite-shadow.png'), url0) + +request2301 = createRequest(Test(2301, 'OPTIONS run'), url1) + +request2401 = createRequest(Test(2401, 'POST run'), url1) + +request2501 = createRequest(Test(2501, 'GET contour.min.map'), url0) + +request2601 = createRequest(Test(2601, 'GET jquery.min.map'), url0) + +request2701 = createRequest(Test(2701, 'OPTIONS a8e5cdbf-c5f1-4001-904c-4f00468197b6'), url1) + +request2801 = createRequest(Test(2801, 'POST a8e5cdbf-c5f1-4001-904c-4f00468197b6'), url1) + +request2901 = createRequest(Test(2901, 'GET custom.json'), url0) + +request2902 = createRequest(Test(2902, 'GET marker-sprite-shadow.png'), url0) + +request3001 = createRequest(Test(3001, 'POST a8e5cdbf-c5f1-4001-904c-4f00468197b6'), url1) + + +class TestRunner: + """A TestRunner instance is created for each worker thread.""" + + # A method for each recorded page. + def page1(self): + """GET / (requests 101-108).""" + result = request101.GET('/') + + grinder.sleep(43) + request102.GET('/vendor/jquery/dist/jquery.min.js') + + request103.GET('/vendor/lodash/dist/lodash.min.js') + + request104.GET('/vendor/d3/d3.min.js') + + request105.GET('/vendor/backbone/backbone.js') + + request106.GET('/vendor/contour/dist/contour.min.js') + + request107.GET('/scripts/app.js') + + request108.GET('/styles/main.css') + + return result + + def page2(self): + """GET epicenter-logo.svg (request 201).""" + result = request201.GET('/styles/assets/logos/epicenter-logo.svg') + + return result + + def page3(self): + """GET mandelbrot-logo.svg (request 301).""" + result = request301.GET('/styles/assets/logos/mandelbrot-logo.svg') + + return result + + def page4(self): + """GET contour-logo.svg (request 401).""" + result = request401.GET('/styles/assets/logos/contour-logo.svg') + + return result + + def page5(self): + """GET julia.svg (request 501).""" + result = request501.GET('/styles/assets/logos/julia.svg') + + return result + + def page6(self): + """GET opensource-logo.svg (request 601).""" + result = request601.GET('/styles/assets/logos/opensource-logo.svg') + + return result + + def page7(self): + """GET logo-white.svg (request 701).""" + result = request701.GET('/styles/assets/logo-white.svg') + + return result + + def page8(self): + """GET map.svg (request 801).""" + result = request801.GET('/styles/assets/logos/map.svg') + + return result + + def page9(self): + """GET logo.svg (request 901).""" + result = request901.GET('/styles/assets/logo.svg') + + return result + + def page10(self): + """GET book-crawl.json (request 1001).""" + result = request1001.GET('/data/book-crawl.json') + + return result + + def page11(self): + """GET ss-symbolicons-block.woff (requests 1101-1102).""" + result = request1101.GET('/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') + + grinder.sleep(346) + request1102.GET('/styles/assets/marker-sprite-shadow.png') + + return result + + def page12(self): + """GET / (requests 1201-1208).""" + result = request1201.GET('/') + self.token_family = \ + httpUtilities.valueFromBodyURI('family') # 'Open+Sans:300' + + grinder.sleep(38) + request1202.GET('/vendor/jquery/dist/jquery.min.js') + + request1203.GET('/styles/main.css') + + request1204.GET('/vendor/lodash/dist/lodash.min.js') + + request1205.GET('/vendor/d3/d3.min.js') + + request1206.GET('/vendor/backbone/backbone.js') + + request1207.GET('/vendor/contour/dist/contour.min.js') + + request1208.GET('/scripts/app.js') + + return result + + def page13(self): + """GET epicenter-logo.svg (request 1301).""" + result = request1301.GET('/styles/assets/logos/epicenter-logo.svg') + + return result + + def page14(self): + """GET mandelbrot-logo.svg (request 1401).""" + result = request1401.GET('/styles/assets/logos/mandelbrot-logo.svg') + + return result + + def page15(self): + """GET contour-logo.svg (request 1501).""" + result = request1501.GET('/styles/assets/logos/contour-logo.svg') + + return result + + def page16(self): + """GET julia.svg (request 1601).""" + result = request1601.GET('/styles/assets/logos/julia.svg') + + return result + + def page17(self): + """GET opensource-logo.svg (request 1701).""" + result = request1701.GET('/styles/assets/logos/opensource-logo.svg') + + return result + + def page18(self): + """GET map.svg (request 1801).""" + result = request1801.GET('/styles/assets/logos/map.svg') + + return result + + def page19(self): + """GET logo-white.svg (request 1901).""" + result = request1901.GET('/styles/assets/logo-white.svg') + + return result + + def page20(self): + """GET logo.svg (request 2001).""" + result = request2001.GET('/styles/assets/logo.svg') + + return result + + def page21(self): + """GET book-crawl.json (request 2101).""" + result = request2101.GET('/data/book-crawl.json') + + return result + + def page22(self): + """GET ss-symbolicons-block.woff (requests 2201-2202).""" + result = request2201.GET('/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') + + grinder.sleep(526) + request2202.GET('/styles/assets/marker-sprite-shadow.png') + + return result + + def page23(self): + """OPTIONS run (request 2301).""" + result = request2301.OPTIONS('/model/run', + '''0\r\n\r\n''') + + return result + + def page24(self): + """POST run (request 2401).""" + result = request2401.POST('/model/run', + '{\"account\":\"showcase\",\"project\":\"route-optimizer\",\"model\":\"TSPModel.jl\"}') + + return result + + def page25(self): + """GET contour.min.map (request 2501).""" + result = request2501.GET('/vendor/contour/dist/dist/contour.min.map') + + return result + + def page26(self): + """GET jquery.min.map (request 2601).""" + result = request2601.GET('/vendor/jquery/dist/jquery.min.map') + + return result + + def page27(self): + """OPTIONS a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 2701).""" + result = request2701.OPTIONS('/model/operation/a8e5cdbf-c5f1-4001-904c-4f00468197b6', + '''0\r\n\r\n''') + + return result + + def page28(self): + """POST a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 2801).""" + result = request2801.POST('/model/operation/a8e5cdbf-c5f1-4001-904c-4f00468197b6', + '{\"name\":\"solve\",\"arguments\":[[[0,2449,3433,5656,1584,2994,5198,8013,3829],[1840,0,1247,5898,2455,4450,5454,9468,5285],[3056,1441,0,6532,3671,5688,4928,14670,6522],[5415,4986,5943,0,3606,4246,2589,7557,2759],[1808,2462,3855,4495,0,2656,4050,7674,3609],[2839,4407,5192,4666,2700,0,4681,5672,2320],[5506,4923,5252,2864,3698,4589,0,9252,4454],[8086,9654,13904,8282,7947,5247,9642,0,4904],[4476,5761,6545,2673,3893,2220,4480,5374,0]]]}') + + return result + + def page29(self): + """GET custom.json (requests 2901-2902).""" + result = request2901.GET('/data/custom.json') + + grinder.sleep(73062) + request2902.GET('/styles/assets/marker-sprite-shadow.png') + + return result + + def page30(self): + """POST a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 3001).""" + result = request3001.POST('/model/operation/a8e5cdbf-c5f1-4001-904c-4f00468197b6', + '{\"name\":\"solve\",\"arguments\":[[[0,2015,2811,2040,18846,1842,19769],[2060,0,3118,3444,19987,3244,20909],[3457,3113,0,4841,21581,3516,22504],[2053,3519,5866,0,16607,2451,17530],[18302,19754,22062,17168,0,20130,1396],[2008,3340,3670,2170,18835,0,19758],[18117,19569,21877,16983,1396,19945,0]]]}') + + return result + + def __call__(self): + """Called for every run performed by the worker thread.""" + self.page1() # GET / (requests 101-108) + + grinder.sleep(112) + self.page2() # GET epicenter-logo.svg (request 201) + self.page3() # GET mandelbrot-logo.svg (request 301) + + grinder.sleep(56) + self.page4() # GET contour-logo.svg (request 401) + self.page5() # GET julia.svg (request 501) + self.page6() # GET opensource-logo.svg (request 601) + self.page7() # GET logo-white.svg (request 701) + self.page8() # GET map.svg (request 801) + self.page9() # GET logo.svg (request 901) + self.page10() # GET book-crawl.json (request 1001) + + grinder.sleep(104) + self.page11() # GET ss-symbolicons-block.woff (requests 1101-1102) + + grinder.sleep(6764) + self.page12() # GET / (requests 1201-1208) + + grinder.sleep(656) + self.page13() # GET epicenter-logo.svg (request 1301) + self.page14() # GET mandelbrot-logo.svg (request 1401) + self.page15() # GET contour-logo.svg (request 1501) + self.page16() # GET julia.svg (request 1601) + self.page17() # GET opensource-logo.svg (request 1701) + self.page18() # GET map.svg (request 1801) + + grinder.sleep(14) + self.page19() # GET logo-white.svg (request 1901) + self.page20() # GET logo.svg (request 2001) + self.page21() # GET book-crawl.json (request 2101) + + grinder.sleep(110) + self.page22() # GET ss-symbolicons-block.woff (requests 2201-2202) + + grinder.sleep(4486) + self.page23() # OPTIONS run (request 2301) + + grinder.sleep(99) + self.page24() # POST run (request 2401) + self.page25() # GET contour.min.map (request 2501) + self.page26() # GET jquery.min.map (request 2601) + + grinder.sleep(95) + self.page27() # OPTIONS a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 2701) + + grinder.sleep(90) + self.page28() # POST a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 2801) + + grinder.sleep(6408) + self.page29() # GET custom.json (requests 2901-2902) + + grinder.sleep(32945) + self.page30() # POST a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 3001) + + +# Instrument page methods. +Test(100, 'Page 1').record(TestRunner.page1) +Test(200, 'Page 2').record(TestRunner.page2) +Test(300, 'Page 3').record(TestRunner.page3) +Test(400, 'Page 4').record(TestRunner.page4) +Test(500, 'Page 5').record(TestRunner.page5) +Test(600, 'Page 6').record(TestRunner.page6) +Test(700, 'Page 7').record(TestRunner.page7) +Test(800, 'Page 8').record(TestRunner.page8) +Test(900, 'Page 9').record(TestRunner.page9) +Test(1000, 'Page 10').record(TestRunner.page10) +Test(1100, 'Page 11').record(TestRunner.page11) +Test(1200, 'Page 12').record(TestRunner.page12) +Test(1300, 'Page 13').record(TestRunner.page13) +Test(1400, 'Page 14').record(TestRunner.page14) +Test(1500, 'Page 15').record(TestRunner.page15) +Test(1600, 'Page 16').record(TestRunner.page16) +Test(1700, 'Page 17').record(TestRunner.page17) +Test(1800, 'Page 18').record(TestRunner.page18) +Test(1900, 'Page 19').record(TestRunner.page19) +Test(2000, 'Page 20').record(TestRunner.page20) +Test(2100, 'Page 21').record(TestRunner.page21) +Test(2200, 'Page 22').record(TestRunner.page22) +Test(2300, 'Page 23').record(TestRunner.page23) +Test(2400, 'Page 24').record(TestRunner.page24) +Test(2500, 'Page 25').record(TestRunner.page25) +Test(2600, 'Page 26').record(TestRunner.page26) +Test(2700, 'Page 27').record(TestRunner.page27) +Test(2800, 'Page 28').record(TestRunner.page28) +Test(2900, 'Page 29').record(TestRunner.page29) +Test(3000, 'Page 30').record(TestRunner.page30) From d4d65ed7f355d3960c6fb2fe1c8363224a8debf1 Mon Sep 17 00:00:00 2001 From: David Wick Date: Thu, 29 May 2014 17:23:31 -0700 Subject: [PATCH 2/7] fixed scenario b to use dynamic run --- tests/load/.gitignore | 1 + tests/load/grinder.properties | 6 +- tests/load/scenario-b.py | 100 +++++++++++++++++++--------------- 3 files changed, 61 insertions(+), 46 deletions(-) create mode 100644 tests/load/.gitignore mode change 100644 => 100755 tests/load/scenario-b.py diff --git a/tests/load/.gitignore b/tests/load/.gitignore new file mode 100644 index 0000000..fdfdba1 --- /dev/null +++ b/tests/load/.gitignore @@ -0,0 +1 @@ +log/ \ No newline at end of file diff --git a/tests/load/grinder.properties b/tests/load/grinder.properties index 24762f2..d3463f9 100755 --- a/tests/load/grinder.properties +++ b/tests/load/grinder.properties @@ -1,12 +1,12 @@ -grinder.script=grinder.py +grinder.script=scenario-b.py grinder.runs=1 grinder.initialProcesses=1 grinder.processes=1 grinder.processIncrement=1 -grinder.processIncrementInterval=100000 -grinder.threads=25 +grinder.processIncrementInterval=1 +grinder.threads=1 grinder.useConsole=false grinder.logDirectory=log diff --git a/tests/load/scenario-b.py b/tests/load/scenario-b.py old mode 100644 new mode 100755 index a4330b7..ad4d8ee --- a/tests/load/scenario-b.py +++ b/tests/load/scenario-b.py @@ -1,6 +1,7 @@ # The Grinder 3.11 # HTTP script recorded by TCPProxy at May 29, 2014 3:14:05 PM +import re from net.grinder.script import Test from net.grinder.script.Grinder import grinder from net.grinder.plugin.http import HTTPPluginControl, HTTPRequest @@ -8,6 +9,14 @@ connectionDefaults = HTTPPluginControl.getConnectionDefaults() httpUtilities = HTTPPluginControl.getHTTPUtilities() +apiHeaders = [ + NVPair('Content-Type', 'application/json; charset=UTF-8'), + NVPair('Accept', 'application/json, text/javascript, */*; q=0.01') +] + +matcher = re.compile('.*"id":\s*"([^"]+)".*') + + # To use a proxy server, uncomment the next line and set the host and port. # connectionDefaults.setProxyServer("localhost", 8001) @@ -21,7 +30,7 @@ def createRequest(test, url, headers=None): # These definitions at the top level of the file are evaluated once, # when the worker process is started. -url0 = 'http://localhost:9002' +url0 = 'http://forio.com/' url1 = 'http://api.forio.com:80' request101 = createRequest(Test(101, 'GET /'), url0) @@ -64,19 +73,19 @@ def createRequest(test, url, headers=None): request1201 = createRequest(Test(1201, 'OPTIONS run'), url1) -request1301 = createRequest(Test(1301, 'POST run'), url1) +request1301 = createRequest(Test(1301, 'POST run'), url1, apiHeaders) -request1401 = createRequest(Test(1401, 'OPTIONS e9e65040-7977-44d1-a0e4-a8f853f3a02b'), url1) +request1401 = createRequest(Test(1401, 'OPTIONS {{run.id}}'), url1) -request1501 = createRequest(Test(1501, 'POST e9e65040-7977-44d1-a0e4-a8f853f3a02b'), url1) +request1501 = createRequest(Test(1501, 'POST {{run.id}}'), url1, apiHeaders) request1601 = createRequest(Test(1601, 'GET sf-sightseeing.json'), url0) -request1701 = createRequest(Test(1701, 'POST e9e65040-7977-44d1-a0e4-a8f853f3a02b'), url1) +request1701 = createRequest(Test(1701, 'POST {{run.id}}'), url1, apiHeaders) request1801 = createRequest(Test(1801, 'GET business-deliver.json'), url0) -request1901 = createRequest(Test(1901, 'POST e9e65040-7977-44d1-a0e4-a8f853f3a02b'), url1) +request1901 = createRequest(Test(1901, 'POST {{run.id}}'), url1, apiHeaders) class TestRunner: @@ -90,83 +99,83 @@ def page1(self): httpUtilities.valueFromBodyURI('family') # 'Open+Sans:300' grinder.sleep(51) - request102.GET('/vendor/jquery/dist/jquery.min.js') + request102.GET('/app/showcase/route-optimizer/vendor/jquery/dist/jquery.min.js') - request103.GET('/styles/main.css') + request103.GET('/app/showcase/route-optimizer/styles/main.css') - request104.GET('/vendor/lodash/dist/lodash.min.js') + request104.GET('/app/showcase/route-optimizer/vendor/lodash/dist/lodash.min.js') - request105.GET('/vendor/d3/d3.min.js') + request105.GET('/app/showcase/route-optimizer/vendor/d3/d3.min.js') - request106.GET('/vendor/backbone/backbone.js') + request106.GET('/app/showcase/route-optimizer/vendor/backbone/backbone.js') - request107.GET('/vendor/contour/dist/contour.min.js') + request107.GET('/app/showcase/route-optimizer/vendor/contour/dist/contour.min.js') grinder.sleep(63) - request108.GET('/scripts/app.js') + request108.GET('/app/showcase/route-optimizer/scripts/app.js') return result def page2(self): """GET epicenter-logo.svg (request 201).""" - result = request201.GET('/styles/assets/logos/epicenter-logo.svg') + result = request201.GET('/app/showcase/route-optimizer/styles/assets/logos/epicenter-logo.svg') return result def page3(self): """GET mandelbrot-logo.svg (request 301).""" - result = request301.GET('/styles/assets/logos/mandelbrot-logo.svg') + result = request301.GET('/app/showcase/route-optimizer/styles/assets/logos/mandelbrot-logo.svg') return result def page4(self): """GET contour-logo.svg (request 401).""" - result = request401.GET('/styles/assets/logos/contour-logo.svg') + result = request401.GET('/app/showcase/route-optimizer/styles/assets/logos/contour-logo.svg') return result def page5(self): """GET julia.svg (request 501).""" - result = request501.GET('/styles/assets/logos/julia.svg') + result = request501.GET('/app/showcase/route-optimizer/styles/assets/logos/julia.svg') return result def page6(self): """GET opensource-logo.svg (request 601).""" - result = request601.GET('/styles/assets/logos/opensource-logo.svg') + result = request601.GET('/app/showcase/route-optimizer/styles/assets/logos/opensource-logo.svg') return result def page7(self): """GET map.svg (request 701).""" - result = request701.GET('/styles/assets/logos/map.svg') + result = request701.GET('/app/showcase/route-optimizer/styles/assets/logos/map.svg') return result def page8(self): """GET logo-white.svg (request 801).""" - result = request801.GET('/styles/assets/logo-white.svg') + result = request801.GET('/app/showcase/route-optimizer/styles/assets/logo-white.svg') return result def page9(self): """GET logo.svg (request 901).""" - result = request901.GET('/styles/assets/logo.svg') + result = request901.GET('/app/showcase/route-optimizer/styles/assets/logo.svg') return result def page10(self): """GET book-crawl.json (request 1001).""" - result = request1001.GET('/data/book-crawl.json') + result = request1001.GET('/app/showcase/route-optimizer/data/book-crawl.json') return result def page11(self): """GET ss-symbolicons-block.woff (requests 1101-1102).""" - result = request1101.GET('/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') + result = request1101.GET('/app/showcase/route-optimizer/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') grinder.sleep(639) - request1102.GET('/styles/assets/marker-sprite-shadow.png') + request1102.GET('/app/showcase/route-optimizer/styles/assets/marker-sprite-shadow.png') return result @@ -184,42 +193,42 @@ def page13(self): return result - def page14(self): - """OPTIONS e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1401).""" - result = request1401.OPTIONS('/model/operation/e9e65040-7977-44d1-a0e4-a8f853f3a02b', + def page14(self, runId): + """OPTIONS {{run.id}} (request 1401).""" + result = request1401.OPTIONS('/model/operation/' + runId, '''0\r\n\r\n''') return result - def page15(self): - """POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1501).""" - result = request1501.POST('/model/operation/e9e65040-7977-44d1-a0e4-a8f853f3a02b', + def page15(self, runId): + """POST {{run.id}} (request 1501).""" + result = request1501.POST('/model/operation/' + runId, '{\"name\":\"solve\",\"arguments\":[[[0,2449,3433,5656,1584,2994,5198,8013,3829],[1840,0,1247,5898,2455,4450,5454,9468,5285],[3056,1441,0,6532,3671,5688,4928,14670,6522],[5415,4986,5943,0,3606,4246,2589,7557,2759],[1808,2462,3855,4495,0,2656,4050,7674,3609],[2839,4407,5192,4666,2700,0,4681,5672,2320],[5506,4923,5252,2864,3698,4589,0,9252,4454],[8086,9654,13904,8282,7947,5247,9642,0,4904],[4476,5761,6545,2673,3893,2220,4480,5374,0]]]}') return result def page16(self): """GET sf-sightseeing.json (request 1601).""" - result = request1601.GET('/data/sf-sightseeing.json') + result = request1601.GET('/app/showcase/route-optimizer/data/sf-sightseeing.json') return result - def page17(self): - """POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1701).""" - result = request1701.POST('/model/operation/e9e65040-7977-44d1-a0e4-a8f853f3a02b', + def page17(self, runId): + """POST {{run.id}} (request 1701).""" + result = request1701.POST('/model/operation/' + runId, '{\"name\":\"solve\",\"arguments\":[[[0,10205,6037,3696,5488,10761,4622,2329,4190],[14522,0,9107,11063,12810,12396,12936,11973,13674],[12343,4168,0,8885,10632,8712,10758,9795,11496],[3523,7369,3202,0,1789,10623,1453,4471,2426],[4713,8193,4025,2001,0,11996,1650,5844,1466],[10469,8465,9478,10670,12414,0,12088,7895,12033],[4469,8601,4434,2257,1606,11903,0,5751,2243],[2601,7957,3789,4350,6094,8238,5768,0,5714],[3518,9056,4888,3023,1278,11594,2219,5597,0]]]}') return result def page18(self): """GET business-deliver.json (request 1801).""" - result = request1801.GET('/data/business-deliver.json') + result = request1801.GET('/app/showcase/route-optimizer/data/business-deliver.json') return result - def page19(self): - """POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1901).""" - result = request1901.POST('/model/operation/e9e65040-7977-44d1-a0e4-a8f853f3a02b', + def page19(self, runId): + """POST {{run.id}} (request 1901).""" + result = request1901.POST('/model/operation/' + runId, '{\"name\":\"solve\",\"arguments\":[[[0,11635,5399,7804,15904,5065,13521,14630,9511],[11917,0,9505,7414,3734,7516,3887,5579,2966],[5660,9744,0,7564,7766,5466,5431,7728,6181],[7877,7411,11729,0,11029,2928,8918,13041,6701],[15082,3733,7681,10826,0,9743,2966,3466,5147],[5727,7432,5471,2869,9597,0,6737,10619,4483],[13388,3773,5887,7962,3159,6776,0,4984,2597],[14253,5713,8738,12582,3756,9831,4722,0,6902],[10172,2965,5741,6258,5179,5416,2692,7016,0]]]}') return result @@ -246,25 +255,30 @@ def __call__(self): self.page12() # OPTIONS run (request 1201) grinder.sleep(111) - self.page13() # POST run (request 1301) + + json = self.page13().text # POST run (request 1301) + run = matcher.match(json).group(1) + + grinder.logger.info(run) + grinder.sleep(114) - self.page14() # OPTIONS e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1401) + self.page14(run) # OPTIONS {{run.id}} (request 1401) grinder.sleep(124) - self.page15() # POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1501) + self.page15(run) # POST {{run.id}} (request 1501) grinder.sleep(38305) self.page16() # GET sf-sightseeing.json (request 1601) grinder.sleep(2286) - self.page17() # POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1701) + self.page17(run) # POST {{run.id}} (request 1701) grinder.sleep(15556) self.page18() # GET business-deliver.json (request 1801) grinder.sleep(3003) - self.page19() # POST e9e65040-7977-44d1-a0e4-a8f853f3a02b (request 1901) + self.page19(run) # POST {{run.id}} (request 1901) # Instrument page methods. From f64487a2823e0398455a079c7a67176ff9aa265c Mon Sep 17 00:00:00 2001 From: David Wick Date: Thu, 12 Jun 2014 09:48:02 -0700 Subject: [PATCH 3/7] fixed static files loading improperly in scenario b --- tests/load/scenario-b.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/load/scenario-b.py b/tests/load/scenario-b.py index ad4d8ee..f41cbda 100755 --- a/tests/load/scenario-b.py +++ b/tests/load/scenario-b.py @@ -9,6 +9,16 @@ connectionDefaults = HTTPPluginControl.getConnectionDefaults() httpUtilities = HTTPPluginControl.getHTTPUtilities() +staticHeaders = [ + NVPair('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'), + NVPair('Accept-Encoding', 'gzip,deflate,sdch'), + NVPair('Accept-Language', 'en-US,en;q=0.8'), + NVPair('Cache-Control', 'no-cache'), + NVPair('Pragma', 'no-cache'), + NVPair('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36'), + NVPair('Connection', 'keep-alive') +] + apiHeaders = [ NVPair('Content-Type', 'application/json; charset=UTF-8'), NVPair('Accept', 'application/json, text/javascript, */*; q=0.01') @@ -20,7 +30,7 @@ # To use a proxy server, uncomment the next line and set the host and port. # connectionDefaults.setProxyServer("localhost", 8001) -def createRequest(test, url, headers=None): +def createRequest(test, url, headers=staticHeaders): """Create an instrumented HTTPRequest.""" request = HTTPRequest(url=url) if headers: request.headers=headers @@ -71,11 +81,11 @@ def createRequest(test, url, headers=None): request1102 = createRequest(Test(1102, 'GET marker-sprite-shadow.png'), url0) -request1201 = createRequest(Test(1201, 'OPTIONS run'), url1) +request1201 = createRequest(Test(1201, 'OPTIONS run'), url1, apiHeaders) request1301 = createRequest(Test(1301, 'POST run'), url1, apiHeaders) -request1401 = createRequest(Test(1401, 'OPTIONS {{run.id}}'), url1) +request1401 = createRequest(Test(1401, 'OPTIONS {{run.id}}'), url1, apiHeaders) request1501 = createRequest(Test(1501, 'POST {{run.id}}'), url1, apiHeaders) @@ -94,7 +104,7 @@ class TestRunner: # A method for each recorded page. def page1(self): """GET / (requests 101-108).""" - result = request101.GET('/') + result = request101.GET('/app/showcase/route-optimizer') self.token_family = \ httpUtilities.valueFromBodyURI('family') # 'Open+Sans:300' From 8d0fab99d063ff6ad6619730c4516f08e88890cc Mon Sep 17 00:00:00 2001 From: David Wick Date: Thu, 12 Jun 2014 10:49:24 -0700 Subject: [PATCH 4/7] added configuration to scenarios a,b. delete c because it needs to be rerecorded. added readme --- tests/load/README.md | 45 ++++ tests/load/grinder.properties | 2 +- tests/load/scenario-a.py | 62 +++-- tests/load/scenario-b.py | 59 ++--- tests/load/scenario-c.py | 442 ---------------------------------- 5 files changed, 115 insertions(+), 495 deletions(-) create mode 100644 tests/load/README.md delete mode 100644 tests/load/scenario-c.py diff --git a/tests/load/README.md b/tests/load/README.md new file mode 100644 index 0000000..8480303 --- /dev/null +++ b/tests/load/README.md @@ -0,0 +1,45 @@ +# Route Optimizer Load Tests + +## Dependencies +- grinder 3.11 (install in `/usr/local/bin/`) +- node.js (recording only) + +## Recording +1. Install project dependencies: `npm install` +2. Set your computer proxy to `localhost:3001` +3. run `./record_filtered` +4. Begin recording requests + +## Playing +1. Configure settings in `grinder.properties` +2. run `./play` +3. Analyize the results + +## Play environment variables + +#### LOAD_SECURE + +Type: `String` +Default: `"yes"` + +Whether or not to use https. + +#### LOAD_APP_HOST + +Type: `String` +Default: `"forio.com"` + +The hostname of the load test target. + +#### LOAD_APP_PATH +Type: `String` +Default: `"showcase/route-optimizer"` + +{{account}}/{{project}} segment of the application url. + + +#### LOAD_API_HOST +Type: `String` +Default: `"api.forio.com"` + +The API hostname of the load test target. \ No newline at end of file diff --git a/tests/load/grinder.properties b/tests/load/grinder.properties index d3463f9..945736d 100755 --- a/tests/load/grinder.properties +++ b/tests/load/grinder.properties @@ -1,4 +1,4 @@ -grinder.script=scenario-b.py +grinder.script=scenario-a.py grinder.runs=1 diff --git a/tests/load/scenario-a.py b/tests/load/scenario-a.py index 3f4f07b..afd4469 100644 --- a/tests/load/scenario-a.py +++ b/tests/load/scenario-a.py @@ -1,6 +1,7 @@ # The Grinder 3.11 # HTTP script recorded by TCPProxy at May 29, 2014 3:12:48 PM +import os from net.grinder.script import Test from net.grinder.script.Grinder import grinder from net.grinder.plugin.http import HTTPPluginControl, HTTPRequest @@ -8,10 +9,22 @@ connectionDefaults = HTTPPluginControl.getConnectionDefaults() httpUtilities = HTTPPluginControl.getHTTPUtilities() -# To use a proxy server, uncomment the next line and set the host and port. -# connectionDefaults.setProxyServer("localhost", 8001) - -def createRequest(test, url, headers=None): +SECURE = os.getenv('LOAD_SECURE', "yes") == "yes" +APP_HOST = os.getenv('LOAD_APP_HOST', 'forio.com') +APP_PATH = os.getenv('LOAD_APP_PATH', 'showcase/route-optimizer') +API_HOST = os.getenv('LOAD_API_HOST', 'api.forio.com') + +staticHeaders = [ + NVPair('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'), + NVPair('Accept-Encoding', 'gzip,deflate,sdch'), + NVPair('Accept-Language', 'en-US,en;q=0.8'), + NVPair('Cache-Control', 'no-cache'), + NVPair('Pragma', 'no-cache'), + NVPair('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36'), + NVPair('Connection', 'keep-alive') +] + +def createRequest(test, url, headers=staticHeaders): """Create an instrumented HTTPRequest.""" request = HTTPRequest(url=url) if headers: request.headers=headers @@ -21,7 +34,8 @@ def createRequest(test, url, headers=None): # These definitions at the top level of the file are evaluated once, # when the worker process is started. -url0 = 'http://localhost:9002' +protocol = ('https' if SECURE else 'http') +url0 = protocol + '://' + APP_HOST request101 = createRequest(Test(101, 'GET /'), url0) @@ -68,88 +82,88 @@ class TestRunner: # A method for each recorded page. def page1(self): """GET / (requests 101-108).""" - result = request101.GET('/') + result = request101.GET('/app/' + APP_PATH) self.token_family = \ httpUtilities.valueFromBodyURI('family') # 'Open+Sans:300' grinder.sleep(173) - request102.GET('/vendor/jquery/dist/jquery.min.js') + request102.GET('/app/' + APP_PATH + '/vendor/jquery/dist/jquery.min.js') - request103.GET('/vendor/lodash/dist/lodash.min.js') + request103.GET('/app/' + APP_PATH + '/vendor/lodash/dist/lodash.min.js') - request104.GET('/vendor/d3/d3.min.js') + request104.GET('/app/' + APP_PATH + '/vendor/d3/d3.min.js') - request105.GET('/vendor/backbone/backbone.js') + request105.GET('/app/' + APP_PATH + '/vendor/backbone/backbone.js') - request106.GET('/vendor/contour/dist/contour.min.js') + request106.GET('/app/' + APP_PATH + '/vendor/contour/dist/contour.min.js') - request107.GET('/scripts/app.js') + request107.GET('/app/' + APP_PATH + '/scripts/app.js') grinder.sleep(68) - request108.GET('/styles/main.css') + request108.GET('/app/' + APP_PATH + '/styles/main.css') return result def page2(self): """GET epicenter-logo.svg (request 201).""" - result = request201.GET('/styles/assets/logos/epicenter-logo.svg') + result = request201.GET('/app/' + APP_PATH + '/styles/assets/logos/epicenter-logo.svg') return result def page3(self): """GET mandelbrot-logo.svg (request 301).""" - result = request301.GET('/styles/assets/logos/mandelbrot-logo.svg') + result = request301.GET('/app/' + APP_PATH + '/styles/assets/logos/mandelbrot-logo.svg') return result def page4(self): """GET contour-logo.svg (request 401).""" - result = request401.GET('/styles/assets/logos/contour-logo.svg') + result = request401.GET('/app/' + APP_PATH + '/styles/assets/logos/contour-logo.svg') return result def page5(self): """GET julia.svg (request 501).""" - result = request501.GET('/styles/assets/logos/julia.svg') + result = request501.GET('/app/' + APP_PATH + '/styles/assets/logos/julia.svg') return result def page6(self): """GET opensource-logo.svg (request 601).""" - result = request601.GET('/styles/assets/logos/opensource-logo.svg') + result = request601.GET('/app/' + APP_PATH + '/styles/assets/logos/opensource-logo.svg') return result def page7(self): """GET map.svg (request 701).""" - result = request701.GET('/styles/assets/logos/map.svg') + result = request701.GET('/app/' + APP_PATH + '/styles/assets/logos/map.svg') return result def page8(self): """GET logo-white.svg (request 801).""" - result = request801.GET('/styles/assets/logo-white.svg') + result = request801.GET('/app/' + APP_PATH + '/styles/assets/logo-white.svg') return result def page9(self): """GET logo.svg (request 901).""" - result = request901.GET('/styles/assets/logo.svg') + result = request901.GET('/app/' + APP_PATH + '/styles/assets/logo.svg') return result def page10(self): """GET book-crawl.json (request 1001).""" - result = request1001.GET('/data/book-crawl.json') + result = request1001.GET('/app/' + APP_PATH + '/data/book-crawl.json') return result def page11(self): """GET ss-symbolicons-block.woff (requests 1101-1102).""" - result = request1101.GET('/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') + result = request1101.GET('/app/' + APP_PATH + '/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') grinder.sleep(715) - request1102.GET('/styles/assets/marker-sprite-shadow.png') + request1102.GET('/app/' + APP_PATH + '/styles/assets/marker-sprite-shadow.png') return result diff --git a/tests/load/scenario-b.py b/tests/load/scenario-b.py index f41cbda..9125fa7 100755 --- a/tests/load/scenario-b.py +++ b/tests/load/scenario-b.py @@ -1,6 +1,8 @@ # The Grinder 3.11 # HTTP script recorded by TCPProxy at May 29, 2014 3:14:05 PM +import os +import uuid import re from net.grinder.script import Test from net.grinder.script.Grinder import grinder @@ -9,6 +11,11 @@ connectionDefaults = HTTPPluginControl.getConnectionDefaults() httpUtilities = HTTPPluginControl.getHTTPUtilities() +SECURE = os.getenv('LOAD_SECURE', "yes") == "yes" +APP_HOST = os.getenv('LOAD_APP_HOST', 'forio.com') +APP_PATH = os.getenv('LOAD_APP_PATH', 'showcase/route-optimizer') +API_HOST = os.getenv('LOAD_API_HOST', 'api.forio.com') + staticHeaders = [ NVPair('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'), NVPair('Accept-Encoding', 'gzip,deflate,sdch'), @@ -26,10 +33,6 @@ matcher = re.compile('.*"id":\s*"([^"]+)".*') - -# To use a proxy server, uncomment the next line and set the host and port. -# connectionDefaults.setProxyServer("localhost", 8001) - def createRequest(test, url, headers=staticHeaders): """Create an instrumented HTTPRequest.""" request = HTTPRequest(url=url) @@ -40,8 +43,9 @@ def createRequest(test, url, headers=staticHeaders): # These definitions at the top level of the file are evaluated once, # when the worker process is started. -url0 = 'http://forio.com/' -url1 = 'http://api.forio.com:80' +protocol = ('https' if SECURE else 'http') +url0 = protocol + '://' + APP_HOST +url1 = protocol + '://' + API_HOST request101 = createRequest(Test(101, 'GET /'), url0) @@ -104,88 +108,88 @@ class TestRunner: # A method for each recorded page. def page1(self): """GET / (requests 101-108).""" - result = request101.GET('/app/showcase/route-optimizer') + result = request101.GET('/app/' + APP_PATH) self.token_family = \ httpUtilities.valueFromBodyURI('family') # 'Open+Sans:300' grinder.sleep(51) - request102.GET('/app/showcase/route-optimizer/vendor/jquery/dist/jquery.min.js') + request102.GET('/app/' + APP_PATH + '/vendor/jquery/dist/jquery.min.js') - request103.GET('/app/showcase/route-optimizer/styles/main.css') + request103.GET('/app/' + APP_PATH + '/styles/main.css') - request104.GET('/app/showcase/route-optimizer/vendor/lodash/dist/lodash.min.js') + request104.GET('/app/' + APP_PATH + '/vendor/lodash/dist/lodash.min.js') - request105.GET('/app/showcase/route-optimizer/vendor/d3/d3.min.js') + request105.GET('/app/' + APP_PATH + '/vendor/d3/d3.min.js') - request106.GET('/app/showcase/route-optimizer/vendor/backbone/backbone.js') + request106.GET('/app/' + APP_PATH + '/vendor/backbone/backbone.js') - request107.GET('/app/showcase/route-optimizer/vendor/contour/dist/contour.min.js') + request107.GET('/app/' + APP_PATH + '/vendor/contour/dist/contour.min.js') grinder.sleep(63) - request108.GET('/app/showcase/route-optimizer/scripts/app.js') + request108.GET('/app/' + APP_PATH + '/scripts/app.js') return result def page2(self): """GET epicenter-logo.svg (request 201).""" - result = request201.GET('/app/showcase/route-optimizer/styles/assets/logos/epicenter-logo.svg') + result = request201.GET('/app/' + APP_PATH + '/styles/assets/logos/epicenter-logo.svg') return result def page3(self): """GET mandelbrot-logo.svg (request 301).""" - result = request301.GET('/app/showcase/route-optimizer/styles/assets/logos/mandelbrot-logo.svg') + result = request301.GET('/app/' + APP_PATH + '/styles/assets/logos/mandelbrot-logo.svg') return result def page4(self): """GET contour-logo.svg (request 401).""" - result = request401.GET('/app/showcase/route-optimizer/styles/assets/logos/contour-logo.svg') + result = request401.GET('/app/' + APP_PATH + '/styles/assets/logos/contour-logo.svg') return result def page5(self): """GET julia.svg (request 501).""" - result = request501.GET('/app/showcase/route-optimizer/styles/assets/logos/julia.svg') + result = request501.GET('/app/' + APP_PATH + '/styles/assets/logos/julia.svg') return result def page6(self): """GET opensource-logo.svg (request 601).""" - result = request601.GET('/app/showcase/route-optimizer/styles/assets/logos/opensource-logo.svg') + result = request601.GET('/app/' + APP_PATH + '/styles/assets/logos/opensource-logo.svg') return result def page7(self): """GET map.svg (request 701).""" - result = request701.GET('/app/showcase/route-optimizer/styles/assets/logos/map.svg') + result = request701.GET('/app/' + APP_PATH + '/styles/assets/logos/map.svg') return result def page8(self): """GET logo-white.svg (request 801).""" - result = request801.GET('/app/showcase/route-optimizer/styles/assets/logo-white.svg') + result = request801.GET('/app/' + APP_PATH + '/styles/assets/logo-white.svg') return result def page9(self): """GET logo.svg (request 901).""" - result = request901.GET('/app/showcase/route-optimizer/styles/assets/logo.svg') + result = request901.GET('/app/' + APP_PATH + '/styles/assets/logo.svg') return result def page10(self): """GET book-crawl.json (request 1001).""" - result = request1001.GET('/app/showcase/route-optimizer/data/book-crawl.json') + result = request1001.GET('/app/' + APP_PATH + '/data/book-crawl.json') return result def page11(self): """GET ss-symbolicons-block.woff (requests 1101-1102).""" - result = request1101.GET('/app/showcase/route-optimizer/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') + result = request1101.GET('/app/' + APP_PATH + '/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') grinder.sleep(639) - request1102.GET('/app/showcase/route-optimizer/styles/assets/marker-sprite-shadow.png') + request1102.GET('/app/' + APP_PATH + '/styles/assets/marker-sprite-shadow.png') return result @@ -219,7 +223,7 @@ def page15(self, runId): def page16(self): """GET sf-sightseeing.json (request 1601).""" - result = request1601.GET('/app/showcase/route-optimizer/data/sf-sightseeing.json') + result = request1601.GET('/app/' + APP_PATH + '/data/sf-sightseeing.json') return result @@ -232,7 +236,7 @@ def page17(self, runId): def page18(self): """GET business-deliver.json (request 1801).""" - result = request1801.GET('/app/showcase/route-optimizer/data/business-deliver.json') + result = request1801.GET('/app/' + APP_PATH + '/data/business-deliver.json') return result @@ -271,7 +275,6 @@ def __call__(self): grinder.logger.info(run) - grinder.sleep(114) self.page14(run) # OPTIONS {{run.id}} (request 1401) diff --git a/tests/load/scenario-c.py b/tests/load/scenario-c.py deleted file mode 100644 index 886f439..0000000 --- a/tests/load/scenario-c.py +++ /dev/null @@ -1,442 +0,0 @@ -# The Grinder 3.11 -# HTTP script recorded by TCPProxy at May 29, 2014 3:20:14 PM - -from net.grinder.script import Test -from net.grinder.script.Grinder import grinder -from net.grinder.plugin.http import HTTPPluginControl, HTTPRequest -from HTTPClient import NVPair -connectionDefaults = HTTPPluginControl.getConnectionDefaults() -httpUtilities = HTTPPluginControl.getHTTPUtilities() - -# To use a proxy server, uncomment the next line and set the host and port. -# connectionDefaults.setProxyServer("localhost", 8001) - -def createRequest(test, url, headers=None): - """Create an instrumented HTTPRequest.""" - request = HTTPRequest(url=url) - if headers: request.headers=headers - test.record(request, HTTPRequest.getHttpMethodFilter()) - return request - -# These definitions at the top level of the file are evaluated once, -# when the worker process is started. - -url0 = 'http://localhost:9002' -url1 = 'http://api.forio.com:80' - -request101 = createRequest(Test(101, 'GET /'), url0) - -request102 = createRequest(Test(102, 'GET jquery.min.js'), url0) - -request103 = createRequest(Test(103, 'GET lodash.min.js'), url0) - -request104 = createRequest(Test(104, 'GET d3.min.js'), url0) - -request105 = createRequest(Test(105, 'GET backbone.js'), url0) - -request106 = createRequest(Test(106, 'GET contour.min.js'), url0) - -request107 = createRequest(Test(107, 'GET app.js'), url0) - -request108 = createRequest(Test(108, 'GET main.css'), url0) - -request201 = createRequest(Test(201, 'GET epicenter-logo.svg'), url0) - -request301 = createRequest(Test(301, 'GET mandelbrot-logo.svg'), url0) - -request401 = createRequest(Test(401, 'GET contour-logo.svg'), url0) - -request501 = createRequest(Test(501, 'GET julia.svg'), url0) - -request601 = createRequest(Test(601, 'GET opensource-logo.svg'), url0) - -request701 = createRequest(Test(701, 'GET logo-white.svg'), url0) - -request801 = createRequest(Test(801, 'GET map.svg'), url0) - -request901 = createRequest(Test(901, 'GET logo.svg'), url0) - -request1001 = createRequest(Test(1001, 'GET book-crawl.json'), url0) - -request1101 = createRequest(Test(1101, 'GET ss-symbolicons-block.woff'), url0) - -request1102 = createRequest(Test(1102, 'GET marker-sprite-shadow.png'), url0) - -request1201 = createRequest(Test(1201, 'GET /'), url0) - -request1202 = createRequest(Test(1202, 'GET jquery.min.js'), url0) - -request1203 = createRequest(Test(1203, 'GET main.css'), url0) - -request1204 = createRequest(Test(1204, 'GET lodash.min.js'), url0) - -request1205 = createRequest(Test(1205, 'GET d3.min.js'), url0) - -request1206 = createRequest(Test(1206, 'GET backbone.js'), url0) - -request1207 = createRequest(Test(1207, 'GET contour.min.js'), url0) - -request1208 = createRequest(Test(1208, 'GET app.js'), url0) - -request1301 = createRequest(Test(1301, 'GET epicenter-logo.svg'), url0) - -request1401 = createRequest(Test(1401, 'GET mandelbrot-logo.svg'), url0) - -request1501 = createRequest(Test(1501, 'GET contour-logo.svg'), url0) - -request1601 = createRequest(Test(1601, 'GET julia.svg'), url0) - -request1701 = createRequest(Test(1701, 'GET opensource-logo.svg'), url0) - -request1801 = createRequest(Test(1801, 'GET map.svg'), url0) - -request1901 = createRequest(Test(1901, 'GET logo-white.svg'), url0) - -request2001 = createRequest(Test(2001, 'GET logo.svg'), url0) - -request2101 = createRequest(Test(2101, 'GET book-crawl.json'), url0) - -request2201 = createRequest(Test(2201, 'GET ss-symbolicons-block.woff'), url0) - -request2202 = createRequest(Test(2202, 'GET marker-sprite-shadow.png'), url0) - -request2301 = createRequest(Test(2301, 'OPTIONS run'), url1) - -request2401 = createRequest(Test(2401, 'POST run'), url1) - -request2501 = createRequest(Test(2501, 'GET contour.min.map'), url0) - -request2601 = createRequest(Test(2601, 'GET jquery.min.map'), url0) - -request2701 = createRequest(Test(2701, 'OPTIONS a8e5cdbf-c5f1-4001-904c-4f00468197b6'), url1) - -request2801 = createRequest(Test(2801, 'POST a8e5cdbf-c5f1-4001-904c-4f00468197b6'), url1) - -request2901 = createRequest(Test(2901, 'GET custom.json'), url0) - -request2902 = createRequest(Test(2902, 'GET marker-sprite-shadow.png'), url0) - -request3001 = createRequest(Test(3001, 'POST a8e5cdbf-c5f1-4001-904c-4f00468197b6'), url1) - - -class TestRunner: - """A TestRunner instance is created for each worker thread.""" - - # A method for each recorded page. - def page1(self): - """GET / (requests 101-108).""" - result = request101.GET('/') - - grinder.sleep(43) - request102.GET('/vendor/jquery/dist/jquery.min.js') - - request103.GET('/vendor/lodash/dist/lodash.min.js') - - request104.GET('/vendor/d3/d3.min.js') - - request105.GET('/vendor/backbone/backbone.js') - - request106.GET('/vendor/contour/dist/contour.min.js') - - request107.GET('/scripts/app.js') - - request108.GET('/styles/main.css') - - return result - - def page2(self): - """GET epicenter-logo.svg (request 201).""" - result = request201.GET('/styles/assets/logos/epicenter-logo.svg') - - return result - - def page3(self): - """GET mandelbrot-logo.svg (request 301).""" - result = request301.GET('/styles/assets/logos/mandelbrot-logo.svg') - - return result - - def page4(self): - """GET contour-logo.svg (request 401).""" - result = request401.GET('/styles/assets/logos/contour-logo.svg') - - return result - - def page5(self): - """GET julia.svg (request 501).""" - result = request501.GET('/styles/assets/logos/julia.svg') - - return result - - def page6(self): - """GET opensource-logo.svg (request 601).""" - result = request601.GET('/styles/assets/logos/opensource-logo.svg') - - return result - - def page7(self): - """GET logo-white.svg (request 701).""" - result = request701.GET('/styles/assets/logo-white.svg') - - return result - - def page8(self): - """GET map.svg (request 801).""" - result = request801.GET('/styles/assets/logos/map.svg') - - return result - - def page9(self): - """GET logo.svg (request 901).""" - result = request901.GET('/styles/assets/logo.svg') - - return result - - def page10(self): - """GET book-crawl.json (request 1001).""" - result = request1001.GET('/data/book-crawl.json') - - return result - - def page11(self): - """GET ss-symbolicons-block.woff (requests 1101-1102).""" - result = request1101.GET('/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') - - grinder.sleep(346) - request1102.GET('/styles/assets/marker-sprite-shadow.png') - - return result - - def page12(self): - """GET / (requests 1201-1208).""" - result = request1201.GET('/') - self.token_family = \ - httpUtilities.valueFromBodyURI('family') # 'Open+Sans:300' - - grinder.sleep(38) - request1202.GET('/vendor/jquery/dist/jquery.min.js') - - request1203.GET('/styles/main.css') - - request1204.GET('/vendor/lodash/dist/lodash.min.js') - - request1205.GET('/vendor/d3/d3.min.js') - - request1206.GET('/vendor/backbone/backbone.js') - - request1207.GET('/vendor/contour/dist/contour.min.js') - - request1208.GET('/scripts/app.js') - - return result - - def page13(self): - """GET epicenter-logo.svg (request 1301).""" - result = request1301.GET('/styles/assets/logos/epicenter-logo.svg') - - return result - - def page14(self): - """GET mandelbrot-logo.svg (request 1401).""" - result = request1401.GET('/styles/assets/logos/mandelbrot-logo.svg') - - return result - - def page15(self): - """GET contour-logo.svg (request 1501).""" - result = request1501.GET('/styles/assets/logos/contour-logo.svg') - - return result - - def page16(self): - """GET julia.svg (request 1601).""" - result = request1601.GET('/styles/assets/logos/julia.svg') - - return result - - def page17(self): - """GET opensource-logo.svg (request 1701).""" - result = request1701.GET('/styles/assets/logos/opensource-logo.svg') - - return result - - def page18(self): - """GET map.svg (request 1801).""" - result = request1801.GET('/styles/assets/logos/map.svg') - - return result - - def page19(self): - """GET logo-white.svg (request 1901).""" - result = request1901.GET('/styles/assets/logo-white.svg') - - return result - - def page20(self): - """GET logo.svg (request 2001).""" - result = request2001.GET('/styles/assets/logo.svg') - - return result - - def page21(self): - """GET book-crawl.json (request 2101).""" - result = request2101.GET('/data/book-crawl.json') - - return result - - def page22(self): - """GET ss-symbolicons-block.woff (requests 2201-2202).""" - result = request2201.GET('/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') - - grinder.sleep(526) - request2202.GET('/styles/assets/marker-sprite-shadow.png') - - return result - - def page23(self): - """OPTIONS run (request 2301).""" - result = request2301.OPTIONS('/model/run', - '''0\r\n\r\n''') - - return result - - def page24(self): - """POST run (request 2401).""" - result = request2401.POST('/model/run', - '{\"account\":\"showcase\",\"project\":\"route-optimizer\",\"model\":\"TSPModel.jl\"}') - - return result - - def page25(self): - """GET contour.min.map (request 2501).""" - result = request2501.GET('/vendor/contour/dist/dist/contour.min.map') - - return result - - def page26(self): - """GET jquery.min.map (request 2601).""" - result = request2601.GET('/vendor/jquery/dist/jquery.min.map') - - return result - - def page27(self): - """OPTIONS a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 2701).""" - result = request2701.OPTIONS('/model/operation/a8e5cdbf-c5f1-4001-904c-4f00468197b6', - '''0\r\n\r\n''') - - return result - - def page28(self): - """POST a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 2801).""" - result = request2801.POST('/model/operation/a8e5cdbf-c5f1-4001-904c-4f00468197b6', - '{\"name\":\"solve\",\"arguments\":[[[0,2449,3433,5656,1584,2994,5198,8013,3829],[1840,0,1247,5898,2455,4450,5454,9468,5285],[3056,1441,0,6532,3671,5688,4928,14670,6522],[5415,4986,5943,0,3606,4246,2589,7557,2759],[1808,2462,3855,4495,0,2656,4050,7674,3609],[2839,4407,5192,4666,2700,0,4681,5672,2320],[5506,4923,5252,2864,3698,4589,0,9252,4454],[8086,9654,13904,8282,7947,5247,9642,0,4904],[4476,5761,6545,2673,3893,2220,4480,5374,0]]]}') - - return result - - def page29(self): - """GET custom.json (requests 2901-2902).""" - result = request2901.GET('/data/custom.json') - - grinder.sleep(73062) - request2902.GET('/styles/assets/marker-sprite-shadow.png') - - return result - - def page30(self): - """POST a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 3001).""" - result = request3001.POST('/model/operation/a8e5cdbf-c5f1-4001-904c-4f00468197b6', - '{\"name\":\"solve\",\"arguments\":[[[0,2015,2811,2040,18846,1842,19769],[2060,0,3118,3444,19987,3244,20909],[3457,3113,0,4841,21581,3516,22504],[2053,3519,5866,0,16607,2451,17530],[18302,19754,22062,17168,0,20130,1396],[2008,3340,3670,2170,18835,0,19758],[18117,19569,21877,16983,1396,19945,0]]]}') - - return result - - def __call__(self): - """Called for every run performed by the worker thread.""" - self.page1() # GET / (requests 101-108) - - grinder.sleep(112) - self.page2() # GET epicenter-logo.svg (request 201) - self.page3() # GET mandelbrot-logo.svg (request 301) - - grinder.sleep(56) - self.page4() # GET contour-logo.svg (request 401) - self.page5() # GET julia.svg (request 501) - self.page6() # GET opensource-logo.svg (request 601) - self.page7() # GET logo-white.svg (request 701) - self.page8() # GET map.svg (request 801) - self.page9() # GET logo.svg (request 901) - self.page10() # GET book-crawl.json (request 1001) - - grinder.sleep(104) - self.page11() # GET ss-symbolicons-block.woff (requests 1101-1102) - - grinder.sleep(6764) - self.page12() # GET / (requests 1201-1208) - - grinder.sleep(656) - self.page13() # GET epicenter-logo.svg (request 1301) - self.page14() # GET mandelbrot-logo.svg (request 1401) - self.page15() # GET contour-logo.svg (request 1501) - self.page16() # GET julia.svg (request 1601) - self.page17() # GET opensource-logo.svg (request 1701) - self.page18() # GET map.svg (request 1801) - - grinder.sleep(14) - self.page19() # GET logo-white.svg (request 1901) - self.page20() # GET logo.svg (request 2001) - self.page21() # GET book-crawl.json (request 2101) - - grinder.sleep(110) - self.page22() # GET ss-symbolicons-block.woff (requests 2201-2202) - - grinder.sleep(4486) - self.page23() # OPTIONS run (request 2301) - - grinder.sleep(99) - self.page24() # POST run (request 2401) - self.page25() # GET contour.min.map (request 2501) - self.page26() # GET jquery.min.map (request 2601) - - grinder.sleep(95) - self.page27() # OPTIONS a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 2701) - - grinder.sleep(90) - self.page28() # POST a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 2801) - - grinder.sleep(6408) - self.page29() # GET custom.json (requests 2901-2902) - - grinder.sleep(32945) - self.page30() # POST a8e5cdbf-c5f1-4001-904c-4f00468197b6 (request 3001) - - -# Instrument page methods. -Test(100, 'Page 1').record(TestRunner.page1) -Test(200, 'Page 2').record(TestRunner.page2) -Test(300, 'Page 3').record(TestRunner.page3) -Test(400, 'Page 4').record(TestRunner.page4) -Test(500, 'Page 5').record(TestRunner.page5) -Test(600, 'Page 6').record(TestRunner.page6) -Test(700, 'Page 7').record(TestRunner.page7) -Test(800, 'Page 8').record(TestRunner.page8) -Test(900, 'Page 9').record(TestRunner.page9) -Test(1000, 'Page 10').record(TestRunner.page10) -Test(1100, 'Page 11').record(TestRunner.page11) -Test(1200, 'Page 12').record(TestRunner.page12) -Test(1300, 'Page 13').record(TestRunner.page13) -Test(1400, 'Page 14').record(TestRunner.page14) -Test(1500, 'Page 15').record(TestRunner.page15) -Test(1600, 'Page 16').record(TestRunner.page16) -Test(1700, 'Page 17').record(TestRunner.page17) -Test(1800, 'Page 18').record(TestRunner.page18) -Test(1900, 'Page 19').record(TestRunner.page19) -Test(2000, 'Page 20').record(TestRunner.page20) -Test(2100, 'Page 21').record(TestRunner.page21) -Test(2200, 'Page 22').record(TestRunner.page22) -Test(2300, 'Page 23').record(TestRunner.page23) -Test(2400, 'Page 24').record(TestRunner.page24) -Test(2500, 'Page 25').record(TestRunner.page25) -Test(2600, 'Page 26').record(TestRunner.page26) -Test(2700, 'Page 27').record(TestRunner.page27) -Test(2800, 'Page 28').record(TestRunner.page28) -Test(2900, 'Page 29').record(TestRunner.page29) -Test(3000, 'Page 30').record(TestRunner.page30) From 1114ebd5556cb9c8aacb8b973b88444c78d847a8 Mon Sep 17 00:00:00 2001 From: David Wick Date: Thu, 12 Jun 2014 10:52:20 -0700 Subject: [PATCH 5/7] formatting --- tests/load/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/load/README.md b/tests/load/README.md index 8480303..c67292b 100644 --- a/tests/load/README.md +++ b/tests/load/README.md @@ -35,7 +35,7 @@ The hostname of the load test target. Type: `String` Default: `"showcase/route-optimizer"` -{{account}}/{{project}} segment of the application url. +`{{account}}`/`{{project}}` segment of the application url. #### LOAD_API_HOST From 768d146b4e7a39eb91e5f75c8aea56015cd10bde Mon Sep 17 00:00:00 2001 From: David Wick Date: Thu, 12 Jun 2014 11:55:34 -0700 Subject: [PATCH 6/7] more generic --- tests/load/proxy.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/load/proxy.js b/tests/load/proxy.js index 0a07ff7..8c578a3 100644 --- a/tests/load/proxy.js +++ b/tests/load/proxy.js @@ -1,11 +1,12 @@ 'use strict'; + var httpProxy = require('http-proxy'); var proxyPort = 3001; httpProxy.createServer(function (req, res, proxy) { var original = req.headers.host; - var isForio = /(api\.)?forio.com|localhost:9002/.test(original); + var isForio = /(api\.)?forio.com|localhost/.test(original); proxy.proxyRequest(req, res, { host: isForio ? 'localhost' : original, From 1c6185614e1704d3e7aeea1be8c670dd8a5c411b Mon Sep 17 00:00:00 2001 From: David Wick Date: Thu, 12 Jun 2014 11:56:53 -0700 Subject: [PATCH 7/7] added scenario c, change config slightly --- tests/load/README.md | 12 +- tests/load/scenario-a.py | 11 +- tests/load/scenario-b.py | 26 ++- tests/load/scenario-c.py | 457 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 493 insertions(+), 13 deletions(-) create mode 100644 tests/load/scenario-c.py diff --git a/tests/load/README.md b/tests/load/README.md index c67292b..72046b7 100644 --- a/tests/load/README.md +++ b/tests/load/README.md @@ -31,11 +31,17 @@ Default: `"forio.com"` The hostname of the load test target. -#### LOAD_APP_PATH +#### LOAD_APP_ACCOUNT Type: `String` -Default: `"showcase/route-optimizer"` +Default: `"showcase"` -`{{account}}`/`{{project}}` segment of the application url. +The account for the application. + +#### LOAD_APP_PROJECT +Type: `String` +Default: `"route-optimizer"` + +The project for the application. #### LOAD_API_HOST diff --git a/tests/load/scenario-a.py b/tests/load/scenario-a.py index afd4469..b2b97ff 100644 --- a/tests/load/scenario-a.py +++ b/tests/load/scenario-a.py @@ -10,9 +10,13 @@ httpUtilities = HTTPPluginControl.getHTTPUtilities() SECURE = os.getenv('LOAD_SECURE', "yes") == "yes" +PROTOCOL = ('https' if SECURE else 'http') APP_HOST = os.getenv('LOAD_APP_HOST', 'forio.com') -APP_PATH = os.getenv('LOAD_APP_PATH', 'showcase/route-optimizer') +APP_ACCOUNT = os.getenv('LOAD_APP_ACCOUNT', 'showcase') +APP_PROJECT = os.getenv('LOAD_APP_PROJECT', 'route-optimizer') +APP_PATH = APP_ACCOUNT + '/' + APP_PROJECT API_HOST = os.getenv('LOAD_API_HOST', 'api.forio.com') +STATIC_URL = PROTOCOL + '://' + APP_HOST staticHeaders = [ NVPair('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'), @@ -20,6 +24,8 @@ NVPair('Accept-Language', 'en-US,en;q=0.8'), NVPair('Cache-Control', 'no-cache'), NVPair('Pragma', 'no-cache'), + NVPair('Host', APP_HOST), + NVPair('Referer', STATIC_URL), NVPair('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36'), NVPair('Connection', 'keep-alive') ] @@ -34,8 +40,7 @@ def createRequest(test, url, headers=staticHeaders): # These definitions at the top level of the file are evaluated once, # when the worker process is started. -protocol = ('https' if SECURE else 'http') -url0 = protocol + '://' + APP_HOST +url0 = STATIC_URL request101 = createRequest(Test(101, 'GET /'), url0) diff --git a/tests/load/scenario-b.py b/tests/load/scenario-b.py index 9125fa7..0b46671 100755 --- a/tests/load/scenario-b.py +++ b/tests/load/scenario-b.py @@ -12,9 +12,13 @@ httpUtilities = HTTPPluginControl.getHTTPUtilities() SECURE = os.getenv('LOAD_SECURE', "yes") == "yes" +PROTOCOL = ('https' if SECURE else 'http') APP_HOST = os.getenv('LOAD_APP_HOST', 'forio.com') -APP_PATH = os.getenv('LOAD_APP_PATH', 'showcase/route-optimizer') +APP_ACCOUNT = os.getenv('LOAD_APP_ACCOUNT', 'showcase') +APP_PROJECT = os.getenv('LOAD_APP_PROJECT', 'route-optimizer') +APP_PATH = APP_ACCOUNT + '/' + APP_PROJECT API_HOST = os.getenv('LOAD_API_HOST', 'api.forio.com') +STATIC_URL = PROTOCOL + '://' + APP_HOST staticHeaders = [ NVPair('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'), @@ -22,13 +26,22 @@ NVPair('Accept-Language', 'en-US,en;q=0.8'), NVPair('Cache-Control', 'no-cache'), NVPair('Pragma', 'no-cache'), + NVPair('Host', APP_HOST), + NVPair('Referer', STATIC_URL), NVPair('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36'), NVPair('Connection', 'keep-alive') ] apiHeaders = [ - NVPair('Content-Type', 'application/json; charset=UTF-8'), - NVPair('Accept', 'application/json, text/javascript, */*; q=0.01') + NVPair('Accept', 'application/json, text/javascript, */*; q=0.01'), + NVPair('Accept-Encoding', 'gzip,deflate,sdch'), + NVPair('Accept-Language', 'en-US,en;q=0.8'), + NVPair('Connection', 'keep-alive'), + NVPair('Content-Type', 'application/json'), + NVPair('Host', API_HOST), + NVPair('Origin', STATIC_URL), + NVPair('Referer', STATIC_URL), + NVPair('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36') ] matcher = re.compile('.*"id":\s*"([^"]+)".*') @@ -43,9 +56,8 @@ def createRequest(test, url, headers=staticHeaders): # These definitions at the top level of the file are evaluated once, # when the worker process is started. -protocol = ('https' if SECURE else 'http') -url0 = protocol + '://' + APP_HOST -url1 = protocol + '://' + API_HOST +url0 = STATIC_URL +url1 = PROTOCOL + '://' + API_HOST request101 = createRequest(Test(101, 'GET /'), url0) @@ -203,7 +215,7 @@ def page12(self): def page13(self): """POST run (request 1301).""" result = request1301.POST('/model/run', - '{\"account\":\"showcase\",\"project\":\"route-optimizer\",\"model\":\"TSPModel.jl\"}') + '{\"account\":\"' + APP_ACCOUNT + '\",\"project\":\"' + APP_PROJECT + '\",\"model\":\"TSPModel.jl\"}') return result diff --git a/tests/load/scenario-c.py b/tests/load/scenario-c.py new file mode 100644 index 0000000..d0d0c7b --- /dev/null +++ b/tests/load/scenario-c.py @@ -0,0 +1,457 @@ +# The Grinder 3.11 +# HTTP script recorded by TCPProxy at May 29, 2014 3:14:05 PM + +import os +import uuid +import re +from net.grinder.script import Test +from net.grinder.script.Grinder import grinder +from net.grinder.plugin.http import HTTPPluginControl, HTTPRequest +from HTTPClient import NVPair +connectionDefaults = HTTPPluginControl.getConnectionDefaults() +httpUtilities = HTTPPluginControl.getHTTPUtilities() + +SECURE = os.getenv('LOAD_SECURE', "yes") == "yes" +PROTOCOL = ('https' if SECURE else 'http') +APP_HOST = os.getenv('LOAD_APP_HOST', 'forio.com') +APP_ACCOUNT = os.getenv('LOAD_APP_ACCOUNT', 'showcase') +APP_PROJECT = os.getenv('LOAD_APP_PROJECT', 'route-optimizer') +APP_PATH = APP_ACCOUNT + '/' + APP_PROJECT +API_HOST = os.getenv('LOAD_API_HOST', 'api.forio.com') +STATIC_URL = PROTOCOL + '://' + APP_HOST + +staticHeaders = [ + NVPair('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'), + NVPair('Accept-Encoding', 'gzip,deflate,sdch'), + NVPair('Accept-Language', 'en-US,en;q=0.8'), + NVPair('Cache-Control', 'no-cache'), + NVPair('Pragma', 'no-cache'), + NVPair('Host', APP_HOST), + NVPair('Referer', STATIC_URL), + NVPair('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36'), + NVPair('Connection', 'keep-alive') +] + +apiHeaders = [ + NVPair('Accept', 'application/json, text/javascript, */*; q=0.01'), + NVPair('Accept-Encoding', 'gzip,deflate,sdch'), + NVPair('Accept-Language', 'en-US,en;q=0.8'), + NVPair('Connection', 'keep-alive'), + NVPair('Content-Type', 'application/json'), + NVPair('Host', API_HOST), + NVPair('Origin', STATIC_URL), + NVPair('Referer', STATIC_URL), + NVPair('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.114 Safari/537.36') +] + +matcher = re.compile('.*"id":\s*"([^"]+)".*') + +def createRequest(test, url, headers=staticHeaders): + """Create an instrumented HTTPRequest.""" + request = HTTPRequest(url=url) + if headers: request.headers=headers + test.record(request, HTTPRequest.getHttpMethodFilter()) + return request + +# These definitions at the top level of the file are evaluated once, +# when the worker process is started. + +url0 = STATIC_URL +url1 = PROTOCOL + '://' + API_HOST + +request101 = createRequest(Test(101, 'GET /'), url0) + +request102 = createRequest(Test(102, 'GET jquery.min.js'), url0) + +request103 = createRequest(Test(103, 'GET main.css'), url0) + +request104 = createRequest(Test(104, 'GET lodash.min.js'), url0) + +request105 = createRequest(Test(105, 'GET d3.min.js'), url0) + +request106 = createRequest(Test(106, 'GET backbone.js'), url0) + +request107 = createRequest(Test(107, 'GET ZeroClipboard.min.js'), url0) + +request108 = createRequest(Test(108, 'GET contour.min.js'), url0) + +request109 = createRequest(Test(109, 'GET app.js'), url0) + +request201 = createRequest(Test(201, 'GET epicenter-logo.svg'), url0) + +request301 = createRequest(Test(301, 'GET mandelbrot-logo.svg'), url0) + +request401 = createRequest(Test(401, 'GET contour-logo.svg'), url0) + +request501 = createRequest(Test(501, 'GET julia.svg'), url0) + +request601 = createRequest(Test(601, 'GET opensource-logo.svg'), url0) + +request701 = createRequest(Test(701, 'GET map.svg'), url0) + +request801 = createRequest(Test(801, 'GET logo-white.svg'), url0) + +request901 = createRequest(Test(901, 'GET logo.svg'), url0) + +request1001 = createRequest(Test(1001, 'GET book-crawl.json'), url0) + +request1101 = createRequest(Test(1101, 'GET ss-social-regular.woff'), url0) + +request1201 = createRequest(Test(1201, 'GET ss-symbolicons-block.woff'), url0) + +request1301 = createRequest(Test(1301, 'GET ZeroClipboard.swf'), url0) + +request1302 = createRequest(Test(1302, 'GET marker-sprite-shadow.png'), url0) + +request1401 = createRequest(Test(1401, 'OPTIONS run'), url1, apiHeaders) + +request1501 = createRequest(Test(1501, 'POST run'), url1, apiHeaders) + +request1601 = createRequest(Test(1601, 'OPTIONS {{run.id}}'), url1, apiHeaders) + +request1701 = createRequest(Test(1701, 'POST {{run.id}}'), url1, apiHeaders) + +request1801 = createRequest(Test(1801, 'GET custom.json'), url0) + +request1901 = createRequest(Test(1901, 'POST {{run.id}}'), url1, apiHeaders) + +request2001 = createRequest(Test(2001, 'OPTIONS routes'), url1, apiHeaders) + +request2101 = createRequest(Test(2101, 'POST routes'), url1, apiHeaders) + +request2201 = createRequest(Test(2201, 'GET {{route.id}}'), url1, apiHeaders) + +request2301 = createRequest(Test(2301, 'POST {{run.id}}'), url1, apiHeaders) + +request2401 = createRequest(Test(2401, 'GET business-deliver.json'), url0) + +request2501 = createRequest(Test(2501, 'POST {{run.id}}'), url1, apiHeaders) + +request2601 = createRequest(Test(2601, 'POST routes'), url1, apiHeaders) + +request2701 = createRequest(Test(2701, 'GET {{route.id}}'), url1, apiHeaders) + +request2801 = createRequest(Test(2801, 'POST {{run.id}}'), url1, apiHeaders) + + +class TestRunner: + """A TestRunner instance is created for each worker thread.""" + + # A method for each recorded page. + def page1(self): + """GET / (requests 101-109).""" + result = request101.GET('/app/' + APP_PATH) + self.token_family = \ + httpUtilities.valueFromBodyURI('family') # 'Open+Sans:300' + + grinder.sleep(39) + request102.GET('/app/' + APP_PATH + '/vendor/jquery/dist/jquery.min.js') + + request103.GET('/app/' + APP_PATH + '/styles/main.css') + + request104.GET('/app/' + APP_PATH + '/vendor/lodash/dist/lodash.min.js') + + request105.GET('/app/' + APP_PATH + '/vendor/d3/d3.min.js') + + request106.GET('/app/' + APP_PATH + '/vendor/backbone/backbone.js') + + request107.GET('/app/' + APP_PATH + '/vendor/zeroclipboard/ZeroClipboard.min.js') + + grinder.sleep(34) + request108.GET('/app/' + APP_PATH + '/vendor/contour/dist/contour.min.js') + + request109.GET('/app/' + APP_PATH + '/scripts/app.js') + + return result + + def page2(self): + """GET epicenter-logo.svg (request 201).""" + result = request201.GET('/app/' + APP_PATH + '/styles/assets/logos/epicenter-logo.svg') + + return result + + def page3(self): + """GET mandelbrot-logo.svg (request 301).""" + result = request301.GET('/app/' + APP_PATH + '/styles/assets/logos/mandelbrot-logo.svg') + + return result + + def page4(self): + """GET contour-logo.svg (request 401).""" + result = request401.GET('/app/' + APP_PATH + '/styles/assets/logos/contour-logo.svg') + + return result + + def page5(self): + """GET julia.svg (request 501).""" + result = request501.GET('/app/' + APP_PATH + '/styles/assets/logos/julia.svg') + + return result + + def page6(self): + """GET opensource-logo.svg (request 601).""" + result = request601.GET('/app/' + APP_PATH + '/styles/assets/logos/opensource-logo.svg') + + return result + + def page7(self): + """GET map.svg (request 701).""" + result = request701.GET('/app/' + APP_PATH + '/styles/assets/logos/map.svg') + + return result + + def page8(self): + """GET logo-white.svg (request 801).""" + result = request801.GET('/app/' + APP_PATH + '/styles/assets/logo-white.svg') + + return result + + def page9(self): + """GET logo.svg (request 901).""" + result = request901.GET('/app/' + APP_PATH + '/styles/assets/logo.svg') + + return result + + def page10(self): + """GET book-crawl.json (request 1001).""" + result = request1001.GET('/app/' + APP_PATH + '/data/book-crawl.json') + + return result + + def page11(self): + """GET ss-social-regular.woff (request 1101).""" + result = request1101.GET('/app/' + APP_PATH + '/styles/assets/fonts/ss-social/ss-social-regular.woff') + + return result + + def page12(self): + """GET ss-symbolicons-block.woff (request 1201).""" + result = request1201.GET('/app/' + APP_PATH + '/styles/assets/fonts/symbolicons/ss-symbolicons-block.woff') + + return result + + def page13(self): + """GET ZeroClipboard.swf (requests 1301-1302).""" + self.token_noCache = \ + '1402596761565' + result = request1301.GET('/app/' + APP_PATH + '/vendor/zeroclipboard/ZeroClipboard.swf' + + '?noCache=' + + self.token_noCache) + + grinder.sleep(691) + request1302.GET('/app/' + APP_PATH + '/styles/assets/marker-sprite-shadow.png') + + return result + + def page14(self): + """OPTIONS run (request 1401).""" + result = request1401.OPTIONS('/model/run', + '''0\r\n\r\n''') + + return result + + def page15(self): + """POST run (request 1501).""" + result = request1501.POST('/model/run', + '{\"account\":\"' + APP_ACCOUNT + '\",\"project\":\"' + APP_PROJECT + '\",\"model\":\"TSPModel.jl\"}') + + return result + + def page16(self, run): + """OPTIONS {{run.id}} (request 1601).""" + result = request1601.OPTIONS('/model/operation/' + run, + '''0\r\n\r\n''') + + return result + + def page17(self, run): + """POST {{run.id}} (request 1701).""" + result = request1701.POST('/model/operation/' + run, + '{\"name\":\"solve\",\"arguments\":[[[0,2449,3433,5656,1584,2994,5198,8013,3829],[1840,0,1247,5898,2455,4450,5454,9468,5285],[3074,1441,0,6532,3387,5688,4928,14320,7006],[5415,4986,5943,0,3606,4246,2589,7557,2759],[1808,2462,3855,4495,0,2656,4050,7674,3609],[2854,4407,5192,4666,2700,0,4681,5672,2320],[5506,4923,5252,2864,3698,4589,0,9252,4454],[8101,9654,13904,8282,7947,5247,9642,0,4904],[4476,5450,6545,2673,3893,2220,4480,5374,0]]]}') + + return result + + def page18(self): + """GET custom.json (request 1801).""" + result = request1801.GET('/app/' + APP_PATH + '/data/custom.json') + + return result + + def page19(self, run): + """POST {{run.id}} (request 1901).""" + result = request1901.POST('/model/operation/' + run, + '{\"name\":\"solve\",\"arguments\":[[[0,1072,394,2472,8560,2216,634,2490],[1605,0,1343,1753,7469,1743,1583,3439],[263,1430,0,2116,8710,2757,240,2097],[2198,1420,1936,0,8168,2974,2176,3076],[8698,7279,8435,8471,0,6256,8675,10953],[2859,1855,2597,3618,6251,0,2837,4698],[15,1087,408,2487,8575,2231,0,2505],[2261,3148,2657,3021,11109,4475,2239,0]]]}') + + return result + + def page20(self): + """OPTIONS routes (request 2001).""" + result = request2001.OPTIONS('/data/' + APP_PATH + '/routes', + '''0\r\n\r\n''') + + return result + + def page21(self): + """POST routes (request 2101).""" + result = request2101.POST('/data/' + APP_PATH + '/routes', + '{\"routeName\":\"Fun Saturday\",\"waypoints\":[{\"name\":\"Forio\",\"latitude\":37.776861,\"longitude\":-122.410573},{\"name\":\"San Francisco City Hall\",\"latitude\":37.779318,\"longitude\":-122.41913999999997},{\"name\":\"City Beer Store\",\"latitude\":37.775724,\"longitude\":-122.40959199999998},{\"name\":\"Nob Hill Grille\",\"latitude\":37.789876,\"longitude\":-122.41738499999997},{\"name\":\"Golden Gate Park\",\"latitude\":37.769421,\"longitude\":-122.48621400000002},{\"name\":\"Toronado\",\"latitude\":37.771826,\"longitude\":-122.431196},{\"name\":\"Cellarmaker Brewing Co.\",\"latitude\":37.777171,\"longitude\":-122.41073},{\"name\":\"21st Amendment Brewery\",\"latitude\":37.782431,\"longitude\":-122.39258999999998}]}') + + return result + + def page22(self, route): + """GET {{route.id}} (request 2201).""" + result = request2201.GET('/data/' + APP_PATH + '/routes/' + route) + + return result + + def page23(self, run): + """POST {{run.id}} (request 2301).""" + result = request2301.POST('/model/operation/' + run, + '{\"name\":\"solve\",\"arguments\":[[[0,1072,394,2472,8560,2216,634,2490],[1605,0,1343,1753,7469,1743,1583,3439],[263,1430,0,2116,8710,2757,240,2097],[2198,1420,1936,0,8168,2974,2176,3076],[8698,7279,8435,8471,0,6256,8675,10953],[2859,1855,2597,3618,6251,0,2837,4698],[15,1087,408,2487,8575,2231,0,2505],[2261,3148,2657,3021,11109,4475,2239,0]]]}') + + return result + + def page24(self): + """GET business-deliver.json (request 2401).""" + result = request2401.GET('/app/' + APP_PATH + '/data/business-deliver.json') + + return result + + def page25(self, run): + """POST {{run.id}} (request 2501).""" + result = request2501.POST('/model/operation/' + run, + '{\"name\":\"solve\",\"arguments\":[[[0,2197,6196,9802,3163,5217,5657,9397,4233],[2191,0,8253,11153,966,5858,6421,9400,5584],[6260,7611,0,6540,7053,1079,1085,4521,4414],[9950,11301,6540,0,11226,7126,7249,10277,5868],[2911,722,7604,10705,0,5208,5772,8750,4389],[5262,6613,1105,7122,5983,0,1550,5626,3416],[5646,6995,997,7345,6144,1605,0,4028,4725],[9762,9265,4330,10474,8903,5409,3991,0,8339],[4341,5692,3945,5596,5451,2922,4508,8467,0]]]}') + + return result + + def page26(self): + """POST routes (request 2601).""" + result = request2601.POST('/data/' + APP_PATH + '/routes', + '{\"routeName\":\"Lunch and Errands\",\"waypoints\":[{\"name\":\"Forio\",\"latitude\":37.776861,\"longitude\":-122.410573},{\"name\":\"Kimberly Mitchell, DDS Inc.\",\"latitude\":37.788292,\"longitude\":-122.40975300000002},{\"name\":\"USPS\",\"latitude\":37.781786,\"longitude\":-122.418836},{\"name\":\"BrainWash\",\"latitude\":37.776374,\"longitude\":-122.408706}]}') + + return result + + def page27(self, route): + """GET {{route.id}} (request 2701).""" + result = request2701.GET('/data/' + APP_PATH + '/routes/' + route) + + return result + + def page28(self, run): + """POST {{run.id}} (request 2801).""" + result = request2801.POST('/model/operation/' + run, + '{\"name\":\"solve\",\"arguments\":[[[0,2542,1348,1013],[1988,0,1708,2063],[1638,1482,0,1713],[446,1785,1404,0]]]}') + + return result + + def __call__(self): + """Called for every run performed by the worker thread.""" + self.page1() # GET / (requests 101-109) + + grinder.sleep(245) + self.page2() # GET epicenter-logo.svg (request 201) + self.page3() # GET mandelbrot-logo.svg (request 301) + self.page4() # GET contour-logo.svg (request 401) + self.page5() # GET julia.svg (request 501) + self.page6() # GET opensource-logo.svg (request 601) + self.page7() # GET map.svg (request 701) + self.page8() # GET logo-white.svg (request 801) + + grinder.sleep(36) + self.page9() # GET logo.svg (request 901) + + grinder.sleep(43) + self.page10() # GET book-crawl.json (request 1001) + self.page11() # GET ss-social-regular.woff (request 1101) + self.page12() # GET ss-symbolicons-block.woff (request 1201) + + grinder.sleep(230) + self.page13() # GET ZeroClipboard.swf (requests 1301-1302) + + grinder.sleep(4581) + self.page14() # OPTIONS run (request 1401) + + grinder.sleep(100) + + json = self.page15().text # POST run (request 1501) + run = matcher.match(json).group(1) + + grinder.logger.info(run) + + grinder.sleep(96) + self.page16(run) # OPTIONS {{run.id}} (request 1601) + + grinder.sleep(89) + self.page17(run) # POST {{run.id}} (request 1701) + + grinder.sleep(22776) + self.page18() # GET custom.json (request 1801) + + grinder.sleep(69582) + self.page19(run) # POST {{run.id}} (request 1901) + + grinder.sleep(13621) + self.page20() # OPTIONS routes (request 2001) + + grinder.sleep(90) + + json = self.page21().text # POST routes (request 2101) + route = matcher.match(json).group(1) + + grinder.logger.info(route) + + grinder.sleep(95) + self.page22(route) # GET {{route.id}} (request 2201) + + grinder.sleep(7673) + self.page23(run) # POST {{run.id}} (request 2301) + + grinder.sleep(18150) + self.page24() # GET business-deliver.json (request 2401) + + grinder.sleep(3821) + self.page25(run) # POST {{run.id}} (request 2501) + + grinder.sleep(36022) + + json = self.page26().text # POST routes (request 2601) + route = matcher.match(json).group(1) + + grinder.logger.info(route) + + grinder.sleep(104) + self.page27(route) # GET {{route.id}} (request 2701) + + grinder.sleep(1689) + self.page28(run) # POST {{run.id}} (request 2801) + + +# Instrument page methods. +Test(100, 'Page 1').record(TestRunner.page1) +Test(200, 'Page 2').record(TestRunner.page2) +Test(300, 'Page 3').record(TestRunner.page3) +Test(400, 'Page 4').record(TestRunner.page4) +Test(500, 'Page 5').record(TestRunner.page5) +Test(600, 'Page 6').record(TestRunner.page6) +Test(700, 'Page 7').record(TestRunner.page7) +Test(800, 'Page 8').record(TestRunner.page8) +Test(900, 'Page 9').record(TestRunner.page9) +Test(1000, 'Page 10').record(TestRunner.page10) +Test(1100, 'Page 11').record(TestRunner.page11) +Test(1200, 'Page 12').record(TestRunner.page12) +Test(1300, 'Page 13').record(TestRunner.page13) +Test(1400, 'Page 14').record(TestRunner.page14) +Test(1500, 'Page 15').record(TestRunner.page15) +Test(1600, 'Page 16').record(TestRunner.page16) +Test(1700, 'Page 17').record(TestRunner.page17) +Test(1800, 'Page 18').record(TestRunner.page18) +Test(1900, 'Page 19').record(TestRunner.page19) +Test(2000, 'Page 20').record(TestRunner.page20) +Test(2100, 'Page 21').record(TestRunner.page21) +Test(2200, 'Page 22').record(TestRunner.page22) +Test(2300, 'Page 23').record(TestRunner.page23) +Test(2400, 'Page 24').record(TestRunner.page24) +Test(2500, 'Page 25').record(TestRunner.page25) +Test(2600, 'Page 26').record(TestRunner.page26) +Test(2700, 'Page 27').record(TestRunner.page27) +Test(2800, 'Page 28').record(TestRunner.page28)