Skip to content

Commit

Permalink
Moving _require_pb_property and _parse_pb_any_to_native to _helpers.
Browse files Browse the repository at this point in the history
  • Loading branch information
dhermes committed Jul 26, 2015
1 parent a939bd1 commit 2753740
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 168 deletions.
75 changes: 75 additions & 0 deletions gcloud_bigtable/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@
import datetime
import pytz

from gcloud_bigtable._generated import (
bigtable_cluster_service_messages_pb2 as messages_pb2)
from gcloud_bigtable._generated import bigtable_cluster_data_pb2 as data_pb2


_TYPE_URL_BASE = 'type.googleapis.com/google.bigtable.'
_ADMIN_TYPE_URL_BASE = _TYPE_URL_BASE + 'admin.cluster.v1.'
_CLUSTER_TYPE_URL = _ADMIN_TYPE_URL_BASE + 'Cluster'
_TYPE_URL_MAP = {
_CLUSTER_TYPE_URL: data_pb2.Cluster,
_ADMIN_TYPE_URL_BASE + 'CreateClusterMetadata': (
messages_pb2.CreateClusterMetadata),
_ADMIN_TYPE_URL_BASE + 'UndeleteClusterMetadata': (
messages_pb2.UndeleteClusterMetadata),
_ADMIN_TYPE_URL_BASE + 'UpdateClusterMetadata': (
messages_pb2.UpdateClusterMetadata),
}


def _pb_timestamp_to_datetime(timestamp):
"""Convert a Timestamp protobuf to a datetime object.
Expand All @@ -40,3 +58,60 @@ def _pb_timestamp_to_datetime(timestamp):
)
)
return naive_dt.replace(tzinfo=pytz.utc)


def _require_pb_property(message_pb, property_name, value):
"""Check that a property agrees with the value on the message.
:type message_pb: :class:`google.protobuf.message.Message`
:param message_pb: The message to check for ``property_name``.
:type property_name: string
:param property_name: The property value to check against.
:type value: objector :class:`NoneType`
:param value: The value to check against the cluster. If ``None``,
will not be checked.
:rtype: object
:returns: The value of ``property_name`` set on ``message_pb``.
:raises: :class:`ValueError` if the result returned from the
``message_pb`` does not contain the ``property_name``
value or if the value returned disagrees with the ``value``
passed with the request (if that value is not null).
"""
# Make sure `property_name` is set on the response.
# NOTE: HasField() doesn't work in protobuf>=3.0.0a3
all_fields = set([field.name for field in message_pb._fields])
if property_name not in all_fields:
raise ValueError('Message does not contain %s.' % (property_name,))
property_val = getattr(message_pb, property_name)
if value is None:
value = property_val
elif value != property_val:
raise ValueError('Message returned %s value disagreeing '
'with value passed in.' % (property_name,))

return value


def _parse_pb_any_to_native(any_val, expected_type=None):
"""Convert a serialized "google.protobuf.Any" value to actual type.
:type any_val: :class:`gcloud_bigtable._generated.any_pb2.Any`
:param any_val: A serialized protobuf value container.
:type expected_type: string
:param expected_type: (Optional) The type URL we expect ``any_val``
to have.
:rtype: object
:returns: The de-serialized object.
:raises: :class:`ValueError` if the ``expected_type`` does not match
the ``type_url`` on the input.
"""
if expected_type is not None and expected_type != any_val.type_url:
raise ValueError('Expected type: %s, Received: %s' % (
expected_type, any_val.type_url))
container_class = _TYPE_URL_MAP[any_val.type_url]
return container_class.FromString(any_val.value)
76 changes: 4 additions & 72 deletions gcloud_bigtable/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,19 @@
from oauth2client.client import SignedJwtAssertionCredentials
from oauth2client.client import _get_application_default_credential_from_file

from gcloud_bigtable._generated import (
bigtable_cluster_service_messages_pb2 as messages_pb2)
from gcloud_bigtable._generated import bigtable_cluster_data_pb2 as data_pb2
from gcloud_bigtable._helpers import _CLUSTER_TYPE_URL
from gcloud_bigtable._helpers import _TYPE_URL_MAP
from gcloud_bigtable._helpers import _parse_pb_any_to_native
from gcloud_bigtable._helpers import _require_pb_property
from gcloud_bigtable._logging import LOGGER
from gcloud_bigtable.cluster_connection import ClusterConnection
from gcloud_bigtable.connection import TIMEOUT_SECONDS


_TYPE_URL_BASE = 'type.googleapis.com/google.bigtable.'
_ADMIN_TYPE_URL_BASE = _TYPE_URL_BASE + 'admin.cluster.v1.'
_CLUSTER_TYPE_URL = _ADMIN_TYPE_URL_BASE + 'Cluster'
_MAX_OPERATION_WAITS = 5
_BASE_OPERATION_WAIT_TIME = 1 # in seconds
_DURATION_LOG_TEMPLATE = ('Long-running operation (metadata type: %s) '
'duration: %d.%09d seconds')
_TYPE_URL_MAP = {
_CLUSTER_TYPE_URL: data_pb2.Cluster,
_ADMIN_TYPE_URL_BASE + 'CreateClusterMetadata': (
messages_pb2.CreateClusterMetadata),
_ADMIN_TYPE_URL_BASE + 'UndeleteClusterMetadata': (
messages_pb2.UndeleteClusterMetadata),
_ADMIN_TYPE_URL_BASE + 'UpdateClusterMetadata': (
messages_pb2.UpdateClusterMetadata),
}


class Cluster(object):
Expand Down Expand Up @@ -387,63 +376,6 @@ def _wait_for_operation(cluster_connection, project_id, zone, cluster_id,
return op_result_pb


def _parse_pb_any_to_native(any_val, expected_type=None):
"""Convert a serialized "google.protobuf.Any" value to actual type.
:type any_val: :class:`gcloud_bigtable._generated.any_pb2.Any`
:param any_val: A serialized protobuf value container.
:type expected_type: string
:param expected_type: (Optional) The type URL we expect ``any_val``
to have.
:rtype: object
:returns: The de-serialized object.
:raises: :class:`ValueError` if the ``expected_type`` does not match
the ``type_url`` on the input.
"""
if expected_type is not None and expected_type != any_val.type_url:
raise ValueError('Expected type: %s, Received: %s' % (
expected_type, any_val.type_url))
container_class = _TYPE_URL_MAP[any_val.type_url]
return container_class.FromString(any_val.value)


def _require_pb_property(message_pb, property_name, value):
"""Check that a property agrees with the value on the message.
:type message_pb: :class:`google.protobuf.message.Message`
:param message_pb: The message to check for ``property_name``.
:type property_name: string
:param property_name: The property value to check against.
:type value: objector :class:`NoneType`
:param value: The value to check against the cluster. If ``None``,
will not be checked.
:rtype: object
:returns: The value of ``property_name`` set on ``message_pb``.
:raises: :class:`ValueError` if the result returned from the
``message_pb`` does not contain the ``property_name``
value or if the value returned disagrees with the ``value``
passed with the request (if that value is not null).
"""
# Make sure `property_name` is set on the response.
# NOTE: HasField() doesn't work in protobuf>=3.0.0a3
all_fields = set([field.name for field in message_pb._fields])
if property_name not in all_fields:
raise ValueError('Message does not contain %s.' % (property_name,))
property_val = getattr(message_pb, property_name)
if value is None:
value = property_val
elif value != property_val:
raise ValueError('Message returned %s value disagreeing '
'with value passed in.' % (property_name,))

return value


def _get_contents(filename):
"""Get the contents of a file.
Expand Down
2 changes: 1 addition & 1 deletion gcloud_bigtable/cluster_standalone.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from gcloud_bigtable._generated import (
bigtable_cluster_service_messages_pb2 as messages_pb2)
from gcloud_bigtable._generated import bigtable_cluster_service_pb2
from gcloud_bigtable.cluster import _require_pb_property
from gcloud_bigtable._helpers import _require_pb_property
from gcloud_bigtable.connection import TIMEOUT_SECONDS
from gcloud_bigtable.connection import make_stub

