Search code examples
ansibleyaml

Formatting yaml block text for use in an ansible assert test


I'm trying to write a fairly simply unittest for an ansible task. Here is the basic task:

---
- name: Test task
  host: localhost
  task:
    - name: My test task
      ansible.builtin.blockinfile:
      dest: /my_output.yaml
      block: |
        thing 1
        thing 2
        thing 3
     register: output

- name: Test output
  ansible.builtin.assert:
    that:
      - output.changed == true
      - output.block: |                   <-- Problem line
          # BEGIN ANSIBLE MANAGED BLOCK
          thing 1
            thing 2
              thing 3
          # END ANSIBLE MANAGED BLOCK

I can confirm that the output to the my_output.yaml does in fact match the block text per the assert, including the spacing on thing 2 and thing 3. However this assertion does not actually run during the test. Obviously, the test isn't currently setup to actually test for ==.

If I use - output.block == | the formatted block text doesn't work. I can also use spacing and \n to represent the formatted text and that does work using - output.block == "# BEGIN AN...MANAGED BLOCK" but it is very difficult to read.

Is there a way to use block in this context?

NOTE... I know that I can use something like this as a separate assert, but it is multiple files and more difficult to 'read'.

- name: Compare output
  ansible.builtin.assert:
    that:
      - lookup('file', '/my_output.yaml') == lookup('file', '/my_output_verified.yaml')

Solution

  • There's a bit of confusion in the above. The pipe sign (|) is a yaml construct for yaml multiline strings. But you are using it inside an assert expression which is by definition a raw Jinja2 expression without double curly braces (see assert documentation and basic conditional when:. Moreover, your second condition is actually not using any test.

    So to achieve your above test with the ease of use of a yaml scalar block, you need to assign the value to a variable and use that variable in your test. Something like the following should do (untested as I don't have an example file nor an output of your registered variable)

    - name: Test output
      vars:
        compare: |
          # BEGIN ANSIBLE MANAGED BLOCK
          thing 1
            thing 2
              thing 3
          # END ANSIBLE MANAGED BLOCK
      ansible.builtin.assert:
        that:
          - output.changed | bool
          - output.block == compare
    

    This should put you on track for your direct problem.

    Now to go further, the real question is: why are you doing this at all? The blockinfile module is (as the vast majority of Ansible modules) fully idempotent and will report changed if it modified something or ok if the content is already aligned. So the blockinfile task is already your test as in any case the content will be the one you passed for the block content.