3

Very simply, I want to run some code and verify that no entities of kind MyEntity(ndb.Model) were put the datastore.

I've tried doing MyEntity.query().fetch(keys_only=True), but that doesn't seem to be strongly-consistent (i.e. it doesn't show the one entity I just added), so returning an empty list is not true confirmation. (I should add that I'm using the testbed.init_datastore_v3_stub and I've tried datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1) and MasterSlaveConsistencyPolicy() with no success.)

I thought there was a way to do a strongly-consistent 'get' for all keys of a kind, but now I can't find any documentation to support that.

I know that I can do a strongly-consistent get if I have a Key, but how would that translate to verification that an entity was not added, so there is no key to get?

Dan McGrath
  • 41,220
  • 11
  • 99
  • 130
Pat
  • 16,515
  • 15
  • 95
  • 114

1 Answers1

2

Well, I finally got it to work by disabling the ndb cache via global context (tipped off by How to Clear/Invalidate NDB Cache in Tests) in addition to the normal unit testing testbeds.

Also helped by:

Helper Mixin:

class NdbTestbedNoCachingStronglyConsistentMixin(unittest.TestCase):
    def setUp(self):
        self.testbed = testbed.Testbed()
        self.testbed.activate()
        policy = None
        # policy = datastore_stub_util.MasterSlaveConsistencyPolicy()
        # policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy(probability=1.0)
        self.testbed.init_datastore_v3_stub(consistency_policy=policy)
        # self.testbed.init_memcache_stub()

        # It's not enough (or necessary) to use stubs for datastore and memcache -
        # we also need to change ndb policy to ensure that datastore queries
        # are strongly-consistent
        cxt = ndb.get_context()

        def disallow(*args, **kwargs):
            return False

        cxt.set_cache_policy(disallow)
        cxt.set_memcache_policy(disallow)
        super(NdbTestbedNoCachingStronglyConsistentMixin, self).setUp()

    def tearDown(self):
        super(NdbTestbedNoCachingStronglyConsistentMixin, self).tearDown()
        self.testbed.deactivate()

With usage like this (some irrelevant code left out):

def _get_entity_keys():
    return MyNdbEntity.query().fetch(keys_only=True)


class TestMyEntity(NdbTestbedNoCachingStronglyConsistentMixin):

    def tearDown(self):
        super(TestMyEntity, self).tearDown()

        # Verify our assumptions that no entities persist between tests
        assert MyNdbEntity.get_by_identifier(self.account, TEST_IDENTIFIER) is None
        assert not _get_entity_keys()

    def test_get_uri_should_retrieve_existing_entity(self):
        provider.get_uri(TEST_IDENTIFIER)  # creates entity
        all_assets_keys = _get_entity_keys()
        created_asset = MyNdbEntity.get_by_identifier(self.account, TEST_IDENTIFIER)

        self.assertIn(created_asset.key, all_assets_keys)

        provider.get_uri(TEST_IDENTIFIER)
        all_assets_keys_after_get = _get_entity_keys()

        self.assertSequenceEqual(all_assets_keys_after_get, all_assets_keys)


    def test_get_uri_should_create_entity_and_prefix_identifier_with_security_id(self):
        expected_identifier = TEST_SECURITY_ID + '-' + TEST_IDENTIFIER
        expected_uri = VIEWER_IMAGE_BASE_URI % expected_identifier

        uri = provider.get_uri(TEST_IDENTIFIER)
        image = _get_entity_keys()[0].get()

        self.assertEqual(image.identifier, expected_identifier)
        self.assertEqual(uri, expected_uri)
Community
  • 1
  • 1
Pat
  • 16,515
  • 15
  • 95
  • 114