pythonyamltavern

How can Tavern `!include` template JSON request body and modify with `<<`?


I'm using tavern to make multiple similar request to a web server, but in the same stage of different tests (ie different YAML files). Each web request takes a long time, so I've split up my overall testing into different test files so that I can use python-xdist to run the tests in parallel. This means I gain nothing by combining all tests as separate stages of the same test.

It seems I can reuse a complete JSON body stored in a JSON or YAML file using !include (see Directly including test data). However, I want to reuse a partial JSON body and then add/override just the parameters that differ for each test (see Reusing requests and YAML fragments")

For example, a test file looks like this:

Option 1: intermediate variables for includes

variables:
  request_template: &reqtemp
    !include components/request.yaml


stages:
  - name: Create infrastructure
    request:
      url: "{service:s}"
      json:
        <<: *reqtemp
# Here I start extending the template with values specific to the test
        name: "infrastructure_name"
        param_1: "param_for_test_1"
        param_2: "another param for test 1"

However, when running a test like this, it will throw an exception expected a mapping or list of mappings for merging, but found scalar. I've tried other syntax options like the below, but still get the same error:

Option 2: no variables

stages:
  - name: Create infrastructure
    request:
      url: "{service:s}"
      json:
        <<: !include components/request.yaml
# Here I start extending the template with values specific to the test
        name: "infrastructure_name"
        param_1: "param_for_test_1"
        param_2: "another param for test 1"

How can I get the benefit of importing a large request body with !include yet be able to modify it on a per-stage basis?


Solution

  • That is not possible.

    << is an optional extension to YAML defined here. It says that

    […] If the value associated with the key is a single mapping node, each of its key/value pairs is inserted into the current mapping, unless the key already exists in it. If the value associated with the merge key is a sequence, then this sequence is expected to contain mapping nodes and each of these nodes is merged in turn according to its order in the sequence. […]

    No matter whether you give your !include as an alias or directly, the YAML semantic is always that your << key is associated with a scalar which happens to have the tag !include. The merge key does not define what to do if the associated value is a scalar, hence the error.

    User-defined tags like !include (user meaning Tavern here) are processed after merging. They are implemented with custom constructors that take a YAML value as input (here, the scalar components/request.yaml) and return a native data structure (like for example, a dict for mappings, a list for sequences, and for scalars typically strings, numbers or booleans depending on the scalar's content). In the case of !include, the loaded data from the referenced file is likely to be returned (I don't know about the gory details).

    The important part is that with custom constructors, we're leaving YAML structures (mappings, sequences and scalars) and therefore cannot process the result with a semantic like !!merge that is defined on YAML structures.

    The only way to overcome this is if Tavern implemented its own !merge semantics that would work on the readily loaded data instead of the YAML structure. Since it doesn't, you're out of luck here.