test_integration.py 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import os
  2. import re
  3. import signal
  4. import subprocess
  5. import sys
  6. import time
  7. from pathlib import Path
  8. import httpx
  9. import pytest
  10. from opencode_ai import OpenCodeClient
  11. @pytest.mark.timeout(30)
  12. def test_integration_live_server_endpoints() -> None:
  13. # Locate repo root by finding sst.config.ts upwards from this file
  14. here = Path(__file__).resolve()
  15. p = here
  16. repo_root = None
  17. for _ in range(8):
  18. if (p / "sst.config.ts").exists():
  19. repo_root = p
  20. break
  21. if p.parent == p:
  22. break
  23. p = p.parent
  24. assert repo_root is not None, "Could not locate repo root (sst.config.ts)"
  25. # Start opencode headless server on a random port
  26. pkg_opencode = repo_root / "packages" / "opencode"
  27. cmd = [
  28. "bun",
  29. "run",
  30. "--conditions=development",
  31. "./src/index.ts",
  32. "serve",
  33. "--port",
  34. "0",
  35. "--hostname",
  36. "127.0.0.1",
  37. ]
  38. proc = subprocess.Popen(
  39. cmd,
  40. cwd=str(pkg_opencode),
  41. stdout=subprocess.PIPE,
  42. stderr=subprocess.STDOUT,
  43. text=True,
  44. bufsize=1,
  45. universal_newlines=True,
  46. )
  47. url = None
  48. start = time.time()
  49. assert proc.stdout is not None
  50. while time.time() - start < 15:
  51. line = proc.stdout.readline()
  52. if not line:
  53. time.sleep(0.05)
  54. if proc.poll() is not None:
  55. break
  56. continue
  57. m = re.search(r"opencode server listening on (http://[^\s]+)", line)
  58. if m:
  59. url = m.group(1)
  60. break
  61. assert url, "Server did not report listening URL"
  62. try:
  63. client = OpenCodeClient(base_url=url)
  64. # Basic endpoints (avoid complex config model parsing issues)
  65. pinfo = client.get_path()
  66. assert pinfo is not None
  67. projects = client.list_projects()
  68. assert projects is not None
  69. # SSE: should get the initial server.connected event
  70. it = client.subscribe_events()
  71. evt = next(it)
  72. assert isinstance(evt, dict)
  73. assert evt.get("type") == "server.connected"
  74. finally:
  75. # Cleanup server process
  76. try:
  77. if proc.poll() is None:
  78. proc.terminate()
  79. try:
  80. proc.wait(timeout=5)
  81. except subprocess.TimeoutExpired:
  82. proc.kill()
  83. except Exception:
  84. pass