From 79883ef7dcc20cb329ffc307c17d77baac62c2bc Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 24 Oct 2019 11:59:18 -0400 Subject: test/py: Split mark to multiple lines We inconsistently note multiple dependencies today in our tests, sometimes with a single line that declares multiple and sometimes multiple single lines. Current pytest seems to fail on the single line format so change to multiple declarations. Reviewed-by: Stephen Warren Reviewed-by: Simon Glass Tested-by: Stephen Warren Tested-by: Simon Glass [on sandbox] Signed-off-by: Tom Rini --- test/py/tests/test_android/test_avb.py | 9 ++++++--- test/py/tests/test_mmc_wr.py | 4 +++- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'test/py') diff --git a/test/py/tests/test_android/test_avb.py b/test/py/tests/test_android/test_avb.py index 81324234355..20ccaf6712f 100644 --- a/test/py/tests/test_android/test_avb.py +++ b/test/py/tests/test_android/test_avb.py @@ -23,7 +23,8 @@ mmc_dev = 1 temp_addr = 0x90000000 temp_addr2 = 0x90002000 -@pytest.mark.buildconfigspec('cmd_avb', 'cmd_mmc') +@pytest.mark.buildconfigspec('cmd_avb') +@pytest.mark.buildconfigspec('cmd_mmc') def test_avb_verify(u_boot_console): """Run AVB 2.0 boot verification chain with avb subset of commands """ @@ -36,7 +37,8 @@ def test_avb_verify(u_boot_console): assert response.find(success_str) -@pytest.mark.buildconfigspec('cmd_avb', 'cmd_mmc') +@pytest.mark.buildconfigspec('cmd_avb') +@pytest.mark.buildconfigspec('cmd_mmc') def test_avb_mmc_uuid(u_boot_console): """Check if 'avb get_uuid' works, compare results with 'part list mmc 1' output @@ -93,7 +95,8 @@ def test_avb_is_unlocked(u_boot_console): assert response == 'Unlocked = 1' -@pytest.mark.buildconfigspec('cmd_avb', 'cmd_mmc') +@pytest.mark.buildconfigspec('cmd_avb') +@pytest.mark.buildconfigspec('cmd_mmc') def test_avb_mmc_read(u_boot_console): """Test mmc read operation """ diff --git a/test/py/tests/test_mmc_wr.py b/test/py/tests/test_mmc_wr.py index 8b18781eac7..ab4c5797442 100644 --- a/test/py/tests/test_mmc_wr.py +++ b/test/py/tests/test_mmc_wr.py @@ -35,7 +35,9 @@ env__mmc_wr_configs = ( """ -@pytest.mark.buildconfigspec('cmd_mmc','cmd_memory', 'cmd_random') +@pytest.mark.buildconfigspec('cmd_mmc') +@pytest.mark.buildconfigspec('cmd_memory') +@pytest.mark.buildconfigspec('cmd_random') def test_mmc_wr(u_boot_console, env__mmc_wr_config): """Test the "mmc write" command. -- cgit v1.2.3 From 3c941e048c824b94ae09fd9e1f91116f55ce0f1f Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Thu, 24 Oct 2019 11:59:19 -0400 Subject: test/py: Fix pytest4 deprecation warnings Fix the following spit from pytest: u-boot/test/py/conftest.py:438: RemovedInPytest4Warning: MarkInfo objects are deprecated as they contain merged marks which are hard to deal with correctly. Please use node.get_closest_marker(name) or node.iter_markers(name). Docs: https://docs.pytest.org/en/latest/mark.html#updating-code for board in mark.args: In both cases, the later suggestion is applicable. Reviewed-by: Stephen Warren Reviewed-by: Simon Glass Signed-off-by: Marek Vasut Cc: Igor Opaniuk [trini: Update for current file with a few more cases, un-pin pytest in CI] Tested-by: Simon Glass [on sandbox] Tested-by: Stephen Warren Signed-off-by: Tom Rini --- test/py/conftest.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) (limited to 'test/py') diff --git a/test/py/conftest.py b/test/py/conftest.py index 00d8ef8ba99..30c898b40a0 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -431,11 +431,9 @@ def setup_boardspec(item): Nothing. """ - mark = item.get_marker('boardspec') - if not mark: - return required_boards = [] - for board in mark.args: + for boards in item.iter_markers('boardspec'): + board = boards.args[0] if board.startswith('!'): if ubconfig.board_type == board[1:]: pytest.skip('board "%s" not supported' % ubconfig.board_type) @@ -459,16 +457,14 @@ def setup_buildconfigspec(item): Nothing. """ - mark = item.get_marker('buildconfigspec') - if mark: - for option in mark.args: - if not ubconfig.buildconfig.get('config_' + option.lower(), None): - pytest.skip('.config feature "%s" not enabled' % option.lower()) - notmark = item.get_marker('notbuildconfigspec') - if notmark: - for option in notmark.args: - if ubconfig.buildconfig.get('config_' + option.lower(), None): - pytest.skip('.config feature "%s" enabled' % option.lower()) + for options in item.iter_markers('buildconfigspec'): + option = options.args[0] + if not ubconfig.buildconfig.get('config_' + option.lower(), None): + pytest.skip('.config feature "%s" not enabled' % option.lower()) + for option in item.iter_markers('notbuildconfigspec'): + option = options.args[0] + if ubconfig.buildconfig.get('config_' + option.lower(), None): + pytest.skip('.config feature "%s" enabled' % option.lower()) def tool_is_in_path(tool): for path in os.environ["PATH"].split(os.pathsep): @@ -491,10 +487,8 @@ def setup_requiredtool(item): Nothing. """ - mark = item.get_marker('requiredtool') - if not mark: - return - for tool in mark.args: + for tools in item.iter_markers('requiredtool'): + tool = tools.args[0] if not tool_is_in_path(tool): pytest.skip('tool "%s" not in $PATH' % tool) -- cgit v1.2.3 From fe1193e254faccc4e6629f1cfbc99d5ceb34428a Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 24 Oct 2019 11:59:20 -0400 Subject: test/py: Automated conversion to Python 3 Use the 2to3 tool to perform numerous automatic conversions from Python 2 syntax to Python 3. Also fix whitespace problems that Python 3 catches that Python 2 did not. Reviewed-by: Stephen Warren Reviewed-by: Simon Glass Tested-by: Stephen Warren Tested-by: Simon Glass [on sandbox] Signed-off-by: Tom Rini --- test/py/conftest.py | 9 ++--- test/py/multiplexed_log.py | 4 +-- test/py/test.py | 4 +-- test/py/tests/test_fit.py | 2 -- test/py/tests/test_fpga.py | 46 ++++++++++++------------ test/py/tests/test_fs/conftest.py | 4 +-- test/py/tests/test_log.py | 8 ++--- test/py/tests/test_mmc_wr.py | 74 +++++++++++++++++++-------------------- 8 files changed, 71 insertions(+), 80 deletions(-) (limited to 'test/py') diff --git a/test/py/conftest.py b/test/py/conftest.py index 30c898b40a0..5c19af1d503 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -19,13 +19,10 @@ import os.path import pytest from _pytest.runner import runtestprotocol import re -import StringIO +import io import sys -try: - import configparser -except: - import ConfigParser as configparser +import configparser # Globals: The HTML log file, and the connection to the U-Boot console. log = None @@ -169,7 +166,7 @@ def pytest_configure(config): with open(dot_config, 'rt') as f: ini_str = '[root]\n' + f.read() - ini_sio = StringIO.StringIO(ini_str) + ini_sio = io.StringIO(ini_str) parser = configparser.RawConfigParser() parser.readfp(ini_sio) ubconfig.buildconfig.update(parser.items('root')) diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py index 637a3bd257b..de0aacc659b 100644 --- a/test/py/multiplexed_log.py +++ b/test/py/multiplexed_log.py @@ -5,8 +5,8 @@ # Generate an HTML-formatted log file containing multiple streams of data, # each represented in a well-delineated/-structured fashion. -import cgi import datetime +import html import os.path import shutil import subprocess @@ -334,7 +334,7 @@ $(document).ready(function () { data = data.replace(chr(13), '') data = ''.join((ord(c) in self._nonprint) and ('%%%02x' % ord(c)) or c for c in data) - data = cgi.escape(data) + data = html.escape(data) return data def _terminate_stream(self): diff --git a/test/py/test.py b/test/py/test.py index a5140945d4b..0ce1838833f 100755 --- a/test/py/test.py +++ b/test/py/test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2015 Stephen Warren @@ -7,8 +7,6 @@ # Wrapper script to invoke pytest with the directory name that contains the # U-Boot tests. -from __future__ import print_function - import os import os.path import sys diff --git a/test/py/tests/test_fit.py b/test/py/tests/test_fit.py index e3210ed43fa..4922b9dcc66 100755 --- a/test/py/tests/test_fit.py +++ b/test/py/tests/test_fit.py @@ -3,8 +3,6 @@ # # Sanity check of the FIT handling in U-Boot -from __future__ import print_function - import os import pytest import struct diff --git a/test/py/tests/test_fpga.py b/test/py/tests/test_fpga.py index e3bb7b41c74..ca7ef8ea40d 100644 --- a/test/py/tests/test_fpga.py +++ b/test/py/tests/test_fpga.py @@ -175,29 +175,29 @@ def test_fpga_load_fail(u_boot_console): f, dev, addr, bit, bit_size = load_file_from_var(u_boot_console, 'bitstream_load') for cmd in ['dump', 'load', 'loadb']: - # missing dev parameter - expected = 'fpga: incorrect parameters passed' - output = u_boot_console.run_command('fpga %s %x $filesize' % (cmd, addr)) - #assert expected in output - assert expected_usage in output - - # more parameters - 0 at the end - expected = 'fpga: more parameters passed' - output = u_boot_console.run_command('fpga %s %x %x $filesize 0' % (cmd, dev, addr)) - #assert expected in output - assert expected_usage in output - - # 0 address - expected = 'fpga: zero fpga_data address' - output = u_boot_console.run_command('fpga %s %x 0 $filesize' % (cmd, dev)) - #assert expected in output - assert expected_usage in output - - # 0 filesize - expected = 'fpga: zero size' - output = u_boot_console.run_command('fpga %s %x %x 0' % (cmd, dev, addr)) - #assert expected in output - assert expected_usage in output + # missing dev parameter + expected = 'fpga: incorrect parameters passed' + output = u_boot_console.run_command('fpga %s %x $filesize' % (cmd, addr)) + #assert expected in output + assert expected_usage in output + + # more parameters - 0 at the end + expected = 'fpga: more parameters passed' + output = u_boot_console.run_command('fpga %s %x %x $filesize 0' % (cmd, dev, addr)) + #assert expected in output + assert expected_usage in output + + # 0 address + expected = 'fpga: zero fpga_data address' + output = u_boot_console.run_command('fpga %s %x 0 $filesize' % (cmd, dev)) + #assert expected in output + assert expected_usage in output + + # 0 filesize + expected = 'fpga: zero size' + output = u_boot_console.run_command('fpga %s %x %x 0' % (cmd, dev, addr)) + #assert expected in output + assert expected_usage in output @pytest.mark.buildconfigspec('cmd_fpga') @pytest.mark.buildconfigspec('cmd_echo') diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py index 9324657d216..354d17672fe 100644 --- a/test/py/tests/test_fs/conftest.py +++ b/test/py/tests/test_fs/conftest.py @@ -508,8 +508,8 @@ def fs_obj_unlink(request, u_boot_config): # Test Case 2 check_call('mkdir %s/dir2' % mount_dir, shell=True) - for i in range(0, 20): - check_call('mkdir %s/dir2/0123456789abcdef%02x' + for i in range(0, 20): + check_call('mkdir %s/dir2/0123456789abcdef%02x' % (mount_dir, i), shell=True) # Test Case 4 diff --git a/test/py/tests/test_log.py b/test/py/tests/test_log.py index cb183444c6f..75325fad61a 100644 --- a/test/py/tests/test_log.py +++ b/test/py/tests/test_log.py @@ -27,9 +27,9 @@ def test_log(u_boot_console): """ for i in range(max_level): if mask & 1: - assert 'log_run() log %d' % i == lines.next() + assert 'log_run() log %d' % i == next(lines) if mask & 3: - assert 'func() _log %d' % i == lines.next() + assert 'func() _log %d' % i == next(lines) def run_test(testnum): """Run a particular test number (the 'log test' command) @@ -43,7 +43,7 @@ def test_log(u_boot_console): output = u_boot_console.run_command('log test %d' % testnum) split = output.replace('\r', '').splitlines() lines = iter(split) - assert 'test %d' % testnum == lines.next() + assert 'test %d' % testnum == next(lines) return lines def test0(): @@ -88,7 +88,7 @@ def test_log(u_boot_console): def test10(): lines = run_test(10) for i in range(7): - assert 'log_test() level %d' % i == lines.next() + assert 'log_test() level %d' % i == next(lines) # TODO(sjg@chromium.org): Consider structuring this as separate tests cons = u_boot_console diff --git a/test/py/tests/test_mmc_wr.py b/test/py/tests/test_mmc_wr.py index ab4c5797442..05e5c1ee85d 100644 --- a/test/py/tests/test_mmc_wr.py +++ b/test/py/tests/test_mmc_wr.py @@ -67,41 +67,39 @@ def test_mmc_wr(u_boot_console, env__mmc_wr_config): for i in range(test_iterations): - # Generate random data - cmd = 'random %s %x' % (src_addr, count_bytes) - response = u_boot_console.run_command(cmd) - good_response = '%d bytes filled with random data' % (count_bytes) - assert good_response in response - - # Select MMC device - cmd = 'mmc dev %d' % devid - if is_emmc: - cmd += ' %d' % partid - response = u_boot_console.run_command(cmd) - assert 'no card present' not in response - if is_emmc: - partid_response = "(part %d)" % partid - else: - partid_response = "" - good_response = 'mmc%d%s is current device' % (devid, partid_response) - assert good_response in response - - # Write data - cmd = 'mmc write %s %x %x' % (src_addr, sector, count_sectors) - response = u_boot_console.run_command(cmd) - good_response = 'MMC write: dev # %d, block # %d, count %d ... %d blocks written: OK' % ( - devid, sector, count_sectors, count_sectors) - assert good_response in response - - # Read data - cmd = 'mmc read %s %x %x' % (dst_addr, sector, count_sectors) - response = u_boot_console.run_command(cmd) - good_response = 'MMC read: dev # %d, block # %d, count %d ... %d blocks read: OK' % ( - devid, sector, count_sectors, count_sectors) - assert good_response in response - - # Compare src and dst data - cmd = 'cmp.b %s %s %x' % (src_addr, dst_addr, count_bytes) - response = u_boot_console.run_command(cmd) - good_response = 'Total of %d byte(s) were the same' % (count_bytes) - assert good_response in response + # Generate random data + cmd = 'random %s %x' % (src_addr, count_bytes) + response = u_boot_console.run_command(cmd) + good_response = '%d bytes filled with random data' % (count_bytes) + assert good_response in response + + # Select MMC device + cmd = 'mmc dev %d' % devid + if is_emmc: + cmd += ' %d' % partid + response = u_boot_console.run_command(cmd) + assert 'no card present' not in response + if is_emmc: + partid_response = "(part %d)" % partid + else: + partid_response = "" + good_response = 'mmc%d%s is current device' % (devid, partid_response) + assert good_response in response + + # Write data + cmd = 'mmc write %s %x %x' % (src_addr, sector, count_sectors) + response = u_boot_console.run_command(cmd) + good_response = 'MMC write: dev # %d, block # %d, count %d ... %d blocks written: OK' % (devid, sector, count_sectors, count_sectors) + assert good_response in response + + # Read data + cmd = 'mmc read %s %x %x' % (dst_addr, sector, count_sectors) + response = u_boot_console.run_command(cmd) + good_response = 'MMC read: dev # %d, block # %d, count %d ... %d blocks read: OK' % (devid, sector, count_sectors, count_sectors) + assert good_response in response + + # Compare src and dst data + cmd = 'cmp.b %s %s %x' % (src_addr, dst_addr, count_bytes) + response = u_boot_console.run_command(cmd) + good_response = 'Total of %d byte(s) were the same' % (count_bytes) + assert good_response in response -- cgit v1.2.3 From fd31fc172c626bdac2afd8af9f8482bfc21a5501 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 24 Oct 2019 11:59:21 -0400 Subject: test/py: Manual python3 fixes - Modern pytest is more visible in telling us about parameters that we had not described, so describe a few more. - ConfigParser.readfp(...) is now configparser.read_file(...) - As part of the "strings vs bytes" conversions in Python 3, we use the default encoding/decoding of utf-8 but in some places tell Python to replace problematic conversions rather than throw a fatal error. - Fix a typo noticed while doing the above ("tot he" -> "to the"). - As suggested by Stephen, re-alphabetize the import list - Per Heinrich, replace how we write contents in test_fit.py Reviewed-by: Simon Glass Tested-by: Stephen Warren Tested-by: Simon Glass [on sandbox] Signed-off-by: Tom Rini --- test/py/conftest.py | 9 ++++----- test/py/multiplexed_log.py | 11 ++++++++--- test/py/pytest.ini | 3 +++ test/py/tests/test_fit.py | 4 ++-- test/py/u_boot_spawn.py | 4 ++-- 5 files changed, 19 insertions(+), 12 deletions(-) (limited to 'test/py') diff --git a/test/py/conftest.py b/test/py/conftest.py index 5c19af1d503..bffee6b8a3a 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -13,17 +13,16 @@ # - Implementing custom pytest markers. import atexit +import configparser import errno +import io import os import os.path import pytest -from _pytest.runner import runtestprotocol import re -import io +from _pytest.runner import runtestprotocol import sys -import configparser - # Globals: The HTML log file, and the connection to the U-Boot console. log = None console = None @@ -168,7 +167,7 @@ def pytest_configure(config): ini_str = '[root]\n' + f.read() ini_sio = io.StringIO(ini_str) parser = configparser.RawConfigParser() - parser.readfp(ini_sio) + parser.read_file(ini_sio) ubconfig.buildconfig.update(parser.items('root')) ubconfig.test_py_dir = test_py_dir diff --git a/test/py/multiplexed_log.py b/test/py/multiplexed_log.py index de0aacc659b..545a7743022 100644 --- a/test/py/multiplexed_log.py +++ b/test/py/multiplexed_log.py @@ -51,7 +51,7 @@ class LogfileStream(object): """Write data to the log stream. Args: - data: The data to write tot he file. + data: The data to write to the file. implicit: Boolean indicating whether data actually appeared in the stream, or was implicitly generated. A valid use-case is to repeat a shell prompt at the start of each separate log @@ -64,7 +64,8 @@ class LogfileStream(object): self.logfile.write(self, data, implicit) if self.chained_file: - self.chained_file.write(data) + # Chained file is console, convert things a little + self.chained_file.write((data.encode('ascii', 'replace')).decode()) def flush(self): """Flush the log stream, to ensure correct log interleaving. @@ -136,6 +137,10 @@ class RunAndLog(object): p = subprocess.Popen(cmd, cwd=cwd, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) (stdout, stderr) = p.communicate() + if stdout is not None: + stdout = stdout.decode('utf-8') + if stderr is not None: + stderr = stderr.decode('utf-8') output = '' if stdout: if stderr: @@ -215,7 +220,7 @@ class Logfile(object): Nothing. """ - self.f = open(fn, 'wt') + self.f = open(fn, 'wt', encoding='utf-8') self.last_stream = None self.blocks = [] self.cur_evt = 1 diff --git a/test/py/pytest.ini b/test/py/pytest.ini index 7e400682bf2..e93d010f1fa 100644 --- a/test/py/pytest.ini +++ b/test/py/pytest.ini @@ -8,3 +8,6 @@ markers = boardspec: U-Boot: Describes the set of boards a test can/can't run on. buildconfigspec: U-Boot: Describes Kconfig/config-header constraints. + notbuildconfigspec: U-Boot: Describes required disabled Kconfig options. + requiredtool: U-Boot: Required host tools for a test. + slow: U-Boot: Specific test will run slowly. diff --git a/test/py/tests/test_fit.py b/test/py/tests/test_fit.py index 4922b9dcc66..356d9a20f29 100755 --- a/test/py/tests/test_fit.py +++ b/test/py/tests/test_fit.py @@ -153,7 +153,7 @@ def test_fit(u_boot_console): src = make_fname('u-boot.dts') dtb = make_fname('u-boot.dtb') with open(src, 'w') as fd: - print(base_fdt, file=fd) + fd.write(base_fdt) util.run_and_log(cons, ['dtc', src, '-O', 'dtb', '-o', dtb]) return dtb @@ -186,7 +186,7 @@ def test_fit(u_boot_console): its = make_its(params) util.run_and_log(cons, [mkimage, '-f', its, fit]) with open(make_fname('u-boot.dts'), 'w') as fd: - print(base_fdt, file=fd) + fd.write(base_fdt) return fit def make_kernel(filename, text): diff --git a/test/py/u_boot_spawn.py b/test/py/u_boot_spawn.py index b011a3e3da2..4f898cdefe5 100644 --- a/test/py/u_boot_spawn.py +++ b/test/py/u_boot_spawn.py @@ -113,7 +113,7 @@ class Spawn(object): Nothing. """ - os.write(self.fd, data) + os.write(self.fd, data.encode(errors='replace')) def expect(self, patterns): """Wait for the sub-process to emit specific data. @@ -171,7 +171,7 @@ class Spawn(object): events = self.poll.poll(poll_maxwait) if not events: raise Timeout() - c = os.read(self.fd, 1024) + c = os.read(self.fd, 1024).decode(errors='replace') if not c: raise EOFError() if self.logfile_read: -- cgit v1.2.3 From 8060209a9278593519f73ba763e67f7aa219a732 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 24 Oct 2019 11:59:22 -0400 Subject: test/py: test_ut.py: Ensure we use bytes In the case of some unit tests we are working with providing a fake flash device that we have written some text strings in to. In this case we want to tell Python to encode things to bytes for us. Reviewed-by: Stephen Warren Reviewed-by: Simon Glass Tested-by: Stephen Warren Tested-by: Simon Glass [on sandbox] Signed-off-by: Tom Rini --- test/py/tests/test_ut.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test/py') diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index 62037d2c453..6c7b8dd2b30 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -10,14 +10,14 @@ def test_ut_dm_init(u_boot_console): fn = u_boot_console.config.source_dir + '/testflash.bin' if not os.path.exists(fn): - data = 'this is a test' - data += '\x00' * ((4 * 1024 * 1024) - len(data)) + data = b'this is a test' + data += b'\x00' * ((4 * 1024 * 1024) - len(data)) with open(fn, 'wb') as fh: fh.write(data) fn = u_boot_console.config.source_dir + '/spi.bin' if not os.path.exists(fn): - data = '\x00' * (2 * 1024 * 1024) + data = b'\x00' * (2 * 1024 * 1024) with open(fn, 'wb') as fh: fh.write(data) -- cgit v1.2.3 From 1813ace6fcc46097d1709a775e72948fcbf52fee Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 24 Oct 2019 11:59:23 -0400 Subject: test/py: test_efi_selftest.py: Updates for python 3 support - In python 3 you must use raw strings for regex as other forms are deprecated and would require further changes to the pattern here. In one case this lets us have a simpler match pattern. - As strings are now Unicode our complex tests (Euro symbol, SHIFT+ALT+FN 5) we need to declare that as a bytes string and then decode it for use. Cc: Heinrich Schuchardt Reviewed-by: Simon Glass Tested-by: Stephen Warren Tested-by: Simon Glass [on sandbox] Signed-off-by: Tom Rini --- test/py/tests/test_efi_selftest.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'test/py') diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py index d5430f9c127..ca01542088f 100644 --- a/test/py/tests/test_efi_selftest.py +++ b/test/py/tests/test_efi_selftest.py @@ -59,7 +59,7 @@ def test_efi_selftest_text_input(u_boot_console): u_boot_console.run_command(cmd='setenv efi_selftest text input') output = u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False) - m = u_boot_console.p.expect(['To terminate type \'x\'']) + m = u_boot_console.p.expect([r'To terminate type \'x\'']) if m != 0: raise Exception('No prompt for \'text input\' test') u_boot_console.drain_console() @@ -68,7 +68,7 @@ def test_efi_selftest_text_input(u_boot_console): u_boot_console.run_command(cmd=chr(4), wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 4 \(unknown\), scan code 0 \(Null\)']) + [r'Unicode char 4 \(unknown\), scan code 0 \(Null\)']) if m != 0: raise Exception('EOT failed in \'text input\' test') u_boot_console.drain_console() @@ -76,7 +76,7 @@ def test_efi_selftest_text_input(u_boot_console): u_boot_console.run_command(cmd=chr(8), wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 8 \(BS\), scan code 0 \(Null\)']) + [r'Unicode char 8 \(BS\), scan code 0 \(Null\)']) if m != 0: raise Exception('BS failed in \'text input\' test') u_boot_console.drain_console() @@ -84,7 +84,7 @@ def test_efi_selftest_text_input(u_boot_console): u_boot_console.run_command(cmd=chr(9), wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 9 \(TAB\), scan code 0 \(Null\)']) + [r'Unicode char 9 \(TAB\), scan code 0 \(Null\)']) if m != 0: raise Exception('BS failed in \'text input\' test') u_boot_console.drain_console() @@ -92,7 +92,7 @@ def test_efi_selftest_text_input(u_boot_console): u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)']) + [r'Unicode char 97 \(\'a\'\), scan code 0 \(Null\)']) if m != 0: raise Exception('\'a\' failed in \'text input\' test') u_boot_console.drain_console() @@ -100,14 +100,14 @@ def test_efi_selftest_text_input(u_boot_console): u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 0 \(Null\), scan code 1 \(Up\)']) + [r'Unicode char 0 \(Null\), scan code 1 \(Up\)']) if m != 0: raise Exception('UP failed in \'text input\' test') u_boot_console.drain_console() # Euro sign - u_boot_console.run_command(cmd='\xe2\x82\xac', wait_for_echo=False, + u_boot_console.run_command(cmd=b'\xe2\x82\xac'.decode(), wait_for_echo=False, send_nl=False, wait_for_prompt=False) - m = u_boot_console.p.expect(['Unicode char 8364 \(\'']) + m = u_boot_console.p.expect([r'Unicode char 8364 \(\'']) if m != 0: raise Exception('Euro sign failed in \'text input\' test') u_boot_console.drain_console() @@ -129,7 +129,7 @@ def test_efi_selftest_text_input_ex(u_boot_console): u_boot_console.run_command(cmd='setenv efi_selftest extended text input') output = u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False) - m = u_boot_console.p.expect(['To terminate type \'CTRL\+x\'']) + m = u_boot_console.p.expect([r'To terminate type \'CTRL\+x\'']) if m != 0: raise Exception('No prompt for \'text input\' test') u_boot_console.drain_console() @@ -138,7 +138,7 @@ def test_efi_selftest_text_input_ex(u_boot_console): u_boot_console.run_command(cmd=chr(4), wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 100 \\(\'d\'\\), scan code 0 \\(CTRL\\+Null\\)']) + [r'Unicode char 100 \(\'d\'\), scan code 0 \(CTRL\+Null\)']) if m != 0: raise Exception('EOT failed in \'text input\' test') u_boot_console.drain_console() @@ -146,7 +146,7 @@ def test_efi_selftest_text_input_ex(u_boot_console): u_boot_console.run_command(cmd=chr(8), wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 8 \(BS\), scan code 0 \(\+Null\)']) + [r'Unicode char 8 \(BS\), scan code 0 \(\+Null\)']) if m != 0: raise Exception('BS failed in \'text input\' test') u_boot_console.drain_console() @@ -154,7 +154,7 @@ def test_efi_selftest_text_input_ex(u_boot_console): u_boot_console.run_command(cmd=chr(9), wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 9 \(TAB\), scan code 0 \(\+Null\)']) + [r'Unicode char 9 \(TAB\), scan code 0 \(\+Null\)']) if m != 0: raise Exception('TAB failed in \'text input\' test') u_boot_console.drain_console() @@ -162,7 +162,7 @@ def test_efi_selftest_text_input_ex(u_boot_console): u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)']) + [r'Unicode char 97 \(\'a\'\), scan code 0 \(Null\)']) if m != 0: raise Exception('\'a\' failed in \'text input\' test') u_boot_console.drain_console() @@ -170,23 +170,23 @@ def test_efi_selftest_text_input_ex(u_boot_console): u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 0 \(Null\), scan code 1 \(\+Up\)']) + [r'Unicode char 0 \(Null\), scan code 1 \(\+Up\)']) if m != 0: raise Exception('UP failed in \'text input\' test') u_boot_console.drain_console() # Euro sign - u_boot_console.run_command(cmd='\xe2\x82\xac', wait_for_echo=False, + u_boot_console.run_command(cmd=b'\xe2\x82\xac'.decode(), wait_for_echo=False, send_nl=False, wait_for_prompt=False) - m = u_boot_console.p.expect(['Unicode char 8364 \(\'']) + m = u_boot_console.p.expect([r'Unicode char 8364 \(\'']) if m != 0: raise Exception('Euro sign failed in \'text input\' test') u_boot_console.drain_console() # SHIFT+ALT+FN 5 - u_boot_console.run_command(cmd='\x1b\x5b\x31\x35\x3b\x34\x7e', + u_boot_console.run_command(cmd=b'\x1b\x5b\x31\x35\x3b\x34\x7e'.decode(), wait_for_echo=False, send_nl=False, wait_for_prompt=False) m = u_boot_console.p.expect( - ['Unicode char 0 \(Null\), scan code 15 \(SHIFT\+ALT\+FN 5\)']) + [r'Unicode char 0 \(Null\), scan code 15 \(SHIFT\+ALT\+FN 5\)']) if m != 0: raise Exception('SHIFT+ALT+FN 5 failed in \'text input\' test') u_boot_console.drain_console() -- cgit v1.2.3 From d2b5240c9a0303e2d2ed3cd540d7e32b6f198664 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 24 Oct 2019 11:59:24 -0400 Subject: test/py: Update test_fs to decode check_output calls The check_output function from the subprocess Python module by default returns data as encoded bytes and leaves decoding to the application. Given our uses of the call, it makes the most sense to immediately decode the results. Reviewed-by: Simon Glass Tested-by: Stephen Warren Tested-by: Simon Glass [on sandbox] Signed-off-by: Tom Rini --- test/py/tests/test_fs/conftest.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'test/py') diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py index 354d17672fe..1949f916197 100644 --- a/test/py/tests/test_fs/conftest.py +++ b/test/py/tests/test_fs/conftest.py @@ -300,38 +300,38 @@ def fs_obj_basic(request, u_boot_config): # Generate the md5sums of reads that we will test against small file out = check_output( 'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum' - % small_file, shell=True) + % small_file, shell=True).decode() md5val = [ out.split()[0] ] # Generate the md5sums of reads that we will test against big file # One from beginning of file. out = check_output( 'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum' - % big_file, shell=True) + % big_file, shell=True).decode() md5val.append(out.split()[0]) # One from end of file. out = check_output( 'dd if=%s bs=1M skip=2499 count=1 2> /dev/null | md5sum' - % big_file, shell=True) + % big_file, shell=True).decode() md5val.append(out.split()[0]) # One from the last 1MB chunk of 2GB out = check_output( 'dd if=%s bs=1M skip=2047 count=1 2> /dev/null | md5sum' - % big_file, shell=True) + % big_file, shell=True).decode() md5val.append(out.split()[0]) # One from the start 1MB chunk from 2GB out = check_output( 'dd if=%s bs=1M skip=2048 count=1 2> /dev/null | md5sum' - % big_file, shell=True) + % big_file, shell=True).decode() md5val.append(out.split()[0]) # One 1MB chunk crossing the 2GB boundary out = check_output( 'dd if=%s bs=512K skip=4095 count=2 2> /dev/null | md5sum' - % big_file, shell=True) + % big_file, shell=True).decode() md5val.append(out.split()[0]) umount_fs(mount_dir) @@ -390,7 +390,7 @@ def fs_obj_ext(request, u_boot_config): % min_file, shell=True) out = check_output( 'dd if=%s bs=1K 2> /dev/null | md5sum' - % min_file, shell=True) + % min_file, shell=True).decode() md5val = [ out.split()[0] ] # Calculate md5sum of Test Case 4 @@ -399,7 +399,7 @@ def fs_obj_ext(request, u_boot_config): check_call('dd if=%s of=%s bs=1K seek=5 count=20' % (min_file, tmp_file), shell=True) out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum' - % tmp_file, shell=True) + % tmp_file, shell=True).decode() md5val.append(out.split()[0]) # Calculate md5sum of Test Case 5 @@ -408,7 +408,7 @@ def fs_obj_ext(request, u_boot_config): check_call('dd if=%s of=%s bs=1K seek=5 count=5' % (min_file, tmp_file), shell=True) out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum' - % tmp_file, shell=True) + % tmp_file, shell=True).decode() md5val.append(out.split()[0]) # Calculate md5sum of Test Case 7 @@ -417,7 +417,7 @@ def fs_obj_ext(request, u_boot_config): check_call('dd if=%s of=%s bs=1K seek=20 count=20' % (min_file, tmp_file), shell=True) out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum' - % tmp_file, shell=True) + % tmp_file, shell=True).decode() md5val.append(out.split()[0]) check_call('rm %s' % tmp_file, shell=True) @@ -582,11 +582,11 @@ def fs_obj_symlink(request, u_boot_config): # Generate the md5sums of reads that we will test against small file out = check_output( 'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum' - % small_file, shell=True) + % small_file, shell=True).decode() md5val = [out.split()[0]] out = check_output( 'dd if=%s bs=10M skip=0 count=1 2> /dev/null | md5sum' - % medium_file, shell=True) + % medium_file, shell=True).decode() md5val.extend([out.split()[0]]) umount_fs(mount_dir) -- cgit v1.2.3 From 8add4fa4177bf697ad892497fe65259dad642366 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 24 Oct 2019 11:59:25 -0400 Subject: test/py: Rework test.py to be a different kind of wrapper Now that we have moved to being based on pytest for python3 we need to make our test.py wrapper more robust in terms of only calling python3 rather than possibly finding and using python2. To do this, change from execvp()'ing pytest to invoking the package itself via python. In the event that pytest is unavailable we still get a user-friendly error: pkg_resources.DistributionNotFound: The 'pytest' distribution was not found and is required by the application Reviewed-by: Simon Glass Tested-by: Stephen Warren Tested-by: Simon Glass [on sandbox] Signed-off-by: Tom Rini --- test/py/test.py | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) (limited to 'test/py') diff --git a/test/py/test.py b/test/py/test.py index 0ce1838833f..bee88d96bc2 100755 --- a/test/py/test.py +++ b/test/py/test.py @@ -10,23 +10,11 @@ import os import os.path import sys - -# Get rid of argv[0] -sys.argv.pop(0) +from pkg_resources import load_entry_point # argv; py.test test_directory_name user-supplied-arguments -args = ['py.test', os.path.dirname(__file__) + '/tests'] +args = [os.path.dirname(__file__) + '/tests'] args.extend(sys.argv) -try: - os.execvp('py.test', args) -except: - # Log full details of any exception for detailed analysis - import traceback - traceback.print_exc() - # Hint to the user that they likely simply haven't installed the required - # dependencies. - print(''' -exec(py.test) failed; perhaps you are missing some dependencies? -See test/py/README.md for the list.''', file=sys.stderr) - sys.exit(1) +if __name__ == '__main__': + sys.exit(load_entry_point('pytest', 'console_scripts', 'pytest')(args)) -- cgit v1.2.3 From ddaa8bed3dea59201392e9f516a9f2dbb12654d9 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 24 Oct 2019 11:59:26 -0400 Subject: test/py: Update docs, add requirements.txt for pip To be more closely aligned with Python community best practices, we need to better document our usage of pip and make use of a requirements.txt file that shows the versions of the tools that we are using. This will aide in ensuring reproducibility of our tests as well. Reviewed-by: Simon Glass Tested-by: Stephen Warren Tested-by: Simon Glass [on sandbox] Signed-off-by: Tom Rini --- test/py/README.md | 47 ++++++++++++++++++++++++++--------------------- test/py/requirements.txt | 22 ++++++++++++++++++++++ 2 files changed, 48 insertions(+), 21 deletions(-) create mode 100644 test/py/requirements.txt (limited to 'test/py') diff --git a/test/py/README.md b/test/py/README.md index 2156661d6c4..3cbe01b73e2 100644 --- a/test/py/README.md +++ b/test/py/README.md @@ -21,19 +21,26 @@ involves executing some binary and interacting with its stdin/stdout. You will need to implement various "hook" scripts that are called by the test suite at the appropriate time. -On Debian or Debian-like distributions, the following packages are required. -Some packages are required to execute any test, and others only for specific -tests. Similar package names should exist in other distributions. - -| Package | Version tested (Ubuntu 14.04) | -| -------------- | ----------------------------- | -| python | 2.7.5-5ubuntu3 | -| python-pytest | 2.5.1-1 | -| python-subunit | - | -| gdisk | 0.8.8-1ubuntu0.1 | -| dfu-util | 0.5-1 | -| dtc | 1.4.0+dfsg-1 | -| openssl | 1.0.1f-1ubuntu2.22 | +In order to run the testsuite at a minimum we require that both python3 and +pip for python3 be installed. All of the required python modules are +described in the requirements.txt file in this directory and can be installed +with the command ```pip install -r requirements.txt``` + +In order to execute certain tests on their supported platforms other tools +will be required. The following is an incomplete list: + +| Package | +| -------------- | +| gdisk | +| dfu-util | +| dtc | +| openssl | +| sudo OR guestmount | +| e2fsprogs | +| dosfstools | + +Please use the apporirate commands for your distribution to match these tools +up with the package that provides them. The test script supports either: @@ -45,18 +52,16 @@ The test script supports either: ### Using `virtualenv` to provide requirements -Older distributions (e.g. Ubuntu 10.04) may not provide all the required -packages, or may provide versions that are too old to run the test suite. One -can use the Python `virtualenv` script to locally install more up-to-date -versions of the required packages without interfering with the OS installation. -For example: +The recommended way to run the test suite, in order to ensure reproducibility +is to use `virtualenv` to set up the necessary environment. This can be done +via the following commands: ```bash $ cd /path/to/u-boot -$ sudo apt-get install python python-virtualenv -$ virtualenv venv +$ sudo apt-get install python3 python3-virtualenv +$ virtualenv -p /usr/bin/python3 venv $ . ./venv/bin/activate -$ pip install pytest +$ pip install -r test/py/requirements.txt ``` ## Testing sandbox diff --git a/test/py/requirements.txt b/test/py/requirements.txt new file mode 100644 index 00000000000..cf251186f4b --- /dev/null +++ b/test/py/requirements.txt @@ -0,0 +1,22 @@ +atomicwrites==1.3.0 +attrs==19.3.0 +coverage==4.5.4 +extras==1.0.0 +fixtures==3.0.0 +importlib-metadata==0.23 +linecache2==1.0.0 +more-itertools==7.2.0 +packaging==19.2 +pbr==5.4.3 +pluggy==0.13.0 +py==1.8.0 +pyparsing==2.4.2 +pytest==5.2.1 +python-mimeparse==1.6.0 +python-subunit==1.3.0 +six==1.12.0 +testtools==2.3.0 +traceback2==1.4.0 +unittest2==1.1.0 +wcwidth==0.1.7 +zipp==0.6.0 -- cgit v1.2.3 From 15579631bc6b644eb504b1d9503174bd06b93439 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Thu, 24 Oct 2019 11:59:28 -0400 Subject: test/py: Use raw strings more to avoid deprecation warnings We have two further uses of raw string usage in the test/py codebase that are used under CI. The first of which is under the bind test and is a direct update. The second of which is to strip VT100 codes from the match buffer. While switching this to a raw string is also a direct update, the comment it notes that problems were encountered on Ubuntu 14.04 (and whatever Python 2 version that was) that required slight tweaks to the regex. Replace that now that we're saying Python 3.5 is the minimum. Reviewed-by: Simon Glass Tested-by: Stephen Warren Tested-by: Simon Glass [on sandbox] Signed-off-by: Tom Rini --- test/py/tests/test_bind.py | 4 ++-- test/py/u_boot_spawn.py | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'test/py') diff --git a/test/py/tests/test_bind.py b/test/py/tests/test_bind.py index 2d48484c6ac..20c6050342a 100644 --- a/test/py/tests/test_bind.py +++ b/test/py/tests/test_bind.py @@ -9,11 +9,11 @@ def in_tree(response, name, uclass, drv, depth, last_child): lines = [x.strip() for x in response.splitlines()] leaf = ' ' * 4 * depth; if not last_child: - leaf = leaf + '\|' + leaf = leaf + r'\|' else: leaf = leaf + '`' leaf = leaf + '-- ' + name - line = (' *{:10.10} [0-9]* \[ [ +] \] {:20.20} {}$' + line = (r' *{:10.10} [0-9]* \[ [ +] \] {:20.20} {}$' .format(uclass, drv, leaf)) prog = re.compile(line) for l in lines: diff --git a/test/py/u_boot_spawn.py b/test/py/u_boot_spawn.py index 4f898cdefe5..6991b78cca8 100644 --- a/test/py/u_boot_spawn.py +++ b/test/py/u_boot_spawn.py @@ -42,10 +42,7 @@ class Spawn(object): self.after = '' self.timeout = None # http://stackoverflow.com/questions/7857352/python-regex-to-match-vt100-escape-sequences - # Note that re.I doesn't seem to work with this regex (or perhaps the - # version of Python in Ubuntu 14.04), hence the inclusion of a-z inside - # [] instead. - self.re_vt100 = re.compile('(\x1b\[|\x9b)[^@-_a-z]*[@-_a-z]|\x1b[@-_a-z]') + self.re_vt100 = re.compile(r'(\x1b\[|\x9b)[^@-_]*[@-_]|\x1b[@-_]', re.I) (self.pid, self.fd) = pty.fork() if self.pid == 0: -- cgit v1.2.3