Package: httpbenchmark
HTTPBenchmark aims to be inbetween Apache Bench (ab) and a more full blown
HTTP test suite. In its simplest form it provides some basic compatibility with
ab in that it supports a -n switch to specify the number of requests to make
and a -c switch to specify how many concurrent users.However, the true intended use is to subclass HTTPBenchmark and to override theworkermethod to implement your own test logic. In this regard you can
think of HTTPBenchmark as a framework that allows you to build unit tests for
your HTTP application that aim to stress a server as well. See the Worker Code
section below.InstallationInstallation is easily accomplished usingpiporeasy_install.pipinstallhttpbenchmarkBasic UsageA script namedpbis provided and is intended to be a basic analog to the
Apacheabscript.pb-n1000-c25http://my-host.tld/endpoint/Worker codeBy default HTTPBenchmark does nothing more than send aGETrequest and
expect a 200 OK return code. To fully utilize the system you should create
your own script that subclassesHTTPBenchmark.Here’s an incomplete and untested example that is load testing some application
that deals with users and friends. It aims to illustrate the fundamentals of
using HTTPBenchmarkfromhttpbenchmarkimportHTTPBenchmarkfromtornadoimportgenimportrandomUSER_IDS=[1111,2222,3333,4444]_url=lambdax:''.join(['http://my-host.tld/',x])classMyBenchmark(HTTPBenchmark):@gen.coroutinedefworker(self):'''
        get_worker should return a callable that will be called by the async http client
        '''ifrandom.choice([True,False]):yieldself.new_user()else:yieldself.returning_user()@gen.coroutinedefnew_user(self):user_id=random.choice(USER_IDS)self.log.debug("New user:%s"%user_id)friends=yieldself.open_json(_url("register?uid=%d"%user_id))# ... handle registration response ...iffailure:self.log.error("Indicate reason for failure")self.log.debug("Show debugging info if you want")self.finish_request(False)else:yieldself.next_step(user_id,friends['friendList'][0])@gen.coroutinedefreturning_user(self):user_id=random.choice(USER_IDS)self.log.debug("Returning user:%s"%user_id)defhandle_login(response,friends):friends=yieldself.open_json(_url("login?uid=%d"%user_id))# ... handle login response ...iffailure:self.log.error("Indicate reason for failure")self.log.debug("Show debugging info if you want")self.finish_request(False)else:yieldself.next_step(user_id,friends['friendList'][0])@gen.coroutinedefnext_step(self,user_id,friend_id):# ... do something else ...iffailure:self.log.error("Indicate reason for failure")self.log.debug("Show debugging info if you want")self.finish_request(False)else:# success!self.finish_request()if__name__=='__main__':MyBenchmark().main()EssentialsThis usesTornado’s async generator interfaceto achive concurrency, your
functions need to be wrapped in@gen.coroutineand you shouldyieldbetween them.workeris where your main code lives. It will be called whenever there
is a free slot based on concurrency.yield self.get(url, code=200)is used to make a GET request. You will
get the response object back when the operation completes.self.post(url,params={},callback)is used to POST data.paramsshould be a dictionary and will be sent as the POST data. It functions
the same asgetotherwise.If you’re posting to a PHP backend and need to use PHP’s neseted array
syntax for parameters you passphp_urlencodeto theself.postmethod
with a value ofTrueand it will encode the params accordingly.self.get_json(url, callback)is a shortcut for getting and parsing json
data that is returned. Your callback should accept two arguments, the first
is the response object and the second is the decoded json.self.finish_request(True/False)should be called to signal the end of a
request. If everything worked as you expected pass itTrue, otherwise
pass itFalseself.debug_response(response)is a handy function to use while you’re
developing your test cases. If you pass it a response object it will print
out a summary of the object as well as the headers and body so you can debug
the live data.TODOAdd some working examples