test_client_config.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. from __future__ import annotations
  2. from typing import Any
  3. import pytest
  4. from django.conf import settings
  5. from django.core.cache import cache
  6. from django.test import override_settings
  7. from sentry import options
  8. from sentry.app import env
  9. from sentry.models.authidentity import AuthIdentity
  10. from sentry.models.authprovider import AuthProvider
  11. from sentry.models.organization import Organization
  12. from sentry.models.organizationmapping import OrganizationMapping
  13. from sentry.organizations.services.organization import organization_service
  14. from sentry.silo.base import SiloMode
  15. from sentry.testutils.factories import Factories
  16. from sentry.testutils.helpers.features import Feature
  17. from sentry.testutils.helpers.options import override_options
  18. from sentry.testutils.pytest.fixtures import django_db_all
  19. from sentry.testutils.region import get_test_env_directory
  20. from sentry.testutils.requests import (
  21. RequestFactory,
  22. make_request,
  23. make_user_request,
  24. make_user_request_from_org,
  25. request_factory,
  26. )
  27. from sentry.testutils.silo import (
  28. assume_test_silo_mode_of,
  29. control_silo_test,
  30. create_test_regions,
  31. no_silo_test,
  32. )
  33. from sentry.types import region
  34. from sentry.web.client_config import get_client_config
  35. @request_factory
  36. def make_user_request_from_non_existant_org(org=None):
  37. request, user = make_user_request_from_org(org)
  38. # This is a non existant value that will fail lookup.
  39. request.session["activeorg"] = 47381
  40. return request, user
  41. def make_user_request_from_org_with_auth_identities(org=None):
  42. request, user = make_user_request_from_org(org)
  43. with assume_test_silo_mode_of(Organization):
  44. org = Organization.objects.get_for_user_ids({user.id})[0]
  45. provider = AuthProvider.objects.create(
  46. organization_id=org.id, provider="google", config={"domain": "olddomain.com"}
  47. )
  48. AuthIdentity.objects.create(user=user, auth_provider=provider, ident="me@google.com", data={})
  49. return request, user
  50. @request_factory
  51. def none_request() -> None:
  52. return None
  53. @pytest.fixture(autouse=True)
  54. def clear_env_request():
  55. env.clear()
  56. yield
  57. env.clear()
  58. multiregion_client_config_test = control_silo_test(
  59. regions=create_test_regions("us", "eu", "acme", single_tenants=["acme"]),
  60. include_monolith_run=True,
  61. )
  62. @multiregion_client_config_test
  63. @pytest.mark.parametrize(
  64. "request_factory",
  65. [
  66. none_request,
  67. make_request,
  68. make_user_request,
  69. make_user_request_from_org,
  70. make_user_request_from_non_existant_org,
  71. make_user_request_from_org_with_auth_identities,
  72. ],
  73. )
  74. @django_db_all(transaction=True)
  75. def test_client_config_in_silo_modes(request_factory: RequestFactory):
  76. request_ret = request_factory()
  77. if request_ret is not None:
  78. request, _ = request_ret
  79. else:
  80. request = None
  81. base_line = dict(get_client_config(request))
  82. def normalize(value: dict[str, Any]):
  83. # Removing the region lists as it varies based on silo mode.
  84. # See Region.to_url()
  85. value.pop("regions")
  86. value.pop("memberRegions")
  87. value["links"].pop("regionUrl")
  88. normalize(base_line)
  89. cache.clear()
  90. for silo_mode in SiloMode:
  91. with override_settings(SILO_MODE=silo_mode):
  92. result = dict(get_client_config(request))
  93. normalize(result)
  94. assert result == base_line
  95. cache.clear()
  96. @no_silo_test
  97. @django_db_all(transaction=True)
  98. def test_client_config_deleted_user():
  99. request, user = make_user_request_from_org()
  100. request.user = user
  101. user.delete()
  102. result = get_client_config(request)
  103. assert result["isAuthenticated"] is False
  104. assert result["user"] is None
  105. @no_silo_test
  106. @django_db_all
  107. def test_client_config_features():
  108. request, user = make_user_request_from_org()
  109. request.user = user
  110. result = get_client_config(request)
  111. assert "features" in result
  112. assert "organizations:create" in result["features"]
  113. assert "system:multi-region" not in result["features"]
  114. with override_options({"auth.allow-registration": True}), Feature(
  115. {"auth:register": True, "system:multi-region": True}
  116. ):
  117. result = get_client_config(request)
  118. assert "features" in result
  119. assert "system:multi-region" in result["features"]
  120. assert "auth:register" in result["features"]
  121. @no_silo_test
  122. @django_db_all
  123. def test_client_config_default_region_data():
  124. request, user = make_user_request_from_org()
  125. request.user = user
  126. result = get_client_config(request)
  127. assert len(result["regions"]) == 1
  128. regions = result["regions"]
  129. assert regions[0]["name"] == settings.SENTRY_MONOLITH_REGION
  130. assert regions[0]["url"] == options.get("system.url-prefix")
  131. assert len(result["memberRegions"]) == 1
  132. regions = result["memberRegions"]
  133. assert regions[0]["name"] == settings.SENTRY_MONOLITH_REGION
  134. assert regions[0]["url"] == options.get("system.url-prefix")
  135. @no_silo_test
  136. @django_db_all
  137. def test_client_config_empty_region_data():
  138. region_directory = region.load_from_config(())
  139. # Usually, we would want to use other testutils functions rather than calling
  140. # `swap_state` directly. We make an exception here in order to test the default
  141. # region data that `load_from_config` fills in.
  142. with get_test_env_directory().swap_state(tuple(region_directory.regions)):
  143. request, user = make_user_request_from_org()
  144. request.user = user
  145. result = get_client_config(request)
  146. assert len(result["regions"]) == 1
  147. regions = result["regions"]
  148. assert regions[0]["name"] == settings.SENTRY_MONOLITH_REGION
  149. assert regions[0]["url"] == options.get("system.url-prefix")
  150. @multiregion_client_config_test
  151. @django_db_all
  152. def test_client_config_with_region_data():
  153. request, user = make_user_request_from_org()
  154. request.user = user
  155. result = get_client_config(request)
  156. assert len(result["regions"]) == 2
  157. regions = result["regions"]
  158. assert {r["name"] for r in regions} == {"eu", "us"}
  159. assert len(result["memberRegions"]) == 1
  160. hidden_regions = [
  161. region.Region(
  162. name="us",
  163. snowflake_id=1,
  164. address="https//us.testserver",
  165. category=region.RegionCategory.MULTI_TENANT,
  166. ),
  167. region.Region(
  168. name="eu",
  169. snowflake_id=5,
  170. address="https//eu.testserver",
  171. visible=False,
  172. category=region.RegionCategory.MULTI_TENANT,
  173. ),
  174. ]
  175. @control_silo_test(regions=hidden_regions, include_monolith_run=True)
  176. @django_db_all
  177. def test_client_config_with_hidden_region_data():
  178. request, user = make_user_request_from_org()
  179. request.user = user
  180. result = get_client_config(request)
  181. assert len(result["regions"]) == 1
  182. regions = result["regions"]
  183. assert {r["name"] for r in regions} == {"us"}
  184. assert len(result["memberRegions"]) == 1
  185. @multiregion_client_config_test
  186. @django_db_all
  187. def test_client_config_with_multiple_membership():
  188. request, user = make_user_request_from_org()
  189. request.user = user
  190. # multiple us memberships and eu too
  191. Factories.create_organization(slug="us-co", owner=user)
  192. Factories.create_organization(slug="eu-co", owner=user)
  193. mapping = OrganizationMapping.objects.get(slug="eu-co")
  194. mapping.update(region_name="eu")
  195. result = get_client_config(request)
  196. # Single-tenant doesn't show up unless you have membership
  197. assert len(result["regions"]) == 2
  198. regions = result["regions"]
  199. assert {r["name"] for r in regions} == {"eu", "us"}
  200. assert len(result["memberRegions"]) == 2
  201. regions = result["memberRegions"]
  202. assert {r["name"] for r in regions} == {"eu", "us"}
  203. @multiregion_client_config_test
  204. @django_db_all
  205. def test_client_config_with_single_tenant_membership():
  206. request, user = make_user_request_from_org()
  207. request.user = user
  208. Factories.create_organization(slug="acme-co", owner=user)
  209. mapping = OrganizationMapping.objects.get(slug="acme-co")
  210. mapping.update(region_name="acme")
  211. result = get_client_config(request)
  212. assert len(result["regions"]) == 3
  213. regions = result["regions"]
  214. assert {r["name"] for r in regions} == {"eu", "us", "acme"}
  215. assert len(result["memberRegions"]) == 2
  216. regions = result["memberRegions"]
  217. assert {r["name"] for r in regions} == {"us", "acme"}
  218. @multiregion_client_config_test
  219. @django_db_all
  220. def test_client_config_links_regionurl():
  221. request, user = make_user_request_from_org()
  222. request.user = user
  223. with override_settings(SILO_MODE=SiloMode.REGION, SENTRY_REGION="us"):
  224. result = get_client_config(request)
  225. assert result["links"]
  226. assert result["links"]["regionUrl"] == "http://us.testserver"
  227. with override_settings(SILO_MODE=SiloMode.CONTROL, SENTRY_REGION=None):
  228. result = get_client_config(request)
  229. assert result["links"]
  230. assert result["links"]["regionUrl"] == "http://us.testserver"
  231. with override_settings(SILO_MODE=SiloMode.MONOLITH, SENTRY_REGION="eu"):
  232. result = get_client_config(request)
  233. assert result["links"]
  234. assert result["links"]["regionUrl"] == "http://eu.testserver"
  235. @control_silo_test(
  236. regions=create_test_regions("us", "eu", "acme", "de", "apac", single_tenants=["acme"]),
  237. include_monolith_run=True,
  238. )
  239. @django_db_all
  240. def test_client_config_region_display_order():
  241. request, user = make_user_request_from_org()
  242. request.user = user
  243. Factories.create_organization(slug="acme-co", owner=user)
  244. mapping = OrganizationMapping.objects.get(slug="acme-co")
  245. mapping.update(region_name="acme")
  246. result = get_client_config(request)
  247. region_names = [region["name"] for region in result["regions"]]
  248. assert region_names == ["us", "apac", "de", "eu", "acme"]
  249. @multiregion_client_config_test
  250. @django_db_all
  251. def test_client_config_links_with_priority_org():
  252. request, user = make_user_request_from_org()
  253. request.user = user
  254. org = Factories.create_organization()
  255. Factories.create_member(organization=org, user=user)
  256. org_context = organization_service.get_organization_by_slug(
  257. slug=org.slug, only_visible=False, user_id=user.id
  258. )
  259. # we want the org context to have priority over the active org
  260. assert request.session["activeorg"] != org.slug
  261. with override_settings(SILO_MODE=SiloMode.REGION, SENTRY_REGION="us"):
  262. result = get_client_config(request, org_context)
  263. assert result["links"]
  264. assert result["links"]["regionUrl"] == "http://us.testserver"
  265. assert result["links"]["organizationUrl"] == f"http://{org.slug}.testserver"
  266. with override_settings(SILO_MODE=SiloMode.CONTROL, SENTRY_REGION=None):
  267. result = get_client_config(request, org_context)
  268. assert result["links"]
  269. assert result["links"]["regionUrl"] == "http://us.testserver"
  270. assert result["links"]["organizationUrl"] == f"http://{org.slug}.testserver"
  271. @django_db_all
  272. def test_project_key_default():
  273. organization = Factories.create_organization(name="test-org")
  274. project = Factories.create_project(organization=organization)
  275. project_key = Factories.create_project_key(project)
  276. assert project_key.dsn_public
  277. with override_settings(SENTRY_PROJECT=project.id):
  278. assert get_client_config()["dsn"] == project_key.dsn_public