Expand Down
95 changes: 95 additions & 0 deletions gcloud_bigtable/test__helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,98 @@ def test_it(self):
# microseconds is 1234000 nanoseconds.
timestamp = Timestamp(seconds=61, nanos=1234000)
self.assertEqual(self._callFUT(timestamp), dt_stamp)


class Test__require_pb_property(unittest2.TestCase):

def _callFUT(self, message_pb, property_name, value):
from gcloud_bigtable._helpers import _require_pb_property
return _require_pb_property(message_pb, property_name, value)

def test_it(self):
from gcloud_bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
serve_nodes = 119
cluster_pb = data_pb2.Cluster(serve_nodes=serve_nodes)
result = self._callFUT(cluster_pb, 'serve_nodes', serve_nodes)
self.assertEqual(result, serve_nodes)

def test_with_null_value_passed_in(self):
from gcloud_bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
serve_nodes = None
actual_serve_nodes = 119
cluster_pb = data_pb2.Cluster(serve_nodes=actual_serve_nodes)
result = self._callFUT(cluster_pb, 'serve_nodes', serve_nodes)
self.assertEqual(result, actual_serve_nodes)

def test_with_value_unset_on_pb(self):
from gcloud_bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
serve_nodes = 119
cluster_pb = data_pb2.Cluster()
with self.assertRaises(ValueError):
self._callFUT(cluster_pb, 'serve_nodes', serve_nodes)

def test_with_values_disagreeing(self):
from gcloud_bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
serve_nodes = 119
other_serve_nodes = 1000
self.assertNotEqual(serve_nodes, other_serve_nodes)
cluster_pb = data_pb2.Cluster(serve_nodes=other_serve_nodes)
with self.assertRaises(ValueError):
self._callFUT(cluster_pb, 'serve_nodes', serve_nodes)


class Test__parse_pb_any_to_native(unittest2.TestCase):

def _callFUT(self, any_val, expected_type=None):
from gcloud_bigtable._helpers import _parse_pb_any_to_native
return _parse_pb_any_to_native(any_val, expected_type=expected_type)

