| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- """Integration tests for GitHub Backup API endpoints."""
- import pytest
- from httpx import AsyncClient
- class TestGitHubBackupConfigAPI:
- """Integration tests for /api/v1/github-backup endpoints."""
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_get_config_no_config(self, async_client: AsyncClient):
- """Verify getting config when none exists returns null."""
- response = await async_client.get("/api/v1/github-backup/config")
- assert response.status_code == 200
- assert response.json() is None
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_create_config(self, async_client: AsyncClient):
- """Verify GitHub backup config can be created."""
- data = {
- "repository_url": "https://github.com/test/repo",
- "access_token": "ghp_testtoken123",
- "branch": "main",
- "schedule_enabled": False,
- "schedule_type": "daily",
- "backup_kprofiles": True,
- "backup_cloud_profiles": True,
- "backup_settings": False,
- "backup_spools": False,
- "backup_archives": False,
- "enabled": True,
- }
- response = await async_client.post("/api/v1/github-backup/config", json=data)
- assert response.status_code == 200
- result = response.json()
- assert result["repository_url"] == "https://github.com/test/repo"
- assert result["branch"] == "main"
- assert result["has_token"] is True
- assert result["enabled"] is True
- assert result["backup_spools"] is False
- assert result["backup_archives"] is False
- # Token should not be exposed in response
- assert "access_token" not in result
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_get_config_after_create(self, async_client: AsyncClient):
- """Verify getting config after creation returns the config."""
- # Create config first
- data = {
- "repository_url": "https://github.com/test/getrepo",
- "access_token": "ghp_testtoken456",
- "branch": "develop",
- "schedule_enabled": True,
- "schedule_type": "weekly",
- "backup_kprofiles": True,
- "backup_cloud_profiles": False,
- "backup_settings": True,
- "enabled": True,
- }
- await async_client.post("/api/v1/github-backup/config", json=data)
- # Get config
- response = await async_client.get("/api/v1/github-backup/config")
- assert response.status_code == 200
- result = response.json()
- assert result is not None
- assert result["repository_url"] == "https://github.com/test/getrepo"
- assert result["branch"] == "develop"
- assert result["schedule_type"] == "weekly"
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_create_config_with_spools_and_archives(self, async_client: AsyncClient):
- """Verify config with spool and archive backup enabled."""
- data = {
- "repository_url": "https://github.com/test/spoolarchive",
- "access_token": "ghp_spooltoken",
- "branch": "main",
- "schedule_enabled": False,
- "schedule_type": "daily",
- "backup_kprofiles": True,
- "backup_cloud_profiles": False,
- "backup_settings": False,
- "backup_spools": True,
- "backup_archives": True,
- "enabled": True,
- }
- response = await async_client.post("/api/v1/github-backup/config", json=data)
- assert response.status_code == 200
- result = response.json()
- assert result["backup_spools"] is True
- assert result["backup_archives"] is True
- assert result["backup_cloud_profiles"] is False
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_update_config_partial(self, async_client: AsyncClient):
- """Verify partial update of GitHub backup config."""
- # Create config first
- create_data = {
- "repository_url": "https://github.com/test/update",
- "access_token": "ghp_token",
- "branch": "main",
- "schedule_enabled": False,
- "schedule_type": "daily",
- "backup_kprofiles": True,
- "backup_cloud_profiles": True,
- "backup_settings": False,
- "backup_spools": False,
- "backup_archives": False,
- "enabled": True,
- }
- await async_client.post("/api/v1/github-backup/config", json=create_data)
- # Partial update
- update_data = {
- "branch": "develop",
- "schedule_enabled": True,
- }
- response = await async_client.patch("/api/v1/github-backup/config", json=update_data)
- assert response.status_code == 200
- result = response.json()
- assert result["branch"] == "develop"
- assert result["schedule_enabled"] is True
- # Original values should be preserved
- assert result["repository_url"] == "https://github.com/test/update"
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_update_config_enable_spools_and_archives(self, async_client: AsyncClient):
- """Verify partial update can enable spool and archive backup."""
- # Create config first
- create_data = {
- "repository_url": "https://github.com/test/updatetoggle",
- "access_token": "ghp_toggletoken",
- "branch": "main",
- "schedule_enabled": False,
- "schedule_type": "daily",
- "backup_kprofiles": True,
- "backup_cloud_profiles": True,
- "backup_settings": False,
- "backup_spools": False,
- "backup_archives": False,
- "enabled": True,
- }
- await async_client.post("/api/v1/github-backup/config", json=create_data)
- # Enable spools and archives via partial update
- update_data = {
- "backup_spools": True,
- "backup_archives": True,
- }
- response = await async_client.patch("/api/v1/github-backup/config", json=update_data)
- assert response.status_code == 200
- result = response.json()
- assert result["backup_spools"] is True
- assert result["backup_archives"] is True
- # Other values preserved
- assert result["backup_kprofiles"] is True
- assert result["backup_settings"] is False
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_update_config_rejects_disabling_insecure_http_for_stored_http_url(
- self, async_client: AsyncClient
- ):
- """Verify PATCH rejects leaving a stored HTTP URL without explicit insecure-HTTP allowance."""
- create_data = {
- "repository_url": "http://git.example.com/test/httprepo",
- "access_token": "gitea_token",
- "branch": "main",
- "provider": "gitea",
- "allow_insecure_http": True,
- "schedule_enabled": False,
- "schedule_type": "daily",
- "backup_kprofiles": True,
- "backup_cloud_profiles": True,
- "backup_settings": False,
- "backup_spools": False,
- "backup_archives": False,
- "enabled": True,
- }
- create_response = await async_client.post("/api/v1/github-backup/config", json=create_data)
- assert create_response.status_code == 200
- response = await async_client.patch("/api/v1/github-backup/config", json={"allow_insecure_http": False})
- assert response.status_code == 422
- assert "Allow insecure HTTP" in response.json()["detail"]
- stored_response = await async_client.get("/api/v1/github-backup/config")
- assert stored_response.status_code == 200
- stored = stored_response.json()
- assert stored["repository_url"] == "http://git.example.com/test/httprepo"
- assert stored["allow_insecure_http"] is True
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_delete_config(self, async_client: AsyncClient):
- """Verify GitHub backup config can be deleted."""
- # Create config first
- create_data = {
- "repository_url": "https://github.com/test/delete",
- "access_token": "ghp_deletetoken",
- "branch": "main",
- "schedule_enabled": False,
- "schedule_type": "daily",
- "backup_kprofiles": True,
- "backup_cloud_profiles": True,
- "backup_settings": False,
- "enabled": True,
- }
- await async_client.post("/api/v1/github-backup/config", json=create_data)
- # Delete
- response = await async_client.delete("/api/v1/github-backup/config")
- assert response.status_code == 200
- # Verify it's deleted
- get_response = await async_client.get("/api/v1/github-backup/config")
- assert get_response.status_code == 200
- assert get_response.json() is None
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_delete_config_not_found(self, async_client: AsyncClient):
- """Verify deleting non-existent config returns 404."""
- # Make sure no config exists
- await async_client.delete("/api/v1/github-backup/config")
- # Try to delete again
- response = await async_client.delete("/api/v1/github-backup/config")
- assert response.status_code == 404
- class TestGitHubBackupStatusAPI:
- """Integration tests for /api/v1/github-backup/status endpoint."""
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_status_no_config(self, async_client: AsyncClient):
- """Verify status when no config exists."""
- # Ensure no config
- await async_client.delete("/api/v1/github-backup/config")
- response = await async_client.get("/api/v1/github-backup/status")
- assert response.status_code == 200
- result = response.json()
- assert result["configured"] is False
- assert result["enabled"] is False
- assert result["is_running"] is False
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_status_with_config(self, async_client: AsyncClient):
- """Verify status when config exists."""
- # Create config
- create_data = {
- "repository_url": "https://github.com/test/status",
- "access_token": "ghp_statustoken",
- "branch": "main",
- "schedule_enabled": True,
- "schedule_type": "hourly",
- "backup_kprofiles": True,
- "backup_cloud_profiles": True,
- "backup_settings": False,
- "enabled": True,
- }
- await async_client.post("/api/v1/github-backup/config", json=create_data)
- response = await async_client.get("/api/v1/github-backup/status")
- assert response.status_code == 200
- result = response.json()
- assert result["configured"] is True
- assert result["enabled"] is True
- assert result["is_running"] is False
- assert result["next_scheduled_run"] is not None
- class TestGitHubBackupLogsAPI:
- """Integration tests for /api/v1/github-backup/logs endpoints."""
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_logs_no_config(self, async_client: AsyncClient):
- """Verify getting logs when no config exists returns empty list."""
- # Ensure no config
- await async_client.delete("/api/v1/github-backup/config")
- response = await async_client.get("/api/v1/github-backup/logs")
- assert response.status_code == 200
- assert response.json() == []
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_logs_with_config(self, async_client: AsyncClient):
- """Verify getting logs with config."""
- # Create config
- create_data = {
- "repository_url": "https://github.com/test/logs",
- "access_token": "ghp_logstoken",
- "branch": "main",
- "schedule_enabled": False,
- "schedule_type": "daily",
- "backup_kprofiles": True,
- "backup_cloud_profiles": True,
- "backup_settings": False,
- "enabled": True,
- }
- await async_client.post("/api/v1/github-backup/config", json=create_data)
- response = await async_client.get("/api/v1/github-backup/logs")
- assert response.status_code == 200
- # No backups run yet, so empty list
- assert response.json() == []
- class TestGitHubBackupTriggerAPI:
- """Integration tests for /api/v1/github-backup/run endpoint."""
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_trigger_no_config(self, async_client: AsyncClient):
- """Verify triggering backup without config returns 404."""
- # Ensure no config
- await async_client.delete("/api/v1/github-backup/config")
- response = await async_client.post("/api/v1/github-backup/run")
- assert response.status_code == 404
- @pytest.mark.asyncio
- @pytest.mark.integration
- async def test_trigger_disabled_config(self, async_client: AsyncClient):
- """Verify triggering backup with disabled config returns 400."""
- # Create disabled config
- create_data = {
- "repository_url": "https://github.com/test/trigger",
- "access_token": "ghp_triggertoken",
- "branch": "main",
- "schedule_enabled": False,
- "schedule_type": "daily",
- "backup_kprofiles": True,
- "backup_cloud_profiles": True,
- "backup_settings": False,
- "enabled": False, # Disabled
- }
- await async_client.post("/api/v1/github-backup/config", json=create_data)
- response = await async_client.post("/api/v1/github-backup/run")
- assert response.status_code == 400
- assert "disabled" in response.json()["detail"].lower()
|