blob: 3626a3f33cb9873ff6502d66ed8c1962df4d6f98 [file] [log] [blame]
Matthew Treinishe8ab5f92017-03-01 15:25:39 -05001.. _tempest_test_writing:
2
3Tempest Test Writing Guide
Matthew Treinish8f28d1f2017-04-08 21:35:41 -04004##########################
Matthew Treinishe8ab5f92017-03-01 15:25:39 -05005
6This guide serves as a starting point for developers working on writing new
deepak_mouryae495cd22018-07-16 12:38:17 +05307Tempest tests. At a high level, tests in Tempest are just tests that conform to
Matthew Treinishe8ab5f92017-03-01 15:25:39 -05008the standard python `unit test`_ framework. But there are several aspects of
Jordan Pittier74a56ab2017-04-26 16:46:20 +02009that are unique to Tempest and its role as an integration test suite running
Matthew Treinishe8ab5f92017-03-01 15:25:39 -050010against a real cloud.
11
12.. _unit test: https://docs.python.org/3.6/library/unittest.html
13
Jordan Pittier74a56ab2017-04-26 16:46:20 +020014.. note:: This guide is for writing tests in the Tempest repository. While many
15 parts of this guide are also applicable to Tempest plugins, not all
Matthew Treinishe8ab5f92017-03-01 15:25:39 -050016 the APIs mentioned are considered stable or recommended for use in
17 plugins. Please refer to :ref:`tempest_plugin` for details about
18 writing plugins
19
20
21Adding a New TestCase
22=====================
23
24The base unit of testing in Tempest is the `TestCase`_ (also called the test
25class). Each TestCase contains test methods which are the individual tests that
26will be executed by the test runner. But, the TestCase is the smallest self
Jordan Pittier74a56ab2017-04-26 16:46:20 +020027contained unit for tests from the Tempest perspective. It's also the level at
28which Tempest is parallel safe. In other words, multiple TestCases can be
Matthew Treinishe8ab5f92017-03-01 15:25:39 -050029executed in parallel, but individual test methods in the same TestCase can not.
30Also, all test methods within a TestCase are assumed to be executed serially. As
31such you can use the test case to store variables that are shared between
32methods.
33
34.. _TestCase: https://docs.python.org/3.6/library/unittest.html#unittest.TestCase
35
36In standard unittest the lifecycle of a TestCase can be described in the
37following phases:
38
Masayuki Igawab78b9232017-11-17 16:12:37 +090039#. setUpClass
40#. setUp
41#. Test Execution
42#. tearDown
43#. doCleanups
44#. tearDownClass
Matthew Treinishe8ab5f92017-03-01 15:25:39 -050045
46setUpClass
47----------
48
49The setUpClass phase is the first phase executed by the test runner and is used
50to perform any setup required for all the test methods to be executed. In
51Tempest this is a very important step and will automatically do the necessary
52setup for interacting with the configured cloud.
53
54To accomplish this you do **not** define a setUpClass function, instead there
55are a number of predefined phases to setUpClass that are used. The phases are:
56
Masayuki Igawab78b9232017-11-17 16:12:37 +090057* skip_checks
58* setup_credentials
59* setup_clients
60* resource_setup
Matthew Treinishe8ab5f92017-03-01 15:25:39 -050061
Andrea Frittoli3be57482017-08-25 22:41:26 +010062which is executed in that order. Cleanup of resources provisioned during
63the resource_setup must be scheduled right after provisioning using
zhufl8d1c71e2017-12-08 17:11:43 +080064the addClassResourceCleanup helper. The resource cleanups stacked this way
Andrea Frittoli3be57482017-08-25 22:41:26 +010065are executed in reverse order during tearDownClass, before the cleanup of
66test credentials takes place. An example of a TestCase which defines all
Matthew Treinishe8ab5f92017-03-01 15:25:39 -050067of these would be::
Masayuki Igawab78b9232017-11-17 16:12:37 +090068
Andrea Frittoli3be57482017-08-25 22:41:26 +010069 from tempest.common import waiters
Matthew Treinishe8ab5f92017-03-01 15:25:39 -050070 from tempest import config
Andrea Frittoli3be57482017-08-25 22:41:26 +010071 from tempest.lib.common.utils import test_utils
Matthew Treinishe8ab5f92017-03-01 15:25:39 -050072 from tempest import test
73
74 CONF = config.CONF
75
76
77 class TestExampleCase(test.BaseTestCase):
78
Roman Doboszedda62a2020-12-01 14:40:45 +010079 @classmethod
80 def skip_checks(cls):
81 """This section is used to evaluate config early and skip all test
82 methods based on these checks
83 """
84 super(TestExampleCase, cls).skip_checks()
85 if not CONF.section.foo
86 cls.skip('A helpful message')
Matthew Treinishe8ab5f92017-03-01 15:25:39 -050087
Roman Doboszedda62a2020-12-01 14:40:45 +010088 @classmethod
89 def setup_credentials(cls):
90 """This section is used to do any manual credential allocation and also
91 in the case of dynamic credentials to override the default network
92 resource creation/auto allocation
93 """
94 # This call is used to tell the credential allocator to not create any
95 # network resources for this test case. It also enables selective
96 # creation of other neutron resources. NOTE: it must go before the
97 # super call
98 cls.set_network_resources()
99 super(TestExampleCase, cls).setup_credentials()
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500100
Roman Doboszedda62a2020-12-01 14:40:45 +0100101 @classmethod
102 def setup_clients(cls):
103 """This section is used to setup client aliases from the manager object
104 or to initialize any additional clients. Except in a few very
105 specific situations you should not need to use this.
106 """
107 super(TestExampleCase, cls).setup_clients()
108 cls.servers_client = cls.os_primary.servers_client
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500109
Roman Doboszedda62a2020-12-01 14:40:45 +0100110 @classmethod
111 def resource_setup(cls):
112 """This section is used to create any resources or objects which are
113 going to be used and shared by **all** test methods in the
114 TestCase. Note then anything created in this section must also be
115 destroyed in the corresponding resource_cleanup() method (which will
116 be run during tearDownClass())
117 """
118 super(TestExampleCase, cls).resource_setup()
119 cls.shared_server = cls.servers_client.create_server(...)
120 cls.addClassResourceCleanup(waiters.wait_for_server_termination,
121 cls.servers_client,
122 cls.shared_server['id'])
123 cls.addClassResourceCleanup(
124 test_utils.call_and_ignore_notfound_exc(
125 cls.servers_client.delete_server,
126 cls.shared_server['id']))
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500127
Matthew Treinish19b7ba42017-04-09 20:39:49 -0400128.. _credentials:
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500129
130Allocating Credentials
131''''''''''''''''''''''
132
133Since Tempest tests are all about testing a running cloud, every test will need
134credentials to be able to make API requests against the cloud. Since this is
135critical to operation and, when running in parallel, easy to make a mistake,
136the base TestCase class will automatically allocate a regular user for each
137TestCase during the setup_credentials() phase. During this process it will also
138initialize a client manager object using those credentials, which will be your
139entry point into interacting with the cloud. For more details on how credentials
140are allocated the :ref:`tempest_cred_provider_conf` section of the Tempest
141Configuration Guide provides more details on the operation of this.
142
143There are some cases when you need more than a single set of credentials, or
144credentials with a more specialized set of roles. To accomplish this you have
145to set a class variable ``credentials`` on the TestCase directly. For example::
146
147 from tempest import test
148
149 class TestExampleAdmin(test.BaseTestCase):
150
151 credentials = ['primary', 'admin']
152
Roman Doboszedda62a2020-12-01 14:40:45 +0100153 @classmethod
154 def skip_checks(cls):
155 ...
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500156
157In this example the ``TestExampleAdmin`` TestCase will allocate 2 sets of
158credentials, one regular user and one admin user. The corresponding manager
Jordan Pittier8160d312017-04-18 11:52:23 +0200159objects will be set as class variables ``cls.os_primary`` and ``cls.os_admin``
160respectively. You can also allocate a second user by putting **'alt'** in the
161list too. A set of alt credentials are the same as primary but can be used
162for tests cases that need a second user/project.
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500163
164You can also specify credentials with specific roles assigned. This is useful
165for cases where there are specific RBAC requirements hard coded into an API.
166The canonical example of this are swift tests which often want to test swift's
Jordan Pittier74a56ab2017-04-26 16:46:20 +0200167concepts of operator and reseller_admin. An actual example from Tempest on how
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500168to do this is::
169
170 class PublicObjectTest(base.BaseObjectTest):
171
172 credentials = [['operator', CONF.object_storage.operator_role],
173 ['operator_alt', CONF.object_storage.operator_role]]
174
175 @classmethod
176 def setup_credentials(cls):
177 super(PublicObjectTest, cls).setup_credentials()
178 ...
179
180In this case the manager objects will be set to ``cls.os_roles_operator`` and
181``cls.os_roles_operator_alt`` respectively.
182
183
184There is no limit to how many credentials you can allocate in this manner,
185however in almost every case you should **not** need more than 3 sets of
186credentials per test case.
187
188To figure out the mapping of manager objects set on the TestCase and the
189requested credentials you can reference:
190
191+-------------------+---------------------+
192| Credentials Entry | Manager Variable |
193+===================+=====================+
zhufl04190882017-05-23 10:21:48 +0800194| primary | cls.os_primary |
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500195+-------------------+---------------------+
zhufl04190882017-05-23 10:21:48 +0800196| admin | cls.os_admin |
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500197+-------------------+---------------------+
198| alt | cls.os_alt |
199+-------------------+---------------------+
200| [$label, $role] | cls.os_roles_$label |
201+-------------------+---------------------+
202
Jordan Pittier74a56ab2017-04-26 16:46:20 +0200203By default cls.os_primary is available since it is allocated in the base Tempest test
zhufl2e644e62017-04-21 14:14:54 +0800204class (located in tempest/test.py). If your TestCase inherits from a different
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500205direct parent class (it'll still inherit from the BaseTestCase, just not
206directly) be sure to check if that class overrides allocated credentials.
207
208Dealing with Network Allocation
209'''''''''''''''''''''''''''''''
210
Jordan Pittier74a56ab2017-04-26 16:46:20 +0200211When Neutron is enabled and a testing requires networking this isn't normally
212automatically setup when a tenant is created. Since Tempest needs isolated
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500213tenants to function properly it also needs to handle network allocation. By
214default the base test class will allocate a network, subnet, and router
zhufl2e644e62017-04-21 14:14:54 +0800215automatically (this depends on the configured credential provider, for more
216details see: :ref:`tempest_conf_network_allocation`). However, there are
217situations where you do no need all of these resources allocated (or your
218TestCase inherits from a class that overrides the default in tempest/test.py).
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500219There is a class level mechanism to override this allocation and specify which
220resources you need. To do this you need to call `cls.set_network_resources()`
221in the `setup_credentials()` method before the `super()`. For example::
222
223 from tempest import test
224
225
226 class TestExampleCase(test.BaseTestCase):
227
Roman Doboszedda62a2020-12-01 14:40:45 +0100228 @classmethod
229 def setup_credentials(cls):
230 cls.set_network_resources(network=True, subnet=True, router=False)
231 super(TestExampleCase, cls).setup_credentials()
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500232
233There are 2 quirks with the usage here. First for the set_network_resources
234function to work properly it **must be called before super()**. This is so
235that children classes' settings are always used instead of a parent classes'.
236The other quirk here is that if you do not want to allocate any network
237resources for your test class simply call `set_network_resources()` without
238any arguments. For example::
239
240 from tempest import test
241
242
243 class TestExampleCase(test.BaseTestCase):
244
Roman Doboszedda62a2020-12-01 14:40:45 +0100245 @classmethod
246 def setup_credentials(cls):
247 cls.set_network_resources()
248 super(TestExampleCase, cls).setup_credentials()
Matthew Treinishe8ab5f92017-03-01 15:25:39 -0500249
250This will not allocate any networking resources. This is because by default all
251the arguments default to False.
252
253It's also worth pointing out that it is common for base test classes for
254different services (and scenario tests) to override this setting. When
255inheriting from classes other than the base TestCase in tempest/test.py it is
256worth checking the immediate parent for what is set to determine if your
257class needs to override that setting.
Matthew Treinish19b7ba42017-04-09 20:39:49 -0400258
Balazs Gibizerdfb30432021-12-14 17:25:16 +0100259Running some tests in serial
260----------------------------
261Tempest potentially runs test cases in parallel, depending on the configuration.
262However, sometimes you need to make sure that tests are not interfering with
263each other via OpenStack resources. Tempest creates separate projects for each
264test class to separate project based resources between test cases.
265
266If your tests use resources outside of projects, e.g. host aggregates then
267you might need to explicitly separate interfering test cases. If you only need
268to separate a small set of testcases from each other then you can use the
269``LockFixture``.
270
271However, in some cases a small set of tests needs to be run independently from
272the rest of the test cases. For example, some of the host aggregate and
273availability zone testing needs compute nodes without any running nova server
274to be able to move compute hosts between availability zones. But many tempest
275tests start one or more nova servers. In this scenario you can mark the small
276set of tests that needs to be independent from the rest with the ``@serial``
277class decorator. This will make sure that even if tempest is configured to run
278the tests in parallel the tests in the marked test class will always be executed
279separately from the rest of the test cases.
280
281Please note that due to test ordering optimization reasons test cases marked
282for ``@serial`` execution need to be put under ``tempest/serial_tests``
283directory. This will ensure that the serial tests will block the parallel tests
284in the least amount of time.
285
Matthew Treinish19b7ba42017-04-09 20:39:49 -0400286Interacting with Credentials and Clients
287========================================
288
289Once you have your basic TestCase setup you'll want to start writing tests. To
290do that you need to interact with an OpenStack deployment. This section will
291cover how credentials and clients are used inside of Tempest tests.
292
293
294Manager Objects
295---------------
296
297The primary interface with which you interact with both credentials and
298API clients is the client manager object. These objects are created
zhufl2e644e62017-04-21 14:14:54 +0800299automatically by the base test class as part of credential setup (for more
300details see the previous :ref:`credentials` section). Each manager object is
Matthew Treinish19b7ba42017-04-09 20:39:49 -0400301initialized with a set of credentials and has each client object already setup
302to use that set of credentials for making all the API requests. Each client is
303accessible as a top level attribute on the manager object. So to start making
304API requests you just access the client's method for making that call and the
305credentials are already setup for you. For example if you wanted to make an API
306call to create a server in Nova::
307
308 from tempest import test
309
310
311 class TestExampleCase(test.BaseTestCase):
Roman Doboszedda62a2020-12-01 14:40:45 +0100312 def test_example_create_server(self):
313 self.os_primary.servers_client.create_server(...)
Matthew Treinish19b7ba42017-04-09 20:39:49 -0400314
zhufl04190882017-05-23 10:21:48 +0800315is all you need to do. As described previously, in the above example the
316``self.os_primary`` is created automatically because the base test class sets the
317``credentials`` attribute to allocate a primary credential set and initializes
318the client manager as ``self.os_primary``. This same access pattern can be used
319for all of the clients in Tempest.
Matthew Treinish19b7ba42017-04-09 20:39:49 -0400320
321Credentials Objects
322-------------------
323
zhufl2e644e62017-04-21 14:14:54 +0800324In certain cases you need direct access to the credentials (the most common
Matthew Treinish19b7ba42017-04-09 20:39:49 -0400325use case would be an API request that takes a user or project id in the request
zhufl2e644e62017-04-21 14:14:54 +0800326body). If you're in a situation where you need to access this you'll need to
Matthew Treinish19b7ba42017-04-09 20:39:49 -0400327access the ``credentials`` object which is allocated from the configured
328credential provider in the base test class. This is accessible from the manager
329object via the manager's ``credentials`` attribute. For example::
330
331 from tempest import test
332
333
334 class TestExampleCase(test.BaseTestCase):
Roman Doboszedda62a2020-12-01 14:40:45 +0100335 def test_example_create_server(self):
336 credentials = self.os_primary.credentials
Matthew Treinish19b7ba42017-04-09 20:39:49 -0400337
338The credentials object provides access to all of the credential information you
339would need to make API requests. For example, building off the previous
340example::
341
342 from tempest import test
343
344
345 class TestExampleCase(test.BaseTestCase):
Roman Doboszedda62a2020-12-01 14:40:45 +0100346 def test_example_create_server(self):
347 credentials = self.os_primary.credentials
348 username = credentials.username
349 user_id = credentials.user_id
350 password = credentials.password
351 tenant_id = credentials.tenant_id