Éric Araujo | 3a9f58f | 2011-06-01 20:42:49 +0200 | [diff] [blame] | 1 | :mod:`packaging.tests.pypi_server` --- PyPI mock server |
| 2 | ======================================================= |
| 3 | |
| 4 | .. module:: packaging.tests.pypi_server |
| 5 | :synopsis: Mock server used to test PyPI-related modules and commands. |
| 6 | |
| 7 | |
| 8 | When you are testing code that works with Packaging, you might find these tools |
| 9 | useful. |
| 10 | |
| 11 | |
| 12 | The mock server |
| 13 | --------------- |
| 14 | |
| 15 | .. class:: PyPIServer |
| 16 | |
| 17 | PyPIServer is a class that implements an HTTP server running in a separate |
| 18 | thread. All it does is record the requests for further inspection. The recorded |
| 19 | data is available under ``requests`` attribute. The default |
| 20 | HTTP response can be overridden with the ``default_response_status``, |
| 21 | ``default_response_headers`` and ``default_response_data`` attributes. |
| 22 | |
| 23 | By default, when accessing the server with urls beginning with `/simple/`, |
| 24 | the server also record your requests, but will look for files under |
| 25 | the `/tests/pypiserver/simple/` path. |
| 26 | |
| 27 | You can tell the sever to serve static files for other paths. This could be |
| 28 | accomplished by using the `static_uri_paths` parameter, as below:: |
| 29 | |
| 30 | server = PyPIServer(static_uri_paths=["first_path", "second_path"]) |
| 31 | |
| 32 | |
| 33 | You need to create the content that will be served under the |
| 34 | `/tests/pypiserver/default` path. If you want to serve content from another |
| 35 | place, you also can specify another filesystem path (which needs to be under |
| 36 | `tests/pypiserver/`. This will replace the default behavior of the server, and |
| 37 | it will not serve content from the `default` dir :: |
| 38 | |
| 39 | server = PyPIServer(static_filesystem_paths=["path/to/your/dir"]) |
| 40 | |
| 41 | |
| 42 | If you just need to add some paths to the existing ones, you can do as shown, |
| 43 | keeping in mind that the server will always try to load paths in reverse order |
| 44 | (e.g here, try "another/super/path" then the default one) :: |
| 45 | |
| 46 | server = PyPIServer(test_static_path="another/super/path") |
| 47 | server = PyPIServer("another/super/path") |
| 48 | # or |
| 49 | server.static_filesystem_paths.append("another/super/path") |
| 50 | |
| 51 | |
| 52 | As a result of what, in your tests, while you need to use the PyPIServer, in |
| 53 | order to isolates the test cases, the best practice is to place the common files |
| 54 | in the `default` folder, and to create a directory for each specific test case:: |
| 55 | |
| 56 | server = PyPIServer(static_filesystem_paths = ["default", "test_pypi_server"], |
| 57 | static_uri_paths=["simple", "external"]) |
| 58 | |
| 59 | |
| 60 | Base class and decorator for tests |
| 61 | ---------------------------------- |
| 62 | |
| 63 | .. class:: PyPIServerTestCase |
| 64 | |
| 65 | ``PyPIServerTestCase`` is a test case class with setUp and tearDown methods that |
| 66 | take care of a single PyPIServer instance attached as a ``pypi`` attribute on |
| 67 | the test class. Use it as one of the base classes in your test case:: |
| 68 | |
| 69 | |
| 70 | class UploadTestCase(PyPIServerTestCase): |
| 71 | |
| 72 | def test_something(self): |
| 73 | cmd = self.prepare_command() |
| 74 | cmd.ensure_finalized() |
| 75 | cmd.repository = self.pypi.full_address |
| 76 | cmd.run() |
| 77 | |
| 78 | environ, request_data = self.pypi.requests[-1] |
| 79 | self.assertEqual(request_data, EXPECTED_REQUEST_DATA) |
| 80 | |
| 81 | |
| 82 | .. decorator:: use_pypi_server |
| 83 | |
| 84 | You also can use a decorator for your tests, if you do not need the same server |
| 85 | instance along all you test case. So, you can specify, for each test method, |
| 86 | some initialisation parameters for the server. |
| 87 | |
| 88 | For this, you need to add a `server` parameter to your method, like this:: |
| 89 | |
| 90 | class SampleTestCase(TestCase): |
| 91 | |
| 92 | @use_pypi_server() |
| 93 | def test_something(self, server): |
| 94 | ... |
| 95 | |
| 96 | |
| 97 | The decorator will instantiate the server for you, and run and stop it just |
| 98 | before and after your method call. You also can pass the server initializer, |
| 99 | just like this:: |
| 100 | |
| 101 | class SampleTestCase(TestCase): |
| 102 | |
| 103 | @use_pypi_server("test_case_name") |
| 104 | def test_something(self, server): |
| 105 | ... |