Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit aca137f

Browse filesBrowse files
committed
Merge pull request #1370 from dhermes/ds-system-test-namespace
Updating datastore system test to allow concurrent runs.
2 parents 9f92042 + 6d85a03 commit aca137f
Copy full SHA for aca137f

File tree

Expand file treeCollapse file tree

1 file changed

+46
-23
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+46
-23
lines changed

‎system_tests/datastore.py

Copy file name to clipboardExpand all lines: system_tests/datastore.py
+46-23Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414

1515
import datetime
1616
import os
17+
import time
1718

1819
import unittest2
1920

2021
from gcloud._helpers import UTC
2122
from gcloud import datastore
22-
from gcloud.datastore import client
23+
from gcloud.datastore import client as client_mod
2324
from gcloud.environment_vars import GCD_DATASET
2425
from gcloud.environment_vars import TESTS_DATASET
2526
from gcloud.exceptions import Conflict
@@ -29,6 +30,8 @@
2930
from system_tests import populate_datastore
3031

3132

33+
# Isolated namespace so concurrent test runs don't collide.
34+
TEST_NAMESPACE = 'ns%d' % (1000 * time.time(),)
3235
EMULATOR_DATASET = os.getenv(GCD_DATASET)
3336

3437

@@ -41,18 +44,22 @@ class Config(object):
4144
CLIENT = None
4245

4346

47+
def clone_client(client):
48+
# Fool the Client constructor to avoid creating a new connection.
49+
cloned_client = datastore.Client(project=client.project,
50+
namespace=client.namespace,
51+
http=object())
52+
cloned_client.connection = client.connection
53+
return cloned_client
54+
55+
4456
def setUpModule():
4557
if EMULATOR_DATASET is None:
46-
client.DATASET = TESTS_DATASET
47-
Config.CLIENT = datastore.Client()
58+
client_mod.DATASET = TESTS_DATASET
59+
Config.CLIENT = datastore.Client(namespace=TEST_NAMESPACE)
4860
else:
49-
Config.CLIENT = datastore.Client(project=EMULATOR_DATASET)
50-
populate_datastore.add_characters(client=Config.CLIENT)
51-
52-
53-
def tearDownModule():
54-
if EMULATOR_DATASET is not None:
55-
clear_datastore.remove_all_entities(client=Config.CLIENT)
61+
Config.CLIENT = datastore.Client(project=EMULATOR_DATASET,
62+
namespace=TEST_NAMESPACE)
5663

5764

5865
class TestDatastore(unittest2.TestCase):
@@ -87,7 +94,6 @@ class TestDatastoreSave(TestDatastore):
8794

8895
@classmethod
8996
def setUpClass(cls):
90-
super(TestDatastoreSave, cls).setUpClass()
9197
cls.PARENT = Config.CLIENT.key('Blog', 'PizzaMan')
9298

9399
def _get_post(self, id_or_name=None, post_content=None):
@@ -194,13 +200,32 @@ class TestDatastoreQuery(TestDatastore):
194200

195201
@classmethod
196202
def setUpClass(cls):
197-
super(TestDatastoreQuery, cls).setUpClass()
203+
cls.CLIENT = clone_client(Config.CLIENT)
204+
# Remove the namespace from the cloned client, since these
205+
# query tests rely on the entities to be already stored and indexed,
206+
# hence ``TEST_NAMESPACE`` set at runtime can't be used.
207+
cls.CLIENT.namespace = None
208+
209+
# In the emulator, re-populating the datastore is cheap.
210+
if EMULATOR_DATASET is not None:
211+
# Populate the datastore with the cloned client.
212+
populate_datastore.add_characters(client=cls.CLIENT)
213+
198214
cls.CHARACTERS = populate_datastore.CHARACTERS
199-
cls.ANCESTOR_KEY = Config.CLIENT.key(*populate_datastore.ANCESTOR)
215+
# Use the client for this test instead of the global.
216+
cls.ANCESTOR_KEY = cls.CLIENT.key(*populate_datastore.ANCESTOR)
217+
218+
@classmethod
219+
def tearDownClass(cls):
220+
# In the emulator, destroy the query entities.
221+
if EMULATOR_DATASET is not None:
222+
# Use the client for this test instead of the global.
223+
clear_datastore.remove_all_entities(client=cls.CLIENT)
200224

201225
def _base_query(self):
202-
return Config.CLIENT.query(kind='Character',
203-
ancestor=self.ANCESTOR_KEY)
226+
# Use the client for this test instead of the global.
227+
return self.CLIENT.query(kind='Character',
228+
ancestor=self.ANCESTOR_KEY)
204229

205230
def test_limit_queries(self):
206231
limit = 5
@@ -245,7 +270,8 @@ def test_ancestor_query(self):
245270
self.assertEqual(len(entities), expected_matches)
246271

247272
def test_query___key___filter(self):
248-
rickard_key = Config.CLIENT.key(*populate_datastore.RICKARD)
273+
# Use the client for this test instead of the global.
274+
rickard_key = self.CLIENT.key(*populate_datastore.RICKARD)
249275

250276
query = self._base_query()
251277
query.add_filter('__key__', '=', rickard_key)
@@ -377,11 +403,8 @@ def test_transaction(self):
377403
self.assertEqual(retrieved_entity, entity)
378404

379405
def test_failure_with_contention(self):
380-
contention_key = 'baz'
381-
# Fool the Client constructor to avoid creating a new connection.
382-
local_client = datastore.Client(project=Config.CLIENT.project,
383-
http=object())
384-
local_client.connection = Config.CLIENT.connection
406+
contention_prop_name = 'baz'
407+
local_client = clone_client(Config.CLIENT)
385408

386409
# Insert an entity which will be retrieved in a transaction
387410
# and updated outside it with a contentious value.
@@ -396,10 +419,10 @@ def test_failure_with_contention(self):
396419
entity_in_txn = local_client.get(key)
397420

398421
# Update the original entity outside the transaction.
399-
orig_entity[contention_key] = u'outside'
422+
orig_entity[contention_prop_name] = u'outside'
400423
Config.CLIENT.put(orig_entity)
401424

402425
# Try to update the entity which we already updated outside the
403426
# transaction.
404-
entity_in_txn[contention_key] = u'inside'
427+
entity_in_txn[contention_prop_name] = u'inside'
405428
txn.put(entity_in_txn)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.