def test_exec(fake_process):
    fake_process.register_subprocess(
        ["multipass", "exec", "test-instance", "--", "sleep", "1"])

    Multipass().exec(command=["sleep", "1"], instance_name="test-instance")

    assert len(fake_process.calls) == 1
def test_transfer_destination_io_error(mock_popen,
                                       mock_details_from_command_error):
    mock_popen.return_value.stdout.read.return_value = b""
    mock_popen.return_value.communicate.side_effect = [
        subprocess.TimeoutExpired(cmd="...", timeout=30),
        (b"", b""),
    ]
    mock_popen.return_value.returncode = -1

    stream = mock.Mock()

    with pytest.raises(MultipassError) as exc_info:
        Multipass().transfer_destination_io(source="test-instance:/test1",
                                            destination=stream)

    assert exc_info.value == MultipassError(
        brief="Failed to transfer file 'test-instance:/test1'.",
        details=mock_details_from_command_error.return_value,
    )
    assert mock_popen.mock_calls == [
        mock.call(
            ["multipass", "transfer", "test-instance:/test1", "-"],
            stdin=-3,
            stdout=-1,
            stderr=-1,
        ),
        mock.call().stdout.read(4096),
        mock.call().communicate(timeout=30),
        mock.call().kill(),
        mock.call().communicate(),
    ]
    assert stream.mock_calls == []
def test_delete_purge(fake_process):
    fake_process.register_subprocess(
        ["multipass", "delete", "test-instance", "--purge"])

    Multipass().delete(instance_name="test-instance", purge=True)

    assert len(fake_process.calls) == 1
def test_transfer_source_io_error(mock_popen, mock_details_from_command_error):
    mock_popen.return_value.communicate.side_effect = [
        subprocess.TimeoutExpired(cmd="...", timeout=30),
        (b"", b""),
    ]
    mock_popen.return_value.returncode = -1
    test_io = io.BytesIO(b"Hello World!\n")

    with pytest.raises(MultipassError) as exc_info:
        Multipass().transfer_source_io(
            source=test_io,
            destination="test-instance:/tmp/foo",
        )

    assert exc_info.value == MultipassError(
        brief=
        "Failed to transfer file to destination 'test-instance:/tmp/foo'.",
        details=mock_details_from_command_error.return_value,
    )
    assert mock_popen.mock_calls == [
        mock.call(
            ["multipass", "transfer", "-", "test-instance:/tmp/foo"],
            stdin=-1,
            stderr=-1,
        ),
        mock.call().stdin.write(b"Hello World!\n"),
        mock.call().communicate(timeout=30),
        mock.call().kill(),
        mock.call().communicate(),
    ]
def test_stop_all_opts(fake_process):
    fake_process.register_subprocess(
        ["multipass", "stop", "test-instance", "--time", "5"])

    Multipass().stop(instance_name="test-instance", delay_mins=5)

    assert len(fake_process.calls) == 1
def test_launch(fake_process):
    fake_process.register_subprocess(
        ["multipass", "launch", "test-image", "--name", "test-instance"])

    Multipass().launch(image="test-image", instance_name="test-instance")

    assert len(fake_process.calls) == 1
def test_transfer(fake_process):
    fake_process.register_subprocess(
        ["multipass", "transfer", "test-instance:/test1", "/test2"])

    Multipass().transfer(source="test-instance:/test1", destination="/test2")

    assert len(fake_process.calls) == 1
def test_umount(fake_process):
    fake_process.register_subprocess(
        ["multipass", "umount", "test-instance:/mnt"])

    Multipass().umount(mount="test-instance:/mnt")

    assert len(fake_process.calls) == 1
def test_mount_all_opts(fake_process):
    project_path = pathlib.Path.home() / "my-project"
    fake_process.register_subprocess([
        "multipass",
        "mount",
        str(project_path),
        "test-instance:/mnt",
        "--uid-map",
        "1:2",
        "--uid-map",
        "3:4",
        "--gid-map",
        "5:6",
        "--gid-map",
        "7:8",
    ])

    Multipass().mount(
        source=project_path,
        target="test-instance:/mnt",
        uid_map={
            "1": "2",
            "3": "4"
        },
        gid_map={
            "5": "6",
            "7": "8"
        },
    )

    assert len(fake_process.calls) == 1
def test_list(fake_process):
    fake_process.register_subprocess(["multipass", "list", "--format", "json"],
                                     stdout=EXAMPLE_LIST)

    vm_list = Multipass().list()

    assert len(fake_process.calls) == 1
    assert vm_list == ["manageable-snipe", "flowing-hawfinch"]
def test_info(fake_process):
    fake_process.register_subprocess(
        ["multipass", "info", "test-instance", "--format", "json"],
        stdout=EXAMPLE_INFO)

    data = Multipass().info(instance_name="test-instance")

    assert len(fake_process.calls) == 1
    assert data == json.loads(EXAMPLE_INFO)
def test_exec_error_no_check(fake_process):
    fake_process.register_subprocess(
        ["multipass", "exec", "test-instance", "--", "false"],
        returncode=1,
    )

    proc = Multipass().exec(command=["false"], instance_name="test-instance")

    assert proc.returncode == 1
def test_exec_error_with_check(fake_process):
    fake_process.register_subprocess(
        ["multipass", "exec", "test-instance", "--", "false"],
        returncode=1,
    )

    with pytest.raises(subprocess.CalledProcessError):
        Multipass().exec(command=["false"],
                         instance_name="test-instance",
                         check=True)
