test_dms_auth.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. """Unit tests for DMS token acquisition; no live server or real secret required."""
  2. from __future__ import annotations
  3. import json
  4. import unittest
  5. from collections.abc import Callable
  6. from urllib.parse import parse_qs, urlparse
  7. from urllib.request import Request
  8. from step0_pre_prepare import DmsAuthSettings, DmsTokenManager
  9. def response(payload: dict[str, object]) -> bytes:
  10. return json.dumps(payload).encode("utf-8")
  11. class FakeTransport:
  12. def __init__(self, handler: Callable[[Request], bytes]) -> None:
  13. self.handler = handler
  14. self.requests: list[Request] = []
  15. def __call__(self, request: Request, timeout: float) -> bytes:
  16. self.requests.append(request)
  17. return self.handler(request)
  18. class DmsTokenManagerTests(unittest.TestCase):
  19. def settings(self, **overrides: object) -> DmsAuthSettings:
  20. values: dict[str, object] = {
  21. "dms_base_url": "https://dms.example/dms",
  22. "username": "user",
  23. "password": "password",
  24. "oauth_api_url": "https://oauth-api.example/oauth",
  25. }
  26. values.update(overrides)
  27. return DmsAuthSettings(**values) # type: ignore[arg-type]
  28. def test_reuses_valid_bootstrap_token_without_login(self) -> None:
  29. def handler(request: Request) -> bytes:
  30. self.assertEqual(urlparse(request.full_url).path, "/oauth/user/validateToken")
  31. self.assertEqual(parse_qs(urlparse(request.full_url).query)["serviceId"], ["2"])
  32. return response({"code": 200, "content": {}})
  33. transport = FakeTransport(handler)
  34. manager = DmsTokenManager(
  35. self.settings(bootstrap_token="existing-token"), transport=transport
  36. )
  37. self.assertEqual(manager.get_token(), "existing-token")
  38. self.assertEqual(manager.get_token(), "existing-token")
  39. self.assertEqual(len(transport.requests), 1)
  40. def test_invalid_bootstrap_token_falls_back_to_login(self) -> None:
  41. validated_tokens: list[str] = []
  42. def handler(request: Request) -> bytes:
  43. path = urlparse(request.full_url).path
  44. if path.endswith("/user/login"):
  45. form = parse_qs((request.data or b"").decode("utf-8"))
  46. self.assertEqual(form["userName"], ["user"])
  47. self.assertEqual(form["clientId"], ["0"])
  48. return response({"code": 200, "content": {}, "message": "fresh-token"})
  49. token = dict(request.header_items()).get("Token", "")
  50. validated_tokens.append(token)
  51. return response({"code": 200 if token == "fresh-token" else 212})
  52. manager = DmsTokenManager(
  53. self.settings(bootstrap_token="expired-token"),
  54. transport=FakeTransport(handler),
  55. )
  56. self.assertEqual(manager.get_token(), "fresh-token")
  57. self.assertEqual(validated_tokens, ["expired-token", "fresh-token"])
  58. def test_discovers_oauth_api_from_frontend_configuration(self) -> None:
  59. def handler(request: Request) -> bytes:
  60. if request.full_url == "https://dms.example/static/config/config.js":
  61. return b'window.config = { oauthUrl: "https://oauth-ui.example/login" }'
  62. if request.full_url == "https://oauth-ui.example/config.js":
  63. return b'window.systemConfig = { BASE_URL: "https://oauth-api.example/oauth" }'
  64. if urlparse(request.full_url).path.endswith("/user/login"):
  65. return response({"code": 200, "content": {}, "message": "fresh-token"})
  66. return response({"code": 200, "content": {}})
  67. manager = DmsTokenManager(
  68. self.settings(oauth_api_url=None, bootstrap_token=None),
  69. transport=FakeTransport(handler),
  70. )
  71. self.assertEqual(manager.get_token(), "fresh-token")
  72. def test_retries_once_after_dms_invalid_token_code(self) -> None:
  73. def handler(request: Request) -> bytes:
  74. if urlparse(request.full_url).path.endswith("/user/login"):
  75. return response({"code": 200, "content": {}, "message": "fresh-token"})
  76. return response({"code": 200, "content": {}})
  77. manager = DmsTokenManager(
  78. self.settings(bootstrap_token="old-token"), transport=FakeTransport(handler)
  79. )
  80. seen: list[str] = []
  81. def operation(token: str) -> dict[str, int]:
  82. seen.append(token)
  83. return {"code": 212 if len(seen) == 1 else 200}
  84. self.assertEqual(manager.call_with_refresh(operation), {"code": 200})
  85. self.assertEqual(seen, ["old-token", "fresh-token"])
  86. if __name__ == "__main__":
  87. unittest.main()