test_github_backup_api.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. """Integration tests for GitHub Backup API endpoints."""
  2. import pytest
  3. from httpx import AsyncClient
  4. class TestGitHubBackupConfigAPI:
  5. """Integration tests for /api/v1/github-backup endpoints."""
  6. @pytest.mark.asyncio
  7. @pytest.mark.integration
  8. async def test_get_config_no_config(self, async_client: AsyncClient):
  9. """Verify getting config when none exists returns null."""
  10. response = await async_client.get("/api/v1/github-backup/config")
  11. assert response.status_code == 200
  12. assert response.json() is None
  13. @pytest.mark.asyncio
  14. @pytest.mark.integration
  15. async def test_create_config(self, async_client: AsyncClient):
  16. """Verify GitHub backup config can be created."""
  17. data = {
  18. "repository_url": "https://github.com/test/repo",
  19. "access_token": "ghp_testtoken123",
  20. "branch": "main",
  21. "schedule_enabled": False,
  22. "schedule_type": "daily",
  23. "backup_kprofiles": True,
  24. "backup_cloud_profiles": True,
  25. "backup_settings": False,
  26. "enabled": True,
  27. }
  28. response = await async_client.post("/api/v1/github-backup/config", json=data)
  29. assert response.status_code == 200
  30. result = response.json()
  31. assert result["repository_url"] == "https://github.com/test/repo"
  32. assert result["branch"] == "main"
  33. assert result["has_token"] is True
  34. assert result["enabled"] is True
  35. # Token should not be exposed in response
  36. assert "access_token" not in result
  37. @pytest.mark.asyncio
  38. @pytest.mark.integration
  39. async def test_get_config_after_create(self, async_client: AsyncClient):
  40. """Verify getting config after creation returns the config."""
  41. # Create config first
  42. data = {
  43. "repository_url": "https://github.com/test/getrepo",
  44. "access_token": "ghp_testtoken456",
  45. "branch": "develop",
  46. "schedule_enabled": True,
  47. "schedule_type": "weekly",
  48. "backup_kprofiles": True,
  49. "backup_cloud_profiles": False,
  50. "backup_settings": True,
  51. "enabled": True,
  52. }
  53. await async_client.post("/api/v1/github-backup/config", json=data)
  54. # Get config
  55. response = await async_client.get("/api/v1/github-backup/config")
  56. assert response.status_code == 200
  57. result = response.json()
  58. assert result is not None
  59. assert result["repository_url"] == "https://github.com/test/getrepo"
  60. assert result["branch"] == "develop"
  61. assert result["schedule_type"] == "weekly"
  62. @pytest.mark.asyncio
  63. @pytest.mark.integration
  64. async def test_update_config_partial(self, async_client: AsyncClient):
  65. """Verify partial update of GitHub backup config."""
  66. # Create config first
  67. create_data = {
  68. "repository_url": "https://github.com/test/update",
  69. "access_token": "ghp_token",
  70. "branch": "main",
  71. "schedule_enabled": False,
  72. "schedule_type": "daily",
  73. "backup_kprofiles": True,
  74. "backup_cloud_profiles": True,
  75. "backup_settings": False,
  76. "enabled": True,
  77. }
  78. await async_client.post("/api/v1/github-backup/config", json=create_data)
  79. # Partial update
  80. update_data = {
  81. "branch": "develop",
  82. "schedule_enabled": True,
  83. }
  84. response = await async_client.patch("/api/v1/github-backup/config", json=update_data)
  85. assert response.status_code == 200
  86. result = response.json()
  87. assert result["branch"] == "develop"
  88. assert result["schedule_enabled"] is True
  89. # Original values should be preserved
  90. assert result["repository_url"] == "https://github.com/test/update"
  91. @pytest.mark.asyncio
  92. @pytest.mark.integration
  93. async def test_delete_config(self, async_client: AsyncClient):
  94. """Verify GitHub backup config can be deleted."""
  95. # Create config first
  96. create_data = {
  97. "repository_url": "https://github.com/test/delete",
  98. "access_token": "ghp_deletetoken",
  99. "branch": "main",
  100. "schedule_enabled": False,
  101. "schedule_type": "daily",
  102. "backup_kprofiles": True,
  103. "backup_cloud_profiles": True,
  104. "backup_settings": False,
  105. "enabled": True,
  106. }
  107. await async_client.post("/api/v1/github-backup/config", json=create_data)
  108. # Delete
  109. response = await async_client.delete("/api/v1/github-backup/config")
  110. assert response.status_code == 200
  111. # Verify it's deleted
  112. get_response = await async_client.get("/api/v1/github-backup/config")
  113. assert get_response.status_code == 200
  114. assert get_response.json() is None
  115. @pytest.mark.asyncio
  116. @pytest.mark.integration
  117. async def test_delete_config_not_found(self, async_client: AsyncClient):
  118. """Verify deleting non-existent config returns 404."""
  119. # Make sure no config exists
  120. await async_client.delete("/api/v1/github-backup/config")
  121. # Try to delete again
  122. response = await async_client.delete("/api/v1/github-backup/config")
  123. assert response.status_code == 404
  124. class TestGitHubBackupStatusAPI:
  125. """Integration tests for /api/v1/github-backup/status endpoint."""
  126. @pytest.mark.asyncio
  127. @pytest.mark.integration
  128. async def test_status_no_config(self, async_client: AsyncClient):
  129. """Verify status when no config exists."""
  130. # Ensure no config
  131. await async_client.delete("/api/v1/github-backup/config")
  132. response = await async_client.get("/api/v1/github-backup/status")
  133. assert response.status_code == 200
  134. result = response.json()
  135. assert result["configured"] is False
  136. assert result["enabled"] is False
  137. assert result["is_running"] is False
  138. @pytest.mark.asyncio
  139. @pytest.mark.integration
  140. async def test_status_with_config(self, async_client: AsyncClient):
  141. """Verify status when config exists."""
  142. # Create config
  143. create_data = {
  144. "repository_url": "https://github.com/test/status",
  145. "access_token": "ghp_statustoken",
  146. "branch": "main",
  147. "schedule_enabled": True,
  148. "schedule_type": "hourly",
  149. "backup_kprofiles": True,
  150. "backup_cloud_profiles": True,
  151. "backup_settings": False,
  152. "enabled": True,
  153. }
  154. await async_client.post("/api/v1/github-backup/config", json=create_data)
  155. response = await async_client.get("/api/v1/github-backup/status")
  156. assert response.status_code == 200
  157. result = response.json()
  158. assert result["configured"] is True
  159. assert result["enabled"] is True
  160. assert result["is_running"] is False
  161. assert result["next_scheduled_run"] is not None
  162. class TestGitHubBackupLogsAPI:
  163. """Integration tests for /api/v1/github-backup/logs endpoints."""
  164. @pytest.mark.asyncio
  165. @pytest.mark.integration
  166. async def test_logs_no_config(self, async_client: AsyncClient):
  167. """Verify getting logs when no config exists returns empty list."""
  168. # Ensure no config
  169. await async_client.delete("/api/v1/github-backup/config")
  170. response = await async_client.get("/api/v1/github-backup/logs")
  171. assert response.status_code == 200
  172. assert response.json() == []
  173. @pytest.mark.asyncio
  174. @pytest.mark.integration
  175. async def test_logs_with_config(self, async_client: AsyncClient):
  176. """Verify getting logs with config."""
  177. # Create config
  178. create_data = {
  179. "repository_url": "https://github.com/test/logs",
  180. "access_token": "ghp_logstoken",
  181. "branch": "main",
  182. "schedule_enabled": False,
  183. "schedule_type": "daily",
  184. "backup_kprofiles": True,
  185. "backup_cloud_profiles": True,
  186. "backup_settings": False,
  187. "enabled": True,
  188. }
  189. await async_client.post("/api/v1/github-backup/config", json=create_data)
  190. response = await async_client.get("/api/v1/github-backup/logs")
  191. assert response.status_code == 200
  192. # No backups run yet, so empty list
  193. assert response.json() == []
  194. class TestGitHubBackupTriggerAPI:
  195. """Integration tests for /api/v1/github-backup/run endpoint."""
  196. @pytest.mark.asyncio
  197. @pytest.mark.integration
  198. async def test_trigger_no_config(self, async_client: AsyncClient):
  199. """Verify triggering backup without config returns 404."""
  200. # Ensure no config
  201. await async_client.delete("/api/v1/github-backup/config")
  202. response = await async_client.post("/api/v1/github-backup/run")
  203. assert response.status_code == 404
  204. @pytest.mark.asyncio
  205. @pytest.mark.integration
  206. async def test_trigger_disabled_config(self, async_client: AsyncClient):
  207. """Verify triggering backup with disabled config returns 400."""
  208. # Create disabled config
  209. create_data = {
  210. "repository_url": "https://github.com/test/trigger",
  211. "access_token": "ghp_triggertoken",
  212. "branch": "main",
  213. "schedule_enabled": False,
  214. "schedule_type": "daily",
  215. "backup_kprofiles": True,
  216. "backup_cloud_profiles": True,
  217. "backup_settings": False,
  218. "enabled": False, # Disabled
  219. }
  220. await async_client.post("/api/v1/github-backup/config", json=create_data)
  221. response = await async_client.post("/api/v1/github-backup/run")
  222. assert response.status_code == 400
  223. assert "disabled" in response.json()["detail"].lower()