Matthew Treinish | 3a851dc | 2015-07-30 11:34:03 -0400 | [diff] [blame] | 1 | ============================= |
| 2 | Tempest Test Plugin Interface |
| 3 | ============================= |
| 4 | |
| 5 | Tempest has an external test plugin interface which enables anyone to integrate |
| 6 | an external test suite as part of a tempest run. This will let any project |
| 7 | leverage being run with the rest of the tempest suite while not requiring the |
| 8 | tests live in the tempest tree. |
| 9 | |
| 10 | Creating a plugin |
| 11 | ================= |
| 12 | |
| 13 | Creating a plugin is fairly straightforward and doesn't require much additional |
| 14 | effort on top of creating a test suite using tempest-lib. One thing to note with |
| 15 | doing this is that the interfaces exposed by tempest are not considered stable |
| 16 | (with the exception of configuration variables which ever effort goes into |
| 17 | ensuring backwards compatibility). You should not need to import anything from |
| 18 | tempest itself except where explicitly noted. If there is an interface from |
| 19 | tempest that you need to rely on in your plugin it likely needs to be migrated |
| 20 | to tempest-lib. In that situation, file a bug, push a migration patch, etc. to |
| 21 | expedite providing the interface in a reliable manner. |
| 22 | |
Marc Koderer | 66210aa | 2015-10-26 10:52:32 +0100 | [diff] [blame] | 23 | Plugin Cookiecutter |
| 24 | ------------------- |
| 25 | |
| 26 | In order to create the basic structure with base classes and test directories |
| 27 | you can use the tempest-plugin-cookiecutter project:: |
| 28 | |
Yuiko Takada | ccb2bbf | 2015-11-17 10:09:44 +0900 | [diff] [blame] | 29 | > pip install -U cookiecutter && cookiecutter https://git.openstack.org/openstack/tempest-plugin-cookiecutter |
Marc Koderer | 66210aa | 2015-10-26 10:52:32 +0100 | [diff] [blame] | 30 | |
| 31 | Cloning into 'tempest-plugin-cookiecutter'... |
| 32 | remote: Counting objects: 17, done. |
| 33 | remote: Compressing objects: 100% (13/13), done. |
| 34 | remote: Total 17 (delta 1), reused 14 (delta 1) |
| 35 | Unpacking objects: 100% (17/17), done. |
| 36 | Checking connectivity... done. |
| 37 | project (default is "sample")? foo |
| 38 | testclass (default is "SampleTempestPlugin")? FooTempestPlugin |
| 39 | |
| 40 | This would create a folder called ``foo_tempest_plugin/`` with all necessary |
| 41 | basic classes. You only need to move/create your test in |
| 42 | ``foo_tempest_plugin/tests``. |
| 43 | |
| 44 | Entry Point |
| 45 | ----------- |
| 46 | |
| 47 | Once you've created your plugin class you need to add an entry point to your |
| 48 | project to enable tempest to find the plugin. The entry point must be added |
| 49 | to the "tempest.test_plugins" namespace. |
| 50 | |
| 51 | If you are using pbr this is fairly straightforward, in the setup.cfg just add |
| 52 | something like the following:: |
| 53 | |
| 54 | [entry_points] |
| 55 | tempest.test_plugins = |
| 56 | plugin_name = module.path:PluginClass |
| 57 | |
Matthew Treinish | 3a851dc | 2015-07-30 11:34:03 -0400 | [diff] [blame] | 58 | Plugin Class |
Marc Koderer | 66210aa | 2015-10-26 10:52:32 +0100 | [diff] [blame] | 59 | ============ |
Matthew Treinish | 3a851dc | 2015-07-30 11:34:03 -0400 | [diff] [blame] | 60 | |
| 61 | To provide tempest with all the required information it needs to be able to run |
| 62 | your plugin you need to create a plugin class which tempest will load and call |
| 63 | to get information when it needs. To simplify creating this tempest provides an |
| 64 | abstract class that should be used as the parent for your plugin. To use this |
| 65 | you would do something like the following:: |
| 66 | |
YAMAMOTO Takashi | cb2ac6e | 2015-10-19 15:54:42 +0900 | [diff] [blame] | 67 | from tempest.test_discover import plugins |
Matthew Treinish | 3a851dc | 2015-07-30 11:34:03 -0400 | [diff] [blame] | 68 | |
YAMAMOTO Takashi | cb2ac6e | 2015-10-19 15:54:42 +0900 | [diff] [blame] | 69 | class MyPlugin(plugins.TempestPlugin): |
Matthew Treinish | 3a851dc | 2015-07-30 11:34:03 -0400 | [diff] [blame] | 70 | |
| 71 | Then you need to ensure you locally define all of the methods in the abstract |
| 72 | class, you can refer to the api doc below for a reference of what that entails. |
| 73 | |
| 74 | Also, note eventually this abstract class will likely live in tempest-lib, when |
| 75 | that migration occurs a deprecation shim will be added to tempest so as to not |
| 76 | break any existing plugins. But, when that occurs migrating to using tempest-lib |
| 77 | as the source for the abstract class will be prudent. |
| 78 | |
| 79 | Abstract Plugin Class |
Marc Koderer | 66210aa | 2015-10-26 10:52:32 +0100 | [diff] [blame] | 80 | --------------------- |
Matthew Treinish | 3a851dc | 2015-07-30 11:34:03 -0400 | [diff] [blame] | 81 | |
| 82 | .. autoclass:: tempest.test_discover.plugins.TempestPlugin |
| 83 | :members: |
| 84 | |
Matthew Treinish | 3a851dc | 2015-07-30 11:34:03 -0400 | [diff] [blame] | 85 | Plugin Structure |
Marc Koderer | 66210aa | 2015-10-26 10:52:32 +0100 | [diff] [blame] | 86 | ================ |
Matthew Treinish | 3a851dc | 2015-07-30 11:34:03 -0400 | [diff] [blame] | 87 | While there are no hard and fast rules for the structure a plugin, there are |
| 88 | basically no constraints on what the plugin looks like as long as the 2 steps |
| 89 | above are done. However, there are some recommended patterns to follow to make |
| 90 | it easy for people to contribute and work with your plugin. For example, if you |
| 91 | create a directory structure with something like:: |
| 92 | |
| 93 | plugin_dir/ |
| 94 | config.py |
| 95 | plugin.py |
| 96 | tests/ |
| 97 | api/ |
| 98 | scenario/ |
| 99 | services/ |
| 100 | client.py |
| 101 | |
| 102 | That will mirror what people expect from tempest. The file |
| 103 | |
| 104 | * **config.py**: contains any plugin specific configuration variables |
| 105 | * **plugin.py**: contains the plugin class used for the entry point |
| 106 | * **tests**: the directory where test discovery will be run, all tests should |
| 107 | be under this dir |
| 108 | * **services**: where the plugin specific service clients are |
| 109 | |
| 110 | Additionally, when you're creating the plugin you likely want to follow all |
| 111 | of the tempest developer and reviewer documentation to ensure that the tests |
| 112 | being added in the plugin act and behave like the rest of tempest. |
| 113 | |
Matthew Treinish | 9392a83 | 2015-08-24 10:00:49 -0400 | [diff] [blame] | 114 | Dealing with configuration options |
Marc Koderer | 66210aa | 2015-10-26 10:52:32 +0100 | [diff] [blame] | 115 | ---------------------------------- |
Matthew Treinish | 9392a83 | 2015-08-24 10:00:49 -0400 | [diff] [blame] | 116 | |
| 117 | Historically Tempest didn't provide external guarantees on its configuration |
| 118 | options. However, with the introduction of the plugin interface this is no |
| 119 | longer the case. An external plugin can rely on using any configuration option |
| 120 | coming from Tempest, there will be at least a full deprecation cycle for any |
| 121 | option before it's removed. However, just the options provided by Tempest |
| 122 | may not be sufficient for the plugin. If you need to add any plugin specific |
| 123 | configuration options you should use the ``register_opts`` and |
| 124 | ``get_opt_lists`` methods to pass them to Tempest when the plugin is loaded. |
| 125 | When adding configuration options the ``register_opts`` method gets passed the |
| 126 | CONF object from tempest. This enables the plugin to add options to both |
| 127 | existing sections and also create new configuration sections for new options. |
| 128 | |
Matthew Treinish | 3a851dc | 2015-07-30 11:34:03 -0400 | [diff] [blame] | 129 | Using Plugins |
| 130 | ============= |
| 131 | |
| 132 | Tempest will automatically discover any installed plugins when it is run. So by |
| 133 | just installing the python packages which contain your plugin you'll be using |
| 134 | them with tempest, nothing else is really required. |
| 135 | |
| 136 | However, you should take care when installing plugins. By their very nature |
| 137 | there are no guarantees when running tempest with plugins enabled about the |
| 138 | quality of the plugin. Additionally, while there is no limitation on running |
| 139 | with multiple plugins it's worth noting that poorly written plugins might not |
| 140 | properly isolate their tests which could cause unexpected cross interactions |
| 141 | between plugins. |
| 142 | |
| 143 | Notes for using plugins with virtualenvs |
| 144 | ---------------------------------------- |
| 145 | |
| 146 | When using a tempest inside a virtualenv (like when running under tox) you have |
| 147 | to ensure that the package that contains your plugin is either installed in the |
| 148 | venv too or that you have system site-packages enabled. The virtualenv will |
| 149 | isolate the tempest install from the rest of your system so just installing the |
| 150 | plugin package on your system and then running tempest inside a venv will not |
| 151 | work. |
| 152 | |
| 153 | Tempest also exposes a tox job, all-plugin, which will setup a tox virtualenv |
| 154 | with system site-packages enabled. This will let you leverage tox without |
| 155 | requiring to manually install plugins in the tox venv before running tests. |