| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| """Unit tests for dev/registry/patch_providers_json.py.""" |
| |
| from __future__ import annotations |
| |
| import json |
| import sys |
| from unittest.mock import patch as mock_patch |
| |
| import pytest |
| from patch_providers_json import main, patch |
| |
| |
| def _write_providers(tmp_path, providers): |
| p = tmp_path / "providers.json" |
| p.write_text(json.dumps({"providers": providers}, indent=2)) |
| return p |
| |
| |
| class TestPatch: |
| def test_appends_missing_version(self, tmp_path): |
| p = _write_providers( |
| tmp_path, |
| [{"id": "amazon", "version": "9.26.0", "versions": ["9.26.0", "9.25.0"]}], |
| ) |
| rc = patch(p, "amazon", ["9.24.0"]) |
| assert rc == 0 |
| data = json.loads(p.read_text()) |
| amazon = next(p for p in data["providers"] if p["id"] == "amazon") |
| assert amazon["versions"] == ["9.26.0", "9.25.0", "9.24.0"] |
| |
| def test_skips_already_present_version(self, tmp_path): |
| p = _write_providers( |
| tmp_path, |
| [{"id": "amazon", "version": "9.26.0", "versions": ["9.26.0", "9.25.0"]}], |
| ) |
| before = json.loads(p.read_text()) |
| rc = patch(p, "amazon", ["9.25.0"]) |
| after = json.loads(p.read_text()) |
| assert rc == 0 |
| # Same content; sorting may rewrite the file but the array is unchanged. |
| assert before["providers"][0]["versions"] == after["providers"][0]["versions"] |
| |
| def test_unknown_provider_id_errors(self, tmp_path, capsys): |
| p = _write_providers(tmp_path, [{"id": "amazon", "version": "9.26.0", "versions": []}]) |
| rc = patch(p, "nonexistent-provider", ["1.0.0"]) |
| assert rc == 1 |
| captured = capsys.readouterr() |
| assert "nonexistent-provider" in captured.out |
| |
| def test_multiple_versions_one_call(self, tmp_path): |
| p = _write_providers( |
| tmp_path, |
| [{"id": "amazon", "version": "9.26.0", "versions": ["9.26.0"]}], |
| ) |
| rc = patch(p, "amazon", ["9.24.0", "9.22.0"]) |
| assert rc == 0 |
| data = json.loads(p.read_text()) |
| amazon = next(p for p in data["providers"] if p["id"] == "amazon") |
| # Sorted newest-first |
| assert amazon["versions"] == ["9.26.0", "9.24.0", "9.22.0"] |
| |
| def test_invalid_version_falls_back_to_lex_sort(self, tmp_path): |
| p = _write_providers( |
| tmp_path, |
| [{"id": "weird", "version": "1.0.0", "versions": ["1.0.0", "not-a-semver"]}], |
| ) |
| # Should not raise |
| rc = patch(p, "weird", ["custom-tag"]) |
| assert rc == 0 |
| data = json.loads(p.read_text()) |
| weird = next(p for p in data["providers"] if p["id"] == "weird") |
| # All three should be present |
| assert set(weird["versions"]) == {"1.0.0", "not-a-semver", "custom-tag"} |
| |
| def test_includes_latest_when_versions_was_empty(self, tmp_path): |
| """Regression: empty `versions[]` must not exclude `provider.version`. |
| |
| After patch, providerVersions.js treats non-empty versions[] as |
| authoritative. If we patch only the new version into an empty list, |
| the latest field would be excluded from the dropdown. |
| """ |
| p = _write_providers( |
| tmp_path, |
| [{"id": "newish", "version": "1.0.0", "versions": []}], |
| ) |
| rc = patch(p, "newish", ["0.9.0"]) |
| assert rc == 0 |
| data = json.loads(p.read_text()) |
| newish = next(p for p in data["providers"] if p["id"] == "newish") |
| assert "1.0.0" in newish["versions"] |
| assert "0.9.0" in newish["versions"] |
| |
| def test_provider_version_field_unchanged(self, tmp_path): |
| """The `version` (singular, latest) field is never touched by the patch.""" |
| p = _write_providers( |
| tmp_path, |
| [{"id": "amazon", "version": "9.26.0", "versions": ["9.26.0", "9.25.0"]}], |
| ) |
| rc = patch(p, "amazon", ["9.24.0"]) |
| assert rc == 0 |
| data = json.loads(p.read_text()) |
| amazon = next(p for p in data["providers"] if p["id"] == "amazon") |
| # Latest pointer must remain 9.26.0 even though we added an older version. |
| assert amazon["version"] == "9.26.0" |
| |
| def test_other_providers_untouched(self, tmp_path): |
| p = _write_providers( |
| tmp_path, |
| [ |
| {"id": "amazon", "version": "9.26.0", "versions": ["9.26.0"]}, |
| {"id": "google", "version": "21.2.0", "versions": ["21.2.0", "21.1.0"]}, |
| ], |
| ) |
| rc = patch(p, "amazon", ["9.24.0"]) |
| assert rc == 0 |
| data = json.loads(p.read_text()) |
| google = next(p for p in data["providers"] if p["id"] == "google") |
| assert google["versions"] == ["21.2.0", "21.1.0"] |
| assert google["version"] == "21.2.0" |
| |
| |
| class TestMainCli: |
| def test_main_exits_with_patch_returncode(self, tmp_path, capsys): |
| p = _write_providers( |
| tmp_path, |
| [{"id": "amazon", "version": "9.26.0", "versions": ["9.26.0"]}], |
| ) |
| argv = [ |
| "patch_providers_json.py", |
| "--providers-json", |
| str(p), |
| "--provider", |
| "amazon", |
| "--version", |
| "9.24.0", |
| ] |
| with mock_patch.object(sys, "argv", argv): |
| rc = main() |
| assert rc == 0 |
| data = json.loads(p.read_text()) |
| amazon = next(p for p in data["providers"] if p["id"] == "amazon") |
| assert "9.24.0" in amazon["versions"] |
| |
| def test_main_unknown_provider_exits_1(self, tmp_path): |
| p = _write_providers( |
| tmp_path, |
| [{"id": "amazon", "version": "9.26.0", "versions": []}], |
| ) |
| argv = [ |
| "patch_providers_json.py", |
| "--providers-json", |
| str(p), |
| "--provider", |
| "ghost", |
| "--version", |
| "1.0.0", |
| ] |
| with mock_patch.object(sys, "argv", argv): |
| rc = main() |
| assert rc == 1 |
| |
| def test_main_requires_version_argument(self, tmp_path): |
| p = _write_providers(tmp_path, []) |
| argv = [ |
| "patch_providers_json.py", |
| "--providers-json", |
| str(p), |
| "--provider", |
| "amazon", |
| ] |
| with mock_patch.object(sys, "argv", argv): |
| with pytest.raises(SystemExit) as exc: |
| main() |
| assert exc.value.code != 0 |