test_sync_api_provider.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. # This module is a copy paste of test_api_provider.py
  2. from http import HTTPStatus
  3. from unittest import mock
  4. import pytest
  5. from clean_python import ctx
  6. from clean_python import Tenant
  7. from clean_python.api_client import ApiException
  8. from clean_python.api_client import SyncApiProvider
  9. MODULE = "clean_python.api_client.sync_api_provider"
  10. @pytest.fixture
  11. def tenant() -> Tenant:
  12. ctx.tenant = Tenant(id=2, name="")
  13. yield ctx.tenant
  14. ctx.tenant = None
  15. @pytest.fixture
  16. def response():
  17. response = mock.Mock()
  18. response.status = int(HTTPStatus.OK)
  19. response.headers = {"Content-Type": "application/json"}
  20. response.data = b'{"foo": 2}'
  21. return response
  22. @pytest.fixture
  23. def api_provider(tenant, response) -> SyncApiProvider:
  24. with mock.patch(MODULE + ".PoolManager"):
  25. api_provider = SyncApiProvider(
  26. url="http://testserver/foo/",
  27. fetch_token=lambda a, b: f"tenant-{b}",
  28. )
  29. api_provider._pool.request.return_value = response
  30. yield api_provider
  31. def test_get(api_provider: SyncApiProvider, response):
  32. actual = api_provider.request("GET", "")
  33. assert api_provider._pool.request.call_count == 1
  34. assert api_provider._pool.request.call_args[1] == dict(
  35. method="GET",
  36. url="http://testserver/foo",
  37. headers={"Authorization": "Bearer tenant-2"},
  38. timeout=5.0,
  39. )
  40. assert actual == {"foo": 2}
  41. def test_post_json(api_provider: SyncApiProvider, response):
  42. response.status == int(HTTPStatus.CREATED)
  43. api_provider._pool.request.return_value = response
  44. actual = api_provider.request("POST", "bar", json={"foo": 2})
  45. assert api_provider._pool.request.call_count == 1
  46. assert api_provider._pool.request.call_args[1] == dict(
  47. method="POST",
  48. url="http://testserver/foo/bar",
  49. body=b'{"foo": 2}',
  50. headers={
  51. "Content-Type": "application/json",
  52. "Authorization": "Bearer tenant-2",
  53. },
  54. timeout=5.0,
  55. )
  56. assert actual == {"foo": 2}
  57. @pytest.mark.parametrize(
  58. "path,params,expected_url",
  59. [
  60. ("", None, "http://testserver/foo"),
  61. ("bar", None, "http://testserver/foo/bar"),
  62. ("bar/", None, "http://testserver/foo/bar"),
  63. ("", {"a": 2}, "http://testserver/foo?a=2"),
  64. ("bar", {"a": 2}, "http://testserver/foo/bar?a=2"),
  65. ("bar/", {"a": 2}, "http://testserver/foo/bar?a=2"),
  66. ("", {"a": [1, 2]}, "http://testserver/foo?a=1&a=2"),
  67. ("", {"a": 1, "b": "foo"}, "http://testserver/foo?a=1&b=foo"),
  68. ],
  69. )
  70. def test_url(api_provider: SyncApiProvider, path, params, expected_url):
  71. api_provider.request("GET", path, params=params)
  72. assert api_provider._pool.request.call_args[1]["url"] == expected_url
  73. def test_timeout(api_provider: SyncApiProvider):
  74. api_provider.request("POST", "bar", timeout=2.1)
  75. assert api_provider._pool.request.call_args[1]["timeout"] == 2.1
  76. @pytest.mark.parametrize(
  77. "status", [HTTPStatus.OK, HTTPStatus.NOT_FOUND, HTTPStatus.INTERNAL_SERVER_ERROR]
  78. )
  79. def test_unexpected_content_type(api_provider: SyncApiProvider, response, status):
  80. response.status = int(status)
  81. response.headers["Content-Type"] = "text/plain"
  82. with pytest.raises(ApiException) as e:
  83. api_provider.request("GET", "bar")
  84. assert e.value.status is status
  85. assert str(e.value) == f"{status}: Unexpected content type 'text/plain'"
  86. def test_json_variant_content_type(api_provider: SyncApiProvider, response):
  87. response.headers["Content-Type"] = "application/something+json"
  88. actual = api_provider.request("GET", "bar")
  89. assert actual == {"foo": 2}
  90. def test_no_content(api_provider: SyncApiProvider, response):
  91. response.status = int(HTTPStatus.NO_CONTENT)
  92. response.headers = {}
  93. actual = api_provider.request("DELETE", "bar/2")
  94. assert actual is None
  95. @pytest.mark.parametrize("status", [HTTPStatus.BAD_REQUEST, HTTPStatus.NOT_FOUND])
  96. def test_error_response(api_provider: SyncApiProvider, response, status):
  97. response.status = int(status)
  98. with pytest.raises(ApiException) as e:
  99. api_provider.request("GET", "bar")
  100. assert e.value.status is status
  101. assert str(e.value) == str(int(status)) + ": {'foo': 2}"
  102. @mock.patch(MODULE + ".PoolManager", new=mock.Mock())
  103. def test_no_token(response, tenant):
  104. api_provider = SyncApiProvider(
  105. url="http://testserver/foo/", fetch_token=lambda a, b: None
  106. )
  107. api_provider._pool.request.return_value = response
  108. api_provider.request("GET", "")
  109. assert api_provider._pool.request.call_args[1]["headers"] == {}