def test_container_executor_skopeo_login_fail(mock_api_client, mock_tls_config,
                                              mock_isdir, mock_run_cmd,
                                              mock_add_file):
    mock_create_container = mock.MagicMock()
    mock_create_container.return_value = {"Id": "123"}
    mock_api_client.return_value.create_container = mock_create_container
    mock_start = mock.MagicMock()
    mock_api_client.return_value.start = mock_start
    mock_remove_container = mock.MagicMock()
    mock_api_client.return_value.remove_container = mock_remove_container
    mock_isdir.return_value = True

    mock_run_cmd.side_effect = [("not logged in", "nothing"),
                                ("Login Failed", "nothing")]

    with command_executor.ContainerExecutor(
            "quay.io/some/image:1",
            base_url="some-url.com",
            timeout=120,
            verify_tls=True,
            cert_path="/some/path",
    ) as executor:
        with pytest.raises(
                RuntimeError,
                match="Login command didn't generate expected output.*"):
            executor.skopeo_login("some-host", "some-name", "some-password")

    assert mock_run_cmd.call_count == 2
    assert mock_run_cmd.call_args_list[0] == mock.call(
        "skopeo login --get-login some-host", tolerate_err=True)
    assert mock_run_cmd.call_args_list[1] == mock.call(
        " sh -c 'cat /tmp/skopeo_password.txt | skopeo login --authfile $HOME/.docker/config.json "
        '-u "some-name" --password-stdin some-host\'')
    mock_add_file.assert_called_once_with("some-password",
                                          "skopeo_password.txt")
def test_container_executor_skopeo_login_already_logged(
        mock_api_client, mock_tls_config, mock_isdir, mock_run_cmd,
        mock_add_file):
    mock_create_container = mock.MagicMock()
    mock_create_container.return_value = {"Id": "123"}
    mock_api_client.return_value.create_container = mock_create_container
    mock_start = mock.MagicMock()
    mock_api_client.return_value.start = mock_start
    mock_remove_container = mock.MagicMock()
    mock_api_client.return_value.remove_container = mock_remove_container
    mock_isdir.return_value = True

    mock_run_cmd.return_value = ("some-name", "nothing")

    with command_executor.ContainerExecutor(
            "quay.io/some/image:1",
            base_url="some-url.com",
            timeout=120,
            verify_tls=True,
            cert_path="/some/path",
    ) as executor:
        executor.skopeo_login("some-host", "some-name", "some-password")

    mock_run_cmd.assert_called_once_with("skopeo login --get-login some-host",
                                         tolerate_err=True)
    mock_add_file.assert_not_called()
def test_container_executor_skopeo_login_missing_credential(
        mock_api_client, mock_tls_config, mock_isdir, mock_run_cmd,
        mock_add_file):
    mock_create_container = mock.MagicMock()
    mock_create_container.return_value = {"Id": "123"}
    mock_api_client.return_value.create_container = mock_create_container
    mock_start = mock.MagicMock()
    mock_api_client.return_value.start = mock_start
    mock_remove_container = mock.MagicMock()
    mock_api_client.return_value.remove_container = mock_remove_container
    mock_isdir.return_value = True

    mock_run_cmd.side_effect = [("not logged in", "nothing"),
                                ("Login Succeeded", "nothing")]

    with command_executor.ContainerExecutor(
            "quay.io/some/image:1",
            base_url="some-url.com",
            timeout=120,
            verify_tls=True,
            cert_path="/some/path",
    ) as executor:
        with pytest.raises(ValueError,
                           match="Skopeo login credentials are not present.*"):
            executor.skopeo_login("some-host", "some-name")

    mock_run_cmd.assert_called_once_with("skopeo login --get-login some-host",
                                         tolerate_err=True)
    mock_add_file.assert_not_called()
