1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
|
.. highlight:: yaml
Test Format
===========
Gabbi tests are expressed in YAML as a series of HTTP requests with their
expected response::
tests:
- name: retrieve root
GET: /
status: 200
This will trigger a ``GET`` request to ``/`` on the configured :doc:`host`. The
test will pass if the response's status code is ``200``.
.. _test-structure:
Test Structure
--------------
The top-level ``tests`` category contains an ordered sequence of test
declarations, each describing the expected response to a given request:
.. _metadata:
Metadata
********
.. list-table::
:header-rows: 1
* - Key
- Description
- Notes
* - ``name``
- The test's name. Must be unique within a file.
- **required**
* - ``desc``
- An arbitrary string describing the test.
-
* - ``verbose``
- If ``True`` or ``all`` (synonymous), prints a representation of the
current request and response to ``stdout``, including both headers and
body. If set to ``headers`` or ``body``, only the corresponding part of
the request and response will be printed. If the output is a TTY, colors
will be used. If the body content-type is JSON it will be formatted for
improved readability. See :class:`~gabbi.httpclient.VerboseHttp` for
details.
- defaults to ``False``
* - ``skip``
- A string message which if set will cause the test to be skipped with the
provided message.
- defaults to ``False``
* - ``xfail``
- Determines whether to expect this test to fail. Note that the test will
be run anyway.
- defaults to ``False``
* - ``use_prior_test``
- Determines if this test will be run in sequence (after) the test prior
to it in the list of tests within a file. To be concrete, when this is
``True`` the test is dependent on the prior test and if that prior
has not yet run, it wil be run, even if only the current test has been
selected. Set this to ``False`` to allow selecting a test without
dependencies.
- defaults to ``True``
* - ``cert_validate``
- States whether the underlying HTTP client should attempt to validate SSL
certificates. In many test environment certificates will be self-signed
so changing this may be requried. It can also be changed when
:doc:`loader` or using :doc:`gabbi-run <runner>`.
- defaults to ``True``
* - ``timeout``
- Sets a timeout (in seconds) for the HTTP request.
- defaults to ``30`` seconds
* - ``disable_response_handler``
- If ``True``, means that the response body will not be processed to
Python data. This can be necessary if a response claims a
``content-type`` but the body is not actually that type but it is still
necessary to run tests against the response. In that situation, if
``disable_response_handler`` is ``False`` the test will be treated as
a failure.
- defaults to ``False``
.. note:: When tests are generated dynamically, the ``TestCase`` name will
include the respective test's ``name``, lowercased with spaces
transformed to ``_``. In at least some test runners this will allow
you to select and filter on test name.
.. _request-parameters:
Request Parameters
******************
.. table::
==================== ======================================== ============
Key Description Notes
==================== ======================================== ============
any uppercase string Any such key is considered an HTTP
method, with the corresponding value
expressing the URL.
This is a shortcut combining ``method``
and ``url`` into a single statement::
GET: /index
corresponds to::
method: GET
url: /index
``method`` The HTTP request method. defaults to
``GET``
``url`` The URL to request. This can either be a Either this
full path (e.g. "/index") or a fully or the
qualified URL (i.e. including host and shortcut
scheme, e.g. above is
"http://example.org/index") — see **required**
:doc:`host` for details.
``request_headers`` A dictionary of key-value pairs
representing request header names and
values. These will be added to the
constructed request.
``query_parameters`` A dictionary of query parameters that
will be added to the ``url`` as query
string. If that URL already contains a
set of query parameters, those wil be
extended. See :doc:`example` for a
demonstration of how the data is
structured.
``data`` A representation to pass as the body of
a request. Note that ``content-type`` in
``request_headers`` should also be set —
see `Data`_ for details.
``redirects`` If ``True``, redirects will defaults to
automatically be followed. ``False``
``ssl`` Determines whether the request uses SSL defaults to
(i.e. HTTPS). Note that the ``url``'s ``False``
scheme takes precedence if present — see
:doc:`host` for details.
==================== ======================================== ============
.. _response-expectations:
Response Expectations
*********************
.. table::
============================== ===================================== ============
Key Description Notes
============================== ===================================== ============
``status`` The expected response status code. defaults to
Multiple acceptable response codes ``200``
may be provided, separated by ``||``
(e.g. ``302 || 301`` — note, however,
that this indicates ambiguity, which
is generally undesirable).
``response_headers`` A dictionary of key-value pairs
representing expected response header
names and values. If a header's value
is wrapped in ``/.../``, it will be
treated as a regular expression to
search for in the response header.
``response_forbidden_headers`` A list of headers which must `not`
be present.
``response_strings`` A list of string fragments expected
to be present in the response body.
If the value is wrapped in ``/.../``
the response body will be searched
for the value as a regular
expression.
``response_json_paths`` A dictionary of JSONPath rules paired
with expected matches. Using this
rule requires that the content being
sent from the server is JSON (i.e. a
content type of ``application/json``
or containing ``+json``)
If the value is wrapped in ``/.../``
the result of the JSONPath query
will be searched for the
value as a regular expression.
``poll`` A dictionary of two keys:
* ``count``: An integer stating the
number of times to attempt this
test before giving up.
* ``delay``: A floating point number
of seconds to delay between
attempts.
This makes it possible to poll for a
resource created via an asynchronous
request. Use with caution.
============================== ===================================== ============
Note that many of these items allow :ref:`substitutions <state-substitution>`.
Default values for a file's ``tests`` may be provided via the top-level
``defaults`` category. These take precedence over the global defaults
(explained below).
For examples see `the gabbi tests`_, :doc:`example` and the `gabbi-demo`_
tutorial.
.. _fixtures:
Fixtures
--------
The top-level ``fixtures`` category contains a sequence of named
:doc:`fixtures`.
.. _response-handlers:
Response Handlers
-----------------
``response_*`` keys are examples of Response Handlers. Custom handlers may be
created by test authors for specific use cases. See :doc:`handlers` for more
information.
.. _state-substitution:
Substitution
------------
There are a number of magical variables that can be used to make
reference to the state of a current test, the one just prior or any
test prior to the current one. The variables are replaced with real
values during test processing.
Global
******
* ``$ENVIRON['<environment variable>']``: The name of an environment
variable. Its value will replace the magical variable. If the
string value of the environment variable is ``"True"`` or
``"False"`` then the resulting value will be the corresponding
boolean, not a string.
Current Test
************
* ``$SCHEME``: The current scheme/protocol (usually ``http`` or ``https``).
* ``$NETLOC``: The host and potentially port of the request.
Immediately Prior Test
**********************
* ``$COOKIE``: All the cookies set by any ``Set-Cookie`` headers in
the prior response, including only the cookie key and value pairs
and no metadata (e.g. ``expires`` or ``domain``).
* ``$URL``: The URL defined in the prior request, after
substitutions have been made. For backwards compatibility with
earlier releases ``$LAST_URL`` may also be used, but if
``$HISTORY`` (see below) is being used, ``$URL`` must be used.
* ``$LOCATION``: The location header returned in the prior response.
* ``$HEADERS['<header>']``: The value of any header from the
prior response.
* ``$RESPONSE['<json path>']``: A JSONPath query into the prior
response. See :doc:`jsonpath` for more on formatting.
Any Previous Test
*****************
* ``$HISTORY['<test name>'].<magical variable expression>``: Any variable
which refers to a prior test may be used in an expression that refers to
any earlier test in the same file by identifying the target test by its
name in a ``$HISTORY`` dictionary. For example, to refer to a value
in a JSON object in the response of a test named ``post json``::
$HISTORY['post json'].$RESPONSE['$.key']
This is a very powerful feature that could lead to test that are
difficult for humans to read. Take care to optimize for the
maintainers that will come after you, not yourself.
.. _casting:
Casting
*******
For ``$ENVIRON`` and ``$RESPONSE`` it is possible to attempt to cast the value
to another type: ``int``, ``float``, ``str``, or ``bool``. If the cast fails
an exception will be raised and the test will fail.
This functionality only works when the magical variable is the whole value of
a YAML entry. If the variable is intermixed with other data, an exception will
be raised and the test will fail.
The format for a cast is to append a ``:`` and the cast type after the
type of the magical variable. For example::
$RESPONSE:int['$.some_string_value']
.. warning:: Prior to the introduction of this feature, ``$ENVIRON`` would
already do some automatic casting of numbers to ints and floats
and the strings ``True`` and ``False`` to booleans. This continues
to be the case, but only if no cast is provided.
.. note:: Where a single-quote character, ``'``, is shown in the variables
above you may also use a double-quote character, ``"``, but in any
given expression the same character must be used at both ends.
All of these variables may be used in all of the following fields:
* ``skip``
* ``url``
* ``query_parameters``
* ``data``
* ``request_headers`` (in both the key and value)
* ``response_strings``
* ``response_json_paths`` (in both the key and value, see
:ref:`json path substitution <json-subs>` for more info)
* ``response_headers`` (in both the key and value)
* ``response_forbidden_headers``
* ``count`` and ``delay`` fields of ``poll``
With these variables it ought to be possible to traverse an API without any
explicit statements about the URLs being used. If you need a
replacement on a field that is not currently supported please raise
an issue or provide a patch.
As all of these features needed to be tested in the development of
gabbi itself, `the gabbi tests`_ are a good source of examples on how
to use the functionality. See also :doc:`example` for a collection
of examples and the `gabbi-demo`_ tutorial.
.. _data:
Data
----
The ``data`` key has some special handing to allow for a bit more
flexibility when doing a ``POST`` or ``PUT``:
* If the value is not a string (that is, it is a sequence or structure)
it is treated as a data structure that will be turned into a
string by the ``dumps`` method on the relevant
:doc:`content handler <handlers>`. For example if the content-type of
the body is ``application/json`` the data structure will be turned
into a JSON string.
* If the value is a string that begins with ``<@`` then the rest of the
string is treated as a filepath to be loaded. The path is relative
to the test directory and may not traverse up into parent directories.
* If the value is an undecorated string, that's the value.
.. note:: When reading from a file care should be taken to ensure that a
reasonable content-type is set for the data as this will control
if any encoding is done of the resulting string value. If it
is text, json, xml or javascript it will be encoded to UTF-8.
.. _the gabbi tests: https://github.com/cdent/gabbi/tree/main/gabbi/tests/gabbits_intercept
.. _gabbi-demo: https://github.com/cdent/gabbi-demo
|