def test_get(self): s = self.make_store() s2 = self.make_store() with write_locked(s): s['foo'] = 'bar' with read_locked(s): self.assertEqual('bar', s['foo']) # The change is immediately visible to other store instances. with read_locked(s2): self.assertEqual('bar', s2['foo'])
def test_delete(self): s = self.make_store() s2 = self.make_store() with write_locked(s): s['foo'] = 'bar' with write_locked(s): del s['foo'] with read_locked(s): self.assertThat(lambda:s['foo'], raises(KeyError)) # The change is immediately visible to other store instances. with read_locked(s2): self.assertThat(lambda:s2['foo'], raises(KeyError))
def test_provision_at_cap(self): source = model.Source(None, None) c = cache.Cache("foo", memory.Store({}), source, maximum=2) c.provision(2) self.assertThat(lambda: c.provision(1), raises(ValueError)) # The source was not interrogated for more resources. self.assertEqual(['2'], source.provision(1)) with read_locked(c.store): self.assertEqual('0,1', c.store['pool/foo']) self.assertThat(lambda:c.store['resource/2'], raises(KeyError))
def available(self): """Report on the number of resources that could be returned. :return: A count of the number of available resources. 0 means unlimited. """ if not self.maximum: return 0 with read_locked(self.store): return self.maximum - len( set(self._get_set('allocated/' + self.name)))
def test_provision_single(self): source = model.Source(None, None) c = cache.Cache("foo", memory.Store({}), source) self.assertEqual(0, c.in_use()) # One instance should be returned self.assertEqual(set(['foo-0']), c.provision(1)) self.assertEqual(1, c.in_use()) # The instance should have been mapped in both directions in the store. with read_locked(c.store): self.assertEqual('0', c.store['pool/foo']) self.assertEqual('foo', c.store['resource/0'])
def test_discard_single(self): source = model.Source(None, None) c = cache.Cache("foo", memory.Store({}), source) c.provision(2) c.discard(['foo-0']) self.assertEqual(1, c.in_use()) self.assertEqual(0, c.cached()) # The instance should have been unmapped in both directions from the # store. with read_locked(c.store): self.assertEqual('1', c.store['pool/foo']) self.assertThat(lambda:c.store['resource/0'], raises(KeyError))
def test_discard_force_ignores_reserve(self): source = model.Source(None, None) c = cache.Cache("foo", memory.Store({}), source, reserve=1) c.discard(c.provision(2), force=True) self.assertThat(source._calls, MatchesAny( Equals([('provision', 2), ('discard', ['0', '1'])]), Equals([('provision', 2), ('discard', ['1', '0'])]))) # The instance should have been unmapped in both directions from the # store. with read_locked(c.store): self.assertEqual('', c.store['pool/foo']) self.assertThat(lambda:c.store['resource/0'], raises(KeyError)) self.assertThat(lambda:c.store['resource/1'], raises(KeyError))
def test_provision_separate_calls(self): source = model.Source(None, None) c = cache.Cache("foo", memory.Store({}), source) self.assertEqual(set(['foo-0', 'foo-1']), c.provision(2)) self.assertEqual(2, c.in_use()) self.assertEqual(set(['foo-2', 'foo-3']), c.provision(2)) self.assertEqual(4, c.in_use()) # The instances should have been mapped in both directions in the store. with read_locked(c.store): self.assertEqual('0,1,2,3', c.store['pool/foo']) self.assertEqual('foo', c.store['resource/0']) self.assertEqual('foo', c.store['resource/1']) self.assertEqual('foo', c.store['resource/2']) self.assertEqual('foo', c.store['resource/3'])
def test_fill_reserve(self): source = model.Source(None, None) c = cache.Cache("foo", memory.Store({}), source, reserve=3) c.provision(1) c.fill_reserve() self.assertEqual(1, c.in_use()) self.assertEqual(2, c.cached()) # Check its all mapped correctly. with read_locked(c.store): self.assertEqual('0,1,2', c.store['pool/foo']) self.assertEqual('0', c.store['allocated/foo']) self.assertEqual('foo', c.store['resource/0']) self.assertEqual('foo', c.store['resource/1']) self.assertEqual('foo', c.store['resource/2'])
def test_discard_multiple(self): source = model.Source(None, None) c = cache.Cache("foo", memory.Store({}), source) c.provision(4) c.discard(['foo-0', 'foo-2']) self.assertEqual(2, c.in_use()) self.assertEqual(0, c.cached()) self.assertEqual( [('provision', 4), ('discard', ['0', '2'])], source._calls) # The instances should have been unmapped in both directions from the # store. with read_locked(c.store): self.assertEqual('1,3', c.store['pool/foo']) self.assertThat(lambda:c.store['resource/0'], raises(KeyError)) self.assertThat(lambda:c.store['resource/2'], raises(KeyError))
def test_provision_pulls_from_reserve(self): source = model.Source(None, None) c = cache.Cache("foo", memory.Store({}), source, reserve=2) c.discard(c.provision(2)) self.assertEqual(0, c.in_use()) self.assertEqual(2, c.cached()) self.assertEqual(set(['foo-0', 'foo-1', 'foo-2']), c.provision(3)) self.assertEqual(3, c.in_use()) self.assertEqual(0, c.cached()) # The instances should have been mapped in both directions in the store. with read_locked(c.store): self.assertEqual('0,1,2', c.store['pool/foo']) self.assertEqual('foo', c.store['resource/0']) self.assertEqual('foo', c.store['resource/1']) self.assertEqual('foo', c.store['resource/2'])
def test_discard_keeps_reserve_level(self): source = model.Source(None, None) c = cache.Cache("foo", memory.Store({}), source, reserve=1) c.discard(c.provision(2)) self.assertEqual(0, c.in_use()) self.assertEqual(1, c.cached()) self.assertThat(source._calls, MatchesAny( Equals([('provision', 2), ('discard', ['0'])]), Equals([('provision', 2), ('discard', ['1'])]))) if source._calls[-1][-1][-1] == '0': gone = 'resource/0' remaining = '1' else: gone = 'resource/1' remaining = '0' # The instance should have been unmapped in both directions from the # store. with read_locked(c.store): self.assertEqual(remaining, c.store['pool/foo']) self.assertThat(lambda:c.store[gone], raises(KeyError)) self.assertEqual('foo', c.store['resource/' + remaining])
def test_read_locked(self): s = memory.Store({}) self.assertEqual('u', s._lock) with read_locked(s): self.assertEqual('r', s._lock) self.assertEqual('u', s._lock)
def test_get_missing(self): s = self.make_store() with read_locked(s): self.assertThat(lambda:s['bar'], raises(KeyError))
def in_use(self): """How many instances are checked out of this cache?""" with read_locked(self.store): return len(set(self._get_set('allocated/' + self.name)))
def instances(self): """Enumerate the instances that have been checked out.""" with read_locked(self.store): return self._external_name( set(self._get_set('allocated/' + self.name)))
def cached(self): """How many instances are sitting in the reserve ready for use.""" with read_locked(self.store): return len( set(self._get_set('pool/' + self.name))) - len( set(self._get_set('allocated/' + self.name)))