test_caching.py 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. from random import Random
  2. from typing import List
  3. from django.core.cache import cache
  4. from sentry.hybridcloud.rpc.services.caching import back_with_silo_cache, region_caching_service
  5. from sentry.hybridcloud.rpc.services.caching.impl import CacheBackend
  6. from sentry.services.hybrid_cloud.user import RpcUser
  7. from sentry.services.hybrid_cloud.user.service import user_service
  8. from sentry.silo import SiloMode
  9. from sentry.testutils.factories import Factories
  10. from sentry.testutils.pytest.fixtures import django_db_all
  11. from sentry.testutils.silo import assume_test_silo_mode, no_silo_test, region_silo_test
  12. from sentry.types.region import get_local_region
  13. @django_db_all(transaction=True)
  14. @region_silo_test(stable=True)
  15. def test_caching_function():
  16. cache.clear()
  17. @back_with_silo_cache(base_key="my-test-key", silo_mode=SiloMode.REGION, t=RpcUser)
  18. def get_user(user_id: int) -> RpcUser:
  19. return user_service.get_many(filter=dict(user_ids=[user_id]))[0]
  20. users = [Factories.create_user() for _ in range(3)]
  21. old: List[RpcUser] = []
  22. for u in users:
  23. next_user = get_user(u.id)
  24. assert next_user == get_user.cb(u.id)
  25. old.append(next_user)
  26. for user in users:
  27. with assume_test_silo_mode(SiloMode.CONTROL):
  28. user.update(username=user.username + "moocow")
  29. # Does not include updates
  30. for u in old:
  31. next_user = get_user(u.id)
  32. assert next_user == u
  33. region_caching_service.clear_key(
  34. region_name=get_local_region().name, key=get_user.key_from(u.id)
  35. )
  36. for u, cached in zip(users, get_user.get_many([u.id for u in users])):
  37. assert cached.username == u.username
  38. @django_db_all(transaction=True)
  39. @no_silo_test(stable=True)
  40. def test_cache_versioning():
  41. cache.clear()
  42. shared_key = "my-key"
  43. true_value = "a"
  44. def reader():
  45. nonlocal true_value
  46. last_length = 0
  47. while True:
  48. results = yield from CacheBackend.get_cache([shared_key], SiloMode.REGION)
  49. value = next(iter(results.values()))
  50. if isinstance(value, str):
  51. assert (
  52. len(value) >= last_length
  53. ), "Read after write broken -- never read a more stale value than has been observed written"
  54. assert all(c == "a" for c in value)
  55. else:
  56. version = value
  57. copied_local_value = true_value
  58. yield
  59. yield from CacheBackend.set_cache(shared_key, copied_local_value, version)
  60. last_length = len(copied_local_value)
  61. def writer():
  62. nonlocal true_value
  63. while True:
  64. for i in range(5):
  65. yield
  66. true_value += "a"
  67. yield from CacheBackend.delete_cache(shared_key, SiloMode.REGION)
  68. def cache_death_event():
  69. while True:
  70. for i in range(20):
  71. yield
  72. cache.clear()
  73. reader1 = reader()
  74. reader2 = reader()
  75. writer1 = writer()
  76. cache_death = cache_death_event()
  77. random = Random(84716393)
  78. for i in range(10000):
  79. next(random.choice([reader1, reader2, writer1, cache_death]))