# # Copyright (c) 2023 Airbyte, Inc., all rights reserved. # import pytest from click.testing import CliRunner from octavia_cli._import import commands @pytest.fixture def patch_click(mocker): mocker.patch.object(commands, "click") @pytest.fixture def context_object(mock_api_client, mock_telemetry_client): return { "PROJECT_IS_INITIALIZED": True, "API_CLIENT": mock_api_client, "WORKSPACE_ID": "workspace_id", "TELEMETRY_CLIENT": mock_telemetry_client, } def test_build_help_message(): assert commands.build_help_message("source") == "Import an existing source to manage it with octavia-cli." @pytest.mark.parametrize("ResourceClass", [commands.UnmanagedSource, commands.UnmanagedDestination]) def test_import_source_or_destination(mocker, context_object, ResourceClass): resource_type = ResourceClass.__name__.lower() mocker.patch.object(commands.click, "style") mocker.patch.object(commands.click, "echo") mocker.patch.object(commands, "get_json_representation") mocker.patch.object( commands.json, "loads", mocker.Mock( return_value={ "name": "foo", "connection_configuration": "bar", f"{resource_type}_definition_id": f"{resource_type}_definition_id", f"{resource_type}_id": f"my_{resource_type}_id", } ), ) mocker.patch.object(commands.definitions, "factory") mocker.patch.object(commands.renderers, "ConnectorSpecificationRenderer") expected_managed_resource, expected_state = (mocker.Mock(), mocker.Mock()) mocker.patch.object( commands.resources, "factory", mocker.Mock(return_value=mocker.Mock(manage=mocker.Mock(return_value=(expected_managed_resource, expected_state)))), ) commands.import_source_or_destination(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], ResourceClass, "resource_to_get") commands.get_json_representation.assert_called_with( context_object["API_CLIENT"], context_object["WORKSPACE_ID"], ResourceClass, "resource_to_get" ) commands.json.loads.assert_called_with(commands.get_json_representation.return_value) remote_configuration = commands.json.loads.return_value commands.definitions.factory.assert_called_with( resource_type, context_object["API_CLIENT"], context_object["WORKSPACE_ID"], f"{resource_type}_definition_id" ) commands.renderers.ConnectorSpecificationRenderer.assert_called_with("foo", commands.definitions.factory.return_value) renderer = commands.renderers.ConnectorSpecificationRenderer.return_value renderer.import_configuration.assert_called_with(project_path=".", configuration=remote_configuration["connection_configuration"]) commands.resources.factory.assert_called_with( context_object["API_CLIENT"], context_object["WORKSPACE_ID"], renderer.import_configuration.return_value ) commands.resources.factory.return_value.manage.assert_called_with(remote_configuration[f"{resource_type}_id"]) commands.click.style.assert_has_calls( [ mocker.call( f"✅ - Imported {resource_type} {expected_managed_resource.name} in {renderer.import_configuration.return_value}. State stored in {expected_state.path}", fg="green", ), mocker.call(f"⚠️ - Please update any secrets stored in {renderer.import_configuration.return_value}", fg="yellow"), ] ) assert commands.click.echo.call_count == 2 @pytest.mark.parametrize( "source_exists, source_was_created, destination_exists, destination_was_created", [ (True, True, True, True), (False, False, False, False), (True, False, True, False), (True, True, False, False), (True, True, True, False), ], ) def test_import_connection(mocker, context_object, source_exists, source_was_created, destination_exists, destination_was_created): mocker.patch.object(commands.click, "style") mocker.patch.object(commands.click, "echo") mocker.patch.object(commands, "get_json_representation") mocker.patch.object( commands.json, "loads", mocker.Mock( return_value={ "source": {"name": "my_source"}, "destination": {"name": "my_destination"}, "name": "my_connection", "connection_id": "my_connection_id", } ), ) remote_configuration = commands.json.loads.return_value mocker.patch.object(commands.definitions, "factory") mock_source_configuration_path = mocker.Mock(is_file=mocker.Mock(return_value=source_exists)) mock_destination_configuration_path = mocker.Mock(is_file=mocker.Mock(return_value=destination_exists)) mocker.patch.object( commands.renderers.ConnectorSpecificationRenderer, "get_output_path", mocker.Mock(side_effect=[mock_source_configuration_path, mock_destination_configuration_path]), ) mocker.patch.object(commands.renderers, "ConnectionRenderer") mock_managed_source = mocker.Mock(was_created=source_was_created) mock_managed_destination = mocker.Mock(was_created=destination_was_created) mock_remote_connection, mock_connection_state = mocker.Mock(), mocker.Mock() mock_managed_connection = mocker.Mock(manage=mocker.Mock(return_value=(mock_remote_connection, mock_connection_state))) mocker.patch.object( commands.resources, "factory", mocker.Mock(side_effect=[mock_managed_source, mock_managed_destination, mock_managed_connection]) ) if all([source_exists, destination_exists, source_was_created, destination_was_created]): commands.import_connection(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], "resource_to_get") commands.get_json_representation.assert_called_with( context_object["API_CLIENT"], context_object["WORKSPACE_ID"], commands.UnmanagedConnection, "resource_to_get" ) commands.renderers.ConnectorSpecificationRenderer.get_output_path.assert_has_calls( [ mocker.call(project_path=".", definition_type="source", resource_name="my_source"), mocker.call(project_path=".", definition_type="destination", resource_name="my_destination"), ] ) commands.resources.factory.assert_has_calls( [ mocker.call(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], mock_source_configuration_path), mocker.call(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], mock_destination_configuration_path), mocker.call( context_object["API_CLIENT"], context_object["WORKSPACE_ID"], commands.renderers.ConnectionRenderer.return_value.import_configuration.return_value, ), ] ) commands.renderers.ConnectionRenderer.assert_called_with( remote_configuration["name"], mock_managed_source, mock_managed_destination ) commands.renderers.ConnectionRenderer.return_value.import_configuration.assert_called_with(".", remote_configuration) new_configuration_path = commands.renderers.ConnectionRenderer.return_value.import_configuration.return_value commands.click.style.assert_called_with( f"✅ - Imported connection {mock_remote_connection.name} in {new_configuration_path}. State stored in {mock_connection_state.path}", fg="green", ) commands.click.echo.assert_called_with(commands.click.style.return_value) if not source_exists or not destination_exists: with pytest.raises( commands.MissingResourceDependencyError, match="is not managed by octavia-cli, please import and apply it before importing your connection.", ): commands.import_connection(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], "resource_to_get") if source_exists and destination_exists and (not source_was_created or not destination_was_created): with pytest.raises(commands.resources.NonExistingResourceError, match="Please run octavia apply before creating this connection."): commands.import_connection(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], "resource_to_get") @pytest.mark.parametrize("command", [commands.source, commands.destination, commands.connection, commands.all]) def test_import_not_initialized(command): runner = CliRunner() result = runner.invoke(command, obj={"PROJECT_IS_INITIALIZED": False}) assert result.exit_code == 1 @pytest.mark.parametrize( "command, ResourceClass, import_function", [ (commands.source, commands.UnmanagedSource, "import_source_or_destination"), (commands.destination, commands.UnmanagedDestination, "import_source_or_destination"), (commands.connection, None, "import_connection"), ], ) def test_import_commands(mocker, context_object, ResourceClass, command, import_function): runner = CliRunner() mock_import_function = mocker.Mock() mocker.patch.object(commands, import_function, mock_import_function) result = runner.invoke(command, ["resource_to_import"], obj=context_object) if import_function == "import_source_or_destination": mock_import_function.assert_called_with( context_object["API_CLIENT"], context_object["WORKSPACE_ID"], ResourceClass, "resource_to_import" ) else: mock_import_function.assert_called_with(context_object["API_CLIENT"], context_object["WORKSPACE_ID"], "resource_to_import") assert result.exit_code == 0 def test_import_all(mocker, context_object): runner = CliRunner() mock_manager = mocker.Mock() mocker.patch.object(commands, "import_source_or_destination", mock_manager.import_source_or_destination) mocker.patch.object(commands, "import_connection", mock_manager.import_connection) mocker.patch.object( commands, "UnmanagedSources", return_value=mocker.Mock(get_listing=mocker.Mock(return_value=[("_", "_", "source_resource_id")])) ) mocker.patch.object( commands, "UnmanagedDestinations", return_value=mocker.Mock(get_listing=mocker.Mock(return_value=[("_", "_", "destination_resource_id")])), ) mocker.patch.object( commands, "UnmanagedConnections", return_value=mocker.Mock(get_listing=mocker.Mock(return_value=[("_", "connection_resource_id", "_", "_", "_")])), ) result = runner.invoke(commands.all, obj=context_object) commands.UnmanagedSources.return_value.get_listing.assert_called_once() commands.UnmanagedDestinations.return_value.get_listing.assert_called_once() commands.UnmanagedConnections.return_value.get_listing.assert_called_once() assert result.exit_code == 0 assert mock_manager.mock_calls[0] == mocker.call.import_source_or_destination( context_object["API_CLIENT"], "workspace_id", commands.UnmanagedSource, "source_resource_id" ) assert mock_manager.mock_calls[1] == mocker.call.import_source_or_destination( context_object["API_CLIENT"], "workspace_id", commands.UnmanagedDestination, "destination_resource_id" ) assert mock_manager.mock_calls[2] == mocker.call.import_connection( context_object["API_CLIENT"], "workspace_id", "connection_resource_id" )