def test_launch_for_type_base(self): self.project.info.name = "core18" self.project.info.type = "base" self.project.info.base = None instance = Multipass(project=self.project, echoer=self.echoer_mock) self.useFixture( fixtures.MockPatchObject( instance, "_get_instance_info", side_effect=[ errors.ProviderInfoError( provider_name="multipass", exit_code=1, stderr=b"error" ), {}, ], ) ) instance.create() self.multipass_cmd_mock().launch.assert_called_once_with( instance_name="snapcraft-core18", cpus="2", mem="2G", disk="256G", image="snapcraft:core18", cloud_init=mock.ANY, )
def test_provision_project(self): multipass = Multipass(project=self.project, echoer=self.echoer_mock) # In the real world, MultipassCommand would return an error when # calling this on an instance that does not exist. multipass.provision_project("source.tar") self.multipass_cmd_mock().execute.assert_has_calls([ mock.call( instance_name=self.instance_name, command=["sudo", "-i", "mkdir", "~/project"], ), mock.call( instance_name=self.instance_name, command=[ "sudo", "-i", "tar", "-xvf", "source.tar", "-C", "~/project", ], ), ]) self.multipass_cmd_mock().copy_files.assert_called_once_with( destination="{}:source.tar".format(self.instance_name), source="source.tar") self.multipass_cmd_mock().launch.assert_not_called() self.multipass_cmd_mock().info.assert_not_called() self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_pull_file(self): multipass = Multipass(project=self.project, echoer=self.echoer_mock) multipass.pull_file("src.txt", "dest.txt") self.multipass_cmd_mock().execute.assert_called_once_with( command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "test", "-f", "src.txt", ], hide_output=False, instance_name="snapcraft-project-name", ) self.multipass_cmd_mock().copy_files.assert_called_once_with( destination="dest.txt", source="{}:src.txt".format(self.instance_name) ) self.multipass_cmd_mock().info.assert_not_called() self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_provision_project(self): multipass = Multipass(project=self.project, echoer=self.echoer_mock) # In the real world, MultipassCommand would return an error when # calling this on an instance that does not exist. multipass.provision_project("source.tar") self.multipass_cmd_mock().execute.assert_has_calls( [ mock.call( instance_name=self.instance_name, command=["mkdir", "project-name"] ), mock.call( instance_name=self.instance_name, command=["tar", "-xvf", "source.tar", "-C", "project-name"], ), ] ) self.multipass_cmd_mock().copy_files.assert_called_once_with( destination="{}:source.tar".format(self.instance_name), source="source.tar" ) self.multipass_cmd_mock().launch.assert_not_called() self.multipass_cmd_mock().info.assert_not_called() self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_instance_does_not_exist_on_destroy(self): # An error is raised if the queried image does not exist self.multipass_cmd_mock().info.side_effect = errors.ProviderInfoError( provider_name=self.instance_name, exit_code=2) multipass = Multipass(project=self.project, echoer=self.echoer_mock) multipass.destroy() self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_instance_does_not_exist_on_destroy(self): # An error is raised if the queried image does not exist self.multipass_cmd_mock().info.side_effect = errors.ProviderInfoError( provider_name=self.instance_name, exit_code=2 ) multipass = Multipass(project=self.project, echoer=self.echoer_mock) multipass.destroy() self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_destroy_instance_with_stop_delay_invalid(self): self.useFixture( fixtures.EnvironmentVariable( "SNAPCRAFT_BUILD_ENVIRONMENT_STOP_TIME", "A")) multipass = Multipass(project=self.project, echoer=self.echoer_mock) multipass.create() self.assertRaises(SnapcraftEnvironmentError, multipass.destroy) self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_launch_with_disk_from_environment(self): self.useFixture( fixtures.EnvironmentVariable("SNAPCRAFT_BUILD_ENVIRONMENT_DISK", "400G")) instance = Multipass(project=self.project, echoer=self.echoer_mock) instance.create() self.multipass_cmd_mock().launch.assert_called_once_with( instance_name=self.instance_name, cpus="2", mem="2G", disk="400G", image="snapcraft:core16", )
def test_pull_file(self): multipass = Multipass(project=self.project, echoer=self.echoer_mock) multipass.pull_file("src.txt", "dest.txt") self.multipass_cmd_mock().execute.assert_called_once_with( command=["test", "-f", "src.txt"], instance_name="snapcraft-project-name") self.multipass_cmd_mock().copy_files.assert_called_once_with( destination="dest.txt", source="{}:src.txt".format(self.instance_name)) self.multipass_cmd_mock().info.assert_not_called() self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_launch_with_ram_from_environment(self): self.useFixture( fixtures.EnvironmentVariable("SNAPCRAFT_BUILD_ENVIRONMENT_MEMORY", "4G")) instance = Multipass(project=self.project, echoer=self.echoer_mock) instance.create() self.multipass_cmd_mock().launch.assert_called_once_with( instance_name=self.instance_name, cpus=mock.ANY, mem="4G", disk="256G", image="16.04", cloud_init=mock.ANY, )
def test_retrieve_snap(self): multipass = Multipass(project=self.project, echoer=self.echoer_mock) # In the real world, MultipassCommand would return an error when # calling this on an instance that does not exist. multipass.retrieve_snap() self.multipass_cmd_mock().copy_files.assert_called_once_with( destination='project-name_{}.snap'.format(self.project.deb_arch), source='{}:project-name/project-name_{}.snap'.format( self.instance_name, self.project.deb_arch)) self.multipass_cmd_mock().execute.assert_not_called() self.multipass_cmd_mock().launch.assert_not_called() self.multipass_cmd_mock().info.assert_not_called() self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_lifecycle(self): with Multipass(project=self.project, echoer=self.echoer_mock, is_ephemeral=False) as instance: instance.mount_project() instance.execute_step(steps.PULL) self.multipass_cmd_mock().launch.assert_called_once_with( instance_name=self.instance_name, cpus="2", mem="2G", disk="256G", image=self.expected_image, cloud_init=mock.ANY, ) self.multipass_cmd_mock().execute.assert_has_calls([ mock.call( instance_name=self.instance_name, hide_output=True, command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "printenv", "HOME", ], ), mock.call( instance_name=self.instance_name, hide_output=False, command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "snapcraft", "pull", ], ), ]) self.multipass_cmd_mock().mount.assert_called_once_with( source=mock.ANY, target="{}:{}".format(self.instance_name, "/root/project"), uid_map=self.expected_uid_map, gid_map=self.expected_gid_map, ) self.multipass_cmd_mock().umount.assert_not_called() self.assertThat(self.multipass_cmd_mock().info.call_count, Equals(3)) self.multipass_cmd_mock().info.assert_has_calls([ mock.call(instance_name=self.instance_name, output_format="json"), mock.call(instance_name=self.instance_name, output_format="json"), ]) self.multipass_cmd_mock().copy_files.assert_not_called() self.multipass_cmd_mock().stop.assert_called_once_with( instance_name=self.instance_name, time=10) self.multipass_cmd_mock().delete.assert_not_called()
def test_launch_with_disk_from_environment(self): self.useFixture( fixtures.EnvironmentVariable("SNAPCRAFT_BUILD_ENVIRONMENT_DISK", "400G") ) self.multipass_cmd_mock().start.side_effect = errors.ProviderStartError( provider_name="multipass", exit_code=1 ) instance = Multipass(project=self.project, echoer=self.echoer_mock) instance.create() self.multipass_cmd_mock().launch.assert_called_once_with( instance_name=self.instance_name, mem="2G", disk="400G", image="16.04", cloud_init=mock.ANY, )
def test_ephemeral_instance_with_contextmanager(self): with Multipass(project=self.project, echoer=self.echoer_mock, is_ephemeral=True) as instance: instance.provision_project("source.tar") instance.build_project() instance.retrieve_snap() self.multipass_cmd_mock().launch.assert_called_once_with( instance_name=self.instance_name, cpus=mock.ANY, mem="2G", disk="256G", image="16.04", cloud_init=mock.ANY, ) # Given SnapInjector is mocked, we only need to verify the commands # called from the Multipass class. self.multipass_cmd_mock().execute.assert_has_calls([ mock.call(instance_name=self.instance_name, command=["mkdir", "~/project"]), mock.call( instance_name=self.instance_name, command=["tar", "-xvf", "source.tar", "-C", "~/project"], ), mock.call( instance_name=self.instance_name, command=[ "snapcraft", "snap", "--output", "project-name_{}.snap".format(self.project.deb_arch), ], ), ]) self.assertThat(self.multipass_cmd_mock().info.call_count, Equals(2)) self.multipass_cmd_mock().info.assert_has_calls([ mock.call(instance_name=self.instance_name, output_format="json"), mock.call(instance_name=self.instance_name, output_format="json"), ]) self.multipass_cmd_mock().copy_files.assert_has_calls([ mock.call( destination="{}:source.tar".format(self.instance_name), source="source.tar", ), mock.call( destination="project-name_{}.snap".format( self.project.deb_arch), source="{}:~/project/project-name_{}.snap".format( self.instance_name, self.project.deb_arch), ), ]) self.multipass_cmd_mock().stop.assert_called_once_with( instance_name=self.instance_name) self.multipass_cmd_mock().delete.assert_called_once_with( instance_name=self.instance_name, purge=True)
def test_retrieve_snap(self): multipass = Multipass(project=self.project, echoer=self.echoer_mock) # In the real world, MultipassCommand would return an error when # calling this on an instance that does not exist. multipass.retrieve_snap() self.multipass_cmd_mock().copy_files.assert_called_once_with( destination="project-name_{}.snap".format(self.project.deb_arch), source="{}:project-name/project-name_{}.snap".format( self.instance_name, self.project.deb_arch ), ) self.multipass_cmd_mock().execute.assert_not_called() self.multipass_cmd_mock().launch.assert_not_called() self.multipass_cmd_mock().info.assert_not_called() self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_build_project(self): multipass = Multipass(project=self.project, echoer=self.echoer_mock) # In the real world, MultipassCommand would return an error when # calling this on an instance that does not exist. multipass.build_project() self.multipass_cmd_mock().execute.assert_called_once_with( instance_name=self.instance_name, command=[ 'sh', '-c', 'cd project-name; /snap/bin/snapcraft ' 'snap --output project-name_{}.snap'.format( self.project.deb_arch) ]) self.multipass_cmd_mock().copy_files.assert_not_called() self.multipass_cmd_mock().launch.assert_not_called() self.multipass_cmd_mock().info.assert_not_called() self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_mount_prime_directory(self): with Multipass( project=self.project, echoer=self.echoer_mock, is_ephemeral=False ) as instance: instance._mount_prime_directory() self.multipass_cmd_mock().mount.assert_called_once_with( source=mock.ANY, target="{}:{}".format(self.instance_name, "/root/prime"), uid_map=self.expected_uid_map, gid_map=self.expected_gid_map, )
def test_provision_project(self): multipass = Multipass(project=self.project, echoer=self.echoer_mock) # In the real world, MultipassCommand would return an error when # calling this on an instance that does not exist. multipass.provision_project('source.tar') self.multipass_cmd_mock().execute.assert_has_calls([ mock.call(instance_name=self.instance_name, command=['mkdir', 'project-name']), mock.call( instance_name=self.instance_name, command=['tar', '-xvf', 'source.tar', '-C', 'project-name']), ]) self.multipass_cmd_mock().copy_files.assert_called_once_with( destination='{}:source.tar'.format(self.instance_name), source='source.tar') self.multipass_cmd_mock().launch.assert_not_called() self.multipass_cmd_mock().info.assert_not_called() self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_build_project(self): multipass = Multipass(project=self.project, echoer=self.echoer_mock) # In the real world, MultipassCommand would return an error when # calling this on an instance that does not exist. multipass.build_project() self.multipass_cmd_mock().execute.assert_called_once_with( instance_name=self.instance_name, command=[ "sh", "-c", "cd project-name; /snap/bin/snapcraft " "snap --output project-name_{}.snap".format(self.project.deb_arch), ], ) self.multipass_cmd_mock().copy_files.assert_not_called() self.multipass_cmd_mock().launch.assert_not_called() self.multipass_cmd_mock().info.assert_not_called() self.multipass_cmd_mock().stop.assert_not_called() self.multipass_cmd_mock().delete.assert_not_called()
def test_ephemeral_instance_with_contextmanager(self): with Multipass(project=self.project, echoer=self.echoer_mock, is_ephemeral=True) as instance: instance.execute_step(steps.PULL) instance.execute_step(steps.BUILD) self.multipass_cmd_mock().launch.assert_called_once_with( instance_name=self.instance_name, cpus="2", mem="2G", disk="256G", image="snapcraft:core16", ) # Given SnapInjector is mocked, we only need to verify the commands # called from the Multipass class. self.multipass_cmd_mock().execute.assert_has_calls([ mock.call( instance_name=self.instance_name, hide_output=False, command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "snapcraft", "pull", ], ), mock.call( instance_name=self.instance_name, hide_output=False, command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "snapcraft", "build", ], ), ]) self.assertThat(self.multipass_cmd_mock().info.call_count, Equals(3)) self.multipass_cmd_mock().info.assert_has_calls([ mock.call(instance_name=self.instance_name, output_format="json"), mock.call(instance_name=self.instance_name, output_format="json"), ]) self.multipass_cmd_mock().stop.assert_called_once_with( instance_name=self.instance_name, time=10) self.multipass_cmd_mock().delete.assert_called_once_with( instance_name=self.instance_name, purge=True)
def test_destroy_instance_with_stop_delay_0(self): self.useFixture( fixtures.EnvironmentVariable( "SNAPCRAFT_BUILD_ENVIRONMENT_STOP_TIME", "0")) multipass = Multipass(project=self.project, echoer=self.echoer_mock) multipass.create() multipass.destroy() self.multipass_cmd_mock().stop.assert_called_once_with( instance_name=self.instance_name) self.multipass_cmd_mock().delete.assert_not_called()
def test_lifecycle(self): with Multipass( project=self.project, echoer=self.echoer_mock, is_ephemeral=False ) as instance: instance.mount_project() instance.execute_step(steps.PULL) self.multipass_cmd_mock().launch.assert_called_once_with( instance_name=self.instance_name, mem="2G", disk="256G", image=self.expected_image, cloud_init=mock.ANY, ) self.multipass_cmd_mock().execute.assert_has_calls( [ mock.call( instance_name=self.instance_name, hide_output=True, command=["printenv", "HOME"], ), mock.call( instance_name=self.instance_name, hide_output=False, command=["snapcraft", "pull"], ), ] ) self.multipass_cmd_mock().mount.assert_called_once_with( source=mock.ANY, target="{}:{}".format(self.instance_name, "/home/multipass/project"), ) self.multipass_cmd_mock().umount.assert_not_called() self.multipass_cmd_mock().info.assert_called_once_with( instance_name=self.instance_name, output_format="json" ) self.multipass_cmd_mock().copy_files.assert_not_called() self.multipass_cmd_mock().stop.assert_called_once_with( instance_name=self.instance_name ) self.multipass_cmd_mock().delete.assert_not_called()
def test_instance_with_contextmanager(self): with Multipass(project=self.project, echoer=self.echoer_mock) as instance: instance.provision_project('source.tar') instance.build_project() instance.retrieve_snap() self.multipass_cmd_mock().launch.assert_called_once_with( image='16.04', instance_name=self.instance_name) self.multipass_cmd_mock().execute.assert_has_calls([ mock.call( instance_name=self.instance_name, command=['sudo', 'snap', 'install', 'snapcraft', '--classic']), mock.call(instance_name=self.instance_name, command=['mkdir', 'project-name']), mock.call( instance_name=self.instance_name, command=['tar', '-xvf', 'source.tar', '-C', 'project-name']), mock.call(instance_name=self.instance_name, command=[ 'sh', '-c', 'cd project-name; /snap/bin/snapcraft ' 'snap --output project-name_{}.snap'.format( self.project.deb_arch) ]), ]) self.multipass_cmd_mock().info.assert_called_once_with( instance_name=self.instance_name, output_format='json') self.multipass_cmd_mock().copy_files.assert_has_calls([ mock.call(destination='{}:source.tar'.format(self.instance_name), source='source.tar'), mock.call(destination='project-name_{}.snap'.format( self.project.deb_arch), source='{}:project-name/project-name_{}.snap'.format( self.instance_name, self.project.deb_arch)), ]) self.multipass_cmd_mock().stop.assert_called_once_with( instance_name=self.instance_name) self.multipass_cmd_mock().delete.assert_called_once_with( instance_name=self.instance_name)
def test_lifecycle(self): with Multipass(project=self.project, echoer=self.echoer_mock, is_ephemeral=False) as instance: instance.mount_project() instance.execute_step(steps.PULL) self.multipass_cmd_mock().launch.assert_called_once_with( instance_name=self.instance_name, cpus="2", mem="2G", disk="256G", image=self.expected_image, ) self.assertThat(self.multipass_cmd_mock().execute.call_count, Equals(9)) self.multipass_cmd_mock().execute.assert_has_calls([ mock.call( command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "snapcraft", "refresh", ], hide_output=False, instance_name="snapcraft-project-name", ), mock.call( command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "mv", "/tmp/L3Jvb3QvLmJhc2hyYw==", "/root/.bashrc", ], hide_output=False, instance_name="snapcraft-project-name", ), mock.call( command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "chown", "root:root", "/root/.bashrc", ], hide_output=False, instance_name="snapcraft-project-name", ), mock.call( command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "chmod", "0600", "/root/.bashrc", ], hide_output=False, instance_name="snapcraft-project-name", ), mock.call( command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "mv", "/tmp/L2Jpbi9fc25hcGNyYWZ0X3Byb21wdA==", "/bin/_snapcraft_prompt", ], hide_output=False, instance_name="snapcraft-project-name", ), mock.call( command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "chown", "root:root", "/bin/_snapcraft_prompt", ], hide_output=False, instance_name="snapcraft-project-name", ), mock.call( command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "chmod", "0755", "/bin/_snapcraft_prompt", ], hide_output=False, instance_name="snapcraft-project-name", ), mock.call( command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "printenv", "HOME", ], hide_output=True, instance_name="snapcraft-project-name", ), mock.call( command=[ "sudo", "-i", "env", "SNAPCRAFT_HAS_TTY=False", "snapcraft", "pull", ], hide_output=False, instance_name="snapcraft-project-name", ), ]) self.multipass_cmd_mock().mount.assert_called_once_with( source=mock.ANY, target="{}:{}".format(self.instance_name, "/root/project"), uid_map=self.expected_uid_map, gid_map=self.expected_gid_map, ) self.multipass_cmd_mock().umount.assert_not_called() self.assertThat(self.multipass_cmd_mock().info.call_count, Equals(3)) self.multipass_cmd_mock().info.assert_has_calls([ mock.call(instance_name=self.instance_name, output_format="json"), mock.call(instance_name=self.instance_name, output_format="json"), ]) self.assertThat(self.multipass_cmd_mock().copy_files.call_count, Equals(2)) self.multipass_cmd_mock().copy_files.assert_has_calls([ mock.call( source=mock.ANY, destination="snapcraft-project-name:/tmp/L3Jvb3QvLmJhc2hyYw==", ), mock.call( source=mock.ANY, destination= "snapcraft-project-name:/tmp/L2Jpbi9fc25hcGNyYWZ0X3Byb21wdA==", ), ]) self.multipass_cmd_mock().stop.assert_called_once_with( instance_name=self.instance_name, time=10) self.multipass_cmd_mock().delete.assert_not_called()
def test_plaftorm_and_base_unsupported(self): project = get_project(base="core17") multipass = Multipass(project=project, echoer=self.echoer_mock) self.assertRaises(errors.UnsupportedHostError, multipass.create)
def test_instance_with_contextmanager(self): fake_snapd = fixture_setup.FakeSnapd() self.useFixture(fake_snapd) fake_snapd.snaps_result = [] fake_snapd.find_result = [ { "core": { "id": "2kkitQ", "channels": { "latest/stable": { "confinement": "strict", "revision": "123" } }, } }, { "snapcraft": { "id": "3lljuR", "channels": { "latest/stable": { "confinement": "classic", "revision": "345" } }, } }, ] self.get_assertion_mock.side_effect = [b"fake-assertion-account-store"] with Multipass(project=self.project, echoer=self.echoer_mock) as instance: instance.provision_project("source.tar") instance.build_project() instance.retrieve_snap() self.multipass_cmd_mock().launch.assert_called_once_with( image="16.04", instance_name=self.instance_name) self.multipass_cmd_mock().execute.assert_has_calls([ mock.call( instance_name=self.instance_name, command=["sudo", "snap", "set", "core", mock.ANY], ), mock.call( instance_name=self.instance_name, command=["sudo", "snap", "watch", "--last=auto-refresh"], ), mock.call( instance_name=self.instance_name, command=["sudo", "snap", "ack", mock.ANY], ), mock.call( instance_name=self.instance_name, command=["sudo", "snap", "install", "core"], ), mock.call( instance_name=self.instance_name, command=["sudo", "snap", "install", "--classic", "snapcraft"], ), mock.call(instance_name=self.instance_name, command=["mkdir", "project-name"]), mock.call( instance_name=self.instance_name, command=["tar", "-xvf", "source.tar", "-C", "project-name"], ), mock.call( instance_name=self.instance_name, command=[ "sh", "-c", "cd project-name; /snap/bin/snapcraft " "snap --output project-name_{}.snap".format( self.project.deb_arch), ], ), ]) self.multipass_cmd_mock().info.assert_called_once_with( instance_name=self.instance_name, output_format="json") self.multipass_cmd_mock().copy_files.assert_has_calls([ mock.call( destination="{}:source.tar".format(self.instance_name), source="source.tar", ), mock.call( destination="project-name_{}.snap".format( self.project.deb_arch), source="{}:project-name/project-name_{}.snap".format( self.instance_name, self.project.deb_arch), ), ]) self.multipass_cmd_mock().stop.assert_called_once_with( instance_name=self.instance_name) self.multipass_cmd_mock().delete.assert_called_once_with( instance_name=self.instance_name)