def test_container_executor_run_cmd_no_output(mock_api_client, mock_tls_config,
                                              mock_isdir):
    mock_create_container = mock.MagicMock()
    mock_create_container.return_value = {"Id": "123"}
    mock_api_client.return_value.create_container = mock_create_container
    mock_start = mock.MagicMock()
    mock_api_client.return_value.start = mock_start
    mock_remove_container = mock.MagicMock()
    mock_api_client.return_value.remove_container = mock_remove_container
    mock_isdir.return_value = True

    mock_exec_create = mock.MagicMock()
    mock_exec_create.return_value = {"Id": "321"}
    mock_api_client.return_value.exec_create = mock_exec_create
    mock_exec_start = mock.MagicMock()
    mock_exec_start.return_value = None
    mock_api_client.return_value.exec_start = mock_exec_start
    mock_exec_inspect = mock.MagicMock()
    mock_exec_inspect.return_value = {"ExitCode": 0}
    mock_api_client.return_value.exec_inspect = mock_exec_inspect

    with command_executor.ContainerExecutor(
            "quay.io/some/image:1",
            base_url="some-url.com",
            timeout=120,
            verify_tls=True,
            cert_path="/some/path",
    ) as executor:
        stdout, stderr = executor._run_cmd("cat file.txt")

    assert stdout == ""
    assert stderr == ""
def test_container_executor_run_cmd_error(mock_api_client, mock_tls_config,
                                          mock_isdir):
    mock_create_container = mock.MagicMock()
    mock_create_container.return_value = {"Id": "123"}
    mock_api_client.return_value.create_container = mock_create_container
    mock_start = mock.MagicMock()
    mock_api_client.return_value.start = mock_start
    mock_remove_container = mock.MagicMock()
    mock_api_client.return_value.remove_container = mock_remove_container
    mock_isdir.return_value = True

    mock_exec_create = mock.MagicMock()
    mock_exec_create.return_value = {"Id": "321"}
    mock_api_client.return_value.exec_create = mock_exec_create
    mock_exec_start = mock.MagicMock()
    mock_exec_start.return_value = b"some output"
    mock_api_client.return_value.exec_start = mock_exec_start
    mock_exec_inspect = mock.MagicMock()
    mock_exec_inspect.return_value = {"ExitCode": 1}
    mock_api_client.return_value.exec_inspect = mock_exec_inspect

    with command_executor.ContainerExecutor(
            "quay.io/some/image:1",
            base_url="some-url.com",
            timeout=120,
            verify_tls=True,
            cert_path="/some/path",
    ) as executor:
        with pytest.raises(
                RuntimeError,
                match="An error has occured when executing a command."):
            stdout, stderr = executor._run_cmd("cat file.txt")
def test_container_executor_add_file(
    mock_api_client,
    mock_tls_config,
    mock_isdir,
    mock_bytesio,
    mock_tarfile,
    mock_tarinfo,
    mock_time,
):
    mock_create_container = mock.MagicMock()
    mock_create_container.return_value = {"Id": "123"}
    mock_api_client.return_value.create_container = mock_create_container
    mock_start = mock.MagicMock()
    mock_api_client.return_value.start = mock_start
    mock_remove_container = mock.MagicMock()
    mock_api_client.return_value.remove_container = mock_remove_container
    mock_isdir.return_value = True

    mock_add_file = mock.MagicMock()
    mock_tarfile.return_value.addfile = mock_add_file
    mock_close = mock.MagicMock()
    mock_tarfile.return_value.close = mock_close
    mock_bytesio1 = mock.MagicMock()
    mock_bytesio2 = mock.MagicMock()
    mock_bytesio.side_effect = [mock_bytesio1, mock_bytesio2]
    mock_seek = mock.MagicMock()
    mock_bytesio1.seek = mock_seek
    mock_put_archive = mock.MagicMock()
    mock_put_archive.return_value = True
    mock_api_client.return_value.put_archive = mock_put_archive

    with command_executor.ContainerExecutor(
            "quay.io/some/image:1",
            base_url="some-url.com",
            timeout=120,
            verify_tls=True,
            cert_path="/some/path",
    ) as executor:
        executor._add_file("abcdefg", "some-file.txt")

    assert mock_bytesio.call_count == 2
    mock_tarfile.assert_called_once_with(fileobj=mock_bytesio1, mode="w")
    mock_tarinfo.assert_called_once_with(name="some-file.txt")
    mock_add_file.assert_called_once_with(mock_tarinfo.return_value,
                                          mock_bytesio2)
    mock_close.assert_called_once_with()
    mock_seek.assert_called_once_with(0)
    mock_put_archive.assert_called_once_with(container="123",
                                             path="/tmp",
                                             data=mock_bytesio1)
