diff --git a/bin/run_tests.py b/bin/run_tests.py index 117f8b9f..1a1895cf 100755 --- a/bin/run_tests.py +++ b/bin/run_tests.py @@ -10,7 +10,7 @@ if __name__ == '__main__': os.chdir(Path(__file__).resolve().parents[1]) # run the unit tests - subprocess.check_call([sys.executable, '-m', 'pytest', 'unit_test']) + subprocess.check_call([sys.executable, '-m', 'pytest', 'unit_test', '--runslow']) # run the integration tests subprocess.check_call([sys.executable, '-m', 'pytest', '-x', '--durations', '0', 'test']) diff --git a/unit_test/conftest.py b/unit_test/conftest.py new file mode 100644 index 00000000..e446d0a1 --- /dev/null +++ b/unit_test/conftest.py @@ -0,0 +1,21 @@ +import pytest + + +def pytest_addoption(parser): + parser.addoption( + "--runslow", action="store_true", default=False, help="run slow tests" + ) + + +def pytest_configure(config): + config.addinivalue_line("markers", "slow: mark test as slow to run") + + +def pytest_collection_modifyitems(config, items): + if config.getoption("--runslow"): + # --runslow given in cli: do not skip slow tests + return + skip_slow = pytest.mark.skip(reason="need --runslow option to run") + for item in items: + if "slow" in item.keywords: + item.add_marker(skip_slow) diff --git a/unit_test/docker_container_test.py b/unit_test/docker_container_test.py new file mode 100644 index 00000000..e8ddc7d1 --- /dev/null +++ b/unit_test/docker_container_test.py @@ -0,0 +1,85 @@ +import pytest +from cibuildwheel.docker_container import DockerContainer +import subprocess +import time +import textwrap + +DEFAULT_IMAGE = 'centos:6' + +@pytest.mark.slow +def test_simple(): + with DockerContainer(DEFAULT_IMAGE) as container: + assert container.call(['echo', 'hello'], capture_output=True) == 'hello\n' + +@pytest.mark.slow +def test_no_lf(): + with DockerContainer(DEFAULT_IMAGE) as container: + assert container.call(['printf', 'hello'], capture_output=True) == 'hello' + +@pytest.mark.slow +def test_environment(): + with DockerContainer(DEFAULT_IMAGE) as container: + assert container.call(['sh', '-c', 'echo $TEST_VAR'], env={'TEST_VAR': '1'}, capture_output=True) == '1\n' + +@pytest.mark.slow +def test_container_removed(): + start_time = time.time() + with DockerContainer(DEFAULT_IMAGE) as container: + container.call(['true']) + docker_containers_listing = subprocess.run('docker container ls', shell=True, check=True, capture_output=True, universal_newlines=True).stdout + assert container.name in docker_containers_listing + old_container_name = container.name + + docker_containers_listing = subprocess.run('docker container ls', shell=True, check=True, capture_output=True, universal_newlines=True).stdout + assert old_container_name not in docker_containers_listing + +@pytest.mark.slow +def test_large_environment(): + # max environment variable size is 128kB + long_env_var_length = 127*1024 + large_environment = { + 'a': '0'*long_env_var_length, + 'b': '0'*long_env_var_length, + 'c': '0'*long_env_var_length, + 'd': '0'*long_env_var_length, + } + + with DockerContainer(DEFAULT_IMAGE) as container: + # check the length of d + assert container.call(['sh', '-c', 'echo ${#d}'], env=large_environment, capture_output=True) == f'{long_env_var_length}\n' + +@pytest.mark.slow +def test_binary_output(): + with DockerContainer(DEFAULT_IMAGE) as container: + # the centos image only has python 2.6, so the below embedded snippets + # are in python2 + + # check that we can pass though arbitrary binary data without erroring + container.call(['/usr/bin/python2', '-c', textwrap.dedent(''' + import sys + sys.stdout.write(''.join(chr(n) for n in range(0, 256))) + ''')]) + + # check that we can capture arbitrary binary data + output = container.call(['/usr/bin/python2', '-c', textwrap.dedent(''' + import sys + sys.stdout.write(''.join(chr(n % 256) for n in range(0, 512))) + ''')], capture_output=True) + + data = bytes(output, encoding='utf8', errors='surrogateescape') + + for i in range(0, 512): + assert data[i] == i % 256 + + # check that environment variables can carry binary data, except null characters + # (https://www.gnu.org/software/libc/manual/html_node/Environment-Variables.html) + binary_data = bytes(n for n in range(1, 256)) + binary_data_string = str(binary_data, encoding='utf8', errors='surrogateescape') + output = container.call( + ['python2', '-c', 'import os, sys; sys.stdout.write(os.environ["TEST_VAR"])'], + env={'TEST_VAR': binary_data_string}, + capture_output=True, + ) + assert output == binary_data_string + +