Additional test for cachedList (#11246)

I was trying to understand how `cachedList` works, and ended up writing this
extra test. I figure we may as well keep it.
This commit is contained in:
Richard van der Hoff 2021-11-04 14:45:34 +00:00 committed by GitHub
parent 8eec25a1d9
commit f36434590c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 0 deletions

1
changelog.d/11246.misc Normal file
View file

@ -0,0 +1 @@
Add an additional test for the `cachedList` method decorator.

View file

@ -17,6 +17,7 @@ from typing import Set
from unittest import mock from unittest import mock
from twisted.internet import defer, reactor from twisted.internet import defer, reactor
from twisted.internet.defer import Deferred
from synapse.api.errors import SynapseError from synapse.api.errors import SynapseError
from synapse.logging.context import ( from synapse.logging.context import (
@ -703,6 +704,48 @@ class CachedListDescriptorTestCase(unittest.TestCase):
obj.mock.assert_called_once_with((40,), 2) obj.mock.assert_called_once_with((40,), 2)
self.assertEqual(r, {10: "fish", 40: "gravy"}) self.assertEqual(r, {10: "fish", 40: "gravy"})
def test_concurrent_lookups(self):
"""All concurrent lookups should get the same result"""
class Cls:
def __init__(self):
self.mock = mock.Mock()
@descriptors.cached()
def fn(self, arg1):
pass
@descriptors.cachedList("fn", "args1")
def list_fn(self, args1) -> "Deferred[dict]":
return self.mock(args1)
obj = Cls()
deferred_result = Deferred()
obj.mock.return_value = deferred_result
# start off several concurrent lookups of the same key
d1 = obj.list_fn([10])
d2 = obj.list_fn([10])
d3 = obj.list_fn([10])
# the mock should have been called exactly once
obj.mock.assert_called_once_with((10,))
obj.mock.reset_mock()
# ... and none of the calls should yet be complete
self.assertFalse(d1.called)
self.assertFalse(d2.called)
self.assertFalse(d3.called)
# complete the lookup. @cachedList functions need to complete with a map
# of input->result
deferred_result.callback({10: "peas"})
# ... which should give the right result to all the callers
self.assertEqual(self.successResultOf(d1), {10: "peas"})
self.assertEqual(self.successResultOf(d2), {10: "peas"})
self.assertEqual(self.successResultOf(d3), {10: "peas"})
@defer.inlineCallbacks @defer.inlineCallbacks
def test_invalidate(self): def test_invalidate(self):
"""Make sure that invalidation callbacks are called.""" """Make sure that invalidation callbacks are called."""