{ "info": { "author": "Ruslan Spivak", "author_email": "ruslan.spivak@gmail.com", "bugtrack_url": null, "classifiers": [ "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Operating System :: Unix", "Programming Language :: Python", "Topic :: Software Development :: Testing" ], "description": "What is Cynic?\n--------------\nThese days almost any application has several integration points\nlike database, payment gateway, or some Web service that it consumes\nover HTTP.\n\nAll communication with the remote systems happens over the network and\nboth networks and those systems often go wonky.\n\nIf we do not test the behavior of **our** system when the remote end\noperates out of spec and goes haywire the only place for testing\nbecomes in production which is, as we all know, for some systems is\nless than acceptable.\n\nBecause the calls to the remote systems use network, the socket\nconnection can have different failure scenarios, for example:\n\n- The remote end resets the connection by sending a TCP RST packet\n\n- The connection may be established, but the response is never sent\n back and the connection is not closed (If you don't use socket\n timeouts in your app you may be in trouble at some point).\n\n- The remote end can send garbage data as the response\n\n- The service can send HTML over HTTP instead of the expected JSON\n response\n\n- The HTTP service can send one byte of the response data every 30\n seconds\n\n- The remote HTTP service sends only headers and no body\n\n- The service can send megabytes of data instead of expected kilobytes\n\n- Etc.\n\nIt would be good to be able to test the behavior of our application\nwhen some of those conditions happen.\n\n**Cynic** tries to help with that testing. Basically it's a test\nharness (test double) that can be used to simulate crafty and devious\nremote systems right from your command line.\n\nCynic will try hard to cause injury to your system.\n\n*It's goal is to make your system under test cynical.*\n\nRead the formatted docs at `http://cynic.readthedocs.org `_\n\nInstallation\n------------\n\n::\n\n $ [sudo] pip install cynic\n\nOr the bleeding edge version from the git master branch:\n\n::\n\n $ [sudo] pip install git+https://github.com/rspivak/cynic.git#egg=cynic\n\n\nQuick intro\n-----------\n\nStart Cynic which in turn will start multiple services on different\nports:\n\n::\n\n $ cynic\n INFO [2012-06-03 23:44:35,603] server: Starting 'HTTPHtmlResponse' on port 2000\n INFO [2012-06-03 23:44:35,603] server: Starting 'HTTPJsonResponse' on port 2001\n INFO [2012-06-03 23:44:35,604] server: Starting 'HTTPNoBodyResponse' on port 2002\n INFO [2012-06-03 23:44:35,604] server: Starting 'HTTPSlowResponse' on port 2003\n INFO [2012-06-03 23:44:35,604] server: Starting 'RSTResponse' on port 2020\n INFO [2012-06-03 23:44:35,604] server: Starting 'RandomDataResponse' on port 2021\n INFO [2012-06-03 23:44:35,604] server: Starting 'NoResponse' on port 2022\n INFO [2012-06-03 23:44:35,604] server: Starting 'LogRecordHandler' on port /tmp/_cynic.sock\n\n\nTest different services\n=======================\n\n1. Connect to the service on port 2020 and get a TCP RST packet\n right away which causes 'Connection reset by peer' message on the\n command line\n\n ::\n\n $ curl http://localhost:2020\n curl: (56) Recv failure: Connection reset by peer\n\n2. Connect to the service on port 2021 and get back 7 bytes of random data\n\n ::\n\n $ telnet localhost 2021\n Trying 127.0.0.1...\n Connected to localhost.\n Escape character is '^]'.\n #6\n Connection closed by foreign host.\n\n3. Connect to the service on port 2001 to get the HTTP JSON response\n\n ::\n\n $ curl http://localhost:2001\n {\"message\": \"Hello, World!\"}\n\n\nSo you got the basic idea. Point your application's integration points to the\nCynic's services and see how your app reacts.\n\n\nLet's check out Cynic's help options\n------------------------------------\n\n::\n\n $ cynic -h\n Usage: cynic [options]\n\n Test harness to make your system under test cynical\n\n Options:\n -h, --help show this help message and exit\n -c CONFIG_PATH, --config=CONFIG_PATH\n Path to an INI configuration file. If no configuration\n file is provided then default configuration is\n applied. To see the default configuration use -d\n option described below.\n -d, --dump Dump default configuration to STDOUT\n\n\nAs you can see if we start **Cynic** without **-c** option the default\nconfiguration is used and **-d** is used to dump that configuration to\nthe standard out.\n\nLet's see what's included in the default configuration\n\n\nDefault configuration\n---------------------\n\n::\n\n $ cynic -d\n\n ############################################################\n # HTTP protocol specific #\n ############################################################\n\n [handler:httphtml]\n # sends simple 'hello world!' HTML page over HTTP as a response\n # and terminates\n class = cynic.handlers.httphtml.HTTPHtmlResponse\n #args = ('/tmp/test.html', )\n host = 0.0.0.0\n port = 2000\n\n [handler:httpjson]\n # sends simple 'hello world!' JSON over HTTP as a response\n # and terminates\n class = cynic.handlers.httpjson.HTTPJsonResponse\n #args = ('/tmp/test.json', )\n host = 0.0.0.0\n port = 2001\n\n [handler:httpnone]\n # sends headers, but not the response body and terminates\n class = cynic.handlers.httpnone.HTTPNoBodyResponse\n host = 0.0.0.0\n port = 2002\n\n [handler:httpslow]\n # sends one byte of the response every 30 seconds.\n # when the data to be sent is exhausted - terminates\n class = cynic.handlers.httpslow.HTTPSlowResponse\n #args = ('/tmp/test.json', 'application/json', 1)\n host = 0.0.0.0\n port = 2003\n\n\n ############################################################\n # Any TCP socket protocol #\n ############################################################\n\n [handler:reset]\n # accepts a connection, sends an RST packet right away\n # and terminates\n class = cynic.handlers.reset.RSTResponse\n host = 0.0.0.0\n port = 2020\n\n [handler:random]\n # accepts a connection, sends 7 bytes from the /dev/urandom device\n # and terminates\n class = cynic.handlers.rnd.RandomDataResponse\n host = 0.0.0.0\n port = 2021\n\n [handler:noresp]\n # accepts a connection, but doesn't send any response back.\n # sleeps for 24 hours and exits\n class = cynic.handlers.noresp.NoResponse\n host = 0.0.0.0\n port = 2022\n\n ############################################################\n # System handlers used internally by the Cynic server #\n ############################################################\n\n [handler:unixlog]\n # a logging server that accepts connections over Unix socket\n # from multiple local processes to output passed log records\n class = cynic.handlers.log.LogRecordHandler\n host = /tmp/_cynic.sock\n port = 0\n family = unix\n\n\nThere are basically two types of handlers:\n\n1. The ones that deal with any TCP socket protocol\n2. HTTP specific handlers\n\n\nLet's have a closer look at some of them.\n\ncynic.handlers.httpslow.HTTPSlowResponse\n========================================\n\nThis handler sends one byte of the HTTP response every 30 seconds.\nThe config part is as follows\n\n::\n\n [handler:httpslow]\n # sends one byte of the response every 30 seconds.\n # when the data to be sent is exhausted - terminates\n class = cynic.handlers.httpslow.HTTPSlowResponse\n #args = ('/tmp/test.json', 'application/json', 1)\n host = 0.0.0.0\n port = 2003\n\nwhere\n\n*class* - a fully qualified dotted Python name of the handler class\n\n*args* - a tuple of Python values to pass as positional arguments to the handler's constructor.\n\n **First argument** specifies absolute path to a file to read\n the data from instead of using a default data sting 'Hello, world!'\n\n **Second argument** specifies the value of HTTP's Content-Type\n response header\n\n **Third argument** specifies time interval in seconds, default\n is 30, after which additional byte is sent to the client\n\n*host* - an IP address to bind the service to (For Unix socket it's a file path)\n\n*port* - port to listen on (not applicable for Unix sockets)\n\n\nEven with this service alone you can be creative and come up with\nseveral test scenarios that will make the life of your system under\ntest quite unbearable:\n\n1. Specify file in the *args* that contains megabytes of data and see how\n your system handles such a large response\n\n2. You can change file path and content type arguments to send HTML,\n JSON, XML, Plain text, etc\n\n3. You can send HTML data but set Content-Type header value to\n *application/json*\n\n4. You can change time interval to test your socket read timeout\n expiration or lack thereof.\n\n5. You can have all above as separate services on different ports.\n Just add *[handler:httpslow1]*, *[handler:httpslow2]*, etc. sections to\n the INI file and tweak the *args*.\n\n\nExtending Cynic with custom handlers\n------------------------------------\n\nIt's very easy to add your own handler to the Cynic.\n\n1. To add a new TCP handler inherit from *cynic.handlers.base.BaseHandler*\n and implement the *handle* method which directly interacts with a\n TCP socket.\n\n2. To add a new HTTP handler inherit from\n *cynic.handlers.base.BaseHTTPHandler* and implement your custom\n do_GET, do_POST, do_PUT, etc methods.\n For more information about the handler see `BaseHTTPRequestHandler `_\n\n3. Add a section *[handler:my_new_name]* to the INI configuration file with corresponding\n configuration parameters.\n\n**XXX: Full example?**\n\nAcknowledgments\n---------------\n\n- Many ideas are taken from `Release It! `_\n\n\nLicense\n-------\n\nCopyright (c) 2012 Ruslan Spivak\n\nPublished under The MIT License, see LICENSE\n\nChange History\n==============\n1.0 (2012-06-04)\n----------------\n- Public release", "description_content_type": null, "docs_url": null, "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/rspivak/cynic", "keywords": null, "license": "MIT", "maintainer": null, "maintainer_email": null, "name": "cynic", "package_url": "https://pypi.org/project/cynic/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/cynic/", "project_urls": { "Download": "UNKNOWN", "Homepage": "https://github.com/rspivak/cynic" }, "release_url": "https://pypi.org/project/cynic/1.0/", "requires_dist": null, "requires_python": null, "summary": "Test harness to make your system under test cynical", "version": "1.0" }, "last_serial": 788725, "releases": { "1.0": [ { "comment_text": "", "digests": { "md5": "83f70207b6aa2864881e95afea24c71a", "sha256": "b3f2f22036bd5fa2217e46ff5635aaafcc044746216232bc2ff8e58c0dde8a6f" }, "downloads": -1, "filename": "cynic-1.0.zip", "has_sig": false, "md5_digest": "83f70207b6aa2864881e95afea24c71a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30043, "upload_time": "2012-06-04T07:04:36", "url": "https://files.pythonhosted.org/packages/fc/e6/ff61c7443817f5460c89ed00f85d5a2611ca1f2cdb9352a18aa1621f1b7c/cynic-1.0.zip" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "83f70207b6aa2864881e95afea24c71a", "sha256": "b3f2f22036bd5fa2217e46ff5635aaafcc044746216232bc2ff8e58c0dde8a6f" }, "downloads": -1, "filename": "cynic-1.0.zip", "has_sig": false, "md5_digest": "83f70207b6aa2864881e95afea24c71a", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 30043, "upload_time": "2012-06-04T07:04:36", "url": "https://files.pythonhosted.org/packages/fc/e6/ff61c7443817f5460c89ed00f85d5a2611ca1f2cdb9352a18aa1621f1b7c/cynic-1.0.zip" } ] }