Skip to content

Commit 0489094

Browse files
committed
Fixing flaky datastore queries in regression tests.
Using an ancestor in queries to ensure consistency. See #562 for context.
1 parent 3e89521 commit 0489094

File tree

3 files changed

+40
-11
lines changed

3 files changed

+40
-11
lines changed

gcloud/datastore/key.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,15 +155,18 @@ def _clone(self):
155155
"""Duplicates the Key.
156156
157157
Most attributes are simple types, so don't require copying. Other
158-
attributes like ``parent`` are long-lived and so we re-use them rather
159-
than creating copies.
158+
attributes like ``parent`` are long-lived and so we re-use them.
160159
161160
:rtype: :class:`gcloud.datastore.key.Key`
162161
:returns: A new ``Key`` instance with the same data as the current one.
163162
"""
164-
return self.__class__(*self.flat_path, parent=self.parent,
165-
dataset_id=self.dataset_id,
166-
namespace=self.namespace)
163+
cloned_self = self.__class__(*self.flat_path,
164+
dataset_id=self.dataset_id,
165+
namespace=self.namespace)
166+
# If the current parent has already been set, we re-use
167+
# the same instance
168+
cloned_self._parent = self._parent
169+
return cloned_self
167170

168171
def completed_key(self, id_or_name):
169172
"""Creates new key from existing partial key by adding final ID/name.

gcloud/datastore/test_key.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,25 @@ def test__clone(self):
152152
self.assertEqual(clone.kind, _KIND)
153153
self.assertEqual(clone.path, _PATH)
154154

155+
def test__clone_with_parent(self):
156+
_DATASET = 'DATASET-ALT'
157+
_NAMESPACE = 'NAMESPACE'
158+
_KIND1 = 'PARENT'
159+
_KIND2 = 'KIND'
160+
_ID1 = 1234
161+
_ID2 = 2345
162+
_PATH = [{'kind': _KIND1, 'id': _ID1}, {'kind': _KIND2, 'id': _ID2}]
163+
164+
parent = self._makeOne(_KIND1, _ID1, namespace=_NAMESPACE,
165+
dataset_id=_DATASET)
166+
key = self._makeOne(_KIND2, _ID2, parent=parent)
167+
self.assertTrue(key.parent is parent)
168+
clone = key._clone()
169+
self.assertTrue(clone.parent is key.parent)
170+
self.assertEqual(clone.dataset_id, _DATASET)
171+
self.assertEqual(clone.namespace, _NAMESPACE)
172+
self.assertEqual(clone.path, _PATH)
173+
155174
def test_completed_key_on_partial_w_id(self):
156175
key = self._makeOne('KIND', dataset_id=self._DEFAULT_DATASET)
157176
_ID = 1234

regression/datastore.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ def test_allocate_ids(self):
5555

5656
class TestDatastoreSave(TestDatastore):
5757

58+
PARENT = datastore.Key('Blog', 'PizzaMan')
59+
5860
def _get_post(self, id_or_name=None, post_content=None):
5961
post_content = post_content or {
6062
'title': u'How to make the perfect pizza in your grill',
@@ -66,7 +68,10 @@ def _get_post(self, id_or_name=None, post_content=None):
6668
'rating': 5.0,
6769
}
6870
# Create an entity with the given content.
69-
entity = datastore.Entity(key=datastore.Key('Post'))
71+
# NOTE: Using a parent to ensure consistency for query
72+
# in `test_empty_kind`.
73+
key = datastore.Key('Post', parent=self.PARENT)
74+
entity = datastore.Entity(key=key)
7075
entity.update(post_content)
7176

7277
# Update the entity key.
@@ -77,8 +82,7 @@ def _get_post(self, id_or_name=None, post_content=None):
7782

7883
def _generic_test_post(self, name=None, key_id=None):
7984
entity = self._get_post(id_or_name=(name or key_id))
80-
with datastore.Transaction():
81-
datastore.put([entity])
85+
datastore.put([entity])
8286

8387
# Register entity to be deleted.
8488
self.case_entities_to_delete.append(entity)
@@ -135,23 +139,26 @@ def test_save_multiple(self):
135139

136140
def test_empty_kind(self):
137141
query = datastore.Query(kind='Post')
142+
query.ancestor = self.PARENT
138143
posts = list(query.fetch(limit=2))
139144
self.assertEqual(posts, [])
140145

141146

142147
class TestDatastoreSaveKeys(TestDatastore):
143148

144149
def test_save_key_self_reference(self):
145-
key = datastore.Key('Person', 'name')
150+
parent_key = datastore.Key('Residence', 'NewYork')
151+
key = datastore.Key('Person', 'name', parent=parent_key)
146152
entity = datastore.Entity(key=key)
147153
entity['fullName'] = u'Full name'
148154
entity['linkedTo'] = key # Self reference.
149155

150-
with datastore.Transaction():
151-
datastore.put([entity])
156+
datastore.put([entity])
152157
self.case_entities_to_delete.append(entity)
153158

154159
query = datastore.Query(kind='Person')
160+
# Adding ancestor to ensure consistency.
161+
query.ancestor = parent_key
155162
query.add_filter('linkedTo', '=', key)
156163

157164
stored_persons = list(query.fetch(limit=2))

0 commit comments

Comments
 (0)