""" Integration tests for version API endpoints. Tests cover: - Version creation via upload - Version auto-detection from filename - Version listing with pagination - Version deletion - Download by version ref - ref_count behavior with version operations """ import pytest from tests.factories import upload_test_file class TestVersionCreation: """Tests for version creation during upload.""" @pytest.mark.integration def test_upload_with_explicit_version(self, integration_client, test_package): """Test creating a version via explicit version parameter.""" project_name, package_name = test_package result = upload_test_file( integration_client, project_name, package_name, b"version create test", version="1.0.0", ) assert result["version"] == "1.0.0" assert result["version_source"] == "explicit" assert result["artifact_id"] @pytest.mark.integration def test_upload_with_version_auto_detect_from_tarball( self, integration_client, test_package ): """Test version auto-detection from tarball filename pattern.""" project_name, package_name = test_package result = upload_test_file( integration_client, project_name, package_name, b"auto version test", filename="myapp-2.1.0.tar.gz", ) assert result["version"] == "2.1.0" # Tarball metadata extractor parses version from filename assert result["version_source"] == "metadata" @pytest.mark.integration def test_upload_with_version_auto_detect_v_prefix( self, integration_client, test_package ): """Test version auto-detection strips 'v' prefix from tarball filename.""" project_name, package_name = test_package result = upload_test_file( integration_client, project_name, package_name, b"v prefix test", filename="package-v3.0.0.tar.gz", ) assert result["version"] == "3.0.0" # Tarball metadata extractor parses version from filename assert result["version_source"] == "metadata" @pytest.mark.integration def test_upload_duplicate_version_warning(self, integration_client, test_package): """Test that duplicate version during upload returns response without error.""" project_name, package_name = test_package # Upload with version 1.0.0 upload_test_file( integration_client, project_name, package_name, b"first upload", version="1.0.0", ) # Upload different content with same version - should succeed but no new version result = upload_test_file( integration_client, project_name, package_name, b"second upload different content", version="1.0.0", ) # Upload succeeds but version may not be set (duplicate) assert result["artifact_id"] class TestVersionCRUD: """Tests for version list, get, delete operations.""" @pytest.mark.integration def test_list_versions(self, integration_client, test_package): """Test listing versions for a package.""" project_name, package_name = test_package # Create some versions upload_test_file( integration_client, project_name, package_name, b"v1 content", version="1.0.0", ) upload_test_file( integration_client, project_name, package_name, b"v2 content", version="2.0.0", ) response = integration_client.get( f"/api/v1/project/{project_name}/{package_name}/versions" ) assert response.status_code == 200 data = response.json() assert "items" in data assert "pagination" in data versions = [v["version"] for v in data["items"]] assert "1.0.0" in versions assert "2.0.0" in versions @pytest.mark.integration def test_list_versions_with_artifact_info(self, integration_client, test_package): """Test that version list includes artifact metadata.""" project_name, package_name = test_package upload_test_file( integration_client, project_name, package_name, b"version with info", version="1.0.0", ) response = integration_client.get( f"/api/v1/project/{project_name}/{package_name}/versions" ) assert response.status_code == 200 data = response.json() assert len(data["items"]) >= 1 version_item = next( (v for v in data["items"] if v["version"] == "1.0.0"), None ) assert version_item is not None assert "size" in version_item assert "artifact_id" in version_item @pytest.mark.integration def test_get_version(self, integration_client, test_package): """Test getting a specific version.""" project_name, package_name = test_package upload_result = upload_test_file( integration_client, project_name, package_name, b"get version test", version="3.0.0", ) response = integration_client.get( f"/api/v1/project/{project_name}/{package_name}/versions/3.0.0" ) assert response.status_code == 200 data = response.json() assert data["version"] == "3.0.0" assert data["artifact_id"] == upload_result["artifact_id"] assert data["version_source"] == "explicit" @pytest.mark.integration def test_get_version_not_found(self, integration_client, test_package): """Test getting a non-existent version returns 404.""" project_name, package_name = test_package response = integration_client.get( f"/api/v1/project/{project_name}/{package_name}/versions/99.99.99" ) assert response.status_code == 404 @pytest.mark.integration def test_delete_version(self, integration_client, test_package): """Test deleting a version.""" project_name, package_name = test_package upload_test_file( integration_client, project_name, package_name, b"delete version test", version="4.0.0", ) # Delete version response = integration_client.delete( f"/api/v1/project/{project_name}/{package_name}/versions/4.0.0" ) assert response.status_code == 204 # Verify deleted response = integration_client.get( f"/api/v1/project/{project_name}/{package_name}/versions/4.0.0" ) assert response.status_code == 404 class TestVersionDownload: """Tests for downloading artifacts by version reference.""" @pytest.mark.integration def test_download_by_version_prefix(self, integration_client, test_package): """Test downloading an artifact using version: prefix.""" project_name, package_name = test_package content = b"download by version test" upload_test_file( integration_client, project_name, package_name, content, version="5.0.0", ) response = integration_client.get( f"/api/v1/project/{project_name}/{package_name}/+/version:5.0.0", follow_redirects=False, ) # Should either redirect or return content assert response.status_code in [200, 302, 307] @pytest.mark.integration def test_download_by_implicit_version(self, integration_client, test_package): """Test downloading an artifact using version number directly (no prefix).""" project_name, package_name = test_package content = b"implicit version download test" upload_test_file( integration_client, project_name, package_name, content, version="6.0.0", ) response = integration_client.get( f"/api/v1/project/{project_name}/{package_name}/+/6.0.0", follow_redirects=False, ) # Should resolve version assert response.status_code in [200, 302, 307] class TestVersionPagination: """Tests for version listing pagination and sorting.""" @pytest.mark.integration def test_versions_pagination(self, integration_client, test_package): """Test version listing respects pagination.""" project_name, package_name = test_package response = integration_client.get( f"/api/v1/project/{project_name}/{package_name}/versions?limit=5" ) assert response.status_code == 200 data = response.json() assert "pagination" in data assert data["pagination"]["limit"] == 5 @pytest.mark.integration def test_versions_sorting(self, integration_client, test_package): """Test version listing can be sorted.""" project_name, package_name = test_package # Create versions with different timestamps upload_test_file( integration_client, project_name, package_name, b"sort test 1", version="1.0.0", ) upload_test_file( integration_client, project_name, package_name, b"sort test 2", version="2.0.0", ) # Test ascending sort response = integration_client.get( f"/api/v1/project/{project_name}/{package_name}/versions?sort=version&order=asc" ) assert response.status_code == 200 data = response.json() versions = [v["version"] for v in data["items"]] # First version should be 1.0.0 when sorted ascending if len(versions) >= 2: assert versions.index("1.0.0") < versions.index("2.0.0")