Adds documentation for Hyper-V testing
The Hyper-V Nova Compute plugin uses Windows Management Instrumentation (WMI) as the main API for hypervisor related operations. WMI has a database / procedural oriented nature that can become difficult to test with a traditional static mock / stub based unit testing approach. This document explains the architecture of the implemented infrastructure. Change-Id: I24e2893da487571ac82f44d1dc213c9cdb7166d0
This commit is contained in:
83
nova/tests/hyperv/README.rst
Normal file
83
nova/tests/hyperv/README.rst
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
=====================================
|
||||||
|
OpenStack Hyper-V Nova Testing Architecture
|
||||||
|
=====================================
|
||||||
|
|
||||||
|
The Hyper-V Nova Compute plugin uses Windows Management Instrumentation (WMI)
|
||||||
|
as the main API for hypervisor related operations.
|
||||||
|
WMI has a database / procedural oriented nature that can become difficult to
|
||||||
|
test with a traditional static mock / stub based unit testing approach.
|
||||||
|
|
||||||
|
The included Hyper-V testing framework has been developed with the
|
||||||
|
following goals:
|
||||||
|
|
||||||
|
1) Dynamic mock generation.
|
||||||
|
2) Decoupling. No dependencies on WMI or any other module.
|
||||||
|
The tests are designed to work with mocked objects in all cases, including
|
||||||
|
OS-dependent (e.g. wmi, os, subprocess) and non-deterministic
|
||||||
|
(e.g. time, uuid) modules
|
||||||
|
3) Transparency. Mocks and real objects can be swapped via DI
|
||||||
|
or monkey patching.
|
||||||
|
4) Platform independence.
|
||||||
|
5) Tests need to be executed against the real object or against the mocks
|
||||||
|
with a simple configuration switch. Development efforts can highly
|
||||||
|
benefit from this feature.
|
||||||
|
6) It must be possible to change a mock's behavior without running the tests
|
||||||
|
against the hypervisor (e.g. by manually adding a value / return value).
|
||||||
|
|
||||||
|
The tests included in this package include dynamically generated mock objects,
|
||||||
|
based on the recording of the attribute values and invocations on the
|
||||||
|
real WMI objects and other OS dependent features.
|
||||||
|
The generated mock objects are serialized in the nova/tests/hyperv/stubs
|
||||||
|
directory as gzipped pickled objects.
|
||||||
|
|
||||||
|
An environment variable controls the execution mode of the tests.
|
||||||
|
|
||||||
|
Recording mode:
|
||||||
|
|
||||||
|
NOVA_GENERATE_TEST_MOCKS=True
|
||||||
|
Tests are executed on the hypervisor (without mocks), and mock objects are
|
||||||
|
generated.
|
||||||
|
|
||||||
|
Replay mode:
|
||||||
|
|
||||||
|
NOVA_GENERATE_TEST_MOCKS=
|
||||||
|
Tests are executed with the existing mock objects (default).
|
||||||
|
|
||||||
|
Mock generation is performed by nova.tests.hyperv.mockproxy.MockProxy.
|
||||||
|
Instances of this class wrap objects that need to be mocked and act as a
|
||||||
|
delegate on the wrapped object by leveraging Python's __getattr__ feature.
|
||||||
|
Attribute values and method call return values are recorded at each access.
|
||||||
|
Objects returned by attributes and method invocations are wrapped in a
|
||||||
|
MockProxy consistently.
|
||||||
|
From a caller perspective, the MockProxy is completely transparent,
|
||||||
|
with the exception of calls to the type(...) builtin function.
|
||||||
|
|
||||||
|
At the end of the test, a mock is generated by each MockProxy by calling
|
||||||
|
the get_mock() method. A mock is represented by an instance of the
|
||||||
|
nova.tests.hyperv.mockproxy.Mock class.
|
||||||
|
|
||||||
|
The Mock class task consists of replicating the behaviour of the mocked
|
||||||
|
objects / modules by returning the same values in the same order, for example:
|
||||||
|
|
||||||
|
def check_path(path):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
|
||||||
|
check_path(path)
|
||||||
|
# The second time os.path.exists returns True
|
||||||
|
check_path(path)
|
||||||
|
|
||||||
|
The injection of MockProxy / Mock instances is performed by the
|
||||||
|
nova.tests.hyperv.basetestcase.BaseTestCase class in the setUp()
|
||||||
|
method via selective monkey patching.
|
||||||
|
Mocks are serialized in tearDown() during recording.
|
||||||
|
|
||||||
|
The actual Hyper-V test case inherits from BaseTestCase:
|
||||||
|
nova.tests.hyperv.test_hypervapi.HyperVAPITestCase
|
||||||
|
|
||||||
|
|
||||||
|
Future directions:
|
||||||
|
|
||||||
|
1) Replace the pickled files with a more generic serialization option (e.g. json)
|
||||||
|
2) Add methods to statically extend the mocks (e.g. method call return values)
|
||||||
|
3) Extend an existing framework, e.g. mox
|
Reference in New Issue
Block a user