def test_can_add_material(self):
        storage = InMemoryStorage()
        girl = Materializer(storage=storage)

        girl.add_material("test", lambda: "woot")

        girl.run()

        expect(storage.items).to_include("test")
        expect(storage.items["test"]).to_equal("woot")
    def test_can_add_material_with_expiration_and_graceperiod(self):
        storage = InMemoryStorage()
        girl = Materializer(storage=storage)

        girl.add_material("test", lambda: "woot", expiration=2, grace_period=4)

        girl.run()

        expect(storage.items).to_include("test")
        expect(storage.items["test"]).to_equal("woot")
    def test_can_get_value_after_material_girl_run(self):
        storage = InMemoryStorage()
        girl = Materializer(storage=storage)

        girl.add_material("test", lambda: "woot")

        girl.run()

        value = girl.get("test")
        expect(value).to_equal("woot")
    def test_can_miss_the_cache(self):
        storage = Mock(retrieve=Mock(return_value=None))

        girl = Materializer(storage=storage, load_on_cachemiss=False)
        girl.add_material("test", lambda: "woot")

        girl.run()
        value = girl.get("test")

        expect(value).to_be_null()
        expect(storage.acquire_lock.call_count).to_equal(1)
        storage.store.assert_called_once_with("test", "woot", expiration=10, grace_period=0)
    def test_can_lock_key_with_timeout(self):
        storage = Mock(store=Mock(), acquire_lock=Mock())

        girl = Materializer(storage=storage)
        girl.add_material("test1", lambda: "woot", lock_timeout=1)
        girl.add_material("test2", lambda: "woot", lock_timeout=2)

        girl.run()

        expect(storage.store.call_count).to_equal(2)
        expect(storage.acquire_lock.call_count).to_equal(2)
        storage.acquire_lock.assert_has_calls([call("test1", timeout=1), call("test2", timeout=2)])
    def test_can_add_material(self):
        storage = InMemoryStorage()
        girl = Materializer(storage=storage)

        girl.add_material(
            'test',
            lambda: 'woot'
        )

        girl.run()

        expect(storage.items).to_include('test')
        expect(storage.items['test']).to_equal('woot')
    def test_can_skip_locked_key(self, logging_info_mock):
        storage = Mock(store=Mock(), acquire_lock=Mock(return_value=None), release_lock=Mock())

        girl = Materializer(storage=storage)

        girl.add_material("test1", lambda: "woot1")
        girl.add_material("test2", lambda: "woot2")

        girl.run()

        expect(storage.store.call_count).to_equal(0)
        expect(storage.acquire_lock.call_count).to_equal(2)
        expect(storage.release_lock.call_count).to_equal(0)
        expect(logging_info_mock.call_count).to_equal(4)
    def test_does_not_add_not_expired_materials(self):
        storage = InMemoryStorage()
        girl = Materializer(storage=storage)

        girl.add_material(
            'test',
            lambda: 'woot'
        )

        girl.run()

        storage.items = {}

        girl.run()

        expect(storage.items).to_be_empty()
    def test_dont_update_not_expired_materials(self):
        storage = InMemoryStorage()
        girl = Materializer(storage=storage)

        woots = self.woots_generator()

        girl.add_material("test", lambda: next(woots))

        girl.run()

        expect(storage.items).to_length(1)
        expect(storage.items["test"]).to_equal("woot1")

        girl.run()

        expect(storage.items).to_length(1)
        expect(storage.items["test"]).to_equal("woot1")
    def test_can_expire_materials(self):
        storage = InMemoryStorage()
        girl = Materializer(storage=storage)

        girl.add_material("test", lambda: "woot")

        girl.run()

        expect(storage.items).to_length(1)
        expect(storage.items["test"]).to_equal("woot")

        girl.expire("test")

        expect(girl.is_expired("test")).to_be_true()

        expect(storage.items).to_length(1)
        expect(storage.items.get("test")).to_be_null()
        expect(storage.items["_expired_test"]).to_equal("woot")