diff --git a/gcloud/datastore/helpers.py b/gcloud/datastore/helpers.py index 960ba3410be1..2e8aa5f80bda 100644 --- a/gcloud/datastore/helpers.py +++ b/gcloud/datastore/helpers.py @@ -60,6 +60,8 @@ def get_protobuf_attribute_and_value(val): name, value = 'integer', long(val) # Always cast to a long. elif isinstance(val, basestring): name, value = 'string', val + else: + raise ValueError("Unknown protobuf attr type %s" % type(val)) return name + '_value', value diff --git a/gcloud/datastore/key.py b/gcloud/datastore/key.py index 6eb9a6b4c929..16e0c4ea1f66 100644 --- a/gcloud/datastore/key.py +++ b/gcloud/datastore/key.py @@ -66,7 +66,9 @@ def from_protobuf(cls, pb, dataset=None): if element.HasField('id'): element_dict['id'] = element.id - elif element.HasField('name'): + # This is safe: we expect proto objects returned will only have + # one of `name` or `id` set. + if element.HasField('name'): element_dict['name'] = element.name path.append(element_dict) diff --git a/gcloud/datastore/test_helpers.py b/gcloud/datastore/test_helpers.py index e976a475668c..0161e7798cb2 100644 --- a/gcloud/datastore/test_helpers.py +++ b/gcloud/datastore/test_helpers.py @@ -83,6 +83,9 @@ def test_unicode(self): self.assertEqual(name, 'string_value') self.assertEqual(value, u'str') + def test_object(self): + self.assertRaises(ValueError, self._callFUT, object()) + class Test_get_value_from_protobuf(unittest2.TestCase): diff --git a/gcloud/datastore/test_key.py b/gcloud/datastore/test_key.py index b722b326ac48..5fca22f24358 100644 --- a/gcloud/datastore/test_key.py +++ b/gcloud/datastore/test_key.py @@ -19,8 +19,7 @@ def _makePB(self, dataset_id=None, namespace=None, path=()): pb.partition_id.namespace = namespace for elem in path: added = pb.path_element.add() - if 'kind' in elem: - added.kind = elem['kind'] + added.kind = elem['kind'] if 'id' in elem: added.id = elem['id'] if 'name' in elem: @@ -101,9 +100,16 @@ def test_from_protobuf_w_path_in_pb(self): pb = self._makePB(_DATASET, _NAMESPACE) _PARENT = 'PARENT' _CHILD = 'CHILD' + _GRANDCHILD = 'GRANDCHILD' _ID = 1234 + _ID2 = 5678 _NAME = 'NAME' - _PATH = [{'kind': _PARENT, 'name': _NAME}, {'kind': _CHILD, 'id': _ID}] + _NAME2 = 'NAME2' + _PATH = [ + {'kind': _PARENT, 'name': _NAME}, + {'kind': _CHILD, 'id': _ID}, + {'kind': _GRANDCHILD, 'id': _ID2, 'name': _NAME2}, + ] pb = self._makePB(path=_PATH) key = self._getTargetClass().from_protobuf(pb) self.assertEqual(key.path(), _PATH) @@ -120,6 +126,13 @@ def test_to_protobuf_defaults(self): self.assertEqual(elem.name, '') self.assertEqual(elem.id, 0) + def test_to_protobuf_w_explicit_dataset_empty_id(self): + from gcloud.datastore.dataset import Dataset + dataset = Dataset('') + key = self._makeOne(dataset) + pb = key.to_protobuf() + self.assertEqual(pb.partition_id.dataset_id, '') + def test_to_protobuf_w_explicit_dataset_no_prefix(self): from gcloud.datastore.dataset import Dataset _DATASET = 'DATASET' @@ -155,14 +168,22 @@ def test_to_protobuf_w_explicit_path(self): _CHILD = 'CHILD' _ID = 1234 _NAME = 'NAME' - _PATH = [{'kind': _PARENT, 'name': _NAME}, {'kind': _CHILD, 'id': _ID}] + _PATH = [ + {'kind': _PARENT, 'name': _NAME}, + {'kind': _CHILD, 'id': _ID}, + {}, + ] key = self._makeOne(path=_PATH) pb = key.to_protobuf() elems = list(pb.path_element) + self.assertEqual(len(elems), len(_PATH)) self.assertEqual(elems[0].kind, _PARENT) self.assertEqual(elems[0].name, _NAME) self.assertEqual(elems[1].kind, _CHILD) self.assertEqual(elems[1].id, _ID) + self.assertEqual(elems[2].kind, '') + self.assertEqual(elems[2].name, '') + self.assertEqual(elems[2].id, 0) def test_from_path_empty(self): key = self._getTargetClass().from_path() @@ -262,6 +283,15 @@ def test_path_setter(self): self.assertEqual(after.namespace(), _NAMESPACE) self.assertEqual(after.path(), _PATH) + def test_kind_getter_empty_path(self): + from gcloud.datastore.dataset import Dataset + _DATASET = 'DATASET' + _NAMESPACE = 'NAMESPACE' + dataset = Dataset(_DATASET) + key = self._makeOne(dataset, _NAMESPACE) + key._path = () # edge case + self.assertEqual(key.kind(), None) + def test_kind_setter(self): from gcloud.datastore.dataset import Dataset _DATASET = 'DATASET' @@ -279,22 +309,14 @@ def test_kind_setter(self): self.assertEqual(after.namespace(), _NAMESPACE) self.assertEqual(after.path(), [{'kind': _KIND_AFTER, 'name': _NAME}]) - def test_name_setter(self): + def test_id_getter_empty_path(self): from gcloud.datastore.dataset import Dataset _DATASET = 'DATASET' _NAMESPACE = 'NAMESPACE' - _KIND = 'KIND' - _NAME_BEFORE = 'NAME_BEFORE' - _NAME_AFTER = 'NAME_AFTER' - _PATH = [{'kind': _KIND, 'name': _NAME_BEFORE}] dataset = Dataset(_DATASET) - key = self._makeOne(dataset, _NAMESPACE, _PATH) - after = key.name(_NAME_AFTER) - self.assertFalse(after is key) - self.assertTrue(isinstance(after, self._getTargetClass())) - self.assertTrue(after.dataset() is dataset) - self.assertEqual(after.namespace(), _NAMESPACE) - self.assertEqual(after.path(), [{'kind': _KIND, 'name': _NAME_AFTER}]) + key = self._makeOne(dataset, _NAMESPACE) + key._path = () # edge case + self.assertEqual(key.id(), None) def test_id_setter(self): from gcloud.datastore.dataset import Dataset @@ -313,6 +335,32 @@ def test_id_setter(self): self.assertEqual(after.namespace(), _NAMESPACE) self.assertEqual(after.path(), [{'kind': _KIND, 'id': _ID_AFTER}]) + def test_name_getter_empty_path(self): + from gcloud.datastore.dataset import Dataset + _DATASET = 'DATASET' + _NAMESPACE = 'NAMESPACE' + dataset = Dataset(_DATASET) + key = self._makeOne(dataset, _NAMESPACE) + key._path = () # edge case + self.assertEqual(key.name(), None) + + def test_name_setter(self): + from gcloud.datastore.dataset import Dataset + _DATASET = 'DATASET' + _NAMESPACE = 'NAMESPACE' + _KIND = 'KIND' + _NAME_BEFORE = 'NAME_BEFORE' + _NAME_AFTER = 'NAME_AFTER' + _PATH = [{'kind': _KIND, 'name': _NAME_BEFORE}] + dataset = Dataset(_DATASET) + key = self._makeOne(dataset, _NAMESPACE, _PATH) + after = key.name(_NAME_AFTER) + self.assertFalse(after is key) + self.assertTrue(isinstance(after, self._getTargetClass())) + self.assertTrue(after.dataset() is dataset) + self.assertEqual(after.namespace(), _NAMESPACE) + self.assertEqual(after.path(), [{'kind': _KIND, 'name': _NAME_AFTER}]) + def test_id_or_name_no_name_or_id(self): key = self._makeOne() self.assertEqual(key.id_or_name(), None) diff --git a/gcloud/datastore/test_query.py b/gcloud/datastore/test_query.py index 9219bf58d6de..4c2cb132266c 100644 --- a/gcloud/datastore/test_query.py +++ b/gcloud/datastore/test_query.py @@ -77,6 +77,26 @@ def test_ancestor_w_non_key_non_list(self): # XXX s.b. ValueError self.assertRaises(TypeError, query.ancestor, object()) + def test_ancester_wo_existing_ancestor_query_w_key_and_propfilter(self): + from gcloud.datastore.key import Key + _KIND = 'KIND' + _ID = 123 + _NAME = 'NAME' + key = Key(path=[{'kind': _KIND, 'id': _ID}]) + query = self._makeOne().filter('name =', _NAME) + after = query.ancestor(key) + self.assertFalse(after is query) + self.assertTrue(isinstance(after, self._getTargetClass())) + q_pb = after.to_protobuf() + self.assertEqual(q_pb.filter.composite_filter.operator, 1) # AND + n_pb, f_pb, = list(q_pb.filter.composite_filter.filter) + p_pb = n_pb.property_filter + self.assertEqual(p_pb.property.name, 'name') + self.assertEqual(p_pb.value.string_value, _NAME) + p_pb = f_pb.property_filter + self.assertEqual(p_pb.property.name, '__key__') + self.assertEqual(p_pb.value.key_value, key.to_protobuf()) + def test_ancester_wo_existing_ancestor_query_w_key(self): from gcloud.datastore.key import Key _KIND = 'KIND' @@ -109,7 +129,7 @@ def test_ancester_wo_existing_ancestor_query_w_list(self): self.assertEqual(p_pb.property.name, '__key__') self.assertEqual(p_pb.value.key_value, key.to_protobuf()) - def test_ancester_clears_existing_ancestor_query(self): + def test_ancester_clears_existing_ancestor_query_w_only(self): _KIND = 'KIND' _ID = 123 query = self._makeOne() @@ -120,6 +140,21 @@ def test_ancester_clears_existing_ancestor_query(self): q_pb = after.to_protobuf() self.assertEqual(list(q_pb.filter.composite_filter.filter), []) + def test_ancester_clears_existing_ancestor_query_w_others(self): + _KIND = 'KIND' + _ID = 123 + _NAME = 'NAME' + query = self._makeOne().filter('name =', _NAME) + between = query.ancestor([_KIND, _ID]) + after = between.ancestor(None) + self.assertFalse(after is query) + self.assertTrue(isinstance(after, self._getTargetClass())) + q_pb = after.to_protobuf() + n_pb, = list(q_pb.filter.composite_filter.filter) + p_pb = n_pb.property_filter + self.assertEqual(p_pb.property.name, 'name') + self.assertEqual(p_pb.value.string_value, _NAME) + def test_kind_setter_wo_existing(self): from gcloud.datastore.dataset import Dataset _DATASET = 'DATASET' diff --git a/gcloud/storage/test_acl.py b/gcloud/storage/test_acl.py index e268eb712f1c..663923663151 100644 --- a/gcloud/storage/test_acl.py +++ b/gcloud/storage/test_acl.py @@ -153,6 +153,14 @@ def test___iter___non_empty_w_roles(self): self.assertEqual(list(acl), [{'entity': '%s-%s' % (TYPE, ID), 'role': ROLE}]) + def test___iter___non_empty_w_empty_role(self): + TYPE = 'type' + ID = 'id' + acl = self._makeOne() + entity = acl.entity(TYPE, ID) + entity.grant('') + self.assertEqual(list(acl), []) + def test_entity_from_dict_allUsers(self): ROLE = 'role' acl = self._makeOne() diff --git a/gcloud/storage/test_connection.py b/gcloud/storage/test_connection.py index 213016af25c2..fcac3276c30e 100644 --- a/gcloud/storage/test_connection.py +++ b/gcloud/storage/test_connection.py @@ -491,6 +491,41 @@ def test_create_bucket_ok(self): def test_delete_bucket_defaults_miss(self): _deleted_keys = [] + class _Key(object): + pass + + class _Bucket(object): + + def __init__(self, name): + self._name = name + self.path = '/b/' + name + + PROJECT = 'project' + KEY = 'key' + conn = self._makeOne(PROJECT) + URI = '/'.join([conn.API_BASE_URL, + 'storage', + conn.API_VERSION, + 'b', + 'key?project=%s' % PROJECT, + ]) + http = conn._http = Http({'status': '200', + 'content-type': 'application/json', + }, + '{}') + + def _new_bucket(name): + return _Bucket(name) + + conn.new_bucket = _new_bucket + self.assertEqual(conn.delete_bucket(KEY), True) + self.assertEqual(_deleted_keys, []) + self.assertEqual(http._called_with['method'], 'DELETE') + self.assertEqual(http._called_with['uri'], URI) + + def test_delete_bucket_force_True(self): + _deleted_keys = [] + class _Key(object): def __init__(self, name): @@ -507,6 +542,7 @@ def __init__(self, name): def __iter__(self): return iter([_Key(x) for x in ('foo', 'bar')]) + PROJECT = 'project' KEY = 'key' conn = self._makeOne(PROJECT) @@ -523,6 +559,7 @@ def __iter__(self): def _new_bucket(name): return _Bucket(name) + conn.new_bucket = _new_bucket self.assertEqual(conn.delete_bucket(KEY, True), True) self.assertEqual(_deleted_keys, ['foo', 'bar'])