def test_container_executor_add_file_fail(
    mock_api_client,
    mock_tls_config,
    mock_isdir,
    mock_bytesio,
    mock_tarfile,
    mock_tarinfo,
    mock_time,
):
    mock_create_container = mock.MagicMock()
    mock_create_container.return_value = {"Id": "123"}
    mock_api_client.return_value.create_container = mock_create_container
    mock_start = mock.MagicMock()
    mock_api_client.return_value.start = mock_start
    mock_remove_container = mock.MagicMock()
    mock_api_client.return_value.remove_container = mock_remove_container
    mock_isdir.return_value = True

    mock_add_file = mock.MagicMock()
    mock_tarfile.return_value.addfile = mock_add_file
    mock_close = mock.MagicMock()
    mock_tarfile.return_value.close = mock_close
    mock_bytesio1 = mock.MagicMock()
    mock_bytesio2 = mock.MagicMock()
    mock_bytesio.side_effect = [mock_bytesio1, mock_bytesio2]
    mock_seek = mock.MagicMock()
    mock_bytesio1.seek = mock_seek
    mock_put_archive = mock.MagicMock()
    mock_put_archive.return_value = False
    mock_api_client.return_value.put_archive = mock_put_archive

    with command_executor.ContainerExecutor(
            "quay.io/some/image:1",
            base_url="some-url.com",
            timeout=120,
            verify_tls=True,
            cert_path="/some/path",
    ) as executor:
        with pytest.raises(
                RuntimeError,
                match="File was not successfully added to the container"):
            executor._add_file("abcdefg", "some-file.txt")
def test_container_executor_init(mock_api_client, mock_tls_config, mock_isdir):
    mock_create_container = mock.MagicMock()
    mock_create_container.return_value = {"Id": "123"}
    mock_api_client.return_value.create_container = mock_create_container
    mock_start = mock.MagicMock()
    mock_api_client.return_value.start = mock_start
    mock_remove_container = mock.MagicMock()
    mock_api_client.return_value.remove_container = mock_remove_container
    mock_isdir.return_value = True

    with command_executor.ContainerExecutor(
            "quay.io/some/image:1",
            base_url="some-url.com",
            timeout=120,
            verify_tls=True,
            cert_path="/some/path",
            registry_username="******",
            registry_password="******",
    ):
        pass

    mock_tls_config.assert_called_once_with(client_cert=("/some/path/cert.pem",
                                                         "/some/path/key.pem"),
                                            verify="/some/path/ca.pem")
    mock_api_client.assert_called_once_with(base_url="some-url.com",
                                            version="auto",
                                            timeout=120,
                                            tls=mock_tls_config.return_value)
    mock_create_container.assert_called_once_with("quay.io/some/image:1",
                                                  detach=True,
                                                  tty=True)
    mock_start.assert_called_once_with("123")
    mock_remove_container.assert_called_once_with("123", force=True)
    mock_api_client.return_value.login.assert_called_once_with(
        username="******",
        password="******",
        registry="quay.io",
        reauth=True)
    mock_api_client.return_value.pull.assert_called_once_with(
        "quay.io/some/image", tag="1")