def test_transfer_destination_io(fake_process):
    stream = mock.Mock()
    fake_process.register_subprocess(
        ["multipass", "transfer", "test-instance:/test1", "-"],
        stdout=b"Hello World!\n")

    Multipass().transfer_destination_io(source="test-instance:/test1",
                                        destination=stream)

    assert len(fake_process.calls) == 1
    assert stream.mock_calls == [mock.call.write(b"Hello World!\n")]
def test_list_error(fake_process, mock_details_from_process_error):
    fake_process.register_subprocess(["multipass", "list", "--format", "json"],
                                     returncode=1)

    with pytest.raises(MultipassError) as exc_info:
        Multipass().list()

    assert len(fake_process.calls) == 1
    assert exc_info.value == MultipassError(
        brief="Failed to query list of VMs.",
        details=mock_details_from_process_error.return_value,
    )
def test_stop_error(fake_process, mock_details_from_process_error):
    fake_process.register_subprocess(["multipass", "stop", "test-instance"],
                                     returncode=1)

    with pytest.raises(MultipassError) as exc_info:
        Multipass().stop(instance_name="test-instance")

    assert len(fake_process.calls) == 1
    assert exc_info.value == MultipassError(
        brief="Failed to stop VM 'test-instance'.",
        details=mock_details_from_process_error.return_value,
    )
def test_umount_error(fake_process, mock_details_from_process_error):
    fake_process.register_subprocess(
        ["multipass", "umount", "test-instance:/mnt"], returncode=1)

    with pytest.raises(MultipassError) as exc_info:
        Multipass().umount(mount="test-instance:/mnt")

    assert len(fake_process.calls) == 1
    assert exc_info.value == MultipassError(
        brief="Failed to unmount 'test-instance:/mnt'.",
        details=mock_details_from_process_error.return_value,
    )
def test_delete_error(fake_process, mock_details_from_process_error):
    fake_process.register_subprocess(
        ["multipass", "delete", "test-instance", "--purge"],
        returncode=1,
    )

    with pytest.raises(MultipassError) as exc_info:
        Multipass().delete(instance_name="test-instance", purge=True)

    assert exc_info.value == MultipassError(
        brief="Failed to delete VM 'test-instance'.",
        details=mock_details_from_process_error.return_value,
    )
def test_transfer_error(fake_process, mock_details_from_process_error):
    fake_process.register_subprocess(
        ["multipass", "transfer", "test-instance:/test1", "/test2"],
        returncode=1)

    with pytest.raises(MultipassError) as exc_info:
        Multipass().transfer(source="test-instance:/test1",
                             destination="/test2")

    assert len(fake_process.calls) == 1
    assert exc_info.value == MultipassError(
        brief="Failed to transfer 'test-instance:/test1' to '/test2'.",
        details=mock_details_from_process_error.return_value,
    )
def test_mount(fake_process):
    project_path = pathlib.Path.home() / "my-project"
    fake_process.register_subprocess(
        ["multipass", "mount",
         str(project_path), "test-instance:/mnt"])

    Multipass().mount(
        source=project_path,
        target="test-instance:/mnt",
        uid_map=None,
        gid_map=None,
    )

    assert len(fake_process.calls) == 1
def test_info_error(fake_process, mock_details_from_process_error):
    fake_process.register_subprocess(
        ["multipass", "info", "test-instance", "--format", "json"],
        stderr=
        'info failed: The following errors occurred:\ninstance "foo" does not exist',
        returncode=1,
    )

    with pytest.raises(MultipassError) as exc_info:
        Multipass().info(instance_name="test-instance")

    assert len(fake_process.calls) == 1
    assert exc_info.value == MultipassError(
        brief="Failed to query info for VM 'test-instance'.",
        details=mock_details_from_process_error.return_value,
    )
def test_mount_error(fake_process, mock_details_from_process_error):
    project_path = pathlib.Path.home() / "my-project"
    fake_process.register_subprocess(
        ["multipass", "mount",
         str(project_path), "test-instance:/mnt"],
        returncode=1,
    )

    with pytest.raises(MultipassError) as exc_info:
        Multipass().mount(
            source=project_path,
            target="test-instance:/mnt",
        )

    assert len(fake_process.calls) == 1
    assert exc_info.value == MultipassError(
        brief=f"Failed to mount {str(project_path)!r} to 'test-instance:/mnt'.",
        details=mock_details_from_process_error.return_value,
    )
def test_transfer_source_io(mock_popen):
    mock_popen.return_value.communicate.return_value = b"", b""
    mock_popen.return_value.returncode = 0

    test_io = io.BytesIO(b"Hello World!\n")

    Multipass().transfer_source_io(
        source=test_io,
        destination="test-instance:/tmp/foo",
    )

    assert mock_popen.mock_calls == [
        mock.call(
            ["multipass", "transfer", "-", "test-instance:/tmp/foo"],
            stdin=-1,
            stderr=-1,
        ),
        mock.call().stdin.write(b"Hello World!\n"),
        mock.call().communicate(timeout=30),
    ]
def test_launch_all_opts(fake_process):
    fake_process.register_subprocess([
        "multipass",
        "launch",
        "test-image",
        "--name",
        "test-instance",
        "--cpus",
        "4",
        "--mem",
        "8G",
        "--disk",
        "80G",
    ])

    Multipass().launch(
        image="test-image",
        instance_name="test-instance",
        cpus="4",
        mem="8G",
        disk="80G",
    )

    assert len(fake_process.calls) == 1
Esempio n. 25
0
def _multipass(*, multipass_path):
    return Multipass(multipass_path=multipass_path)
Esempio n. 26
0
def multipass():
    yield Multipass()
def test_stop(fake_process):
    fake_process.register_subprocess(["multipass", "stop", "test-instance"])

    Multipass().stop(instance_name="test-instance")

    assert len(fake_process.calls) == 1