summaryrefslogtreecommitdiffstats
path: root/test/integration/targets/template/tasks/main.yml
blob: c0d2e11a6580610688dd09c18975636d0c09b5c8 (plain)
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
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
# test code for the template module
# (c) 2014, Michael DeHaan <michael.dehaan@gmail.com>

# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.

- set_fact:
    output_dir: "{{ lookup('env', 'OUTPUT_DIR') }}"

- name: show python interpreter
  debug:
     msg: "{{ ansible_python['executable'] }}"

- name: show jinja2 version
  debug:
     msg: "{{ lookup('pipe', '{{ ansible_python[\"executable\"] }} -c \"import jinja2; print(jinja2.__version__)\"') }}"

- name: get default group
  shell: id -gn
  register: group

- name: fill in a basic template
  template: src=foo.j2 dest={{output_dir}}/foo.templated mode=0644
  register: template_result

- assert:
    that:
        - "'changed' in template_result"
        - "'dest' in template_result"
        - "'group' in template_result"
        - "'gid' in template_result"
        - "'md5sum' in template_result"
        - "'checksum' in template_result"
        - "'owner' in template_result"
        - "'size' in template_result"
        - "'src' in template_result"
        - "'state' in template_result"
        - "'uid' in template_result"

- name: verify that the file was marked as changed
  assert:
    that:
      - "template_result.changed == true"

# Basic template with non-ascii names
- name: Check that non-ascii source and dest work
  template:
    src: 'café.j2'
    dest: '{{ output_dir }}/café.txt'
  register: template_results

- name: Check that the resulting file exists
  stat:
    path: '{{ output_dir }}/café.txt'
  register: stat_results

- name: Check that template created the right file
  assert:
    that:
      - 'template_results is changed'
      - 'stat_results.stat["exists"]'

# test for import with context on jinja-2.9 See https://github.com/ansible/ansible/issues/20494
- name: fill in a template using import with context ala issue 20494
  template: src=import_with_context.j2 dest={{output_dir}}/import_with_context.templated mode=0644
  register: template_result

- name: copy known good import_with_context.expected into place
  copy: src=import_with_context.expected dest={{output_dir}}/import_with_context.expected

- name: compare templated file to known good import_with_context
  shell: diff -uw {{output_dir}}/import_with_context.templated {{output_dir}}/import_with_context.expected
  register: diff_result

- name: verify templated import_with_context matches known good
  assert:
    that:
        - 'diff_result.stdout == ""'
        - "diff_result.rc == 0"

# test for nested include https://github.com/ansible/ansible/issues/34886
- name: test if parent variables are defined in nested include
  template: src=for_loop.j2 dest={{output_dir}}/for_loop.templated mode=0644

- name: save templated output
  shell: "cat {{output_dir}}/for_loop.templated"
  register: for_loop_out
- debug: var=for_loop_out
- name: verify variables got templated
  assert:
    that:
        - '"foo" in for_loop_out.stdout'
        - '"bar" in for_loop_out.stdout'
        - '"bam" in for_loop_out.stdout'

# test for 'import as' on jinja-2.9 See https://github.com/ansible/ansible/issues/20494
- name: fill in a template using import as ala fails2 case in issue 20494
  template: src=import_as.j2 dest={{output_dir}}/import_as.templated mode=0644
  register: import_as_template_result

- name: copy known good import_as.expected into place
  copy: src=import_as.expected dest={{output_dir}}/import_as.expected

- name: compare templated file to known good import_as
  shell: diff -uw {{output_dir}}/import_as.templated {{output_dir}}/import_as.expected
  register: import_as_diff_result

- name: verify templated import_as matches known good
  assert:
    that:
        - 'import_as_diff_result.stdout == ""'
        - "import_as_diff_result.rc == 0"

# test for 'import as with context' on jinja-2.9 See https://github.com/ansible/ansible/issues/20494
- name: fill in a template using import as with context ala fails2 case in issue 20494
  template: src=import_as_with_context.j2 dest={{output_dir}}/import_as_with_context.templated mode=0644
  register: import_as_with_context_template_result

- name: copy known good import_as_with_context.expected into place
  copy: src=import_as_with_context.expected dest={{output_dir}}/import_as_with_context.expected

