test_discovery_api.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. """Integration tests for Discovery API endpoints.
  2. Tests the full request/response cycle for /api/v1/discovery/ endpoints.
  3. """
  4. import pytest
  5. from httpx import AsyncClient
  6. class TestDiscoveryAPI:
  7. """Integration tests for /api/v1/discovery/ endpoints."""
  8. # ========================================================================
  9. # Info endpoint
  10. # ========================================================================
  11. @pytest.mark.asyncio
  12. @pytest.mark.integration
  13. async def test_get_discovery_info(self, async_client: AsyncClient):
  14. """Verify discovery info endpoint returns expected fields."""
  15. response = await async_client.get("/api/v1/discovery/info")
  16. assert response.status_code == 200
  17. data = response.json()
  18. assert "is_docker" in data
  19. assert "ssdp_running" in data
  20. assert "scan_running" in data
  21. assert "subnets" in data
  22. assert isinstance(data["is_docker"], bool)
  23. assert isinstance(data["ssdp_running"], bool)
  24. assert isinstance(data["scan_running"], bool)
  25. assert isinstance(data["subnets"], list)
  26. @pytest.mark.asyncio
  27. @pytest.mark.integration
  28. async def test_discovery_info_subnets_are_cidr(self, async_client: AsyncClient):
  29. """Verify subnets are valid CIDR notation strings."""
  30. response = await async_client.get("/api/v1/discovery/info")
  31. assert response.status_code == 200
  32. data = response.json()
  33. for subnet in data["subnets"]:
  34. assert isinstance(subnet, str)
  35. # Should contain a slash for CIDR notation
  36. assert "/" in subnet, f"Subnet {subnet} is not in CIDR notation"
  37. # ========================================================================
  38. # SSDP Discovery endpoints
  39. # ========================================================================
  40. @pytest.mark.asyncio
  41. @pytest.mark.integration
  42. async def test_get_discovery_status(self, async_client: AsyncClient):
  43. """Verify SSDP discovery status endpoint works."""
  44. response = await async_client.get("/api/v1/discovery/status")
  45. assert response.status_code == 200
  46. data = response.json()
  47. assert "running" in data
  48. assert isinstance(data["running"], bool)
  49. @pytest.mark.asyncio
  50. @pytest.mark.integration
  51. async def test_start_discovery(self, async_client: AsyncClient):
  52. """Verify SSDP discovery can be started."""
  53. response = await async_client.post("/api/v1/discovery/start?duration=1.0")
  54. assert response.status_code == 200
  55. data = response.json()
  56. assert "running" in data
  57. @pytest.mark.asyncio
  58. @pytest.mark.integration
  59. async def test_stop_discovery(self, async_client: AsyncClient):
  60. """Verify SSDP discovery can be stopped."""
  61. response = await async_client.post("/api/v1/discovery/stop")
  62. assert response.status_code == 200
  63. data = response.json()
  64. assert "running" in data
  65. assert data["running"] is False
  66. @pytest.mark.asyncio
  67. @pytest.mark.integration
  68. async def test_get_discovered_printers_empty(self, async_client: AsyncClient):
  69. """Verify empty list when no printers discovered."""
  70. response = await async_client.get("/api/v1/discovery/printers")
  71. assert response.status_code == 200
  72. data = response.json()
  73. assert isinstance(data, list)
  74. # ========================================================================
  75. # Subnet scanning endpoints
  76. # ========================================================================
  77. @pytest.mark.asyncio
  78. @pytest.mark.integration
  79. async def test_start_subnet_scan(self, async_client: AsyncClient):
  80. """Verify subnet scan can be started."""
  81. response = await async_client.post(
  82. "/api/v1/discovery/scan",
  83. json={"subnet": "192.168.1.0/30", "timeout": 0.1}, # Small subnet for testing
  84. )
  85. assert response.status_code == 200
  86. data = response.json()
  87. assert "running" in data
  88. assert "scanned" in data
  89. assert "total" in data
  90. @pytest.mark.asyncio
  91. @pytest.mark.integration
  92. async def test_get_scan_status(self, async_client: AsyncClient):
  93. """Verify subnet scan status endpoint works."""
  94. response = await async_client.get("/api/v1/discovery/scan/status")
  95. assert response.status_code == 200
  96. data = response.json()
  97. assert "running" in data
  98. assert "scanned" in data
  99. assert "total" in data
  100. @pytest.mark.asyncio
  101. @pytest.mark.integration
  102. async def test_stop_subnet_scan(self, async_client: AsyncClient):
  103. """Verify subnet scan can be stopped."""
  104. response = await async_client.post("/api/v1/discovery/scan/stop")
  105. assert response.status_code == 200
  106. data = response.json()
  107. assert "running" in data
  108. @pytest.mark.asyncio
  109. @pytest.mark.integration
  110. async def test_subnet_scan_invalid_subnet(self, async_client: AsyncClient):
  111. """Verify invalid subnet format is rejected."""
  112. response = await async_client.post("/api/v1/discovery/scan", json={"subnet": "invalid-subnet", "timeout": 1.0})
  113. # Should return 422 validation error or 200 with empty results
  114. assert response.status_code in [200, 422]
  115. class TestDiscoveryService:
  116. """Unit tests for discovery service functionality."""
  117. @pytest.mark.asyncio
  118. @pytest.mark.integration
  119. async def test_docker_detection_fields(self, async_client: AsyncClient):
  120. """Verify Docker detection returns consistent response."""
  121. # Call multiple times to ensure consistency
  122. response1 = await async_client.get("/api/v1/discovery/info")
  123. response2 = await async_client.get("/api/v1/discovery/info")
  124. assert response1.status_code == 200
  125. assert response2.status_code == 200
  126. assert response1.json()["is_docker"] == response2.json()["is_docker"]
  127. @pytest.mark.asyncio
  128. @pytest.mark.integration
  129. async def test_subnets_consistent_across_calls(self, async_client: AsyncClient):
  130. """Verify subnet detection returns consistent results."""
  131. response1 = await async_client.get("/api/v1/discovery/info")
  132. response2 = await async_client.get("/api/v1/discovery/info")
  133. assert response1.status_code == 200
  134. assert response2.status_code == 200
  135. assert response1.json()["subnets"] == response2.json()["subnets"]