aboutsummaryrefslogtreecommitdiff
path: root/lava_scheduler_app/tests/test_uboot_templates.py
blob: 79b69e605983f39161d6aa699dfa997c7d4faa39 (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
import os
import sys
import yaml
import unittest
import logging
import tempfile
# pylint: disable=superfluous-parens,ungrouped-imports
from lava_dispatcher.parser import JobParser
from lava_dispatcher.device import NewDevice
from lava_dispatcher.action import Timeout
from lava_dispatcher.test.utils import DummyLogger, infrastructure_error
from lava_scheduler_app.tests.test_base_templates import (
    BaseTemplate,
    prepare_jinja_template,
)

# pylint: disable=too-many-branches,too-many-public-methods
# pylint: disable=too-many-nested-blocks


class TestUbootTemplates(BaseTemplate.BaseTemplateCases):
    """
    Test rendering of jinja2 templates

    When adding or modifying a jinja2 template, add or update the test here.
    Use realistic data - complete exports of the device dictionary preferably.
    Set debug to True to see the content of the rendered templates
    Set system to True to use the system templates - note that this requires
    that the templates in question are in sync with the branch upon which the
    test is run. Therefore, if the templates should be the same, this can be
    used to check that the templates are correct. If there are problems, check
    for a template with a .dpkg-dist extension. Check the diff between the
    checkout and the system file matches the difference between the system file
    and the dpkg-dist version. If the diffs match, copy the dpkg-dist onto the
    system file.
    """

    def test_armada375_template(self):
        """
        Test the armada-375 template as if it was a device dictionary
        """
        data = """
{% extends 'base-uboot.jinja2' %}
{% set console_device = console_device|default('ttyS0') %}
{% set baud_rate = baud_rate|default(115200) %}
{% set bootloader_prompt = bootloader_prompt|default('Marvell>>') %}
{% set bootm_kernel_addr = '0x02080000' %}
{% set bootm_ramdisk_addr = '0x02880000' %}
{% set bootm_dtb_addr = '0x02000000' %}
{% set base_ip_args = 'ip=dhcp' %}
{% set uboot_mkimage_arch = 'arm' %}
{% set append_dtb = true %}
{% set use_xip = true %}
{% set uboot_bootx_cmd = "bootm {KERNEL_ADDR} {RAMDISK_ADDR}" %}
        """
        self.assertTrue(self.validate_data('armada-375-01', data))
        template_dict = prepare_jinja_template('armada-375-01', data, raw=False)
        params = template_dict['actions']['deploy']['parameters']
        self.assertIsNotNone(params)
        self.assertIn('use_xip', params)
        self.assertIn('append_dtb', params)
        self.assertTrue(params['use_xip'])
        self.assertTrue(params['append_dtb'])
        params = template_dict['actions']['boot']['methods']['u-boot']['ramdisk']['commands']
        for line in params:
            if 'run loadkernel' in line:
                self.assertIn('bootm', line)

    def test_beaglebone_black_template(self):
        data = """{% extends 'beaglebone-black.jinja2' %}
{% set map = {'eth0': {'lngswitch03': 19}, 'eth1': {'lngswitch03': 8}} %}
{% set hard_reset_command = '/usr/bin/pduclient --daemon localhost --hostname lngpdu01 --command reboot --port 19' %}
{% set tags = {'eth0': ['1G', '100M'], 'eth1': ['100M']} %}
{% set interfaces = ['eth0', 'eth1'] %}
{% set sysfs = {'eth0': '/sys/devices/platform/ocp/4a100000.ethernet/net/eth0',
'eth1': '/sys/devices/platform/ocp/47400000.usb/47401c00.usb/musb-hdrc.1.auto/usb1/1-1/1-1:1.0/net/eth1'} %}
{% set power_off_command = '/usr/bin/pduclient --daemon localhost --hostname lngpdu01 --command off --port 19' %}
{% set mac_addr = {'eth0': '90:59:af:5e:69:fd', 'eth1': '00:e0:4c:53:44:58'} %}
{% set power_on_command = '/usr/bin/pduclient --daemon localhost --hostname lngpdu01 --command on --port 19' %}
{% set connection_command = 'telnet localhost 7333' %}"""
        self.assertTrue(self.validate_data('staging-bbb-01', data))
        template_dict = prepare_jinja_template('staging-bbb-01', data, raw=False)
        self.assertIsNotNone(template_dict['actions']['deploy']['methods']['ssh']['host'])
        self.assertEqual('', template_dict['actions']['deploy']['methods']['ssh']['host'])
        self.assertNotEqual('None', template_dict['actions']['deploy']['methods']['ssh']['host'])
        data += "{% set ssh_host = '192.168.0.10' %}"
        template_dict = prepare_jinja_template('staging-bbb-01', data, raw=False)
        self.assertIsNotNone(template_dict['actions']['deploy']['methods']['ssh']['host'])
        self.assertEqual('192.168.0.10', template_dict['actions']['deploy']['methods']['ssh']['host'])

    def test_b2260_template(self):
        data = """{% extends 'b2260.jinja2' %}"""
        self.assertTrue(self.validate_data('staging-b2260-01', data))
        template_dict = prepare_jinja_template('staging-b2260-01', data, raw=False)
        self.assertEqual({'seconds': 15}, template_dict['timeouts']['actions']['power-off'])

    def test_mustang_template(self):
        data = """{% extends 'mustang.jinja2' %}
{% set connection_command = 'telnet serial4 7012' %}
{% set hard_reset_command = '/usr/bin/pduclient --daemon staging-master --hostname pdu15 --command reboot --port 05' %}
{% set power_off_command = '/usr/bin/pduclient --daemon staging-master --hostname pdu15 --command off --port 05' %}
{% set power_on_command = '/usr/bin/pduclient --daemon staging-master --hostname pdu15 --command on --port 05' %}"""
        self.assertTrue(self.validate_data('staging-mustang-01', data))
        template_dict = prepare_jinja_template('staging-mustang-01', data, raw=False)
        self.assertIsInstance(template_dict['parameters']['text_offset'], str)
        commands = template_dict['actions']['boot']['methods']['u-boot']['ramdisk']['commands']
        for line in commands:
            if 'setenv initrd_high' in line:
                self.fail('Mustang should not have initrd_high set')
            if 'setenv fdt_high' in line:
                self.fail('Mustang should not have fdt_high set')

    def test_rpi3_32_template(self):
        checked = False
        data = """{% extends 'bcm2837-rpi-3-b-32.jinja2' %}"""
        self.assertTrue(self.validate_data('staging-rpi3-01', data))

        # test appending to kernel args
        context = {'extra_kernel_args': 'extra_arg=extra_val'}
        template_dict = prepare_jinja_template('staging-rpi3-01', data, job_ctx=context, raw=False)
        commands = template_dict['actions']['boot']['methods']['u-boot']['ramdisk']['commands']
        self.assertIsNotNone(commands)
        self.assertIsInstance(commands, list)
        for line in commands:
            if 'setenv bootargs' in line:
                self.assertIn("earlycon=", line)
                self.assertIn("extra_arg=extra_val", line)
                checked = True
        self.assertTrue(checked)

        # test overwriting kernel args
        checked = False
        context = {'custom_kernel_args': 'custom_arg=custom_val'}
        template_dict = prepare_jinja_template('staging-rpi3-01', data, job_ctx=context, raw=False)
        commands = template_dict['actions']['boot']['methods']['u-boot']['ramdisk']['commands']
        self.assertIsNotNone(commands)
        self.assertIsInstance(commands, list)
        for line in commands:
            if 'setenv bootargs' in line:
                self.assertNotIn("earlycon=", line)
                self.assertIn("custom_arg=custom_val", line)
                checked = True
        self.assertTrue(checked)

    def test_panda_template(self):
        logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
        logger = logging.getLogger('unittests')
        logger.disabled = True
        logger.propagate = False
        data = """{% extends 'panda.jinja2' %}
{% set connection_command = 'telnet serial4 7012' %}
{% set hard_reset_command = '/usr/bin/pduclient --daemon staging-master --hostname pdu15 --command reboot --port 05' %}
{% set power_off_command = '/usr/bin/pduclient --daemon staging-master --hostname pdu15 --command off --port 05' %}
{% set power_on_command = '/usr/bin/pduclient --daemon staging-master --hostname pdu15 --command on --port 05' %}"""
        self.assertTrue(self.validate_data('staging-panda-01', data))
        context = {'extra_kernel_args': 'intel_mmio=on mmio=on'}
        template_dict = prepare_jinja_template('staging-panda-01', data, job_ctx=context, raw=False)
        self.assertIn('bootloader-commands', template_dict['timeouts']['actions'])
        self.assertEqual(180.0, Timeout.parse(template_dict['timeouts']['actions']['bootloader-commands']))
        commands = template_dict['actions']['boot']['methods']['u-boot']['ramdisk']['commands']
        checked = False
        self.assertIsNotNone(commands)
        self.assertIsInstance(commands, list)
        self.assertIn('usb start', commands)
        for line in commands:
            if 'setenv bootargs' in line:
                self.assertIn('console=ttyO2', line)
                self.assertIn(' ' + context['extra_kernel_args'] + ' ', line)
                checked = True
        self.assertTrue(checked)
        checked = False
        for line in commands:
            if 'setenv initrd_high' in line:
                checked = True
        self.assertTrue(checked)

    def test_juno_uboot_template(self):
        data = """{% extends 'juno-uboot.jinja2' %}
{% set connection_command = 'telnet serial4 7001' %}
{% set hard_reset_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu18 --command reboot --port 10 --delay 10' %}
{% set power_off_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu18 --command off --port 10 --delay 10' %}
{% set power_on_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu18 --command on --port 10 --delay 10' %}
{% set usb_label = 'SanDiskCruzerBlade' %}
{% set usb_uuid = 'usb-SanDisk_Cruzer_Blade_20060266531DA442AD42-0:0' %}
{% set usb_device_id = 0 %}
{% set nfs_uboot_bootcmd = (
"          - setenv bootcmd 'dhcp; setenv serverip {SERVER_IP}; run loadkernel; run loadinitrd; run loadfdt; {BOOTX}'
          - boot") %}"""
        self.assertTrue(self.validate_data('staging-juno-01', data))
        template_dict = prepare_jinja_template('staging-juno-01', data, raw=False)
        self.assertIsNotNone(template_dict)

    def test_cubietruck_template(self):
        data = """{% extends 'cubietruck.jinja2' %}
{% set usb_label = 'SanDisk_Ultra' %}
{% set sata_label = 'ST160LM003' %}
{% set uuid_required = False %}
{% set usb_uuid = "usb-SanDisk_Ultra_20060775320F43006019-0:0" %}
{% set sata_uuid = "ata-ST160LM003_HN-M160MBB_S2SYJ9KC102184" %}
{% set connection_command = 'telnet localhost 6002' %}
{% set console_device = 'ttyfake1' %}"""
        self.assertTrue(self.validate_data('staging-cubietruck-01', data))
        template_dict = prepare_jinja_template('staging-cubietruck-01', data, raw=False)
        self.assertIsNotNone(template_dict)
        self.assertIn('u-boot', template_dict['actions']['boot']['methods'])
        self.assertIn('SanDisk_Ultra', template_dict['parameters']['media']['usb'])
        self.assertEqual(template_dict['parameters']['media']['usb']['SanDisk_Ultra']['device_id'], 0)
        self.assertEqual(template_dict['parameters']['media']['usb']['SanDisk_Ultra']['uuid'],
                         'usb-SanDisk_Ultra_20060775320F43006019-0:0')
        self.assertIn('ST160LM003', template_dict['parameters']['media']['sata'])
        self.assertIn('uboot_interface', template_dict['parameters']['media']['sata']['ST160LM003'])
        self.assertEqual('scsi', template_dict['parameters']['media']['sata']['ST160LM003']['uboot_interface'])
        self.assertIn('uuid', template_dict['parameters']['media']['sata']['ST160LM003'])
        self.assertIn('ata-ST160LM003_HN-M160MBB_S2SYJ9KC102184',
                      template_dict['parameters']['media']['sata']['ST160LM003']['uuid'])
        self.assertIn('ssh', template_dict['actions']['boot']['methods'])

    def test_extra_nfs_opts(self):
        data = """{% extends 'panda.jinja2' %}
{% set connection_command = 'telnet serial4 7012' %}
{% set hard_reset_command = '/usr/bin/pduclient --daemon staging-master --hostname pdu15 --command reboot --port 05' %}
{% set power_off_command = '/usr/bin/pduclient --daemon staging-master --hostname pdu15 --command off --port 05' %}
{% set power_on_command = '/usr/bin/pduclient --daemon staging-master --hostname pdu15 --command on --port 05' %}"""
        job_ctx = {}
        template_dict = prepare_jinja_template('staging-panda-01', data, job_ctx=job_ctx, raw=False)
        for line in template_dict['actions']['boot']['methods']['u-boot']['nfs']['commands']:
            if line.startswith("setenv nfsargs"):
                self.assertIn(',tcp,hard,intr ', line)
                self.assertNotIn('nfsvers', line)
        job_ctx = {'extra_nfsroot_args': ',nolock,nfsvers=3'}
        template_dict = prepare_jinja_template('staging-panda-01', data, job_ctx=job_ctx, raw=False)
        for line in template_dict['actions']['boot']['methods']['u-boot']['nfs']['commands']:
            if line.startswith("setenv nfsargs"):
                self.assertIn(',tcp,hard,intr,nolock,nfsvers=3 ', line)
        commands = template_dict['actions']['boot']['methods']['u-boot']['ramdisk']['commands']
        checked = False
        for line in commands:
            if 'setenv initrd_high' in line:
                checked = True
        self.assertTrue(checked)

    def test_juno_uboot_vland_template(self):
        data = """{% extends 'juno-uboot.jinja2' %}
{% set map = {'iface0': {'lngswitch03': 19}, 'iface1': {'lngswitch03': 8}} %}
{% set hard_reset_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname lngpdu01 --command reboot --port 19' %}
{% set tags = {'iface0': [], 'iface1': ['RJ45', '10M', '100M']} %}
{% set interfaces = ['iface0', 'iface1'] %}
{% set device_mac = '90:59:af:5e:69:fd' %}
{% set sysfs = {'iface0': '/sys/devices/platform/ocp/4a100000.ethernet/net/',
'iface1': '/sys/devices/platform/ocp/47400000.usb/47401c00.usb/musb-hdrc.1.auto/usb1/1-1/1-1:1.0/net/'} %}
{% set power_off_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname lngpdu01 --command off --port 19' %}
{% set mac_addr = {'iface0': '90:59:af:5e:69:fd', 'iface1': '00:e0:4c:53:44:58'} %}
{% set power_on_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname lngpdu01 --command on --port 19' %}
{% set connection_command = 'telnet localhost 7333' %}"""
        self.assertTrue(self.validate_data('staging-x86-01', data))
        template_dict = prepare_jinja_template('staging-qemu-01', data, raw=False)
        self.assertIn('interfaces', template_dict['parameters'])
        self.assertIn('iface0', template_dict['parameters']['interfaces'])
        self.assertIn('port', template_dict['parameters']['interfaces']['iface0'])
        self.assertIn('target', template_dict['parameters']['interfaces'])
        self.assertIn('ip', template_dict['parameters']['interfaces']['target'])
        self.assertIsNone(template_dict['parameters']['interfaces']['target']['ip'])
        self.assertIsNotNone(template_dict['parameters']['interfaces']['target']['mac'])

    @unittest.skipIf(infrastructure_error('lxc-info'), "lxc-info not installed")
    def test_panda_lxc_template(self):
        logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
        logger = logging.getLogger('unittests')
        logger.disabled = True
        logger.propagate = False
        logger = logging.getLogger('dispatcher')
        logging.disable(logging.DEBUG)
        logger.disabled = True
        logger.propagate = False
        data = """{% extends 'panda.jinja2' %}
{% set power_off_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu15 --command off --port 07' %}
{% set hard_reset_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu15 --command reboot --port 07' %}
{% set connection_command = 'telnet serial4 7010' %}
{% set power_on_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu15 --command on --port 07' %}"""
        self.assertTrue(self.validate_data('staging-panda-01', data))
        template_dict = prepare_jinja_template('staging-panda-01', data, raw=False)
        fdesc, device_yaml = tempfile.mkstemp()
        os.write(fdesc, yaml.dump(template_dict).encode())
        panda = NewDevice(device_yaml)
        lxc_yaml = os.path.join(os.path.dirname(__file__), 'devices', 'panda-lxc-aep.yaml')
        with open(lxc_yaml) as sample_job_data:
            parser = JobParser()
            job = parser.parse(sample_job_data, panda, 4577, None, "")
        os.close(fdesc)
        job.logger = DummyLogger()
        job.logger.disabled = True
        job.logger.propagate = False
        job.validate()

    def test_ethaddr(self):
        data = """{% extends 'b2260.jinja2' %}
{% set hard_reset_command = '/usr/local/lab-scripts/snmp_pdu_control --port 14 --hostname pdu18 --command reboot' %}
{% set power_off_command = '/usr/local/lab-scripts/snmp_pdu_control --port 14 --hostname pdu18 --command off' %}
{% set connection_command = 'telnet localhost 7114' %}
{% set power_on_command = '/usr/local/lab-scripts/snmp_pdu_control --port 14 --hostname pdu18 --command on' %}
{% set uboot_mac_addr = '00:80:e1:12:81:30' %}"""
        self.assertTrue(self.validate_data('staging-b2260-01', data))
        template_dict = prepare_jinja_template('staging-b2260-01', data, raw=False)
        ethaddr = False
        for command in template_dict['actions']['boot']['methods']['u-boot']['ramdisk']['commands']:
            if command.startswith('setenv ethaddr'):
                self.assertEqual(command, 'setenv ethaddr 00:80:e1:12:81:30')
                ethaddr = True
        self.assertTrue(ethaddr)
        ethaddr = False
        for command in template_dict['actions']['boot']['methods']['u-boot']['nfs']['commands']:
            if command.startswith('setenv ethaddr'):
                self.assertEqual(command, 'setenv ethaddr 00:80:e1:12:81:30')
                ethaddr = True
        self.assertTrue(ethaddr)

    def test_ip_args(self):
        data = """{% extends 'arndale.jinja2' %}
{% set power_off_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu15 --command off --port 07' %}
{% set hard_reset_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu15 --command reboot --port 07' %}
{% set connection_command = 'telnet serial4 7010' %}
{% set power_on_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu15 --command on --port 07' %}"""
        self.assertTrue(self.validate_data('staging-arndale-01', data))
        template_dict = prepare_jinja_template('staging-panda-01', data, raw=False)
        for line in template_dict['actions']['boot']['methods']['u-boot']['ramdisk']['commands']:
            if line.startswith("setenv nfsargs"):
                self.assertIn('ip=:::::eth0:dhcp', line)
                self.assertNotIn('ip=dhcp', line)
            elif line.startswith("setenv bootargs"):
                self.assertIn("drm_kms_helper.edid_firmware=edid-1920x1080.fw", line)

    def test_d03(self):
        data = """{% extends 'd03.jinja2' %}
{% set hard_reset_command = '/usr/bin/pduclient --daemon services --hostname pdu09 --command reboot --port 07' %}
{% set grub_installed_device = '(hd2,gpt1)' %}
{% set power_off_command = '/usr/bin/pduclient --daemon services --hostname pdu09 --command off --port 07' %}
{% set connection_command = 'telnet localhost 7001' %}
{% set power_on_command = '/usr/bin/pduclient --daemon services --hostname pdu09 --command on --port 07' %}
{% set boot_character_delay = 30 %}"""
        self.assertTrue(self.validate_data('staging-d03-01', data))
        template_dict = prepare_jinja_template('staging-d03-01',
                                               data, raw=False)
        self.assertIn('character_delays', template_dict)
        self.assertIn('boot', template_dict['character_delays'])
        self.assertNotIn('test', template_dict['character_delays'])
        self.assertEqual(30, template_dict['character_delays']['boot'])

    def test_juno_vexpress_template(self):
        data = """{% extends 'juno.jinja2' %}
    {% set connection_command = 'telnet serial4 7001' %}
    {% set hard_reset_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu18 --command reboot --port 10 --delay 10' %}
    {% set power_off_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu18 --command off --port 10 --delay 10' %}
    {% set power_on_command = '/usr/local/lab-scripts/snmp_pdu_control --hostname pdu18 --command on --port 10 --delay 10' %}
    {% set usb_label = 'SanDiskCruzerBlade' %}
    {% set usb_uuid = 'usb-SanDisk_Cruzer_Blade_20060266531DA442AD42-0:0' %}
    {% set usb_device_id = 0 %}
    {% set nfs_uboot_bootcmd = (
    "          - setenv bootcmd 'dhcp; setenv serverip {SERVER_IP}; run loadkernel; run loadinitrd; run loadfdt; {BOOTX}'
              - boot") %}"""
        self.assertTrue(self.validate_data('staging-juno-01', data))
        test_template = prepare_jinja_template('staging-juno-01', data, raw=True)
        rendered = test_template.render()
        template_dict = yaml.safe_load(rendered)
        self.assertIsNotNone(template_dict)
        self.assertEqual({'boot': 30}, template_dict['character_delays'])
        self.assertIn('error-messages', template_dict['constants']['u-boot'])
        self.assertEqual('juno#', template_dict['actions']['boot']['methods']['u-boot']['parameters']['bootloader_prompt'])
        self.assertEqual('Shell>', template_dict['actions']['boot']['methods']['uefi']['parameters']['bootloader_prompt'])
        self.assertEqual('Start:', template_dict['actions']['boot']['methods']['uefi-menu']['parameters']['bootloader_prompt'])

        rendered = test_template.render(bootloader_prompt="vexpress>")
        template_dict = yaml.safe_load(rendered)
        self.assertIsNotNone(template_dict)
        self.assertEqual({'boot': 30}, template_dict['character_delays'])
        self.assertIn('error-messages', template_dict['constants']['u-boot'])
        self.assertEqual('vexpress>', template_dict['actions']['boot']['methods']['u-boot']['parameters']['bootloader_prompt'])
        self.assertEqual('Shell>', template_dict['actions']['boot']['methods']['uefi']['parameters']['bootloader_prompt'])
        self.assertEqual('Start:', template_dict['actions']['boot']['methods']['uefi-menu']['parameters']['bootloader_prompt'])

    def test_imx8m_template(self):
        fastboot_cmd_order = ['update',
                              'ptable',
                              'partition',
                              'hyp',
                              'modem',
                              'rpm',
                              'sbl1',
                              'sbl2',
                              'sec',
                              'tz',
                              'aboot',
                              'boot',
                              'rootfs',
                              'vendor',
                              'system',
                              'cache',
                              'userdata']

        rendered = self.render_device_dictionary_file('imx8m-01.jinja2')
        template_dict = yaml.safe_load(rendered)
        self.assertIsNotNone(template_dict)
        self.assertIn('error-messages', template_dict['constants']['u-boot'])
        self.assertEqual('u-boot=>', template_dict['actions']['boot']['methods']['u-boot']['parameters']['bootloader_prompt'])

        context = {'bootloader_prompt': 'imx8m=>'}
        rendered = self.render_device_dictionary_file('imx8m-01.jinja2', context)
        template_dict = yaml.safe_load(rendered)
        self.assertIsNotNone(template_dict)
        self.assertIn('error-messages', template_dict['constants']['u-boot'])
        self.assertEqual('imx8m=>', template_dict['actions']['boot']['methods']['u-boot']['parameters']['bootloader_prompt'])

        for cmd in template_dict['flash_cmds_order']:
            idx = template_dict['flash_cmds_order'].index(cmd)
            self.assertEqual(cmd, fastboot_cmd_order[idx])
        # test overwriting kernel args
        checked = False
        context = {'console_device': 'ttyUSB1'}
        rendered = self.render_device_dictionary_file('imx8m-01.jinja2', context)
        template_dict = yaml.safe_load(rendered)
        commands = template_dict['actions']['boot']['methods']['u-boot']['ramdisk']['commands']
        self.assertIsNotNone(commands)
        self.assertIsInstance(commands, list)
        for line in commands:
            if 'setenv bootargs' in line:
                self.assertIn("console=ttyUSB1", line)
                checked = True
        self.assertTrue(checked)

    def test_xilinx_zcu102(self):
        with open(os.path.join(os.path.dirname(__file__), 'devices', 'zcu102.jinja2')) as zcu:
            data = zcu.read()
        self.assertTrue(self.validate_data('zcu-01', data))
        template_dict = prepare_jinja_template('zcu-01', data, raw=False)
        self.assertIn('u-boot', template_dict['actions']['boot']['methods'])
        self.assertIn('ramdisk', template_dict['actions']['boot']['methods']['u-boot'])
        commands = template_dict['actions']['boot']['methods']['u-boot']['ramdisk']['commands']
        for command in commands:
            if not command.startswith('setenv loadkernel'):
                continue
            self.assertNotIn('tftp ', command)
            self.assertIn('tftpb', command)

        for command in commands:
            if not command.startswith('setenv bootargs'):
                continue
            self.assertNotIn('console=ttyS0,115200n8', command)
            self.assertNotIn('console=', command)
            self.assertNotIn('console=ttyO0', command)
            self.assertNotIn('115200n8', command)
            self.assertNotIn('n8', command)

    def test_flasher(self):
        data = """{% extends 'b2260.jinja2' %}
{% set flasher_deploy_commands = ['flashing', 'something --else'] %}
"""
        self.assertTrue(self.validate_data('staging-b2260-01', data))
        template_dict = prepare_jinja_template('staging-b2260-01', data, raw=False)
        self.assertEqual(['flashing', 'something --else'],
                         template_dict['actions']['deploy']['methods']['flasher']['commands'])

    def test_user_command(self):
        data = """{% extends 'b2260.jinja2' %}
{% set user_commands = {'set_boot_to_usb': {'do': '/bin/true', 'undo': '/bin/true'},
                        'set_boot_to_sd': {'do': '/bin/true', 'undo': '/bin/true'}} %}
"""
        self.assertTrue(self.validate_data('staging-b2260-01', data))
        template_dict = prepare_jinja_template('staging-b2260-01', data, raw=False)
        self.assertEqual({'set_boot_to_usb': {'do': '/bin/true', 'undo': '/bin/true'},
                          'set_boot_to_sd': {'do': '/bin/true', 'undo': '/bin/true'}},
                         template_dict['commands']['users'])

    def test_meson8b_template(self):
        template_dict = self.render_device_dictionary_file('meson8b-odroidc1-1.jinja2', raw=False)
        self.assertIsNotNone(template_dict)
        template_dict['constants']['u-boot'].get('interrupt_ctrl_list', self.fail)
        self.assertEqual(template_dict['constants']['u-boot']['interrupt_ctrl_list'], ['c'])