1# SPDX-License-Identifier: GPL-2.0
2# (C) Copyright 2023, Advanced Micro Devices, Inc.
3
4"""
5Note: This test doesn't rely on boardenv_* configuration value but they can
6change test behavior.
7
8For example:
9
10# Setup env__saveenv_test_skip to True if saveenv test is not possible or
11# desired and should be skipped.
12env__saveenv_test_skip = True
13
14# Setup env__saveenv_test to set the bootmode if 'modeboot' u-boot environment
15# variable is not set. Test will be skipped if bootmode is not set in both
16# places i.e, boardenv and modeboot u-boot environment variable
17env__saveenv_test = {
18    'bootmode': 'qspiboot',
19}
20
21# This test will be also skipped if the bootmode is detected to JTAG.
22"""
23
24import pytest
25import random
26import ipaddress
27import string
28import uuid
29
30# Setup the env
31def setup_saveenv_env(u_boot_console):
32    if u_boot_console.config.env.get('env__saveenv_test_skip', False):
33        pytest.skip('saveenv test is not enabled')
34
35    output = u_boot_console.run_command('echo $modeboot')
36    if output:
37        bootmode = output
38    else:
39        f = u_boot_console.config.env.get('env__saveenv_test', None)
40        if not f:
41            pytest.skip('bootmode cannot be determined')
42        bootmode = f.get('bootmode', 'jtagboot')
43
44    if 'jtag' in bootmode:
45        pytest.skip('skipping saveenv test due to jtag bootmode')
46
47# Check return code
48def ret_code(u_boot_console):
49    return u_boot_console.run_command('echo $?')
50
51# Verify env variable
52def check_env(u_boot_console, var_name, var_value):
53    if var_value:
54        output = u_boot_console.run_command(f'printenv {var_name}')
55        var_value = str(var_value)
56        if (var_value.startswith("'") and var_value.endswith("'")) or (
57            var_value.startswith('"') and var_value.endswith('"')
58        ):
59            var_value = var_value.split(var_value[-1])[1]
60        assert var_value in output
61        assert ret_code(u_boot_console).endswith('0')
62    else:
63        u_boot_console.p.send(f'printenv {var_name}\n')
64        output = u_boot_console.p.expect(['not defined'])
65        assert output == 0
66        assert ret_code(u_boot_console).endswith('1')
67
68# Set env variable
69def set_env(u_boot_console, var_name, var_value):
70    u_boot_console.run_command(f'setenv {var_name} {var_value}')
71    assert ret_code(u_boot_console).endswith('0')
72    check_env(u_boot_console, var_name, var_value)
73
74@pytest.mark.buildconfigspec('cmd_saveenv')
75@pytest.mark.buildconfigspec('hush_parser')
76def test_saveenv(u_boot_console):
77    """Test the saveenv command in non-JTAG bootmode.
78    It saves the U-Boot environment in persistent storage.
79    """
80    setup_saveenv_env(u_boot_console)
81
82    # Set env for random mac address
83    rand_mac = '%02x:%02x:%02x:%02x:%02x:%02x' % (
84        random.randint(0, 255),
85        random.randint(0, 255),
86        random.randint(0, 255),
87        random.randint(0, 255),
88        random.randint(0, 255),
89        random.randint(0, 255),
90    )
91    set_env(u_boot_console, 'mac_addr', rand_mac)
92
93    # Set env for random IPv4 address
94    rand_ipv4 = ipaddress.IPv4Address._string_from_ip_int(
95        random.randint(0, ipaddress.IPv4Address._ALL_ONES)
96    )
97    set_env(u_boot_console, 'ipv4_addr', rand_ipv4)
98
99    # Set env for random IPv6 address
100    rand_ipv6 = ipaddress.IPv6Address._string_from_ip_int(
101        random.randint(0, ipaddress.IPv6Address._ALL_ONES)
102    )
103    set_env(u_boot_console, 'ipv6_addr', rand_ipv6)
104
105    # Set env for random number
106    rand_num = random.randrange(1, 10**9)
107    set_env(u_boot_console, 'num_var', rand_num)
108
109    # Set env for uuid
110    uuid_str = uuid.uuid4().hex.lower()
111    set_env(u_boot_console, 'uuid_var', uuid_str)
112
113    # Set env for random string including special characters
114    sc = "!#%&()*+,-./:;<=>?@[\\]^_`{|}~"
115    rand_str = ''.join(
116        random.choices(' ' + string.ascii_letters + sc + string.digits, k=300)
117    )
118    set_env(u_boot_console, 'str_var', f'"{rand_str}"')
119
120    # Set env for empty string
121    set_env(u_boot_console, 'empty_var', '')
122
123    # Save the env variables
124    u_boot_console.run_command('saveenv')
125    assert ret_code(u_boot_console).endswith('0')
126
127    # Reboot
128    u_boot_console.run_command('reset', wait_for_reboot=True)
129
130    # Verify the saved env variables
131    check_env(u_boot_console, 'mac_addr', rand_mac)
132    check_env(u_boot_console, 'ipv4_addr', rand_ipv4)
133    check_env(u_boot_console, 'ipv6_addr', rand_ipv6)
134    check_env(u_boot_console, 'num_var', rand_num)
135    check_env(u_boot_console, 'uuid_var', uuid_str)
136    check_env(u_boot_console, 'str_var', rand_str)
137    check_env(u_boot_console, 'empty_var', '')
138