|
39 | 39 | from . import KIND, eventually, equals |
40 | 40 |
|
41 | 41 | USE_REDIS_CACHE = bool(os.environ.get("REDIS_CACHE_URL")) |
| 42 | +USE_MEMCACHE = bool(os.environ.get("MEMCACHED_HOSTS")) |
42 | 43 |
|
43 | 44 |
|
44 | 45 | def _assert_contemporaneous(timestamp1, timestamp2, delta_margin=2): |
@@ -149,6 +150,37 @@ class SomeKind(ndb.Model): |
149 | 150 | assert entity.baz == "night" |
150 | 151 |
|
151 | 152 |
|
| 153 | +@pytest.mark.skipif(not USE_MEMCACHE, reason="Memcache is not configured") |
| 154 | +def test_retrieve_entity_with_memcache(ds_entity, memcache_context): |
| 155 | + entity_id = test_utils.system.unique_resource_id() |
| 156 | + ds_entity(KIND, entity_id, foo=42, bar="none", baz=b"night") |
| 157 | + |
| 158 | + class SomeKind(ndb.Model): |
| 159 | + foo = ndb.IntegerProperty() |
| 160 | + bar = ndb.StringProperty() |
| 161 | + baz = ndb.StringProperty() |
| 162 | + |
| 163 | + key = ndb.Key(KIND, entity_id) |
| 164 | + entity = key.get() |
| 165 | + assert isinstance(entity, SomeKind) |
| 166 | + assert entity.foo == 42 |
| 167 | + assert entity.bar == "none" |
| 168 | + assert entity.baz == "night" |
| 169 | + |
| 170 | + cache_key = _cache.global_cache_key(key._key) |
| 171 | + cache_key = global_cache_module.MemcacheCache._key(cache_key) |
| 172 | + assert memcache_context.global_cache.client.get(cache_key) is not None |
| 173 | + |
| 174 | + patch = mock.patch("google.cloud.ndb._datastore_api._LookupBatch.add") |
| 175 | + patch.side_effect = Exception("Shouldn't call this") |
| 176 | + with patch: |
| 177 | + entity = key.get() |
| 178 | + assert isinstance(entity, SomeKind) |
| 179 | + assert entity.foo == 42 |
| 180 | + assert entity.bar == "none" |
| 181 | + assert entity.baz == "night" |
| 182 | + |
| 183 | + |
152 | 184 | @pytest.mark.usefixtures("client_context") |
153 | 185 | def test_retrieve_entity_not_found(ds_entity): |
154 | 186 | entity_id = test_utils.system.unique_resource_id() |
@@ -586,6 +618,33 @@ class SomeKind(ndb.Model): |
586 | 618 | assert redis_context.global_cache.redis.get(cache_key) is None |
587 | 619 |
|
588 | 620 |
|
| 621 | +@pytest.mark.skipif(not USE_MEMCACHE, reason="Memcache is not configured") |
| 622 | +def test_insert_entity_with_memcache(dispose_of, memcache_context): |
| 623 | + class SomeKind(ndb.Model): |
| 624 | + foo = ndb.IntegerProperty() |
| 625 | + bar = ndb.StringProperty() |
| 626 | + |
| 627 | + entity = SomeKind(foo=42, bar="none") |
| 628 | + key = entity.put() |
| 629 | + dispose_of(key._key) |
| 630 | + cache_key = _cache.global_cache_key(key._key) |
| 631 | + cache_key = global_cache_module.MemcacheCache._key(cache_key) |
| 632 | + assert memcache_context.global_cache.client.get(cache_key) is None |
| 633 | + |
| 634 | + retrieved = key.get() |
| 635 | + assert retrieved.foo == 42 |
| 636 | + assert retrieved.bar == "none" |
| 637 | + |
| 638 | + assert memcache_context.global_cache.client.get(cache_key) is not None |
| 639 | + |
| 640 | + entity.foo = 43 |
| 641 | + entity.put() |
| 642 | + |
| 643 | + # This is py27 behavior. I can see a case being made for caching the |
| 644 | + # entity on write rather than waiting for a subsequent lookup. |
| 645 | + assert memcache_context.global_cache.client.get(cache_key) is None |
| 646 | + |
| 647 | + |
589 | 648 | @pytest.mark.usefixtures("client_context") |
590 | 649 | def test_update_entity(ds_entity): |
591 | 650 | entity_id = test_utils.system.unique_resource_id() |
@@ -750,6 +809,30 @@ class SomeKind(ndb.Model): |
750 | 809 | assert redis_context.global_cache.redis.get(cache_key) == b"0" |
751 | 810 |
|
752 | 811 |
|
| 812 | +@pytest.mark.skipif(not USE_MEMCACHE, reason="Memcache is not configured") |
| 813 | +def test_delete_entity_with_memcache(ds_entity, memcache_context): |
| 814 | + entity_id = test_utils.system.unique_resource_id() |
| 815 | + ds_entity(KIND, entity_id, foo=42) |
| 816 | + |
| 817 | + class SomeKind(ndb.Model): |
| 818 | + foo = ndb.IntegerProperty() |
| 819 | + |
| 820 | + key = ndb.Key(KIND, entity_id) |
| 821 | + cache_key = _cache.global_cache_key(key._key) |
| 822 | + cache_key = global_cache_module.MemcacheCache._key(cache_key) |
| 823 | + |
| 824 | + assert key.get().foo == 42 |
| 825 | + assert memcache_context.global_cache.client.get(cache_key) is not None |
| 826 | + |
| 827 | + assert key.delete() is None |
| 828 | + assert memcache_context.global_cache.client.get(cache_key) is None |
| 829 | + |
| 830 | + # This is py27 behavior. Not entirely sold on leaving _LOCKED value for |
| 831 | + # Datastore misses. |
| 832 | + assert key.get() is None |
| 833 | + assert memcache_context.global_cache.client.get(cache_key) == b"0" |
| 834 | + |
| 835 | + |
753 | 836 | @pytest.mark.usefixtures("client_context") |
754 | 837 | def test_delete_entity_in_transaction(ds_entity): |
755 | 838 | entity_id = test_utils.system.unique_resource_id() |
|
0 commit comments