def test_it(self):
from gcloud_bigtable._generated import any_pb2
from gcloud_bigtable._generated import bigtable_data_pb2 as data_pb2
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable import _helpers as MUT

type_url = 'type.googleapis.com/' + data_pb2._CELL.full_name
fake_type_url_map = {type_url: data_pb2.Cell}

cell = data_pb2.Cell(
timestamp_micros=0,
value=b'foobar',
)
any_val = any_pb2.Any(
type_url=type_url,
value=cell.SerializeToString(),
)
with _Monkey(MUT, _TYPE_URL_MAP=fake_type_url_map):
result = self._callFUT(any_val)

self.assertEqual(result, cell)

def test_unknown_type_url(self):
from gcloud_bigtable._generated import any_pb2
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable import _helpers as MUT

fake_type_url_map = {}
any_val = any_pb2.Any()
with _Monkey(MUT, _TYPE_URL_MAP=fake_type_url_map):
with self.assertRaises(KeyError):
self._callFUT(any_val)

def test_disagreeing_type_url(self):
from gcloud_bigtable._generated import any_pb2
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable import _helpers as MUT

type_url1 = 'foo'
type_url2 = 'bar'
fake_type_url_map = {type_url1: None}
any_val = any_pb2.Any(type_url=type_url2)
with _Monkey(MUT, _TYPE_URL_MAP=fake_type_url_map):
with self.assertRaises(ValueError):
self._callFUT(any_val, expected_type=type_url1)
95 changes: 0 additions & 95 deletions gcloud_bigtable/test_cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,101 +572,6 @@ def test_timeout(self):
self.assertEqual(connection._called, conn_called)


class Test__parse_pb_any_to_native(unittest2.TestCase):

def _callFUT(self, any_val, expected_type=None):
from gcloud_bigtable.cluster import _parse_pb_any_to_native
return _parse_pb_any_to_native(any_val, expected_type=expected_type)

def test_it(self):
from gcloud_bigtable._generated import any_pb2
from gcloud_bigtable._generated import bigtable_data_pb2 as data_pb2
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable import cluster as MUT

type_url = 'type.googleapis.com/' + data_pb2._CELL.full_name
fake_type_url_map = {type_url: data_pb2.Cell}

cell = data_pb2.Cell(
timestamp_micros=0,
value=b'foobar',
)
any_val = any_pb2.Any(
type_url=type_url,
value=cell.SerializeToString(),
)
with _Monkey(MUT, _TYPE_URL_MAP=fake_type_url_map):
result = self._callFUT(any_val)

self.assertEqual(result, cell)

def test_unknown_type_url(self):
from gcloud_bigtable._generated import any_pb2
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable import cluster as MUT

fake_type_url_map = {}
any_val = any_pb2.Any()
with _Monkey(MUT, _TYPE_URL_MAP=fake_type_url_map):
with self.assertRaises(KeyError):
self._callFUT(any_val)

def test_disagreeing_type_url(self):
from gcloud_bigtable._generated import any_pb2
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable import cluster as MUT

type_url1 = 'foo'
type_url2 = 'bar'
fake_type_url_map = {type_url1: None}
any_val = any_pb2.Any(type_url=type_url2)
with _Monkey(MUT, _TYPE_URL_MAP=fake_type_url_map):
with self.assertRaises(ValueError):
self._callFUT(any_val, expected_type=type_url1)


class Test__require_pb_property(unittest2.TestCase):

def _callFUT(self, message_pb, property_name, value):
from gcloud_bigtable.cluster import _require_pb_property
return _require_pb_property(message_pb, property_name, value)

def test_it(self):
from gcloud_bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
serve_nodes = 119
cluster_pb = data_pb2.Cluster(serve_nodes=serve_nodes)
result = self._callFUT(cluster_pb, 'serve_nodes', serve_nodes)
self.assertEqual(result, serve_nodes)

def test_with_null_serve_nodes(self):
from gcloud_bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
serve_nodes = None
actual_serve_nodes = 119
cluster_pb = data_pb2.Cluster(serve_nodes=actual_serve_nodes)
result = self._callFUT(cluster_pb, 'serve_nodes', serve_nodes)
self.assertEqual(result, actual_serve_nodes)

def test_with_serve_nodes_unset_on_cluster(self):
from gcloud_bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
serve_nodes = 119
cluster_pb = data_pb2.Cluster()
with self.assertRaises(ValueError):
self._callFUT(cluster_pb, 'serve_nodes', serve_nodes)

def test_with_serve_nodes_disagreeing(self):
from gcloud_bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
serve_nodes = 119
other_serve_nodes = 1000
self.assertNotEqual(serve_nodes, other_serve_nodes)
cluster_pb = data_pb2.Cluster(serve_nodes=other_serve_nodes)
with self.assertRaises(ValueError):
self._callFUT(cluster_pb, 'serve_nodes', serve_nodes)


class Test__get_contents(unittest2.TestCase):

def _callFUT(self, filename):
Expand Down

0 comments on commit 2753740

Please sign in to comment.