def test_execute_interface(docker_container): with patch('reproman.resource.ResourceManager._get_inventory' ) as get_inventory: config = { "status": "running", "engine_url": "unix:///var/run/docker.sock", "type": "docker-container", "name": "testing-container", } get_inventory.return_value = {"testing-container": config} for internal in [False, True]: path = '/tmp/{}'.format(str(uuid.uuid4())) cmd = ['execute', '--resource', 'testing-container'] if internal: cmd.append('--internal') cmd.extend(['mkdir', path]) manager = ResourceManager() with patch("reproman.interface.execute.get_manager", return_value=manager): main(cmd) session = manager.get_resource( "testing-container").get_session() assert session.exists(path) # on 2nd run mkdir should fail since already exists with swallow_outputs() as cmo: with pytest.raises(SystemExit) as cme: main(cmd) assert cme.value.code == 1 assert "File exists" in cmo.err
def test_delete_interface(): """ Test deleting a resource. """ with patch('docker.Client', new_callable=mock_docker_client) as client, \ patch('reproman.interface.delete.get_manager', new=mock_get_manager), \ swallow_logs(new_level=logging.DEBUG) as log: main(['delete', '--skip-confirmation', 'my-resource']) calls = [ call(base_url='tcp://127.0.0.1:2375'), call().remove_container( { 'State': 'running', 'Id': '326b0fdfbf838', 'Names': ['/my-resource'] }, force=True) ] client.assert_has_calls(calls, any_order=True) assert_in('Deleted the environment my-resource', log.lines) main(['delete', '-y', '--force', 'missing-resource']) assert_in('Deleted the environment missing-resource', log.lines)
def test_retrace_to_output_file(reprozip_spec2): with make_tempfile() as outfile: args = ['retrace', '--spec', reprozip_spec2, '--output-file', outfile] main(args) ## Perform a simple check of whether the output file can be ## loaded. provenance = Provenance.factory(outfile) assert len(provenance.get_distributions()) == 1
def test_retrace(reprozip_spec2): """ Test installing packages on the localhost. """ with swallow_logs(new_level=logging.DEBUG) as log: args = ['retrace', '--spec', reprozip_spec2, ] main(args) assert_in("reading spec file " + reprozip_spec2, log.lines)
def test_multi_debian_files(): with swallow_logs() as log: args = ['diff', multi_debian_yaml, diff_1_yaml] with raises(SystemExit): main(args) assert_in_in("multiple <class 'reproman.distributions.debian.DebianDistribution'> found", log.lines) with swallow_logs() as log: args = ['diff', diff_1_yaml, multi_debian_yaml] with raises(SystemExit): main(args) assert_in_in("multiple <class 'reproman.distributions.debian.DebianDistribution'> found", log.lines)
def test_create_start_stop(tmpdir): tmpdir = str(tmpdir) inventory_file = op.join(tmpdir, "inventory.yml") rm = ResourceManager(inventory_file) # Simple smoke test. We can't easily test the effects of start/stop with # shell because those the start and stop methods are noops. with patch("reproman.interface.create.get_manager", return_value=rm): main(["create", "-t", "shell", "testshell"]) with open(inventory_file) as ifh: inventory = yaml.safe_load(ifh) assert inventory["testshell"]["status"] == "available" with patch("reproman.interface.start.get_manager", return_value=rm): main(["start", "testshell"]) with patch("reproman.interface.stop.get_manager", return_value=rm): main(["stop", "testshell"]) with patch("reproman.interface.delete.get_manager", return_value=rm): main(["delete", "--skip-confirmation", "testshell"]) with open(inventory_file) as ifh: inventory = yaml.safe_load(ifh) assert "testshell" not in inventory
def test_same(): with swallow_outputs() as outputs: args = ['diff', diff_1_yaml, diff_1_yaml] rv = main(args) assert_equal(rv, 0) assert_equal(outputs.out, '') assert_equal(outputs.err, '')
def test_delete_interface(): """ Test deleting a resource. """ with patch('docker.Client') as client, \ patch('reproman.resource.ResourceManager._save'), \ patch('reproman.resource.ResourceManager._get_inventory') as get_inventory, \ swallow_logs(new_level=logging.DEBUG) as log: client.return_value = MagicMock( containers=lambda all: [{ 'Id': '326b0fdfbf838', 'Names': ['/my-resource'], 'State': 'running' }]) get_inventory.return_value = { "my-resource": { "status": "running", "engine_url": "tcp://127.0.0.1:2375", "type": "docker-container", "name": "my-resource", "id": "326b0fdfbf838" } } args = ['delete', '--skip-confirmation', 'my-resource'] with patch("reproman.interface.delete.get_manager", return_value=ResourceManager()): main(args) calls = [ call(base_url='tcp://127.0.0.1:2375'), call().remove_container( { 'State': 'running', 'Id': '326b0fdfbf838', 'Names': ['/my-resource'] }, force=True) ] client.assert_has_calls(calls, any_order=True) assert_in('Deleted the environment my-resource', log.lines)
def test_diff_files(): with swallow_outputs() as outputs: args = ['diff', diff_1_yaml, diff_2_yaml] rv = main(args) assert_equal(rv, 3) assert_equal(outputs.err, '') assert_in('Files:', outputs.out) assert_in('< /etc/a', outputs.out) assert_in('> /etc/c', outputs.out) assert_not_in('< /etc/b', outputs.out) assert_not_in('> /etc/b', outputs.out)
def test_create_interface(): """ Test creating an environment """ with patch('docker.Client') as client, \ patch('reproman.resource.ResourceManager.save_inventory'), \ patch('reproman.resource.ResourceManager._get_inventory'), \ swallow_logs(new_level=logging.DEBUG) as log: client.return_value = MagicMock( containers=lambda all: [], pull=lambda repository, stream: [ b'{ "status" : "status 1", "progress" : "progress 1" }', b'{ "status" : "status 2", "progress" : "progress 2" }' ], create_container=lambda name, image, stdin_open, tty, command: { 'Id': '18b31b30e3a5' } ) args = ['create', '--resource-type', 'docker-container', '--backend', 'engine_url=tcp://127.0.0.1:2376', '--', 'my-test-resource' ] with patch("reproman.interface.create.get_manager", return_value=ResourceManager()): main(args) calls = [ call(base_url='tcp://127.0.0.1:2376'), call().start(container='18b31b30e3a5') ] client.assert_has_calls(calls, any_order=True) assert_in("status 1 progress 1", log.lines) assert_in("status 2 progress 2", log.lines) assert_in("Created the environment my-test-resource", log.lines)
def test_login_interface(): """ Test logging into an environment """ with patch('docker.Client') as client, \ patch('reproman.resource.ResourceManager._get_inventory') as get_inventory, \ patch('dockerpty.start'), \ swallow_logs(new_level=logging.DEBUG) as log: client.return_value = MagicMock( containers=lambda all: [{ 'Id': '18b31b30e3a5', 'Names': ['/my-test-resource'], 'State': 'running' }], ) get_inventory.return_value = { "my-test-resource": { "status": "running", "engine_url": "tcp://127.0.0.1:2375", "type": "docker-container", "name": "my-test-resource", "id": "18b31b30e3a5" } } args = ['login', 'my-test-resource'] with patch("reproman.interface.login.get_manager", return_value=ResourceManager()): main(args) assert client.call_count == 1 calls = [call(base_url='tcp://127.0.0.1:2375')] client.assert_has_calls(calls, any_order=True) assert_in("Opening TTY connection to docker container.", log.lines)
def test_diff_svn(): with swallow_outputs() as outputs: args = ['diff', diff_1_yaml, diff_2_yaml] rv = main(args) assert_equal(rv, 3) assert_equal(outputs.err, '') assert_in('SVN repositories:', outputs.out) assert_in('< c8ed47ab-45c9-818d-5d62-549dcc6d97d4 (/path/to/svn/repo/1/only)', outputs.out) assert_in('> d7192e3a-60de-5caa-ccdc9525dea75aabf (/path/to/svn/repo/2/only)', outputs.out) assert_in('SVN repository 95e4b738-84c7-154c-f082-34d40e21fdd4', outputs.out) assert_in('< 12 (/path/1/to/different/svn/commit)', outputs.out) assert_in('> 14 (/path/2/to/different/svn/commit)', outputs.out) assert_not_in('(/path/1/to/common/svn/repo)', outputs.out) assert_not_in('(/path/2/to/common/svn/repo)', outputs.out)
def test_diff_debian_packages(): with swallow_outputs() as outputs: args = ['diff', diff_1_yaml, diff_2_yaml] rv = main(args) assert_equal(rv, 3) assert_equal(outputs.err, '') assert_in('Debian packages:', outputs.out) assert_in('< lib1only x86', outputs.out) assert_in('> lib2only x86', outputs.out) assert_in('< libarchdiff x86', outputs.out) assert_in('> libarchdiff amd64', outputs.out) assert_in('Debian package libversdiff x86:', outputs.out) assert_in('< 2.4.6', outputs.out) assert_in('> 2.4.7', outputs.out) assert_not_in('libsame', outputs.out)
def test_diff_git(): with swallow_outputs() as outputs: args = ['diff', diff_1_yaml, diff_2_yaml] rv = main(args) assert_equal(rv, 3) assert_equal(outputs.err, '') assert_in('Git repositories:', outputs.out) assert_in('< 43e8e6577c7bf493ddb01ea7d49bef7dc7a6643b (/path/to/git/repo/1/only)', outputs.out) assert_in('> 64b1865267891fdd1a45251ca6f32df213dc546e (/path/to/git/repo/2/only)', outputs.out) assert_in('Git repository 5b8267181f6cae8dc37aeef21ea54171bd932522', outputs.out) assert_in('< branch None, commit 3e3aaa73a9c0ca061c7679af5fa7318e70f528ac (/path/1/to/different/git/commit)', outputs.out) assert_in('> branch None, commit 9d199f7fa7e6f691719e0860c5cf81193e815ad5 (/path/2/to/different/git/commit)', outputs.out) assert_not_in('/path/1/to/common/git/repo', outputs.out) assert_not_in('/path/2/to/common/git/repo', outputs.out) assert_not_in('99ac7f69a070077038a9eb9eca61c028db97181d', outputs.out) assert_not_in('d057b128759d80a47500adba0c4d3e95092bb87f', outputs.out)
def test_diff_satisfies(): with swallow_outputs() as outputs: args = ['diff', '--satisfies', diff_satisfies_1_yaml, diff_satisfies_2_yaml] rv = main(args) assert_equal(rv, 3) assert_in('Files:', outputs.out) assert_in('> /etc/c', outputs.out) assert_in('Debian packages:', outputs.out) assert_in('> lib3 amd64 2.4.6', outputs.out) assert_in('> lib4 x86 2.4.7', outputs.out) assert_not_in('lib2', outputs.out) assert_not_in('lib5', outputs.out) assert_not_in('lib1', outputs.out)
def test_diff_conda_packages(): with swallow_outputs() as outputs: args = ['diff', diff_1_yaml, diff_2_yaml] rv = main(args) assert_equal(rv, 3) assert_equal(outputs.err, '') assert_in('Conda packages:', outputs.out) assert_in('< c_lib1only py36_0', outputs.out) assert_in('> c_lib2only py36_0', outputs.out) assert_in('< c_libbuilddiff py36_0', outputs.out) assert_in('> c_libbuilddiff hdf63c60_3', outputs.out) # TO DO: ensure the version strings (second and third lines below) # come from the conda report -- these could just match the debian # output checked in test_diff_debian_packages() assert_in('Conda package c_libversdiff py36_0:', outputs.out) assert_in('< 2.4.6', outputs.out) assert_in('> 2.4.7', outputs.out) assert_not_in('c_libsame', outputs.out)
def test_diff_no_distributions(): with swallow_outputs() as outputs: args = ['diff', diff_1_yaml, empty_yaml] rv = main(args) assert_equal(rv, 3) assert_equal(outputs.err, '') assert_in('Debian packages:', outputs.out) assert_in('< lib1only x86', outputs.out) assert_in('< libsame x86', outputs.out) assert_in('< libarchdiff x86', outputs.out) assert_in('< libversdiff x86', outputs.out) assert_in('Conda packages:', outputs.out) assert_in('< c_lib1only py36_0', outputs.out) assert_in('< c_libsame py36_0', outputs.out) assert_in('< c_libbuilddiff py36_0', outputs.out) assert_in('< c_libversdiff py36_0', outputs.out) assert_in('Files:', outputs.out) assert_in('< /etc/a', outputs.out) assert_in('< /etc/b', outputs.out)
def test_install_interface(demo1_spec): with patch('docker.Client') as client, \ patch('reproman.distributions.debian.DebianDistribution.install_packages'), \ patch('reproman.resource.ResourceManager._get_inventory') as get_inventory, \ patch('requests.get') as requests, \ swallow_logs(new_level=logging.DEBUG) as log: client.return_value = MagicMock( containers=lambda all: [{ 'Id': '326b0fdfbf838', 'Names': ['/my-resource'], 'State': 'running' }], exec_inspect=lambda id: {'ExitCode': 0}) get_inventory.return_value = { "my-resource": { "status": "running", "engine_url": "tcp://127.0.0.1:2375", "type": "docker-container", "name": "my-resource", "id": "326b0fdfbf838" } } requests.return_value = type("TestObject", (object, ), {})() requests.return_value.text = '<a href="/archive/debian/20171208T032012Z/dists/sid/">next change</a>' args = [ 'install', 'my-resource', demo1_spec, ] with patch("reproman.interface.install.get_manager", return_value=ResourceManager()): main(args) def container_call(cmd): return call().exec_create(cmd=cmd, container={ 'State': 'running', 'Id': '326b0fdfbf838', 'Names': ['/my-resource'] }) calls = [ call(base_url='tcp://127.0.0.1:2375'), call().exec_create(cmd=[ 'bash', '-c', 'test -e /etc/apt/sources.list.d/reproman.sources.list && echo Found' ], container={ 'Id': '326b0fdfbf838', 'State': 'running', 'Names': ['/my-resource'] }), call().exec_create( cmd= 'sh -c \'echo "# ReproMan repo sources" > /etc/apt/sources.list.d/reproman.sources.list\'', container={ 'Id': '326b0fdfbf838', 'State': 'running', 'Names': ['/my-resource'] }), call().exec_create( cmd= "grep -q 'deb http://snapshot.debian.org/archive/debian/20170531T084046Z/ sid main contrib non-free' /etc/apt/sources.list.d/reproman.sources.list", container={ 'Id': '326b0fdfbf838', 'State': 'running', 'Names': ['/my-resource'] }), call().exec_create( cmd= "grep -q 'deb http://snapshot.debian.org/archive/debian/20171208T032012Z/ sid main contrib non-free' /etc/apt/sources.list.d/reproman.sources.list", container={ 'Id': '326b0fdfbf838', 'State': 'running', 'Names': ['/my-resource'] }), call().exec_create( cmd= "grep -q 'deb http://snapshot-neuro.debian.net:5002/archive/neurodebian/20171208T032012Z/ xenial main contrib non-free' /etc/apt/sources.list.d/reproman.sources.list", container={ 'Id': '326b0fdfbf838', 'State': 'running', 'Names': ['/my-resource'] }), call().exec_create( cmd= "grep -q 'deb http://snapshot-neuro.debian.net:5002/archive/neurodebian/20171208T032012Z/ xenial main contrib non-free' /etc/apt/sources.list.d/reproman.sources.list", container={ 'Id': '326b0fdfbf838', 'State': 'running', 'Names': ['/my-resource'] }), call().exec_create(cmd=[ 'apt-key', 'adv', '--recv-keys', '--keyserver', 'hkp://pool.sks-keyservers.net:80', '0xA5D32F012649A5A9' ], container={ 'Id': '326b0fdfbf838', 'State': 'running', 'Names': ['/my-resource'] }), call().exec_create( cmd= "grep -q 'deb http://snapshot-neuro.debian.net:5002/archive/neurodebian/20171208T032012Z/ xenial main contrib non-free' /etc/apt/sources.list.d/reproman.sources.list", container={ 'Id': '326b0fdfbf838', 'State': 'running', 'Names': ['/my-resource'] }), call().exec_create( cmd= "grep -q 'deb http://snapshot-neuro.debian.net:5002/archive/neurodebian/20171208T032012Z/ xenial main contrib non-free' /etc/apt/sources.list.d/reproman.sources.list", container={ 'Id': '326b0fdfbf838', 'State': 'running', 'Names': ['/my-resource'] }), call().exec_create(cmd=[ 'apt-key', 'adv', '--recv-keys', '--keyserver', 'hkp://pool.sks-keyservers.net:80', '0xA5D32F012649A5A9' ], container={ 'Id': '326b0fdfbf838', 'State': 'running', 'Names': ['/my-resource'] }), call().exec_create(cmd=[ 'apt-get', '-o', 'Acquire::Check-Valid-Until=false', 'update' ], container={ 'Id': '326b0fdfbf838', 'State': 'running', 'Names': ['/my-resource'] }) ] client.assert_has_calls(calls, any_order=True) assert_in('Adding Debian update to environment command list.', log.lines) assert_in( "Running command ['bash', '-c', 'test -e /etc/apt/sources.list.d/reproman.sources.list && echo Found']", log.lines) assert_in( 'Running command "grep -q \'deb http://snapshot.debian.org/archive/debian/20170531T084046Z/ sid main contrib non-free\' /etc/apt/sources.list.d/reproman.sources.list"', log.lines) assert_in( 'Running command "grep -q \'deb http://snapshot.debian.org/archive/debian/20171208T032012Z/ sid main contrib non-free\' /etc/apt/sources.list.d/reproman.sources.list"', log.lines) assert_in( 'Running command "grep -q \'deb http://snapshot-neuro.debian.net:5002/archive/neurodebian/20171208T032012Z/ xenial main contrib non-free\' /etc/apt/sources.list.d/reproman.sources.list"', log.lines) assert_in( "Running command ['apt-key', 'adv', '--recv-keys', '--keyserver', 'hkp://pool.sks-keyservers.net:80', '0xA5D32F012649A5A9']", log.lines) assert_in( "Running command ['apt-get', '-o', 'Acquire::Check-Valid-Until=false', 'update']", log.lines)
def test_retrace_normalize_paths(): # Retrace should normalize paths before passing them to tracers. with swallow_outputs() as cm: main(["retrace", "/sbin/../sbin/iptables"]) assert "name: debian" in cm.out
def test_retrace_normalize_paths(): # Retrace should normalize paths before passing them to tracers. with swallow_outputs() as cm: main(["retrace", "/bin/.." + COMMON_SYSTEM_PATH]) assert "name: debian" in cm.out