From 0edfa0a87a03810d39d71d498fe09f8a98cc5bee Mon Sep 17 00:00:00 2001 From: Pawel Snoch Date: Thu, 11 Jun 2026 14:12:00 +0200 Subject: [PATCH 1/2] Create tests for stream commands --- tests/integration/streams/test_streams.py | 186 ++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 tests/integration/streams/test_streams.py diff --git a/tests/integration/streams/test_streams.py b/tests/integration/streams/test_streams.py new file mode 100644 index 00000000..319f4e92 --- /dev/null +++ b/tests/integration/streams/test_streams.py @@ -0,0 +1,186 @@ +from linodecli.exit_codes import ExitCodes +from tests.integration.helpers import ( + BASE_CMDS, + assert_headers_in_lines, + assert_help_actions_list, + exec_failing_test_command, + exec_test_command, + get_random_text, +) +from tests.integration.streams.fixtures import ( + create_destination_akamai_object_storage_type, +) + + +def test_help_streams(): + output = exec_test_command( + BASE_CMDS["streams"] + ["--help", "--text", "--delimiter=,"] + ) + actions = [ + "create", + "delete", + "destination-create", + "destination-delete", + "destination-history-view", + "destination-update", + "destination-view", + "destinations-list", + "history-view", + "ls, list", + "update", + "view", + ] + assert_help_actions_list(actions, output) + + +def test_list_destinations(create_destination_akamai_object_storage_type): + result = exec_test_command( + BASE_CMDS["streams"] + ["destinations-list", "--delimiter", ",", "--text"] + ) + lines = result.splitlines() + headers = [ + "created", + "created_by", + "details", + "id", + "label", + "status", + "type", + "updated", + "updated_by", + "version", + ] + assert_headers_in_lines(headers, lines) + + +def test_create_destination_error(): + result = exec_failing_test_command( + BASE_CMDS["streams"] + + [ + "destination-create", + "--label", + "test", + "--type", + "custom_https", + "--details", + "test", + "--delimiter", + ",", + "--text", + ], + expected_code=ExitCodes.REQUEST_FAILED, + ) + assert "Request failed: 400" in result + assert "details,Must be of type Object" in result + + +def test_create_view_update_remove_destination(): + label = get_random_text(8) + "_destination_cli_test" + result_create_stream = exec_test_command( + BASE_CMDS["streams"] + + [ + "destination-create", + "--details", + "--label", + label, + "--type", + "--delimiter", + ",", + "--text", + ] + ).splitlines() + headers = [ + "created", + "created_by", + "details", + "id", + "label", + "status", + "type", + "updated", + "updated_by", + "version", + ] + assert_headers_in_lines(headers, result_create_stream) + assert label in result_create_stream[1] + + result_view = exec_test_command( + BASE_CMDS["streams"] + + ["destination-view", result_create_stream[0], "--delimiter", ",", "--text"] + ).splitlines() + assert_headers_in_lines(headers, result_view) + assert label in result_view[1] + + result_update_stream = exec_test_command( + BASE_CMDS["streams"] + + [ + "destination-update", + result_create_stream[0], + "--delimiter", + ",", + "--text", + ] + ).splitlines() + assert_headers_in_lines(headers, result_update_stream) + + exec_test_command( + BASE_CMDS["streams"] + + [ + "destination-delete", + result_create_stream[0], + "--delimiter", + ",", + "--text", + ] + ).splitlines() + + exec_test_command( + BASE_CMDS["streams"] + + ["destination-view", result_create_stream[0], "--delimiter", ",", "--text"] + ) + + +def test_list_streams(): + result = exec_test_command( + BASE_CMDS["streams"] + ["list", "--delimiter", ",", "--text"] + ) + lines = result.splitlines() + headers = [ + "created", + "created_by", + "destinations.details.access_key_id", + "destinations.details.bucket_name", + "destinations.details.host", + "destinations.details.path", + "details.cluster_ids", + "details.is_auto_add_all_clusters_enabled", + "id", + "label", + "status", + "type", + "updated", + "updated_by", + "version", + ] + assert_headers_in_lines(headers, lines) + + +def test_create_stream_invalid_destination_error(): + result = exec_failing_test_command( + BASE_CMDS["streams"] + + [ + "create", + "--label", + "test", + "--type", + "audit_logs", + "--destinations", + "12341234", + "--delimiter", + ",", + "--text", + ], + expected_code=ExitCodes.REQUEST_FAILED, + ) + assert "Request failed: 400" in result + assert "Destination not found" in result From 7e2847237ca5d560a8d05e8f429c3cd07e81b6c9 Mon Sep 17 00:00:00 2001 From: Pawel Snoch Date: Tue, 30 Jun 2026 15:59:35 +0200 Subject: [PATCH 2/2] Extends integration tests for streams commands --- tests/integration/helpers.py | 1 + tests/integration/streams/fixtures.py | 122 ++++++++++++++ tests/integration/streams/test_destination.py | 158 ++++++++++++++++++ tests/integration/streams/test_streams.py | 146 ++++++---------- 4 files changed, 329 insertions(+), 98 deletions(-) create mode 100644 tests/integration/streams/fixtures.py create mode 100644 tests/integration/streams/test_destination.py diff --git a/tests/integration/helpers.py b/tests/integration/helpers.py index 03a0fc30..7a3f2ee8 100644 --- a/tests/integration/helpers.py +++ b/tests/integration/helpers.py @@ -47,6 +47,7 @@ "regions", "ssh", "stackscripts", + "streams", "tickets", "tags", "users", diff --git a/tests/integration/streams/fixtures.py b/tests/integration/streams/fixtures.py new file mode 100644 index 00000000..66aa3e34 --- /dev/null +++ b/tests/integration/streams/fixtures.py @@ -0,0 +1,122 @@ +import os +from typing import Any, Dict + +import pytest +import requests + +from tests.integration.helpers import ( + BASE_CMDS, + delete_target_id, + exec_test_command, + get_random_region_with_caps, + get_random_text, +) + + +def get_object_storage_buckets() -> Dict[str, Any]: + token = os.getenv("LINODE_CLI_TOKEN") + if token is None: + raise ValueError("LINODE_CLI_TOKEN environment variable is not set. ") + host = os.getenv("LINODE_CLI_API_HOST") + if token is None: + raise ValueError( + "LINODE_CLI_API_HOST environment variable is not set. " + ) + version = os.getenv("LINODE_CLI_API_VERSION") + if token is None: + raise ValueError( + "LINODE_CLI_API_VERSION environment variable is not set. " + ) + + url = f"https://{host}/{version}/object-storage/buckets" + headers = { + "Authorization": f"Bearer {token}", + "Content-Type": "application/json", + } + + response = requests.get(url, headers=headers, timeout=30) + response.raise_for_status() + + return response.json() + + +@pytest.fixture(scope="session") +def create_stream(create_destination_akamai_object_storage_type): + label = get_random_text(8) + "_stream_cli_test" + result_create_stream = exec_test_command( + BASE_CMDS["streams"] + + [ + "create", + "--label", + label, + "--type", + "audit_logs", + "--destinations", + create_destination_akamai_object_storage_type[0], + "--delimiter", + ",", + "--text", + ] + ).splitlines() + yield result_create_stream + delete_target_id("streams", str(result_create_stream[1]), "delete") + + +@pytest.fixture +def create_object_storage_keys(): + label = get_random_text(8) + "_destination_cli_test" + test_bucket = get_object_storage_buckets()["data"][0] + result_keys = exec_test_command( + BASE_CMDS["object-storage"] + + [ + "keys-create", + "--label", + label, + "--bucket_access", + '[{"region": "' + + test_bucket["region"] + + '", "bucket_name": "' + + test_bucket["label"] + + '", "permissions": "read_write" }]', + "--text", + "--no-headers", + "--delimiter", + ",", + "--format", + "access_key,id", + ] + ).split(",") + yield result_keys[0], test_bucket["label"], test_bucket["s3_endpoint"] + delete_target_id("object-storage", str(result_keys[1]), "keys-delete") + + +@pytest.fixture(scope="function") +def create_destination_akamai_object_storage_type(create_object_storage_keys): + get_random_region_with_caps(required_capabilities=["Linodes"]) + + label = get_random_text(8) + "_destination_cli_test" + result_create_destination = exec_test_command( + BASE_CMDS["streams"] + + [ + "destination-create", + "--label", + label, + "--type", + "akamai_object_storage", + "--details.host", + create_object_storage_keys[2], + "--details.bucket_name", + create_object_storage_keys[1], + "--details.path", + "audit-logs", + "--details.access_key_id", + create_object_storage_keys[0], + "--delimiter", + ",", + "--text", + ] + ).splitlines() + yield result_create_destination + delete_target_id( + "streams", str(result_create_destination[0]), "destination-delete" + ) diff --git a/tests/integration/streams/test_destination.py b/tests/integration/streams/test_destination.py new file mode 100644 index 00000000..a50156c0 --- /dev/null +++ b/tests/integration/streams/test_destination.py @@ -0,0 +1,158 @@ +from linodecli.exit_codes import ExitCodes +from tests.integration.helpers import ( + BASE_CMDS, + assert_headers_in_lines, + exec_failing_test_command, + exec_test_command, +) +from tests.integration.streams.fixtures import ( + create_destination_akamai_object_storage_type, + create_object_storage_keys, +) + + +def test_list_destinations(): + result = exec_test_command( + BASE_CMDS["streams"] + + ["destinations-list", "--delimiter", ",", "--text"] + ) + lines = result.splitlines() + headers = [ + "created", + "created_by", + "details", + "id", + "label", + "status", + "type", + "updated", + "updated_by", + "version", + ] + assert_headers_in_lines(headers, lines) + + +def test_create_destination_error(): + result = exec_failing_test_command( + BASE_CMDS["streams"] + + [ + "destination-create", + "--label", + "test", + "--type", + "custom_https", + "--details", + "test", + "--delimiter", + ",", + "--text", + ], + expected_code=ExitCodes.REQUEST_FAILED, + ) + assert "Request failed: 400" in result + assert "details,Must be of type Object" in result + + +def test_view_destination_error(): + result = exec_failing_test_command( + BASE_CMDS["streams"] + + [ + "destination-view", + "1", + "--delimiter", + ",", + "--text", + ], + expected_code=ExitCodes.REQUEST_FAILED, + ) + assert "Request failed: 404" in result + assert "Destination not found" in result + + +def test_destination_history_view_error(): + result = exec_failing_test_command( + BASE_CMDS["streams"] + + [ + "destination-history-view", + "1", + "--delimiter", + ",", + "--text", + ], + expected_code=ExitCodes.REQUEST_FAILED, + ) + assert "Request failed: 404" in result + assert "Destination not found" in result + + +def test_update_destination_error(): + result = exec_failing_test_command( + BASE_CMDS["streams"] + + [ + "destination-update", + "1", + "--details", + "test", + "--delimiter", + ",", + "--text", + ], + expected_code=ExitCodes.REQUEST_FAILED, + ) + assert "Request failed: 404" in result + assert "Destination not found" in result + + +def test_remove_destination_error(): + result = exec_failing_test_command( + BASE_CMDS["streams"] + + [ + "destination-delete", + "1", + "--delimiter", + ",", + "--text", + ], + expected_code=ExitCodes.REQUEST_FAILED, + ) + assert "Request failed: 404" in result + assert "Destination not found" in result + + +def test_view_delete_destination(create_destination_akamai_object_storage_type): + result_view = exec_test_command( + BASE_CMDS["streams"] + + [ + "destination-view", + create_destination_akamai_object_storage_type, + "--delimiter", + ",", + "--text", + ], + ) + assert result_view == "test" + + exec_test_command( + BASE_CMDS["streams"] + + [ + "delete", + create_destination_akamai_object_storage_type, + "--delimiter", + ",", + "--text", + ], + ) + + result = exec_failing_test_command( + BASE_CMDS["streams"] + + [ + "destination-view", + create_destination_akamai_object_storage_type, + "--delimiter", + ",", + "--text", + ], + expected_code=ExitCodes.REQUEST_FAILED, + ) + assert "Request failed: 404" in result + assert "Not found" in result diff --git a/tests/integration/streams/test_streams.py b/tests/integration/streams/test_streams.py index 319f4e92..dbeb1b0f 100644 --- a/tests/integration/streams/test_streams.py +++ b/tests/integration/streams/test_streams.py @@ -5,10 +5,6 @@ assert_help_actions_list, exec_failing_test_command, exec_test_command, - get_random_text, -) -from tests.integration.streams.fixtures import ( - create_destination_akamai_object_storage_type, ) @@ -33,37 +29,17 @@ def test_help_streams(): assert_help_actions_list(actions, output) -def test_list_destinations(create_destination_akamai_object_storage_type): - result = exec_test_command( - BASE_CMDS["streams"] + ["destinations-list", "--delimiter", ",", "--text"] - ) - lines = result.splitlines() - headers = [ - "created", - "created_by", - "details", - "id", - "label", - "status", - "type", - "updated", - "updated_by", - "version", - ] - assert_headers_in_lines(headers, lines) - - -def test_create_destination_error(): +def test_create_stream_error(): result = exec_failing_test_command( BASE_CMDS["streams"] + [ - "destination-create", + "create", + "--destinations", + "1", "--label", "test", "--type", - "custom_https", - "--details", - "test", + "audit_logs", "--delimiter", ",", "--text", @@ -71,76 +47,42 @@ def test_create_destination_error(): expected_code=ExitCodes.REQUEST_FAILED, ) assert "Request failed: 400" in result - assert "details,Must be of type Object" in result + assert "Destination not found" in result -def test_create_view_update_remove_destination(): - label = get_random_text(8) + "_destination_cli_test" - result_create_stream = exec_test_command( +def test_delete_stream_error(): + result = exec_failing_test_command( BASE_CMDS["streams"] + [ - "destination-create", - "--details", - "--label", - label, - "--type", + "delete", + "-2", "--delimiter", ",", "--text", - ] - ).splitlines() - headers = [ - "created", - "created_by", - "details", - "id", - "label", - "status", - "type", - "updated", - "updated_by", - "version", - ] - assert_headers_in_lines(headers, result_create_stream) - assert label in result_create_stream[1] + ], + expected_code=ExitCodes.REQUEST_FAILED, + ) + assert "Request failed: 404" in result + assert "Not found" in result - result_view = exec_test_command( - BASE_CMDS["streams"] - + ["destination-view", result_create_stream[0], "--delimiter", ",", "--text"] - ).splitlines() - assert_headers_in_lines(headers, result_view) - assert label in result_view[1] - result_update_stream = exec_test_command( - BASE_CMDS["streams"] - + [ - "destination-update", - result_create_stream[0], - "--delimiter", - ",", - "--text", - ] - ).splitlines() - assert_headers_in_lines(headers, result_update_stream) - - exec_test_command( +def test_stream_history_view_error(): + result = exec_failing_test_command( BASE_CMDS["streams"] + [ - "destination-delete", - result_create_stream[0], + "history-view", + "1", "--delimiter", ",", "--text", - ] - ).splitlines() - - exec_test_command( - BASE_CMDS["streams"] - + ["destination-view", result_create_stream[0], "--delimiter", ",", "--text"] - ) + ], + expected_code=ExitCodes.REQUEST_FAILED, + ) + assert "Request failed: 404" in result + assert "Stream not found" in result -def test_list_streams(): +def test_list_destinations(): result = exec_test_command( BASE_CMDS["streams"] + ["list", "--delimiter", ",", "--text"] ) @@ -148,12 +90,9 @@ def test_list_streams(): headers = [ "created", "created_by", - "destinations.details.access_key_id", - "destinations.details.bucket_name", - "destinations.details.host", - "destinations.details.path", - "details.cluster_ids", + "destinations.details.access_key_id", "destinations.details.bucket_name", "destinations.details.host" , "destinations.details.path", "details.cluster_ids", "details.is_auto_add_all_clusters_enabled", + "details", "id", "label", "status", @@ -165,22 +104,33 @@ def test_list_streams(): assert_headers_in_lines(headers, lines) -def test_create_stream_invalid_destination_error(): +def test_update_stream_error(): result = exec_failing_test_command( BASE_CMDS["streams"] + [ - "create", - "--label", - "test", - "--type", - "audit_logs", - "--destinations", - "12341234", + "update", + "1", "--delimiter", ",", "--text", ], expected_code=ExitCodes.REQUEST_FAILED, ) - assert "Request failed: 400" in result - assert "Destination not found" in result + assert "Request failed: 404" in result + assert "Stream not found" in result + + +def test_view_stream_error(): + result = exec_failing_test_command( + BASE_CMDS["streams"] + + [ + "view", + "1", + "--delimiter", + ",", + "--text", + ], + expected_code=ExitCodes.REQUEST_FAILED, + ) + assert "Request failed: 404" in result + assert "Stream not found" in result