diff --git a/airbyte-ci/connectors/metadata_service/lib/metadata_service/gcs_upload.py b/airbyte-ci/connectors/metadata_service/lib/metadata_service/gcs_upload.py index 268332bcb89a..695e90a46d81 100644 --- a/airbyte-ci/connectors/metadata_service/lib/metadata_service/gcs_upload.py +++ b/airbyte-ci/connectors/metadata_service/lib/metadata_service/gcs_upload.py @@ -217,7 +217,11 @@ def upload_metadata_to_gcs(bucket_name: str, metadata_file_path: Path, validator if metadata is None: raise ValueError(f"Metadata file {metadata_file_path} is invalid for uploading: {error}") - service_account_info = json.loads(os.environ.get("GCS_CREDENTIALS")) + gcs_creds = os.environ.get("GCS_CREDENTIALS") + if not gcs_creds: + raise ValueError("Please set the GCS_CREDENTIALS env var.") + + service_account_info = json.loads(gcs_creds) credentials = service_account.Credentials.from_service_account_info(service_account_info) storage_client = storage.Client(credentials=credentials) bucket = storage_client.bucket(bucket_name) diff --git a/airbyte-ci/connectors/metadata_service/lib/metadata_service/validators/metadata_validator.py b/airbyte-ci/connectors/metadata_service/lib/metadata_service/validators/metadata_validator.py index a4006d4837d5..94bc6942c5b6 100644 --- a/airbyte-ci/connectors/metadata_service/lib/metadata_service/validators/metadata_validator.py +++ b/airbyte-ci/connectors/metadata_service/lib/metadata_service/validators/metadata_validator.py @@ -71,7 +71,7 @@ def validate_metadata_images_in_dockerhub( print(f"Checking that the following images are on dockerhub: {images_to_check}") for image, version in images_to_check: - if not is_image_on_docker_hub(image, version): + if not is_image_on_docker_hub(image, version, retries=3): return False, f"Image {image}:{version} does not exist in DockerHub" return True, None @@ -151,7 +151,7 @@ def validate_metadata_base_images_in_dockerhub( ) -> ValidationResult: metadata_definition_dict = metadata_definition.dict() - image_address = get(metadata_definition_dict, "data.connectorOptions.baseImage") + image_address = get(metadata_definition_dict, "data.connectorBuildOptions.baseImage") if image_address is None: return True, None diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/__init__.py b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/__init__.py index cd7cbc8f7685..685f9639ac5a 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/__init__.py +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/__init__.py @@ -7,28 +7,45 @@ def list_all_paths_in_fixture_directory(folder_name: str) -> List[str]: file_path = os.path.join(os.path.dirname(__file__), folder_name) + + # If folder_name has subdirectories, os.walk will return a list of tuples, + # one for folder_name and one for each of its subdirectories. + fixture_files = [] for root, dirs, files in os.walk(file_path): - return [os.path.join(root, file_name) for file_name in files] + fixture_files.extend(os.path.join(root, file_name) for file_name in files) + return fixture_files @pytest.fixture(scope="session") def valid_metadata_yaml_files() -> List[str]: - return list_all_paths_in_fixture_directory("metadata_validate/valid") + files = list_all_paths_in_fixture_directory("metadata_validate/valid") + if not files: + pytest.fail("No files found in metadata_validate/valid") + return files @pytest.fixture(scope="session") def invalid_metadata_yaml_files() -> List[str]: - return list_all_paths_in_fixture_directory("metadata_validate/invalid") + files = list_all_paths_in_fixture_directory("metadata_validate/invalid") + if not files: + pytest.fail("No files found in metadata_validate/invalid") + return files @pytest.fixture(scope="session") def valid_metadata_upload_files() -> List[str]: - return list_all_paths_in_fixture_directory("metadata_upload/valid") + files = list_all_paths_in_fixture_directory("metadata_upload/valid") + if not files: + pytest.fail("No files found in metadata_upload/valid") + return files @pytest.fixture(scope="session") def invalid_metadata_upload_files() -> List[str]: - return list_all_paths_in_fixture_directory("metadata_upload/invalid") + files = list_all_paths_in_fixture_directory("metadata_upload/invalid") + if not files: + pytest.fail("No files found in metadata_upload/invalid") + return files @pytest.fixture(scope="session") diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_breaking_change_image_tag_does_not_exist.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_breaking_change_image_tag_does_not_exist.yaml index 0b4174048ec0..685f75ed08e1 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_breaking_change_image_tag_does_not_exist.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_breaking_change_image_tag_does_not_exist.yaml @@ -16,7 +16,7 @@ data: releaseStage: alpha releases: breakingChanges: - 6.0.0: # tag does not exist + 0.0.0: # tag does not exist upgradeDeadline: 2023-08-22 message: "This version made a change." documentationUrl: https://docs.airbyte.com/integrations/sources/onesignal diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_cloud_image_tag_does_not_exist.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_cloud_image_tag_does_not_exist.yaml index 461e53e021d5..799a7d4f3424 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_cloud_image_tag_does_not_exist.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_cloud_image_tag_does_not_exist.yaml @@ -18,7 +18,7 @@ data: cloud: enabled: true dockerRepository: airbyte/exists-3 - dockerImageTag: 6.6.6 # tag does not exist + dockerImageTag: 99.99.99 # tag does not exist oss: enabled: true dockerRepository: airbyte/exists-4 diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_main_image_tag_does_not_exist.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_main_image_tag_does_not_exist.yaml index 1ea6ea03f992..5e5732263165 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_main_image_tag_does_not_exist.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_main_image_tag_does_not_exist.yaml @@ -5,7 +5,7 @@ data: connectorType: source dockerRepository: airbyte/exists-1 githubIssueLabel: source-alloydb-strict-encrypt - dockerImageTag: 6.6.6 # tag does not exist + dockerImageTag: 99.99.99 # tag does not exist documentationUrl: https://docs.airbyte.com/integrations/sources/existingsource connectorSubtype: database releaseStage: generally_available diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_normalization_image_tag_does_not_exist.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_normalization_image_tag_does_not_exist.yaml index 2eb1dedd082d..7f4375c486f2 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_normalization_image_tag_does_not_exist.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_normalization_image_tag_does_not_exist.yaml @@ -13,7 +13,7 @@ data: normalizationConfig: normalizationIntegrationType: postgres normalizationRepository: airbyte/exists-2 - dockerImageTag: 6.6.6 # tag does not exist + normalizationTag: 99.99.99 # tag does not exist registries: cloud: enabled: true diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_oss_repo_does_not_exist.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_oss_repo_does_not_exist.yaml index b1712fef132d..ffb3735e5655 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_oss_repo_does_not_exist.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/tag_nonexistent/metadata_oss_repo_does_not_exist.yaml @@ -22,6 +22,6 @@ data: oss: enabled: true dockerRepository: airbyte/exists-4 - dockerImageTag: 6.6.6 # tag does not exist + dockerImageTag: 99.99.99 # tag does not exist tags: - language:java diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/valid_overrides_but_base_image_nonexistent/metadata_main_image_tag_does_not_exist_but_is_overrode.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/valid_overrides_but_image_nonexistent/metadata_main_image_tag_does_not_exist_but_is_overrode.yaml similarity index 94% rename from airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/valid_overrides_but_base_image_nonexistent/metadata_main_image_tag_does_not_exist_but_is_overrode.yaml rename to airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/valid_overrides_but_image_nonexistent/metadata_main_image_tag_does_not_exist_but_is_overrode.yaml index 59c8d124b3f8..81ee107bd267 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/valid_overrides_but_base_image_nonexistent/metadata_main_image_tag_does_not_exist_but_is_overrode.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/valid_overrides_but_image_nonexistent/metadata_main_image_tag_does_not_exist_but_is_overrode.yaml @@ -5,7 +5,7 @@ data: connectorType: source dockerRepository: airbyte/exists-1 githubIssueLabel: source-alloydb-strict-encrypt - dockerImageTag: 6.6.6 # tag does not exist + dockerImageTag: 99.99.99 # tag does not exist documentationUrl: https://docs.airbyte.com/integrations/sources/existingsource connectorSubtype: database releaseStage: generally_available diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/valid_overrides_but_base_image_nonexistent/metadata_main_repo_does_not_exist_but_is_overrode.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/valid_overrides_but_image_nonexistent/metadata_main_repo_does_not_exist_but_is_overrode.yaml similarity index 100% rename from airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/valid_overrides_but_base_image_nonexistent/metadata_main_repo_does_not_exist_but_is_overrode.yaml rename to airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/valid_overrides_but_image_nonexistent/metadata_main_repo_does_not_exist_but_is_overrode.yaml diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/valid/metadata_base_image_exists.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/valid/metadata_base_image_exists.yaml index b107fd4c8d49..9fae02a082aa 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/valid/metadata_base_image_exists.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/valid/metadata_base_image_exists.yaml @@ -6,7 +6,7 @@ data: hosts: - zopim.com connectorBuildOptions: - baseImage: docker.io/airbyte/python-connector-base:1.1.0@sha256:bd98f6505c6764b1b5f99d3aedc23dfc9e9af631a62533f60eb32b1d3dbab20c + baseImage: docker.io/airbyte/base-repo-exists:1.1.0@sha256:bd98f6505c6764b1b5f99d3aedc23dfc9e9af631a62533f60eb32b1d3dbab20c connectorSubtype: api connectorType: source definitionId: 40d24d0f-b8f9-4fe0-9e6c-b06c0f3f45e4 diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/base_image_nonexistent/metadata_base_image_digest_does_not_exists.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/base_image_nonexistent/metadata_base_image_digest_does_not_exists.yaml similarity index 88% rename from airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/base_image_nonexistent/metadata_base_image_digest_does_not_exists.yaml rename to airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/base_image_nonexistent/metadata_base_image_digest_does_not_exists.yaml index 335960385af7..0f20fe4d28c8 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/base_image_nonexistent/metadata_base_image_digest_does_not_exists.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/base_image_nonexistent/metadata_base_image_digest_does_not_exists.yaml @@ -6,7 +6,7 @@ data: hosts: - zopim.com connectorBuildOptions: - baseImage: docker.io/airbyte/python-connector-base:1.1.0@sha256:doesnotexists + baseImage: docker.io/airbyte/base-repo-exists:1.1.0@sha256:MISSINGSHA connectorSubtype: api connectorType: source definitionId: 40d24d0f-b8f9-4fe0-9e6c-b06c0f3f45e4 diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/base_image_nonexistent/metadata_base_image_name_does_not_exists.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/base_image_nonexistent/metadata_base_image_name_does_not_exists.yaml similarity index 100% rename from airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/base_image_nonexistent/metadata_base_image_name_does_not_exists.yaml rename to airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/base_image_nonexistent/metadata_base_image_name_does_not_exists.yaml diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/base_image_nonexistent/metadata_base_image_tag_does_not_exists.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/base_image_nonexistent/metadata_base_image_tag_does_not_exists.yaml similarity index 82% rename from airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/base_image_nonexistent/metadata_base_image_tag_does_not_exists.yaml rename to airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/base_image_nonexistent/metadata_base_image_tag_does_not_exists.yaml index b377a89fff7c..fed77cbd1399 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_upload/invalid/base_image_nonexistent/metadata_base_image_tag_does_not_exists.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/base_image_nonexistent/metadata_base_image_tag_does_not_exists.yaml @@ -6,7 +6,7 @@ data: hosts: - zopim.com connectorBuildOptions: - baseImage: docker.io/airbyte/python-connector-base:does-not-exists@sha256:bd98f6505c6764b1b5f99d3aedc23dfc9e9af631a62533f60eb32b1d3dbab20c + baseImage: docker.io/airbyte/base-repo-exists:99.99.99@sha256:bd98f6505c6764b1b5f99d3aedc23dfc9e9af631a62533f60eb32b1d3dbab20c connectorSubtype: api connectorType: source definitionId: 40d24d0f-b8f9-4fe0-9e6c-b06c0f3f45e4 diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_breaking_change_versions_under_releases.yml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_breaking_change_versions_under_releases.yml new file mode 100644 index 000000000000..27e2c17d1abf --- /dev/null +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_breaking_change_versions_under_releases.yml @@ -0,0 +1,18 @@ +metadataSpecVersion: 1.0 +data: + name: AlloyDB for PostgreSQL + definitionId: 1fa90628-2b9e-11ed-a261-0242ac120002 + connectorType: source + dockerRepository: airbyte/image-exists-1 + githubIssueLabel: source-alloydb-strict-encrypt + dockerImageTag: 0.0.1 + documentationUrl: https://docs.airbyte.com/integrations/sources/alloydb + connectorSubtype: database + releaseStage: generally_available + license: MIT + releasestests/fixtures/metadata_validate/invalid/metadata_breaking_change_versions_under_releases.yml: + 2.1.3: + message: "This version changes the connector’s authentication method from `ApiKey` to `oAuth`, per the [API guide](https://amazon-sqs.com/api/someguide)." + upgradeDeadline: 2023-08-22 + tags: + - language:java diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_breaking_changes_not_under_releases.yml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_breaking_changes_not_under_releases.yml new file mode 100644 index 000000000000..e2b9918cccf0 --- /dev/null +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_breaking_changes_not_under_releases.yml @@ -0,0 +1,18 @@ +metadataSpecVersion: 1.0 +data: + name: AlloyDB for PostgreSQL + definitionId: 1fa90628-2b9e-11ed-a261-0242ac120002 + connectorType: source + dockerRepository: airbyte/image-exists-1 + githubIssueLabel: source-alloydb-strict-encrypt + dockerImageTag: 0.0.1 + documentationUrl: https://docs.airbyte.com/integrations/sources/alloydb + connectorSubtype: database + releaseStage: generally_available + license: MIT + breakingChanges: + 2.1.3: + message: "This version changes the connector’s authentication method from `ApiKey` to `oAuth`, per the [API guide](https://amazon-sqs.com/api/someguide)." + upgradeDeadline: 2023-08-22 + tags: + - language:java diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_invalid_base_image_no_sha.yml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_invalid_base_image_no_sha.yml new file mode 100644 index 000000000000..91de8734a4bf --- /dev/null +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_invalid_base_image_no_sha.yml @@ -0,0 +1,29 @@ +data: + allowedHosts: + hosts: + - "*.googleapis.com" + connectorBuildOptions: + baseImage: docker.io/airbyte/base-repo-exists:1.1.0 + connectorSubtype: file + connectorType: source + definitionId: 71607ba1-c0ac-4799-8049-7f4b90dd50f7 + dockerImageTag: 0.3.7 + dockerRepository: airbyte/source-google-sheets + githubIssueLabel: source-google-sheets + icon: google-sheets.svg + license: Elv2 + name: Google Sheets + registries: + cloud: + enabled: true + oss: + enabled: true + releaseStage: generally_available + documentationUrl: https://docs.airbyte.com/integrations/sources/google-sheets + tags: + - language:python + ab_internal: + sl: 300 + ql: 400 + supportLevel: certified +metadataSpecVersion: "1.0" diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_major_version_no_breaking_change_entry_for_version.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_major_version_no_breaking_change_entry_for_version.yaml index 46f419ed2838..86bdde803417 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_major_version_no_breaking_change_entry_for_version.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/invalid/metadata_major_version_no_breaking_change_entry_for_version.yaml @@ -16,9 +16,10 @@ data: enabled: true releaseStage: alpha releases: - 1.0.0: - upgradeDeadline: 2023-08-22 - message: "This version made a change." + breakingChanges: + 1.0.0: + upgradeDeadline: 2023-08-22 + message: "This version made a change." documentationUrl: https://docs.airbyte.com/integrations/sources/onesignal tags: - language:python diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/valid/metadata_build_base_image.yaml b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/valid/metadata_build_base_image.yaml index df8b955c2c26..4b2c65d6ebea 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/valid/metadata_build_base_image.yaml +++ b/airbyte-ci/connectors/metadata_service/lib/tests/fixtures/metadata_validate/valid/metadata_build_base_image.yaml @@ -3,7 +3,7 @@ data: hosts: - "*.googleapis.com" connectorBuildOptions: - baseImage: airbyte/python-connector-base:1.0.0 + baseImage: docker.io/airbyte/base-repo-exists:1.1.0@sha256:bd98f6505c6764b1b5f99d3aedc23dfc9e9af631a62533f60eb32b1d3dbab20c connectorSubtype: file connectorType: source definitionId: 71607ba1-c0ac-4799-8049-7f4b90dd50f7 diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/test_commands.py b/airbyte-ci/connectors/metadata_service/lib/tests/test_commands.py index e8d1858df708..2ef3ec4188fa 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/test_commands.py +++ b/airbyte-ci/connectors/metadata_service/lib/tests/test_commands.py @@ -10,12 +10,16 @@ from metadata_service.gcs_upload import MetadataUploadInfo, UploadedFile from metadata_service.validators.metadata_validator import ValidatorOptions from pydantic import BaseModel, ValidationError, error_wrappers +from test_gcs_upload import stub_is_image_on_docker_hub # TEST VALIDATE COMMAND -def test_valid_metadata_yaml_files(valid_metadata_yaml_files, tmp_path): +def test_valid_metadata_yaml_files(mocker, valid_metadata_yaml_files, tmp_path): runner = CliRunner() + # Mock dockerhub for base image checks + mocker.patch("metadata_service.validators.metadata_validator.is_image_on_docker_hub", side_effect=stub_is_image_on_docker_hub) + assert len(valid_metadata_yaml_files) > 0, "No files found" for file_path in valid_metadata_yaml_files: @@ -30,13 +34,13 @@ def test_invalid_metadata_yaml_files(invalid_metadata_yaml_files, tmp_path): for file_path in invalid_metadata_yaml_files: result = runner.invoke(commands.validate, [file_path, str(tmp_path)]) - assert result.exit_code != 0, f"Validation succeeded (when it shouldve failed) for {file_path}" + assert result.exit_code != 0, f"Validation succeeded (when it should have failed) for {file_path}" def test_metadata_file_not_found_fails(tmp_path): runner = CliRunner() result = runner.invoke(commands.validate, ["non_existent_file.yaml", str(tmp_path)]) - assert result.exit_code != 0, "Validation succeeded (when it shouldve failed) for non_existent_file.yaml" + assert result.exit_code != 0, "Validation succeeded (when it should have failed) for non_existent_file.yaml" def test_docs_path_not_found_fails(valid_metadata_yaml_files): @@ -45,7 +49,7 @@ def test_docs_path_not_found_fails(valid_metadata_yaml_files): assert len(valid_metadata_yaml_files) > 0, "No files found" result = runner.invoke(commands.validate, [valid_metadata_yaml_files[0], "non_existent_docs_path"]) - assert result.exit_code != 0, "Validation succeeded (when it shouldve failed) for non_existent_docs_path" + assert result.exit_code != 0, "Validation succeeded (when it should have failed) for non_existent_docs_path" def mock_metadata_upload_info( diff --git a/airbyte-ci/connectors/metadata_service/lib/tests/test_gcs_upload.py b/airbyte-ci/connectors/metadata_service/lib/tests/test_gcs_upload.py index 819ca93c6d18..26c6260adf8e 100644 --- a/airbyte-ci/connectors/metadata_service/lib/tests/test_gcs_upload.py +++ b/airbyte-ci/connectors/metadata_service/lib/tests/test_gcs_upload.py @@ -4,6 +4,7 @@ import json from pathlib import Path +from typing import Optional import pytest import yaml @@ -14,15 +15,19 @@ from metadata_service.validators.metadata_validator import ValidatorOptions from pydash.objects import get -# Version exists by default, but "666" is bad! (6.0.0 too since breaking changes regex tho) -MOCK_VERSIONS_THAT_DO_NOT_EXIST = ["6.6.6", "6.0.0"] +MOCK_VERSIONS_THAT_DO_NOT_EXIST = ["99.99.99", "0.0.0"] +MISSING_SHA = "MISSINGSHA" DOCS_PATH = "/docs" MOCK_DOC_URL_PATH = "integrations/sources/existingsource.md" VALID_DOC_FILE_PATH = Path(DOCS_PATH) / MOCK_DOC_URL_PATH -def stub_is_image_on_docker_hub(image_name: str, version: str) -> bool: - return "exists" in image_name and version not in MOCK_VERSIONS_THAT_DO_NOT_EXIST +def stub_is_image_on_docker_hub(image_name: str, version: str, digest: Optional[str] = None, retries: int = 0, wait_sec: int = 30) -> bool: + image_repo_exists = "exists" in image_name + version_exists = version not in MOCK_VERSIONS_THAT_DO_NOT_EXIST + sha_is_valid = (digest != MISSING_SHA) if digest is not None else True + image_exists = all([image_repo_exists, version_exists, sha_is_valid]) + return image_exists @pytest.fixture(autouse=True) @@ -38,6 +43,30 @@ def fake_exists(self): monkeypatch.setattr(Path, "exists", fake_exists) +def assert_upload_invalid_metadata_fails_correctly(metadata_file_path: Path, expected_error_match: str, validate_success_error_match: str): + """ + When attempting to upload invalid metadata, we expect it to fail in a predictable way, depending on what is exactly invalid + about the file. This helper aims to make it easier for a developer who is adding new test cases to figure out that their test + is failing because the test data that should be invalid is passing all of the validation steps. + + Because we don't exit the uploading process if validation fails, this case often looks like a weird error message that is hard to + grok. + """ + try: + with pytest.raises(ValueError, match=expected_error_match) as exc_info: + gcs_upload.upload_metadata_to_gcs( + "my_bucket", + metadata_file_path, + validator_opts=ValidatorOptions(docs_path=DOCS_PATH), + ) + print(f"Upload raised {exc_info.value}") + except AssertionError as e: + if validate_success_error_match in str(e): + raise AssertionError(f"Validation succeeded (when it should have failed) for {metadata_file_path}") from e + else: + raise e + + def setup_upload_mocks( mocker, version_blob_md5_hash, @@ -215,6 +244,7 @@ def test_upload_metadata_to_gcs_valid_metadata( mocker.spy(gcs_upload, "_doc_upload") for valid_metadata_upload_file in valid_metadata_upload_files: + print(f"\nTesting upload of valid metadata file: " + valid_metadata_upload_file) metadata_file_path = Path(valid_metadata_upload_file) metadata = ConnectorMetadataDefinitionV0.parse_obj(yaml.safe_load(metadata_file_path.read_text())) @@ -323,31 +353,44 @@ def test_upload_metadata_to_gcs_non_existent_metadata_file(): ) -def test_upload_invalid_metadata_to_gcs(invalid_metadata_yaml_files): +def test_upload_invalid_metadata_to_gcs(mocker, invalid_metadata_yaml_files): + # Mock dockerhub + mocker.patch("metadata_service.validators.metadata_validator.is_image_on_docker_hub", side_effect=stub_is_image_on_docker_hub) + + # Test that all invalid metadata files throw a ValueError for invalid_metadata_file in invalid_metadata_yaml_files: + print(f"\nTesting upload of invalid metadata file: " + invalid_metadata_file) metadata_file_path = Path(invalid_metadata_file) - # If your test fails with 'Please set the DOCKER_HUB_USERNAME and DOCKER_HUB_PASSWORD environment variables.' - # then your test data passed validation when it shouldn't have! - with pytest.raises(ValueError, match="Validation error"): - gcs_upload.upload_metadata_to_gcs( - "my_bucket", - metadata_file_path, - validator_opts=ValidatorOptions(docs_path=DOCS_PATH), - ) + + error_match_if_validation_fails_as_expected = "Validation error" + + # If validation succeeds, it goes on to upload any new/changed files. + # We don't mock the gcs stuff in this test, so it fails trying to + # mock compute the md5 hash. + error_match_if_validation_succeeds = "Please set the GCS_CREDENTIALS env var." + + assert_upload_invalid_metadata_fails_correctly( + metadata_file_path, error_match_if_validation_fails_as_expected, error_match_if_validation_succeeds + ) def test_upload_metadata_to_gcs_invalid_docker_images(mocker, invalid_metadata_upload_files): setup_upload_mocks(mocker, None, None, "new_md5_hash", None, None, None, None, None) - # Test that all invalid metadata files throw a ValueError + # Test that valid metadata files that reference invalid docker images throw a ValueError for invalid_metadata_file in invalid_metadata_upload_files: + print(f"\nTesting upload of valid metadata file with invalid docker image: " + invalid_metadata_file) metadata_file_path = Path(invalid_metadata_file) - with pytest.raises(ValueError, match="does not exist in DockerHub"): - gcs_upload.upload_metadata_to_gcs( - "my_bucket", - metadata_file_path, - validator_opts=ValidatorOptions(doc_paths=DOCS_PATH), - ) + + error_match_if_validation_fails_as_expected = "does not exist in DockerHub" + + # If validation succeeds, it goes on to upload any new/changed files. + # We mock gcs stuff in this test, so it fails trying to compare the md5 hashes. + error_match_if_validation_succeeds = "Unexpected path" + + assert_upload_invalid_metadata_fails_correctly( + metadata_file_path, error_match_if_validation_fails_as_expected, error_match_if_validation_succeeds + ) def test_upload_metadata_to_gcs_with_prerelease(mocker, valid_metadata_upload_files): @@ -359,6 +402,7 @@ def test_upload_metadata_to_gcs_with_prerelease(mocker, valid_metadata_upload_fi doc_upload_spy = mocker.spy(gcs_upload, "_doc_upload") for valid_metadata_upload_file in valid_metadata_upload_files: + print(f"\nTesting prerelease upload of valid metadata file: " + valid_metadata_upload_file) # Assuming there is a valid metadata file in the list, if not, you might need to create one metadata_file_path = Path(valid_metadata_upload_file) prerelease_image_tag = "1.5.6-dev.f80318f754"