diff --git a/datastore/api/snippets_test.py b/datastore/api/snippets_test.py index 973c18fb1a2d..9bb65dbbc3d1 100644 --- a/datastore/api/snippets_test.py +++ b/datastore/api/snippets_test.py @@ -11,291 +11,269 @@ # See the License for the specific language governing permissions and # limitations under the License. -from functools import wraps import time from gcloud import datastore +import pytest import snippets -from testing import CloudTest, mark_flaky +from testing import mark_flaky -def eventually_consistent(f): - @wraps(f) - def inner(self, *args, **kwargs): - # This is pretty hacky, but make datastore wait 1s after any - # put operation to in order to account for eventual consistency. - original_put_multi = self.client.put_multi +class CleanupClient(datastore.Client): + def __init__(self, *args, **kwargs): + super(CleanupClient, self).__init__(*args, **kwargs) + self.entities_to_delete = [] + self.keys_to_delete = [] - def put_multi(*args, **kwargs): - result = original_put_multi(*args, **kwargs) - time.sleep(1) - return result + def cleanup(self): + with self.batch(): + self.delete_multi( + [x.key for x in self.entities_to_delete] + + self.keys_to_delete) - self.client.put_multi = put_multi - - try: - result = f(self, *args, **kwargs) - finally: - self.client.put_multi = original_put_multi +# This is pretty hacky, but make datastore wait 1s after any +# put operation to in order to account for eventual consistency. +class WaitingClient(CleanupClient): + def put_multi(self, *args, **kwargs): + result = super(WaitingClient, self).put_multi(*args, **kwargs) + time.sleep(1) return result - return inner -@mark_flaky -class DatastoreSnippetsTest(CloudTest): +@pytest.yield_fixture +def client(cloud_config): + client = CleanupClient(cloud_config.GCLOUD_PROJECT) + yield client + client.cleanup() + - def setUp(self): - super(DatastoreSnippetsTest, self).setUp() - self.client = datastore.Client(self.config.GCLOUD_PROJECT) - self.to_delete_entities = [] - self.to_delete_keys = [] +@pytest.yield_fixture +def waiting_client(cloud_config): + client = WaitingClient(cloud_config.GCLOUD_PROJECT) + yield client + client.cleanup() - def tearDown(self): - super(DatastoreSnippetsTest, self).tearDown() - with self.client.batch(): - self.client.delete_multi( - [x.key for x in self.to_delete_entities] + self.to_delete_keys) +@mark_flaky +class TestDatastoreSnippets: # These tests mostly just test the absence of exceptions. + def test_incomplete_key(self, client): + assert snippets.incomplete_key(client) + + def test_named_key(self, client): + assert snippets.named_key(client) + + def test_key_with_parent(self, client): + assert snippets.key_with_parent(client) + + def test_key_with_multilevel_parent(self, client): + assert snippets.key_with_multilevel_parent(client) + + def test_basic_entity(self, client): + assert snippets.basic_entity(client) + + def test_entity_with_parent(self, client): + assert snippets.entity_with_parent(client) + + def test_properties(self, client): + assert snippets.properties(client) + + def test_array_value(self, client): + assert snippets.array_value(client) + + def test_upsert(self, client): + task = snippets.upsert(client) + client.entities_to_delete.append(task) + assert task + + def test_insert(self, client): + task = snippets.insert(client) + client.entities_to_delete.append(task) + assert task + + def test_update(self, client): + task = snippets.insert(client) + client.entities_to_delete.append(task) + assert task + + def test_lookup(self, client): + task = snippets.lookup(client) + client.entities_to_delete.append(task) + assert task + + def test_delete(self, client): + snippets.delete(client) + + def test_batch_upsert(self, client): + tasks = snippets.batch_upsert(client) + client.entities_to_delete.extend(tasks) + assert tasks + + def test_batch_lookup(self, client): + tasks = snippets.batch_lookup(client) + client.entities_to_delete.extend(tasks) + assert tasks + + def test_batch_delete(self, client): + snippets.batch_delete(client) + + def test_unindexed_property_query(self, waiting_client): + tasks = snippets.unindexed_property_query(waiting_client) + waiting_client.entities_to_delete.extend(tasks) + assert tasks + + def test_basic_query(self, waiting_client): + tasks = snippets.basic_query(waiting_client) + waiting_client.entities_to_delete.extend(tasks) + assert tasks + + def test_projection_query(self, waiting_client): + priorities, percents = snippets.projection_query(waiting_client) + waiting_client.entities_to_delete.extend( + waiting_client.query(kind='Task').fetch()) + assert priorities + assert percents + + def test_ancestor_query(self, client): + tasks = snippets.ancestor_query(client) + client.entities_to_delete.extend(tasks) + assert tasks + + def test_run_query(self, client): + snippets.run_query(client) - def test_incomplete_key(self): - self.assertTrue( - snippets.incomplete_key(self.client)) - - def test_named_key(self): - self.assertTrue( - snippets.named_key(self.client)) - - def test_key_with_parent(self): - self.assertTrue( - snippets.key_with_parent(self.client)) - - def test_key_with_multilevel_parent(self): - self.assertTrue( - snippets.key_with_multilevel_parent(self.client)) - - def test_basic_entity(self): - self.assertTrue( - snippets.basic_entity(self.client)) - - def test_entity_with_parent(self): - self.assertTrue( - snippets.entity_with_parent(self.client)) - - def test_properties(self): - self.assertTrue( - snippets.properties(self.client)) - - def test_array_value(self): - self.assertTrue( - snippets.array_value(self.client)) - - def test_upsert(self): - task = snippets.upsert(self.client) - self.to_delete_entities.append(task) - self.assertTrue(task) - - def test_insert(self): - task = snippets.insert(self.client) - self.to_delete_entities.append(task) - self.assertTrue(task) - - def test_update(self): - task = snippets.insert(self.client) - self.to_delete_entities.append(task) - self.assertTrue(task) - - def test_lookup(self): - task = snippets.lookup(self.client) - self.to_delete_entities.append(task) - self.assertTrue(task) - - def test_delete(self): - snippets.delete(self.client) - - def test_batch_upsert(self): - tasks = snippets.batch_upsert(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - def test_batch_lookup(self): - tasks = snippets.batch_lookup(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - def test_batch_delete(self): - snippets.batch_delete(self.client) - - @eventually_consistent - def test_unindexed_property_query(self): - tasks = snippets.unindexed_property_query(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - @eventually_consistent - def test_basic_query(self): - tasks = snippets.basic_query(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - @eventually_consistent - def test_projection_query(self): - priorities, percents = snippets.projection_query(self.client) - self.to_delete_entities.extend(self.client.query(kind='Task').fetch()) - self.assertTrue(priorities) - self.assertTrue(percents) - - def test_ancestor_query(self): - tasks = snippets.ancestor_query(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - @eventually_consistent - def test_run_query(self): - snippets.run_query(self.client) - - @eventually_consistent - def test_cursor_paging(self): + def test_cursor_paging(self, waiting_client): for n in range(6): - self.to_delete_entities.append( - snippets.insert(self.client)) + waiting_client.entities_to_delete.append( + snippets.insert(waiting_client)) page_one, cursor_one, page_two, cursor_two = snippets.cursor_paging( - self.client) - - self.assertTrue(len(page_one) == 5) - self.assertTrue(len(page_two) == 1) - self.assertTrue(cursor_one) - self.assertTrue(cursor_two) - - @eventually_consistent - def test_property_filter(self): - tasks = snippets.property_filter(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - @eventually_consistent - def test_composite_filter(self): - tasks = snippets.composite_filter(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - @eventually_consistent - def test_key_filter(self): - tasks = snippets.key_filter(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - @eventually_consistent - def test_ascending_sort(self): - tasks = snippets.ascending_sort(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - @eventually_consistent - def test_descending_sort(self): - tasks = snippets.descending_sort(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - @eventually_consistent - def test_multi_sort(self): - tasks = snippets.multi_sort(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - @eventually_consistent - def test_keys_only_query(self): - keys = snippets.keys_only_query(self.client) - self.to_delete_entities.extend(self.client.query(kind='Task').fetch()) - self.assertTrue(keys) - - @eventually_consistent - def test_distinct_query(self): - tasks = snippets.distinct_query(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - @eventually_consistent - def test_distinct_on_query(self): - tasks = snippets.distinct_on_query(self.client) - self.to_delete_entities.extend(tasks) - self.assertTrue(tasks) - - def test_kindless_query(self): - tasks = snippets.kindless_query(self.client) - self.assertTrue(tasks) - - def test_inequality_range(self): - snippets.inequality_range(self.client) - - def test_inequality_invalid(self): - snippets.inequality_invalid(self.client) - - def test_equal_and_inequality_range(self): - snippets.equal_and_inequality_range(self.client) - - def test_inequality_sort(self): - snippets.inequality_sort(self.client) - - def test_inequality_sort_invalid_not_same(self): - snippets.inequality_sort_invalid_not_same(self.client) - - def test_inequality_sort_invalid_not_first(self): - snippets.inequality_sort_invalid_not_first(self.client) - - def test_array_value_inequality_range(self): - snippets.array_value_inequality_range(self.client) - - def test_array_value_equality(self): - snippets.array_value_equality(self.client) - - def test_exploding_properties(self): - task = snippets.exploding_properties(self.client) - self.assertTrue(task) - - def test_transactional_update(self): - keys = snippets.transactional_update(self.client) - self.to_delete_keys.extend(keys) - - def test_transactional_get_or_create(self): - task = snippets.transactional_get_or_create(self.client) - self.to_delete_entities.append(task) - self.assertTrue(task) - - def transactional_single_entity_group_read_only(self): + waiting_client) + + assert len(page_one) == 5 + assert len(page_two) == 1 + assert cursor_one + assert cursor_two + + def test_property_filter(self, waiting_client): + tasks = snippets.property_filter(waiting_client) + waiting_client.entities_to_delete.extend(tasks) + assert tasks + + def test_composite_filter(self, waiting_client): + tasks = snippets.composite_filter(waiting_client) + waiting_client.entities_to_delete.extend(tasks) + assert tasks + + def test_key_filter(self, waiting_client): + tasks = snippets.key_filter(waiting_client) + waiting_client.entities_to_delete.extend(tasks) + assert tasks + + def test_ascending_sort(self, waiting_client): + tasks = snippets.ascending_sort(waiting_client) + waiting_client.entities_to_delete.extend(tasks) + assert tasks + + def test_descending_sort(self, waiting_client): + tasks = snippets.descending_sort(waiting_client) + waiting_client.entities_to_delete.extend(tasks) + assert tasks + + def test_multi_sort(self, waiting_client): + tasks = snippets.multi_sort(waiting_client) + waiting_client.entities_to_delete.extend(tasks) + assert tasks + + def test_keys_only_query(self, waiting_client): + keys = snippets.keys_only_query(waiting_client) + waiting_client.entities_to_delete.extend( + waiting_client.query(kind='Task').fetch()) + assert keys + + def test_distinct_query(self, waiting_client): + tasks = snippets.distinct_query(waiting_client) + waiting_client.entities_to_delete.extend(tasks) + assert tasks + + def test_distinct_on_query(self, waiting_client): + tasks = snippets.distinct_on_query(waiting_client) + waiting_client.entities_to_delete.extend(tasks) + assert tasks + + def test_kindless_query(self, client): + tasks = snippets.kindless_query(client) + assert tasks + + def test_inequality_range(self, client): + snippets.inequality_range(client) + + def test_inequality_invalid(self, client): + snippets.inequality_invalid(client) + + def test_equal_and_inequality_range(self, client): + snippets.equal_and_inequality_range(client) + + def test_inequality_sort(self, client): + snippets.inequality_sort(client) + + def test_inequality_sort_invalid_not_same(self, client): + snippets.inequality_sort_invalid_not_same(client) + + def test_inequality_sort_invalid_not_first(self, client): + snippets.inequality_sort_invalid_not_first(client) + + def test_array_value_inequality_range(self, client): + snippets.array_value_inequality_range(client) + + def test_array_value_equality(self, client): + snippets.array_value_equality(client) + + def test_exploding_properties(self, client): + task = snippets.exploding_properties(client) + assert task + + def test_transactional_update(self, client): + keys = snippets.transactional_update(client) + client.keys_to_delete.extend(keys) + + def test_transactional_get_or_create(self, client): + task = snippets.transactional_get_or_create(client) + client.entities_to_delete.append(task) + assert task + + def transactional_single_entity_group_read_only(self, client): task_list, tasks_in_list = \ - snippets.transactional_single_entity_group_read_only(self.client) - self.to_delete_entities.append(task_list) - self.to_delete_entities.extend(tasks_in_list) - self.assertTrue(task_list) - self.assertTrue(tasks_in_list) - - @eventually_consistent - def test_namespace_run_query(self): + snippets.transactional_single_entity_group_read_only(client) + client.entities_to_delete.append(task_list) + client.entities_to_delete.extend(tasks_in_list) + assert task_list + assert tasks_in_list + + def test_namespace_run_query(self, waiting_client): all_namespaces, filtered_namespaces = snippets.namespace_run_query( - self.client) - self.assertTrue(all_namespaces) - self.assertTrue(filtered_namespaces) - self.assertTrue('google' in filtered_namespaces) - - @eventually_consistent - def test_kind_run_query(self): - kinds = snippets.kind_run_query(self.client) - self.to_delete_entities.extend(self.client.query(kind='Task').fetch()) - self.assertTrue(kinds) - self.assertTrue('Task' in kinds) - - @eventually_consistent - def test_property_run_query(self): - kinds = snippets.property_run_query(self.client) - self.to_delete_entities.extend(self.client.query(kind='Task').fetch()) - self.assertTrue(kinds) - self.assertTrue('Task' in kinds) - - @eventually_consistent - def test_property_by_kind_run_query(self): - reprs = snippets.property_by_kind_run_query(self.client) - self.to_delete_entities.extend(self.client.query(kind='Task').fetch()) - self.assertTrue(reprs) + waiting_client) + assert all_namespaces + assert filtered_namespaces + assert 'google' in filtered_namespaces + + def test_kind_run_query(self, waiting_client): + kinds = snippets.kind_run_query(waiting_client) + waiting_client.entities_to_delete.extend( + waiting_client.query(kind='Task').fetch()) + assert kinds + assert 'Task' in kinds + + def test_property_run_query(self, waiting_client): + kinds = snippets.property_run_query(waiting_client) + waiting_client.entities_to_delete.extend( + waiting_client.query(kind='Task').fetch()) + assert kinds + assert 'Task' in kinds + + def test_property_by_kind_run_query(self, waiting_client): + reprs = snippets.property_by_kind_run_query(waiting_client) + waiting_client.entities_to_delete.extend( + waiting_client.query(kind='Task').fetch()) + assert reprs diff --git a/datastore/api/tasks_test.py b/datastore/api/tasks_test.py index 528a40702e50..983589970300 100644 --- a/datastore/api/tasks_test.py +++ b/datastore/api/tasks_test.py @@ -12,58 +12,69 @@ # limitations under the License. from gcloud import datastore +import pytest import tasks -from testing import CloudTest, mark_flaky +from testing import mark_flaky + + +@pytest.yield_fixture +def client(cloud_config): + client = datastore.Client(cloud_config.GCLOUD_PROJECT) + + yield client + + # Delete anything created during the test. + with client.batch(): + client.delete_multi( + [x.key for x in client.query(kind='Task').fetch()]) @mark_flaky -class DatastoreTasksTest(CloudTest): - - def setUp(self): - super(DatastoreTasksTest, self).setUp() - self.client = datastore.Client(self.config.GCLOUD_PROJECT) - - def tearDown(self): - super(DatastoreTasksTest, self).tearDown() - with self.client.batch(): - self.client.delete_multi( - [x.key for x in self.client.query(kind='Task').fetch()]) - - def test_create_client(self): - tasks.create_client(self.config.GCLOUD_PROJECT) - - def test_add_task(self): - task_key = tasks.add_task(self.client, 'Test task') - task = self.client.get(task_key) - self.assertTrue(task) - self.assertEqual(task['description'], 'Test task') - - def test_mark_done(self): - task_key = tasks.add_task(self.client, 'Test task') - tasks.mark_done(self.client, task_key.id) - task = self.client.get(task_key) - self.assertTrue(task) - self.assertTrue(task['done']) - - def test_list_tasks(self): - task1_key = tasks.add_task(self.client, 'Test task 1') - task2_key = tasks.add_task(self.client, 'Test task 2') - task_list = tasks.list_tasks(self.client) - self.assertEqual([x.key for x in task_list], [task1_key, task2_key]) - - def test_delete_task(self): - task_key = tasks.add_task(self.client, 'Test task 1') - tasks.delete_task(self.client, task_key.id) - self.assertIsNone(self.client.get(task_key)) - - def test_format_tasks(self): - task1_key = tasks.add_task(self.client, 'Test task 1') - tasks.add_task(self.client, 'Test task 2') - tasks.mark_done(self.client, task1_key.id) - - output = tasks.format_tasks(tasks.list_tasks(self.client)) - - self.assertTrue('Test task 1' in output) - self.assertTrue('Test task 2' in output) - self.assertTrue('done' in output) - self.assertTrue('created' in output) +def test_create_client(cloud_config): + tasks.create_client(cloud_config.GCLOUD_PROJECT) + + +@mark_flaky +def test_add_task(client): + task_key = tasks.add_task(client, 'Test task') + task = client.get(task_key) + assert task + assert task['description'] == 'Test task' + + +@mark_flaky +def test_mark_done(client): + task_key = tasks.add_task(client, 'Test task') + tasks.mark_done(client, task_key.id) + task = client.get(task_key) + assert task + assert task['done'] + + +@mark_flaky +def test_list_tasks(client): + task1_key = tasks.add_task(client, 'Test task 1') + task2_key = tasks.add_task(client, 'Test task 2') + task_list = tasks.list_tasks(client) + assert [x.key for x in task_list] == [task1_key, task2_key] + + +@mark_flaky +def test_delete_task(client): + task_key = tasks.add_task(client, 'Test task 1') + tasks.delete_task(client, task_key.id) + assert client.get(task_key) is None + + +@mark_flaky +def test_format_tasks(client): + task1_key = tasks.add_task(client, 'Test task 1') + tasks.add_task(client, 'Test task 2') + tasks.mark_done(client, task1_key.id) + + output = tasks.format_tasks(tasks.list_tasks(client)) + + assert 'Test task 1' in output + assert 'Test task 2' in output + assert 'done' in output + assert 'created' in output diff --git a/scripts/run-tests.py b/scripts/run-tests.py index 524de1c445fb..e5f6fbd04dde 100755 --- a/scripts/run-tests.py +++ b/scripts/run-tests.py @@ -15,6 +15,7 @@ # limitations under the License. import argparse +import os import subprocess import sys @@ -40,8 +41,9 @@ def main(): per_directory_args = [] if args.junit: - per_directory_args.append( - '--junitxml={}/junit.xml'.format(directory)) + if os.path.isdir(directory): + per_directory_args.append( + '--junitxml={}/junit.xml'.format(directory)) # We could use pytest.main, however, we need import isolatation between # test runs. Without using subprocess, any test files that are named