Writing tests and using the fixture framework
This section describes how to write tests for the provider drivers and how to use our fixture framework and system for mocking the responses.
Examples in this section refer to the compute API but things described in this section are also applicable to other APIs.
Creating Fixtures
In our test cases fixtures store different responses returned by the provider APIs.
They are stored and named in the following format:
test/<api name>/fixtures/<provider name>/<fixture name>
.
Fixtures are usually generated by "manually" performing (usually using a tool like curl) different actions with the provider API and saving responses in the files.
Note: You are advised against using the examples from the provider API docs because empirical evidence has shown that in a lot of cases they are wrong or out of date.
Mocking responses and using MockHttp class
Each provider test file usually contains a class which inherits from the base MockHttp
class.
This class is responsible for loading fixtures and returning a mocked response for
each API call.
Which method is called is primary determined by the requested path. All the forward slashes,
periods and dashes in the requested path are replaced by an underscore (_
).
Some examples:
Requested path: /servers/list.all
use_params: MockHttp.use_params = None
Name of the method on the Mock class: _servers_list_all
Requested path: /servers/reboot-all
use_params: MockHttp.use_params = None
Name of the method on the Mock class: _servers_reboot_all
Some providers use the same path for all the requests and the actual action is determined by
some parameter in a query string. To overcome this problem, set the use_param
MockHttp class
attribute to the name of the query string parameter which specifies the action.
Good example of a provider API which does this is the Amazon EC2 API
(test/compute/test_ec2.py
).
Example:
Requested path: /?Action=RebootInstances&InstanceId=12345
use_params: MockHttp.use_params = 'Action'
Name of the method on the Mock class: _RebootInstances
Usually we also want to test different scenarios for a single API call. Good example of this is testing a success and different failure scenarios when creating a node. Because we are testing a single API call, this means that the request path will in most cases be the same. This makes loading a different response fixture for each API call without inspecting the request parameters or doing something similar very cumbersome.
This problem can be overcome by setting the type
attribute on the MockHttp
class before
issuing a request. The specified type
will be automatically appended to the end of the
constructed method name.
Example:
Requested path: /servers/reboot-all
use_params: MockHttp.use_params = None
type: MockHttp.type = 'FAILURE'
Name of the method on the Mock class: _servers_reboot_all_FAILURE
MockHttp class example
Bellow is an example of a MockHttp class from the Amazon EC2 tests with a single method.
Return value of a mock method is a tuple - (status_code, response_body, response_headers, response_status_string).
- response_code (intger) - response status code (httplib.OK, httplib.NOT_FOUND, ...)
- response_body (string) - actual mocked response body which is usually read from a fixture
- response_headers (dictionary) - response headers
-
response_status_string (string) - string representation of the response status code (httplib.responses[httplib.OK], httplib.responses[httplib.CONTINUE], ...)
::python class EC2MockHttp(MockHttp):
fixtures = ComputeFileFixtures('ec2') def _DescribeInstances(self, method, url, body, headers): body = self.fixtures.load('describe_instances.xml') return (httplib.OK, body, {'Content-Type': 'application/xml'}, httplib.responses[httplib.OK])