183d290c5STom Rini# SPDX-License-Identifier: GPL-2.0 25ab097abSStephen Warren# Copyright (c) 2015 Stephen Warren 35ab097abSStephen Warren# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. 45ab097abSStephen Warren 55ab097abSStephen Warren# Test operation of shell commands relating to environment variables. 65ab097abSStephen Warren 75ab097abSStephen Warrenimport pytest 8*b7a7c411SQuentin Schulzimport u_boot_utils 95ab097abSStephen Warren 105ab097abSStephen Warren# FIXME: This might be useful for other tests; 115ab097abSStephen Warren# perhaps refactor it into ConsoleBase or some other state object? 125ab097abSStephen Warrenclass StateTestEnv(object): 13e8debf39SStephen Warren """Container that represents the state of all U-Boot environment variables. 145ab097abSStephen Warren This enables quick determination of existant/non-existant variable 155ab097abSStephen Warren names. 16e8debf39SStephen Warren """ 175ab097abSStephen Warren 185ab097abSStephen Warren def __init__(self, u_boot_console): 19e8debf39SStephen Warren """Initialize a new StateTestEnv object. 205ab097abSStephen Warren 215ab097abSStephen Warren Args: 225ab097abSStephen Warren u_boot_console: A U-Boot console. 235ab097abSStephen Warren 245ab097abSStephen Warren Returns: 255ab097abSStephen Warren Nothing. 26e8debf39SStephen Warren """ 275ab097abSStephen Warren 285ab097abSStephen Warren self.u_boot_console = u_boot_console 295ab097abSStephen Warren self.get_env() 305ab097abSStephen Warren self.set_var = self.get_non_existent_var() 315ab097abSStephen Warren 325ab097abSStephen Warren def get_env(self): 33e8debf39SStephen Warren """Read all current environment variables from U-Boot. 345ab097abSStephen Warren 355ab097abSStephen Warren Args: 365ab097abSStephen Warren None. 375ab097abSStephen Warren 385ab097abSStephen Warren Returns: 395ab097abSStephen Warren Nothing. 40e8debf39SStephen Warren """ 415ab097abSStephen Warren 427a8f8865SStephen Warren if self.u_boot_console.config.buildconfig.get( 437a8f8865SStephen Warren 'config_version_variable', 'n') == 'y': 44da37f006SHeiko Schocher with self.u_boot_console.disable_check('main_signon'): 45da37f006SHeiko Schocher response = self.u_boot_console.run_command('printenv') 46da37f006SHeiko Schocher else: 475ab097abSStephen Warren response = self.u_boot_console.run_command('printenv') 485ab097abSStephen Warren self.env = {} 495ab097abSStephen Warren for l in response.splitlines(): 505ab097abSStephen Warren if not '=' in l: 515ab097abSStephen Warren continue 525ab097abSStephen Warren (var, value) = l.strip().split('=', 1) 535ab097abSStephen Warren self.env[var] = value 545ab097abSStephen Warren 555ab097abSStephen Warren def get_existent_var(self): 56e8debf39SStephen Warren """Return the name of an environment variable that exists. 575ab097abSStephen Warren 585ab097abSStephen Warren Args: 595ab097abSStephen Warren None. 605ab097abSStephen Warren 615ab097abSStephen Warren Returns: 625ab097abSStephen Warren The name of an environment variable. 63e8debf39SStephen Warren """ 645ab097abSStephen Warren 655ab097abSStephen Warren for var in self.env: 665ab097abSStephen Warren return var 675ab097abSStephen Warren 685ab097abSStephen Warren def get_non_existent_var(self): 69e8debf39SStephen Warren """Return the name of an environment variable that does not exist. 705ab097abSStephen Warren 715ab097abSStephen Warren Args: 725ab097abSStephen Warren None. 735ab097abSStephen Warren 745ab097abSStephen Warren Returns: 755ab097abSStephen Warren The name of an environment variable. 76e8debf39SStephen Warren """ 775ab097abSStephen Warren 785ab097abSStephen Warren n = 0 795ab097abSStephen Warren while True: 805ab097abSStephen Warren var = 'test_env_' + str(n) 815ab097abSStephen Warren if var not in self.env: 825ab097abSStephen Warren return var 835ab097abSStephen Warren n += 1 845ab097abSStephen Warren 85636f38d8SStephen Warrenste = None 86636f38d8SStephen Warren@pytest.fixture(scope='function') 875ab097abSStephen Warrendef state_test_env(u_boot_console): 88e8debf39SStephen Warren """pytest fixture to provide a StateTestEnv object to tests.""" 895ab097abSStephen Warren 90636f38d8SStephen Warren global ste 91636f38d8SStephen Warren if not ste: 92636f38d8SStephen Warren ste = StateTestEnv(u_boot_console) 93636f38d8SStephen Warren return ste 945ab097abSStephen Warren 955ab097abSStephen Warrendef unset_var(state_test_env, var): 96e8debf39SStephen Warren """Unset an environment variable. 975ab097abSStephen Warren 985ab097abSStephen Warren This both executes a U-Boot shell command and updates a StateTestEnv 995ab097abSStephen Warren object. 1005ab097abSStephen Warren 1015ab097abSStephen Warren Args: 102db261f00SStephen Warren state_test_env: The StateTestEnv object to update. 1035ab097abSStephen Warren var: The variable name to unset. 1045ab097abSStephen Warren 1055ab097abSStephen Warren Returns: 1065ab097abSStephen Warren Nothing. 107e8debf39SStephen Warren """ 1085ab097abSStephen Warren 1095ab097abSStephen Warren state_test_env.u_boot_console.run_command('setenv %s' % var) 1105ab097abSStephen Warren if var in state_test_env.env: 1115ab097abSStephen Warren del state_test_env.env[var] 1125ab097abSStephen Warren 1135ab097abSStephen Warrendef set_var(state_test_env, var, value): 114e8debf39SStephen Warren """Set an environment variable. 1155ab097abSStephen Warren 1165ab097abSStephen Warren This both executes a U-Boot shell command and updates a StateTestEnv 1175ab097abSStephen Warren object. 1185ab097abSStephen Warren 1195ab097abSStephen Warren Args: 120db261f00SStephen Warren state_test_env: The StateTestEnv object to update. 1215ab097abSStephen Warren var: The variable name to set. 1225ab097abSStephen Warren value: The value to set the variable to. 1235ab097abSStephen Warren 1245ab097abSStephen Warren Returns: 1255ab097abSStephen Warren Nothing. 126e8debf39SStephen Warren """ 1275ab097abSStephen Warren 1283e229a83SStephen Warren bc = state_test_env.u_boot_console.config.buildconfig 1293e229a83SStephen Warren if bc.get('config_hush_parser', None): 1303e229a83SStephen Warren quote = '"' 1313e229a83SStephen Warren else: 1323e229a83SStephen Warren quote = '' 1333e229a83SStephen Warren if ' ' in value: 1343e229a83SStephen Warren pytest.skip('Space in variable value on non-Hush shell') 1353e229a83SStephen Warren 1363e229a83SStephen Warren state_test_env.u_boot_console.run_command( 1373e229a83SStephen Warren 'setenv %s %s%s%s' % (var, quote, value, quote)) 1385ab097abSStephen Warren state_test_env.env[var] = value 1395ab097abSStephen Warren 1405ab097abSStephen Warrendef validate_empty(state_test_env, var): 141e8debf39SStephen Warren """Validate that a variable is not set, using U-Boot shell commands. 1425ab097abSStephen Warren 1435ab097abSStephen Warren Args: 1445ab097abSStephen Warren var: The variable name to test. 1455ab097abSStephen Warren 1465ab097abSStephen Warren Returns: 1475ab097abSStephen Warren Nothing. 148e8debf39SStephen Warren """ 1495ab097abSStephen Warren 1505ab097abSStephen Warren response = state_test_env.u_boot_console.run_command('echo $%s' % var) 1515ab097abSStephen Warren assert response == '' 1525ab097abSStephen Warren 1535ab097abSStephen Warrendef validate_set(state_test_env, var, value): 154e8debf39SStephen Warren """Validate that a variable is set, using U-Boot shell commands. 1555ab097abSStephen Warren 1565ab097abSStephen Warren Args: 1575ab097abSStephen Warren var: The variable name to test. 1585ab097abSStephen Warren value: The value the variable is expected to have. 1595ab097abSStephen Warren 1605ab097abSStephen Warren Returns: 1615ab097abSStephen Warren Nothing. 162e8debf39SStephen Warren """ 1635ab097abSStephen Warren 1645ab097abSStephen Warren # echo does not preserve leading, internal, or trailing whitespace in the 1655ab097abSStephen Warren # value. printenv does, and hence allows more complete testing. 1665ab097abSStephen Warren response = state_test_env.u_boot_console.run_command('printenv %s' % var) 1675ab097abSStephen Warren assert response == ('%s=%s' % (var, value)) 1685ab097abSStephen Warren 1695ab097abSStephen Warrendef test_env_echo_exists(state_test_env): 170e8debf39SStephen Warren """Test echoing a variable that exists.""" 1715ab097abSStephen Warren 1725ab097abSStephen Warren var = state_test_env.get_existent_var() 1735ab097abSStephen Warren value = state_test_env.env[var] 1745ab097abSStephen Warren validate_set(state_test_env, var, value) 1755ab097abSStephen Warren 1766b83c38dSMichal Simek@pytest.mark.buildconfigspec('cmd_echo') 1775ab097abSStephen Warrendef test_env_echo_non_existent(state_test_env): 178e8debf39SStephen Warren """Test echoing a variable that doesn't exist.""" 1795ab097abSStephen Warren 1805ab097abSStephen Warren var = state_test_env.set_var 1815ab097abSStephen Warren validate_empty(state_test_env, var) 1825ab097abSStephen Warren 1835ab097abSStephen Warrendef test_env_printenv_non_existent(state_test_env): 184e8debf39SStephen Warren """Test printenv error message for non-existant variables.""" 1855ab097abSStephen Warren 1865ab097abSStephen Warren var = state_test_env.set_var 1875ab097abSStephen Warren c = state_test_env.u_boot_console 1885ab097abSStephen Warren with c.disable_check('error_notification'): 1895ab097abSStephen Warren response = c.run_command('printenv %s' % var) 1905ab097abSStephen Warren assert(response == '## Error: "%s" not defined' % var) 1915ab097abSStephen Warren 1926b83c38dSMichal Simek@pytest.mark.buildconfigspec('cmd_echo') 1935ab097abSStephen Warrendef test_env_unset_non_existent(state_test_env): 194e8debf39SStephen Warren """Test unsetting a nonexistent variable.""" 1955ab097abSStephen Warren 1965ab097abSStephen Warren var = state_test_env.get_non_existent_var() 1975ab097abSStephen Warren unset_var(state_test_env, var) 1985ab097abSStephen Warren validate_empty(state_test_env, var) 1995ab097abSStephen Warren 2005ab097abSStephen Warrendef test_env_set_non_existent(state_test_env): 201e8debf39SStephen Warren """Test set a non-existant variable.""" 2025ab097abSStephen Warren 2035ab097abSStephen Warren var = state_test_env.set_var 2045ab097abSStephen Warren value = 'foo' 2055ab097abSStephen Warren set_var(state_test_env, var, value) 2065ab097abSStephen Warren validate_set(state_test_env, var, value) 2075ab097abSStephen Warren 2085ab097abSStephen Warrendef test_env_set_existing(state_test_env): 209e8debf39SStephen Warren """Test setting an existant variable.""" 2105ab097abSStephen Warren 2115ab097abSStephen Warren var = state_test_env.set_var 2125ab097abSStephen Warren value = 'bar' 2135ab097abSStephen Warren set_var(state_test_env, var, value) 2145ab097abSStephen Warren validate_set(state_test_env, var, value) 2155ab097abSStephen Warren 2166b83c38dSMichal Simek@pytest.mark.buildconfigspec('cmd_echo') 2175ab097abSStephen Warrendef test_env_unset_existing(state_test_env): 218e8debf39SStephen Warren """Test unsetting a variable.""" 2195ab097abSStephen Warren 2205ab097abSStephen Warren var = state_test_env.set_var 2215ab097abSStephen Warren unset_var(state_test_env, var) 2225ab097abSStephen Warren validate_empty(state_test_env, var) 2235ab097abSStephen Warren 2245ab097abSStephen Warrendef test_env_expansion_spaces(state_test_env): 225e8debf39SStephen Warren """Test expanding a variable that contains a space in its value.""" 2265ab097abSStephen Warren 2275ab097abSStephen Warren var_space = None 2285ab097abSStephen Warren var_test = None 2295ab097abSStephen Warren try: 2305ab097abSStephen Warren var_space = state_test_env.get_non_existent_var() 2315ab097abSStephen Warren set_var(state_test_env, var_space, ' ') 2325ab097abSStephen Warren 2335ab097abSStephen Warren var_test = state_test_env.get_non_existent_var() 2345ab097abSStephen Warren value = ' 1${%(var_space)s}${%(var_space)s} 2 ' % locals() 2355ab097abSStephen Warren set_var(state_test_env, var_test, value) 2365ab097abSStephen Warren value = ' 1 2 ' 2375ab097abSStephen Warren validate_set(state_test_env, var_test, value) 2385ab097abSStephen Warren finally: 2395ab097abSStephen Warren if var_space: 2405ab097abSStephen Warren unset_var(state_test_env, var_space) 2415ab097abSStephen Warren if var_test: 2425ab097abSStephen Warren unset_var(state_test_env, var_test) 243*b7a7c411SQuentin Schulz 244*b7a7c411SQuentin Schulz@pytest.mark.buildconfigspec('cmd_importenv') 245*b7a7c411SQuentin Schulzdef test_env_import_checksum_no_size(state_test_env): 246*b7a7c411SQuentin Schulz """Test that omitted ('-') size parameter with checksum validation fails the 247*b7a7c411SQuentin Schulz env import function. 248*b7a7c411SQuentin Schulz """ 249*b7a7c411SQuentin Schulz c = state_test_env.u_boot_console 250*b7a7c411SQuentin Schulz ram_base = u_boot_utils.find_ram_base(state_test_env.u_boot_console) 251*b7a7c411SQuentin Schulz addr = '%08x' % ram_base 252*b7a7c411SQuentin Schulz 253*b7a7c411SQuentin Schulz with c.disable_check('error_notification'): 254*b7a7c411SQuentin Schulz response = c.run_command('env import -c %s -' % addr) 255*b7a7c411SQuentin Schulz assert(response == '## Error: external checksum format must pass size') 256*b7a7c411SQuentin Schulz 257*b7a7c411SQuentin Schulz@pytest.mark.buildconfigspec('cmd_importenv') 258*b7a7c411SQuentin Schulzdef test_env_import_whitelist_checksum_no_size(state_test_env): 259*b7a7c411SQuentin Schulz """Test that omitted ('-') size parameter with checksum validation fails the 260*b7a7c411SQuentin Schulz env import function when variables are passed as parameters. 261*b7a7c411SQuentin Schulz """ 262*b7a7c411SQuentin Schulz c = state_test_env.u_boot_console 263*b7a7c411SQuentin Schulz ram_base = u_boot_utils.find_ram_base(state_test_env.u_boot_console) 264*b7a7c411SQuentin Schulz addr = '%08x' % ram_base 265*b7a7c411SQuentin Schulz 266*b7a7c411SQuentin Schulz with c.disable_check('error_notification'): 267*b7a7c411SQuentin Schulz response = c.run_command('env import -c %s - foo1 foo2 foo4' % addr) 268*b7a7c411SQuentin Schulz assert(response == '## Error: external checksum format must pass size') 269*b7a7c411SQuentin Schulz 270*b7a7c411SQuentin Schulz@pytest.mark.buildconfigspec('cmd_exportenv') 271*b7a7c411SQuentin Schulz@pytest.mark.buildconfigspec('cmd_importenv') 272*b7a7c411SQuentin Schulzdef test_env_import_whitelist(state_test_env): 273*b7a7c411SQuentin Schulz """Test importing only a handful of env variables from an environment.""" 274*b7a7c411SQuentin Schulz c = state_test_env.u_boot_console 275*b7a7c411SQuentin Schulz ram_base = u_boot_utils.find_ram_base(state_test_env.u_boot_console) 276*b7a7c411SQuentin Schulz addr = '%08x' % ram_base 277*b7a7c411SQuentin Schulz 278*b7a7c411SQuentin Schulz set_var(state_test_env, 'foo1', 'bar1') 279*b7a7c411SQuentin Schulz set_var(state_test_env, 'foo2', 'bar2') 280*b7a7c411SQuentin Schulz set_var(state_test_env, 'foo3', 'bar3') 281*b7a7c411SQuentin Schulz 282*b7a7c411SQuentin Schulz c.run_command('env export %s' % addr) 283*b7a7c411SQuentin Schulz 284*b7a7c411SQuentin Schulz unset_var(state_test_env, 'foo1') 285*b7a7c411SQuentin Schulz set_var(state_test_env, 'foo2', 'test2') 286*b7a7c411SQuentin Schulz set_var(state_test_env, 'foo4', 'bar4') 287*b7a7c411SQuentin Schulz 288*b7a7c411SQuentin Schulz # no foo1 in current env, foo2 overridden, foo3 should be of the value 289*b7a7c411SQuentin Schulz # before exporting and foo4 should be of the value before importing. 290*b7a7c411SQuentin Schulz c.run_command('env import %s - foo1 foo2 foo4' % addr) 291*b7a7c411SQuentin Schulz 292*b7a7c411SQuentin Schulz validate_set(state_test_env, 'foo1', 'bar1') 293*b7a7c411SQuentin Schulz validate_set(state_test_env, 'foo2', 'bar2') 294*b7a7c411SQuentin Schulz validate_set(state_test_env, 'foo3', 'bar3') 295*b7a7c411SQuentin Schulz validate_set(state_test_env, 'foo4', 'bar4') 296*b7a7c411SQuentin Schulz 297*b7a7c411SQuentin Schulz # Cleanup test environment 298*b7a7c411SQuentin Schulz unset_var(state_test_env, 'foo1') 299*b7a7c411SQuentin Schulz unset_var(state_test_env, 'foo2') 300*b7a7c411SQuentin Schulz unset_var(state_test_env, 'foo3') 301*b7a7c411SQuentin Schulz unset_var(state_test_env, 'foo4') 302*b7a7c411SQuentin Schulz 303*b7a7c411SQuentin Schulz@pytest.mark.buildconfigspec('cmd_exportenv') 304*b7a7c411SQuentin Schulz@pytest.mark.buildconfigspec('cmd_importenv') 305*b7a7c411SQuentin Schulzdef test_env_import_whitelist_delete(state_test_env): 306*b7a7c411SQuentin Schulz 307*b7a7c411SQuentin Schulz """Test importing only a handful of env variables from an environment, with. 308*b7a7c411SQuentin Schulz deletion if a var A that is passed to env import is not in the 309*b7a7c411SQuentin Schulz environment to be imported. 310*b7a7c411SQuentin Schulz """ 311*b7a7c411SQuentin Schulz c = state_test_env.u_boot_console 312*b7a7c411SQuentin Schulz ram_base = u_boot_utils.find_ram_base(state_test_env.u_boot_console) 313*b7a7c411SQuentin Schulz addr = '%08x' % ram_base 314*b7a7c411SQuentin Schulz 315*b7a7c411SQuentin Schulz set_var(state_test_env, 'foo1', 'bar1') 316*b7a7c411SQuentin Schulz set_var(state_test_env, 'foo2', 'bar2') 317*b7a7c411SQuentin Schulz set_var(state_test_env, 'foo3', 'bar3') 318*b7a7c411SQuentin Schulz 319*b7a7c411SQuentin Schulz c.run_command('env export %s' % addr) 320*b7a7c411SQuentin Schulz 321*b7a7c411SQuentin Schulz unset_var(state_test_env, 'foo1') 322*b7a7c411SQuentin Schulz set_var(state_test_env, 'foo2', 'test2') 323*b7a7c411SQuentin Schulz set_var(state_test_env, 'foo4', 'bar4') 324*b7a7c411SQuentin Schulz 325*b7a7c411SQuentin Schulz # no foo1 in current env, foo2 overridden, foo3 should be of the value 326*b7a7c411SQuentin Schulz # before exporting and foo4 should be empty. 327*b7a7c411SQuentin Schulz c.run_command('env import -d %s - foo1 foo2 foo4' % addr) 328*b7a7c411SQuentin Schulz 329*b7a7c411SQuentin Schulz validate_set(state_test_env, 'foo1', 'bar1') 330*b7a7c411SQuentin Schulz validate_set(state_test_env, 'foo2', 'bar2') 331*b7a7c411SQuentin Schulz validate_set(state_test_env, 'foo3', 'bar3') 332*b7a7c411SQuentin Schulz validate_empty(state_test_env, 'foo4') 333*b7a7c411SQuentin Schulz 334*b7a7c411SQuentin Schulz # Cleanup test environment 335*b7a7c411SQuentin Schulz unset_var(state_test_env, 'foo1') 336*b7a7c411SQuentin Schulz unset_var(state_test_env, 'foo2') 337*b7a7c411SQuentin Schulz unset_var(state_test_env, 'foo3') 338*b7a7c411SQuentin Schulz unset_var(state_test_env, 'foo4') 339