test_github_backup_api.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  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. "backup_spools": False,
  27. "backup_archives": False,
  28. "enabled": True,
  29. }
  30. response = await async_client.post("/api/v1/github-backup/config", json=data)
  31. assert response.status_code == 200
  32. result = response.json()
  33. assert result["repository_url"] == "https://github.com/test/repo"
  34. assert result["branch"] == "main"
  35. assert result["has_token"] is True
  36. assert result["enabled"] is True
  37. assert result["backup_spools"] is False
  38. assert result["backup_archives"] is False
  39. # Token should not be exposed in response
  40. assert "access_token" not in result
  41. @pytest.mark.asyncio
  42. @pytest.mark.integration
  43. async def test_get_config_after_create(self, async_client: AsyncClient):
  44. """Verify getting config after creation returns the config."""
  45. # Create config first
  46. data = {
  47. "repository_url": "https://github.com/test/getrepo",
  48. "access_token": "ghp_testtoken456",
  49. "branch": "develop",
  50. "schedule_enabled": True,
  51. "schedule_type": "weekly",
  52. "backup_kprofiles": True,
  53. "backup_cloud_profiles": False,
  54. "backup_settings": True,
  55. "enabled": True,
  56. }
  57. await async_client.post("/api/v1/github-backup/config", json=data)
  58. # Get config
  59. response = await async_client.get("/api/v1/github-backup/config")
  60. assert response.status_code == 200
  61. result = response.json()
  62. assert result is not None
  63. assert result["repository_url"] == "https://github.com/test/getrepo"
  64. assert result["branch"] == "develop"
  65. assert result["schedule_type"] == "weekly"
  66. @pytest.mark.asyncio
  67. @pytest.mark.integration
  68. async def test_create_config_with_spools_and_archives(self, async_client: AsyncClient):
  69. """Verify config with spool and archive backup enabled."""
  70. data = {
  71. "repository_url": "https://github.com/test/spoolarchive",
  72. "access_token": "ghp_spooltoken",
  73. "branch": "main",
  74. "schedule_enabled": False,
  75. "schedule_type": "daily",
  76. "backup_kprofiles": True,
  77. "backup_cloud_profiles": False,
  78. "backup_settings": False,
  79. "backup_spools": True,
  80. "backup_archives": True,
  81. "enabled": True,
  82. }
  83. response = await async_client.post("/api/v1/github-backup/config", json=data)
  84. assert response.status_code == 200
  85. result = response.json()
  86. assert result["backup_spools"] is True
  87. assert result["backup_archives"] is True
  88. assert result["backup_cloud_profiles"] is False
  89. @pytest.mark.asyncio
  90. @pytest.mark.integration
  91. async def test_update_config_partial(self, async_client: AsyncClient):
  92. """Verify partial update of GitHub backup config."""
  93. # Create config first
  94. create_data = {
  95. "repository_url": "https://github.com/test/update",
  96. "access_token": "ghp_token",
  97. "branch": "main",
  98. "schedule_enabled": False,
  99. "schedule_type": "daily",
  100. "backup_kprofiles": True,
  101. "backup_cloud_profiles": True,
  102. "backup_settings": False,
  103. "backup_spools": False,
  104. "backup_archives": False,
  105. "enabled": True,
  106. }
  107. await async_client.post("/api/v1/github-backup/config", json=create_data)
  108. # Partial update
  109. update_data = {
  110. "branch": "develop",
  111. "schedule_enabled": True,
  112. }
  113. response = await async_client.patch("/api/v1/github-backup/config", json=update_data)
  114. assert response.status_code == 200
  115. result = response.json()
  116. assert result["branch"] == "develop"
  117. assert result["schedule_enabled"] is True
  118. # Original values should be preserved
  119. assert result["repository_url"] == "https://github.com/test/update"
  120. @pytest.mark.asyncio
  121. @pytest.mark.integration
  122. async def test_update_config_enable_spools_and_archives(self, async_client: AsyncClient):
  123. """Verify partial update can enable spool and archive backup."""
  124. # Create config first
  125. create_data = {
  126. "repository_url": "https://github.com/test/updatetoggle",
  127. "access_token": "ghp_toggletoken",
  128. "branch": "main",
  129. "schedule_enabled": False,
  130. "schedule_type": "daily",
  131. "backup_kprofiles": True,
  132. "backup_cloud_profiles": True,
  133. "backup_settings": False,
  134. "backup_spools": False,
  135. "backup_archives": False,
  136. "enabled": True,
  137. }
  138. await async_client.post("/api/v1/github-backup/config", json=create_data)
  139. # Enable spools and archives via partial update
  140. update_data = {
  141. "backup_spools": True,
  142. "backup_archives": True,
  143. }
  144. response = await async_client.patch("/api/v1/github-backup/config", json=update_data)
  145. assert response.status_code == 200
  146. result = response.json()
  147. assert result["backup_spools"] is True
  148. assert result["backup_archives"] is True
  149. # Other values preserved
  150. assert result["backup_kprofiles"] is True
  151. assert result["backup_settings"] is False
  152. @pytest.mark.asyncio
  153. @pytest.mark.integration
  154. async def test_delete_config(self, async_client: AsyncClient):
  155. """Verify GitHub backup config can be deleted."""
  156. # Create config first
  157. create_data = {
  158. "repository_url": "https://github.com/test/delete",
  159. "access_token": "ghp_deletetoken",
  160. "branch": "main",
  161. "schedule_enabled": False,
  162. "schedule_type": "daily",
  163. "backup_kprofiles": True,
  164. "backup_cloud_profiles": True,
  165. "backup_settings": False,
  166. "enabled": True,
  167. }
  168. await async_client.post("/api/v1/github-backup/config", json=create_data)
  169. # Delete
  170. response = await async_client.delete("/api/v1/github-backup/config")
  171. assert response.status_code == 200
  172. # Verify it's deleted
  173. get_response = await async_client.get("/api/v1/github-backup/config")
  174. assert get_response.status_code == 200
  175. assert get_response.json() is None
  176. @pytest.mark.asyncio
  177. @pytest.mark.integration
  178. async def test_delete_config_not_found(self, async_client: AsyncClient):
  179. """Verify deleting non-existent config returns 404."""
  180. # Make sure no config exists
  181. await async_client.delete("/api/v1/github-backup/config")
  182. # Try to delete again
  183. response = await async_client.delete("/api/v1/github-backup/config")
  184. assert response.status_code == 404
  185. class TestGitHubBackupStatusAPI:
  186. """Integration tests for /api/v1/github-backup/status endpoint."""
  187. @pytest.mark.asyncio
  188. @pytest.mark.integration
  189. async def test_status_no_config(self, async_client: AsyncClient):
  190. """Verify status when no config exists."""
  191. # Ensure no config
  192. await async_client.delete("/api/v1/github-backup/config")
  193. response = await async_client.get("/api/v1/github-backup/status")
  194. assert response.status_code == 200
  195. result = response.json()
  196. assert result["configured"] is False
  197. assert result["enabled"] is False
  198. assert result["is_running"] is False
  199. @pytest.mark.asyncio
  200. @pytest.mark.integration
  201. async def test_status_with_config(self, async_client: AsyncClient):
  202. """Verify status when config exists."""
  203. # Create config
  204. create_data = {
  205. "repository_url": "https://github.com/test/status",
  206. "access_token": "ghp_statustoken",
  207. "branch": "main",
  208. "schedule_enabled": True,
  209. "schedule_type": "hourly",
  210. "backup_kprofiles": True,
  211. "backup_cloud_profiles": True,
  212. "backup_settings": False,
  213. "enabled": True,
  214. }
  215. await async_client.post("/api/v1/github-backup/config", json=create_data)
  216. response = await async_client.get("/api/v1/github-backup/status")
  217. assert response.status_code == 200
  218. result = response.json()
  219. assert result["configured"] is True
  220. assert result["enabled"] is True
  221. assert result["is_running"] is False
  222. assert result["next_scheduled_run"] is not None
  223. class TestGitHubBackupLogsAPI:
  224. """Integration tests for /api/v1/github-backup/logs endpoints."""
  225. @pytest.mark.asyncio
  226. @pytest.mark.integration
  227. async def test_logs_no_config(self, async_client: AsyncClient):
  228. """Verify getting logs when no config exists returns empty list."""
  229. # Ensure no config
  230. await async_client.delete("/api/v1/github-backup/config")
  231. response = await async_client.get("/api/v1/github-backup/logs")
  232. assert response.status_code == 200
  233. assert response.json() == []
  234. @pytest.mark.asyncio
  235. @pytest.mark.integration
  236. async def test_logs_with_config(self, async_client: AsyncClient):
  237. """Verify getting logs with config."""
  238. # Create config
  239. create_data = {
  240. "repository_url": "https://github.com/test/logs",
  241. "access_token": "ghp_logstoken",
  242. "branch": "main",
  243. "schedule_enabled": False,
  244. "schedule_type": "daily",
  245. "backup_kprofiles": True,
  246. "backup_cloud_profiles": True,
  247. "backup_settings": False,
  248. "enabled": True,
  249. }
  250. await async_client.post("/api/v1/github-backup/config", json=create_data)
  251. response = await async_client.get("/api/v1/github-backup/logs")
  252. assert response.status_code == 200
  253. # No backups run yet, so empty list
  254. assert response.json() == []
  255. class TestGitHubBackupTriggerAPI:
  256. """Integration tests for /api/v1/github-backup/run endpoint."""
  257. @pytest.mark.asyncio
  258. @pytest.mark.integration
  259. async def test_trigger_no_config(self, async_client: AsyncClient):
  260. """Verify triggering backup without config returns 404."""
  261. # Ensure no config
  262. await async_client.delete("/api/v1/github-backup/config")
  263. response = await async_client.post("/api/v1/github-backup/run")
  264. assert response.status_code == 404
  265. @pytest.mark.asyncio
  266. @pytest.mark.integration
  267. async def test_trigger_disabled_config(self, async_client: AsyncClient):
  268. """Verify triggering backup with disabled config returns 400."""
  269. # Create disabled config
  270. create_data = {
  271. "repository_url": "https://github.com/test/trigger",
  272. "access_token": "ghp_triggertoken",
  273. "branch": "main",
  274. "schedule_enabled": False,
  275. "schedule_type": "daily",
  276. "backup_kprofiles": True,
  277. "backup_cloud_profiles": True,
  278. "backup_settings": False,
  279. "enabled": False, # Disabled
  280. }
  281. await async_client.post("/api/v1/github-backup/config", json=create_data)
  282. response = await async_client.post("/api/v1/github-backup/run")
  283. assert response.status_code == 400
  284. assert "disabled" in response.json()["detail"].lower()