- name: compare templated file to known good import_as_with_context
  shell: diff -uw {{output_dir}}/import_as_with_context.templated {{output_dir}}/import_as_with_context.expected
  register: import_as_with_context_diff_result

- name: verify templated import_as_with_context matches known good
  assert:
    that:
        - 'import_as_with_context_diff_result.stdout == ""'
        - "import_as_with_context_diff_result.rc == 0"

# VERIFY comment_start_string and comment_end_string

- name: Render a template with "comment_start_string" set to [#
  template:
    src: custom_comment_string.j2
    dest: "{{output_dir}}/custom_comment_string.templated"
    comment_start_string: "[#"
    comment_end_string: "#]"
  register: custom_comment_string_result

- name: Get checksum of known good custom_comment_string.expected
  stat:
    path: "{{role_path}}/files/custom_comment_string.expected"
  register: custom_comment_string_good

- name: Verify templated custom_comment_string matches known good using checksum
  assert:
    that:
        - "custom_comment_string_result.checksum == custom_comment_string_good.stat.checksum"

# VERIFY trim_blocks

- name: Render a template with "trim_blocks" set to False
  template:
    src: trim_blocks.j2
    dest: "{{output_dir}}/trim_blocks_false.templated"
    trim_blocks: False
  register: trim_blocks_false_result

- name: Get checksum of known good trim_blocks_false.expected
  stat:
    path: "{{role_path}}/files/trim_blocks_false.expected"
  register: trim_blocks_false_good

- name: Verify templated trim_blocks_false matches known good using checksum
  assert:
    that:
        - "trim_blocks_false_result.checksum == trim_blocks_false_good.stat.checksum"

- name: Render a template with "trim_blocks" set to True
  template:
    src: trim_blocks.j2
    dest: "{{output_dir}}/trim_blocks_true.templated"
    trim_blocks: True
  register: trim_blocks_true_result

- name: Get checksum of known good trim_blocks_true.expected
  stat:
    path: "{{role_path}}/files/trim_blocks_true.expected"
  register: trim_blocks_true_good

- name: Verify templated trim_blocks_true matches known good using checksum
  assert:
    that:
        - "trim_blocks_true_result.checksum == trim_blocks_true_good.stat.checksum"

# VERIFY lstrip_blocks

- name: Render a template with "lstrip_blocks" set to False
  template:
    src: lstrip_blocks.j2
    dest: "{{output_dir}}/lstrip_blocks_false.templated"
    lstrip_blocks: False
  register: lstrip_blocks_false_result

- name: Get checksum of known good lstrip_blocks_false.expected
  stat:
    path: "{{role_path}}/files/lstrip_blocks_false.expected"
  register: lstrip_blocks_false_good

- name: Verify templated lstrip_blocks_false matches known good using checksum
  assert:
    that:
        - "lstrip_blocks_false_result.checksum == lstrip_blocks_false_good.stat.checksum"

- name: Render a template with "lstrip_blocks" set to True
  template:
    src: lstrip_blocks.j2
    dest: "{{output_dir}}/lstrip_blocks_true.templated"
    lstrip_blocks: True
  register: lstrip_blocks_true_result
  ignore_errors: True

- name: Get checksum of known good lstrip_blocks_true.expected
  stat:
    path: "{{role_path}}/files/lstrip_blocks_true.expected"
  register: lstrip_blocks_true_good

- name: Verify templated lstrip_blocks_true matches known good using checksum
  assert:
    that:
        - "lstrip_blocks_true_result.checksum == lstrip_blocks_true_good.stat.checksum"

# VERIFY CONTENTS

- name: copy known good into place
  copy: src=foo.txt dest={{output_dir}}/foo.txt

- name: compare templated file to known good
  shell: diff -uw {{output_dir}}/foo.templated {{output_dir}}/foo.txt
  register: diff_result

- name: verify templated file matches known good
  assert:
    that:
        - 'diff_result.stdout == ""'
        - "diff_result.rc == 0"

# VERIFY MODE

- name: set file mode
  file: path={{output_dir}}/foo.templated mode=0644
  register: file_result

- name: ensure file mode did not change
  assert:
    that:
      - "file_result.changed != True"

# VERIFY dest as a directory does not break file attributes
# Note: expanduser is needed to go down the particular codepath that was broken before
- name: setup directory for test
  file: state=directory dest={{output_dir | expanduser}}/template-dir mode=0755 owner=nobody group={{ group.stdout }}

- name: set file mode when the destination is a directory
  template: src=foo.j2 dest={{output_dir | expanduser}}/template-dir/ mode=0600 owner=root group={{ group.stdout }}

- name: set file mode when the destination is a directory
  template: src=foo.j2 dest={{output_dir | expanduser}}/template-dir/ mode=0600 owner=root group={{ group.stdout }}
  register: file_result

- name: check that the file has the correct attributes
  stat: path={{output_dir | expanduser}}/template-dir/foo.j2
  register: file_attrs

- assert:
    that:
      - "file_attrs.stat.uid == 0"
      - "file_attrs.stat.pw_name == 'root'"
      - "file_attrs.stat.mode == '0600'"

- name: check that the containing directory did not change attributes
  stat: path={{output_dir | expanduser}}/template-dir/
  register: dir_attrs

- assert:
    that:
      - "dir_attrs.stat.uid != 0"
      - "dir_attrs.stat.pw_name == 'nobody'"
      - "dir_attrs.stat.mode == '0755'"

- name: Check that template to a directory where the directory does not end with a / is allowed
  template: src=foo.j2 dest={{output_dir | expanduser}}/template-dir mode=0600 owner=root group={{ group.stdout }}

- name: make a symlink to the templated file
  file:
    path: '{{ output_dir }}/foo.symlink'
    src: '{{ output_dir }}/foo.templated'
    state: link

- name: check that templating the symlink results in the file being templated
  template:
    src: foo.j2
    dest: '{{output_dir}}/foo.symlink'
    mode: 0600
    follow: True
  register: template_result

- assert:
    that:
      - "template_result.changed == True"

- name: check that the file has the correct attributes
  stat: path={{output_dir | expanduser}}/template-dir/foo.j2
  register: file_attrs

- assert:
    that:
      - "file_attrs.stat.mode == '0600'"

- name: check that templating the symlink again makes no changes
  template:
    src: foo.j2
    dest: '{{output_dir}}/foo.symlink'
    mode: 0600
    follow: True
  register: template_result

- assert:
    that:
      - "template_result.changed == False"

# Test strange filenames

- name: Create a temp dir for filename tests
  file:
    state: directory
    dest: '{{ output_dir }}/filename-tests'

- name: create a file with an unusual filename
  template:
    src: foo.j2
    dest: "{{ output_dir }}/filename-tests/foo t'e~m\\plated"
  register: template_result

- assert:
    that:
      - "template_result.changed == True"

- name: check that the unusual filename was created
  command: "ls {{ output_dir }}/filename-tests/"
  register: unusual_results

- assert:
    that:
      - "\"foo t'e~m\\plated\" in unusual_results.stdout_lines"
      - "{{unusual_results.stdout_lines| length}} == 1"

- name: check that the unusual filename can be checked for changes
  template:
    src: foo.j2
    dest: "{{ output_dir }}/filename-tests/foo t'e~m\\plated"
  register: template_result

- assert:
    that:
      - "template_result.changed == False"


# check_mode

- name: fill in a basic template in check mode
  template: src=short.j2 dest={{output_dir}}/short.templated
  register: template_result
  check_mode: True

- name: check file exists
  stat: path={{output_dir}}/short.templated
  register: templated

- name: verify that the file was marked as changed in check mode but was not created
  assert:
    that:
      - "not templated.stat.exists"
      - "template_result is changed"

- name: fill in a basic template
  template: src=short.j2 dest={{output_dir}}/short.templated

- name: fill in a basic template in check mode
  template: src=short.j2 dest={{output_dir}}/short.templated
  register: template_result
  check_mode: True

- name: verify that the file was marked as not changes in check mode
  assert:
    that:
      - "template_result is not changed"
      - "'templated_var_loaded' in lookup('file', output_dir + '/short.templated')"

- name: change var for the template
  set_fact:
    templated_var: "changed"

- name: fill in a basic template with changed var in check mode
  template: src=short.j2 dest={{output_dir}}/short.templated
  register: template_result
  check_mode: True

- name: verify that the file was marked as changed in check mode but the content was not changed
  assert:
    that:
      - "'templated_var_loaded' in lookup('file', output_dir + '/short.templated')"
      - "template_result is changed"

# Create a template using a child template, to ensure that variables
# are passed properly from the parent to subtemplate context (issue #20063)

- name: test parent and subtemplate creation of context
  template: src=parent.j2 dest={{output_dir}}/parent_and_subtemplate.templated
  register: template_result

- stat: path={{output_dir}}/parent_and_subtemplate.templated

- name: verify that the parent and subtemplate creation worked
  assert:
    that:
    - "template_result is changed"

#
# template module can overwrite a file that's been hard linked
# https://github.com/ansible/ansible/issues/10834
#

- name: ensure test dir is absent
  file:
    path: '{{ output_dir | expanduser }}/hlink_dir'
    state: absent

- name: create test dir
  file:
    path: '{{ output_dir | expanduser }}/hlink_dir'
    state: directory

- name: template out test file to system 1
  template:
    src: foo.j2
    dest: '{{ output_dir | expanduser }}/hlink_dir/test_file'

- name: make hard link
  file:
    src: '{{ output_dir | expanduser }}/hlink_dir/test_file'
    dest: '{{ output_dir | expanduser }}/hlink_dir/test_file_hlink'
    state: hard

- name: template out test file to system 2
  template:
    src: foo.j2
    dest: '{{ output_dir | expanduser }}/hlink_dir/test_file'
  register: hlink_result

- name: check that the files are still hardlinked
  stat:
    path: '{{ output_dir | expanduser }}/hlink_dir/test_file'
  register: orig_file

- name: check that the files are still hardlinked
  stat:
    path: '{{ output_dir | expanduser }}/hlink_dir/test_file_hlink'
  register: hlink_file

# We've done nothing at this point to update the content of the file so it should still be hardlinked
- assert:
    that:
      - "hlink_result.changed == False"
      - "orig_file.stat.inode == hlink_file.stat.inode"

- name: change var for the template
  set_fact:
    templated_var: "templated_var_loaded"

# UNIX TEMPLATE
- name: fill in a basic template (Unix)
  template:
    src: foo2.j2
    dest: '{{ output_dir }}/foo.unix.templated'
  register: template_result

- name: verify that the file was marked as changed (Unix)
  assert:
    that:
      - 'template_result is changed'

- name: fill in a basic template again (Unix)
  template:
    src: foo2.j2
    dest: '{{ output_dir }}/foo.unix.templated'
  register: template_result2

- name: verify that the template was not changed (Unix)
  assert:
    that:
      - 'template_result2 is not changed'

# VERIFY UNIX CONTENTS
- name: copy known good into place (Unix)
  copy:
    src: foo.unix.txt
    dest: '{{ output_dir }}/foo.unix.txt'

- name: Dump templated file (Unix)
  command: hexdump -C {{ output_dir }}/foo.unix.templated

- name: Dump expected file (Unix)
  command: hexdump -C {{ output_dir }}/foo.unix.txt

- name: compare templated file to known good (Unix)
  command: diff -u {{ output_dir }}/foo.unix.templated {{ output_dir }}/foo.unix.txt
  register: diff_result

- name: verify templated file matches known good (Unix)
  assert:
    that:
        - 'diff_result.stdout == ""'
        - "diff_result.rc == 0"

# DOS TEMPLATE
- name: fill in a basic template (DOS)
  template:
    src: foo2.j2
    dest: '{{ output_dir }}/foo.dos.templated'
    newline_sequence: '\r\n'
  register: template_result

- name: verify that the file was marked as changed (DOS)
  assert:
    that:
      - 'template_result is changed'

- name: fill in a basic template again (DOS)
  template:
    src: foo2.j2
    dest: '{{ output_dir }}/foo.dos.templated'
    newline_sequence: '\r\n'
  register: template_result2

- name: verify that the template was not changed (DOS)
  assert:
    that:
      - 'template_result2 is not changed'

# VERIFY DOS CONTENTS
- name: copy known good into place (DOS)
  copy:
    src: foo.dos.txt
    dest: '{{ output_dir }}/foo.dos.txt'

- name: Dump templated file (DOS)
  command: hexdump -C {{ output_dir }}/foo.dos.templated

- name: Dump expected file (DOS)
  command: hexdump -C {{ output_dir }}/foo.dos.txt

- name: compare templated file to known good (DOS)
  command: diff -u {{ output_dir }}/foo.dos.templated {{ output_dir }}/foo.dos.txt
  register: diff_result

- name: verify templated file matches known good (DOS)
  assert:
    that:
        - 'diff_result.stdout == ""'
        - "diff_result.rc == 0"

# VERIFY DOS CONTENTS
- name: copy known good into place (Unix)
  copy:
    src: foo.unix.txt
    dest: '{{ output_dir }}/foo.unix.txt'

- name: Dump templated file (Unix)
  command: hexdump -C {{ output_dir }}/foo.unix.templated

- name: Dump expected file (Unix)
  command: hexdump -C {{ output_dir }}/foo.unix.txt

- name: compare templated file to known good (Unix)
  command: diff -u {{ output_dir }}/foo.unix.templated {{ output_dir }}/foo.unix.txt
  register: diff_result

- name: verify templated file matches known good (Unix)
  assert:
    that:
        - 'diff_result.stdout == ""'
        - "diff_result.rc == 0"

# Check that mode=preserve works with template
- name: Create a template which has strange permissions
  copy:
    content: !unsafe '{{ ansible_managed }}\n'
    dest: '{{ output_dir }}/foo-template.j2'
    mode: 0547
  delegate_to: localhost

- name: Use template with mode=preserve
  template:
    src: '{{ output_dir }}/foo-template.j2'
    dest: '{{ output_dir }}/foo-templated.txt'
    mode: 'preserve'
  register: template_results

- name: Get permissions from the templated file
  stat:
    path: '{{ output_dir }}/foo-templated.txt'
  register: stat_results

- name: Check that the resulting file has the correct permissions
  assert:
    that:
      - 'template_results is changed'
      - 'template_results.mode == "0547"'
      - 'stat_results.stat["mode"] == "0547"'

# Test output_encoding
- name: Prepare the list of encodings we want to check, including empty string for defaults
  set_fact:
    template_encoding_1252_encodings: ['', 'utf-8', 'windows-1252']

- name: Copy known good encoding_1252_*.expected into place
  copy:
    src: 'encoding_1252_{{ item | default("utf-8", true) }}.expected'
    dest: '{{ output_dir }}/encoding_1252_{{ item }}.expected'
  loop: '{{ template_encoding_1252_encodings }}'

- name: Generate the encoding_1252_* files from templates using various encoding combinations
  template:
    src: 'encoding_1252.j2'
    dest: '{{ output_dir }}/encoding_1252_{{ item }}.txt'
    output_encoding: '{{ item }}'
  loop: '{{ template_encoding_1252_encodings }}'

- name: Compare the encoding_1252_* templated files to known good
  command: diff -u {{ output_dir }}/encoding_1252_{{ item }}.expected {{ output_dir }}/encoding_1252_{{ item }}.txt
  register: encoding_1252_diff_result
  loop: '{{ template_encoding_1252_encodings }}'

- name: Check that nested undefined values return Undefined
  vars:
    dict_var:
      bar: {}
    list_var:
      - foo: {}
  assert:
    that:
      - dict_var is defined
      - dict_var.bar is defined
      - dict_var.bar.baz is not defined
      - dict_var.bar.baz | default('DEFAULT') == 'DEFAULT'
      - dict_var.bar.baz.abc is not defined
      - dict_var.bar.baz.abc | default('DEFAULT') == 'DEFAULT'
      - dict_var.baz is not defined
      - dict_var.baz.abc is not defined
      - dict_var.baz.abc | default('DEFAULT') == 'DEFAULT'
      - list_var.0 is defined
      - list_var.1 is not defined
      - list_var.0.foo is defined
      - list_var.0.foo.bar is not defined
      - list_var.0.foo.bar | default('DEFAULT') == 'DEFAULT'
      - list_var.1.foo is not defined
      - list_var.1.foo | default('DEFAULT') == 'DEFAULT'
      - dict_var is defined
      - dict_var['bar'] is defined
      - dict_var['bar']['baz'] is not defined
      - dict_var['bar']['baz'] | default('DEFAULT') == 'DEFAULT'
      - dict_var['bar']['baz']['abc'] is not defined
      - dict_var['bar']['baz']['abc'] | default('DEFAULT') == 'DEFAULT'
      - dict_var['baz'] is not defined
      - dict_var['baz']['abc'] is not defined
      - dict_var['baz']['abc'] | default('DEFAULT') == 'DEFAULT'
      - list_var[0] is defined
      - list_var[1] is not defined
      - list_var[0]['foo'] is defined
      - list_var[0]['foo']['bar'] is not defined
      - list_var[0]['foo']['bar'] | default('DEFAULT') == 'DEFAULT'
      - list_var[1]['foo'] is not defined
      - list_var[1]['foo'] | default('DEFAULT') == 'DEFAULT'
      - dict_var['bar'].baz is not defined
      - dict_var['bar'].baz | default('DEFAULT') == 'DEFAULT'

- template:
    src: template_destpath_test.j2
    dest: "{{ output_dir }}/template_destpath.templated"

- copy:
    content: "{{ output_dir}}/template_destpath.templated\n"
    dest: "{{ output_dir }}/template_destpath.expected"

- name: compare templated file to known good template_destpath
  shell: diff -uw {{output_dir}}/template_destpath.templated {{output_dir}}/template_destpath.expected
  register: diff_result

- name: verify templated template_destpath matches known good
  assert:
    that:
        - 'diff_result.stdout == ""'
        - "diff_result.rc == 0"

- debug:
    msg: "{{ 'x' in y }}"
  ignore_errors: yes
  register: error

- name: check that proper error message is emitted when in operator is used
  assert:
    that: "\"'y' is undefined\" in error.msg"

- template:
    src: template_import_macro_globals.j2
    dest: "{{ output_dir }}/template_import_macro_globals.templated"

- command: "cat {{ output_dir }}/template_import_macro_globals.templated"
  register: out

- assert:
    that:
      - out.stdout == "bar=lookedup_bar"

# aliases file requires root for template tests so this should be safe
- import_tasks: backup_test.yml

- name: test STRING_TYPE_FILTERS
  copy:
    content: "{{ a_dict | to_nice_json(indent=(indent_value|int))}}\n"
    dest: "{{ output_dir }}/string_type_filters.templated"
  vars:
    a_dict:
      foo: bar
      foobar: 1
    indent_value: 2

- name: copy known good string_type_filters.expected into place
  copy:
    src: string_type_filters.expected
    dest: "{{ output_dir }}/string_type_filters.expected"

- command: "diff {{ output_dir }}/string_type_filters.templated {{ output_dir}}/string_type_filters.expected"
  register: out

- assert:
    that:
      - out.rc == 0

- template:
    src: empty_template.j2
    dest: "{{ output_dir }}/empty_template.templated"

- assert:
    that:
      - test
  vars:
    test: "{{ lookup('file', '{{ output_dir }}/empty_template.templated')|length == 0 }}"

- name: test jinja2 override without colon throws proper error
  block:
  - template:
      src: override_separator.j2
      dest: "{{ output_dir }}/override_separator.templated"
  - assert:
      that:
        - False
  rescue:
  - assert:
      that:
        - "'failed to parse jinja2 override' in ansible_failed_result.msg"

- name: test jinja2 override with colon in value
  template:
    src: override_colon_value.j2
    dest: "{{ output_dir }}/override_colon_value.templated"
  ignore_errors: yes
  register: override_colon_value_task

- copy:
    src: override_colon_value.expected
    dest: "{{output_dir}}/override_colon_value.expected"

- command: "diff {{ output_dir }}/override_colon_value.templated {{ output_dir}}/override_colon_value.expected"
  register: override_colon_value_diff

- assert:
    that:
      - override_colon_value_task is success
      - override_colon_value_diff.rc == 0

- assert:
    that:
      - data_not_converted | type_debug == 'NativeJinjaUnsafeText'
      - data_converted | type_debug == 'dict'
  vars:
    data_not_converted: "{{ lookup('template', 'json_macro.j2', convert_data=False) }}"
    data_converted: "{{ lookup('template', 'json_macro.j2') }}"

- name: Test convert_data is correctly set to True for nested vars evaluation
  debug:
    msg: "{{ lookup('template', 'indirect_dict.j2', convert_data=False) }}"
  vars:
    d:
      foo: bar
    v: "{{ d }}"