Skip to content

Commit

Permalink
Implementing cluster_standalone.Cluster.undelete().
Browse files Browse the repository at this point in the history
In the process, re-purposing the _process_cluster_response
method as _process_operation, since Undelete returns an
operation directly rather than via a Cluster, as is done by
create and update cluster.
  • Loading branch information
dhermes committed Jul 27, 2015
1 parent f417ea8 commit 5c29830
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 39 deletions.
46 changes: 31 additions & 15 deletions gcloud_bigtable/cluster_standalone.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
bigtable_cluster_service_messages_pb2 as messages_pb2)
from gcloud_bigtable._generated import bigtable_cluster_service_pb2
from gcloud_bigtable._generated import operations_pb2
from gcloud_bigtable._helpers import _CLUSTER_CREATE_METADATA
from gcloud_bigtable._helpers import _parse_pb_any_to_native
from gcloud_bigtable._helpers import _pb_timestamp_to_datetime
from gcloud_bigtable._helpers import _require_pb_property
Expand Down Expand Up @@ -68,11 +67,12 @@ def _prepare_create_request(cluster):
)


def _process_cluster_response(cluster_response):
def _process_operation(operation_pb):
"""Processes a create protobuf response.
:type cluster_response: :class:`bigtable_cluster_data_pb2.Cluster`
:param cluster_response: The response from a CreateCluster request.
:type operation_pb: :class:`operations_pb2.Operation`
:param operation_pb: The long-running operation response from a
Create/Update/Undelete cluster request.
:rtype: tuple
:returns: A pair of an integer and datetime stamp. The integer is the ID
Expand All @@ -81,16 +81,13 @@ def _process_cluster_response(cluster_response):
:raises: :class:`ValueError` if the operation name doesn't match the
``_OPERATION_NAME_RE`` regex.
"""
match = _OPERATION_NAME_RE.match(cluster_response.current_operation.name)
match = _OPERATION_NAME_RE.match(operation_pb.name)
if match is None:
raise ValueError('Cluster create operation name was not in the '
'expected format.',
cluster_response.current_operation.name)
'expected format.', operation_pb.name)
operation_id = int(match.group('operation_id'))

request_metadata = _parse_pb_any_to_native(
cluster_response.current_operation.metadata,
expected_type=_CLUSTER_CREATE_METADATA)
request_metadata = _parse_pb_any_to_native(operation_pb.metadata)
operation_begin = _pb_timestamp_to_datetime(
request_metadata.request_time)

Expand Down Expand Up @@ -309,12 +306,12 @@ def create(self, timeout_seconds=TIMEOUT_SECONDS):
CLUSTER_ADMIN_HOST, CLUSTER_ADMIN_PORT)
with stub:
response = stub.CreateCluster.async(request_pb, timeout_seconds)
# We expect a `._generated.bigtable_cluster_data_pb2.Cluster`.
# We expect an `operations_pb2.Operation`.
cluster_pb = response.result()

self._operation_type = 'create'
self._operation_id, self._operation_begin = _process_cluster_response(
cluster_pb)
self._operation_id, self._operation_begin = _process_operation(
cluster_pb.current_operation)

def update(self, timeout_seconds=TIMEOUT_SECONDS):
"""Update this cluster.
Expand Down Expand Up @@ -348,8 +345,8 @@ def update(self, timeout_seconds=TIMEOUT_SECONDS):
cluster_pb = response.result()

self._operation_type = 'update'
self._operation_id, self._operation_begin = _process_cluster_response(
cluster_pb)
self._operation_id, self._operation_begin = _process_operation(
cluster_pb.current_operation)

def delete(self, timeout_seconds=TIMEOUT_SECONDS):
"""Delete this cluster.
Expand All @@ -365,3 +362,22 @@ def delete(self, timeout_seconds=TIMEOUT_SECONDS):
response = stub.DeleteCluster.async(request_pb, timeout_seconds)
# We expect a `._generated.empty_pb2.Empty`
response.result()

def undelete(self, timeout_seconds=TIMEOUT_SECONDS):
"""Undelete this cluster.
:type timeout_seconds: integer
:param timeout_seconds: Number of seconds for request time-out.
If not passed, defaults to ``TIMEOUT_SECONDS``.
"""
request_pb = messages_pb2.UndeleteClusterRequest(name=self.name)
stub = make_stub(self.client._credentials, CLUSTER_STUB_FACTORY,
CLUSTER_ADMIN_HOST, CLUSTER_ADMIN_PORT)
with stub:
response = stub.UndeleteCluster.async(request_pb, timeout_seconds)
# We expect a `._generated.operations_pb2.Operation`
operation_pb2 = response.result()

self._operation_type = 'undelete'
self._operation_id, self._operation_begin = _process_operation(
operation_pb2)
89 changes: 65 additions & 24 deletions gcloud_bigtable/test_cluster_standalone.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,16 @@ class _Client(object):
self.assertEqual(request_pb.cluster.serve_nodes, serve_nodes)


class Test__process_cluster_response(unittest2.TestCase):
class Test__process_operation(unittest2.TestCase):

def _callFUT(self, cluster_response):
from gcloud_bigtable.cluster_standalone import (
_process_cluster_response)
return _process_cluster_response(cluster_response)
def _callFUT(self, operation_pb):
from gcloud_bigtable.cluster_standalone import _process_operation
return _process_operation(operation_pb)

def test_it(self):
from gcloud_bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
from gcloud_bigtable._generated import (
bigtable_cluster_service_messages_pb2 as messages_pb2)
from gcloud_bigtable._generated import operations_pb2
from gcloud_bigtable._helpers import _CLUSTER_CREATE_METADATA
from gcloud_bigtable._testing import _MockCalled
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable import cluster_standalone as MUT
Expand All @@ -78,22 +74,20 @@ def test_it(self):
expected_operation_id))

current_op = operations_pb2.Operation(name=operation_name)
cluster = data_pb2.Cluster(current_operation=current_op)

request_metadata = messages_pb2.CreateClusterMetadata()
mock_parse_pb_any_to_native = _MockCalled(request_metadata)
expected_operation_begin = object()
mock_pb_timestamp_to_datetime = _MockCalled(expected_operation_begin)
with _Monkey(MUT, _parse_pb_any_to_native=mock_parse_pb_any_to_native,
_pb_timestamp_to_datetime=mock_pb_timestamp_to_datetime):
operation_id, operation_begin = self._callFUT(cluster)
operation_id, operation_begin = self._callFUT(current_op)

self.assertEqual(operation_id, expected_operation_id)
self.assertTrue(operation_begin is expected_operation_begin)

mock_parse_pb_any_to_native.check_called(
self, [(current_op.metadata,)],
[{'expected_type': _CLUSTER_CREATE_METADATA}])
self, [(current_op.metadata,)])
mock_pb_timestamp_to_datetime.check_called(
self, [(request_metadata.request_time,)])

Expand Down Expand Up @@ -354,6 +348,9 @@ def test_operation_finished_not_done(self):
self._operation_finished_helper(done=False)

def test_create(self):
from gcloud_bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
from gcloud_bigtable._generated import operations_pb2
from gcloud_bigtable._testing import _MockCalled
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable import cluster_standalone as MUT
Expand All @@ -362,9 +359,9 @@ def test_create(self):
# _prepare_create_request
request_pb = object()

# Create response_pb. Again just a mock since it is passed to
# _process_cluster_response, which we monkey patch.
response_pb = object()
# Create response_pb
current_op = operations_pb2.Operation()
response_pb = data_pb2.Cluster(current_operation=current_op)

# Create expected_result.
expected_result = None
Expand All @@ -381,9 +378,9 @@ def result_method(client):
mock_prepare_create_request = _MockCalled(request_pb)
op_id = 5678
op_begin = object()
mock_process_cluster_response = _MockCalled((op_id, op_begin))
mock_process_operation = _MockCalled((op_id, op_begin))
with _Monkey(MUT, _prepare_create_request=mock_prepare_create_request,
_process_cluster_response=mock_process_cluster_response):
_process_operation=mock_process_operation):
self._grpc_client_test_helper('CreateCluster', result_method,
request_pb, response_pb,
expected_result, PROJECT_ID)
Expand All @@ -393,11 +390,12 @@ def result_method(client):
self.assertEqual(CLUSTER_CREATED[0]._operation_id, op_id)
self.assertTrue(CLUSTER_CREATED[0]._operation_begin is op_begin)
mock_prepare_create_request.check_called(self, [(CLUSTER_CREATED[0],)])
mock_process_cluster_response.check_called(self, [(response_pb,)])
mock_process_operation.check_called(self, [(current_op,)])

def test_update(self):
from gcloud_bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
from gcloud_bigtable._generated import operations_pb2
from gcloud_bigtable._testing import _MockCalled
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable import cluster_standalone as MUT
Expand All @@ -413,9 +411,9 @@ def test_update(self):
serve_nodes=serve_nodes,
)

# Create response_pb. Again just a mock since it is passed to
# _process_cluster_response, which we monkey patch.
response_pb = object()
# Create response_pb
current_op = operations_pb2.Operation()
response_pb = data_pb2.Cluster(current_operation=current_op)

# Create expected_result.
expected_result = None
Expand All @@ -433,9 +431,9 @@ def result_method(client):

op_id = 5678
op_begin = object()
mock_process_cluster_response = _MockCalled((op_id, op_begin))
mock_process_operation = _MockCalled((op_id, op_begin))
with _Monkey(MUT,
_process_cluster_response=mock_process_cluster_response):
_process_operation=mock_process_operation):
self._grpc_client_test_helper('UpdateCluster', result_method,
request_pb, response_pb,
expected_result, PROJECT_ID)
Expand All @@ -444,7 +442,7 @@ def result_method(client):
self.assertEqual(CLUSTER_CREATED[0]._operation_type, 'update')
self.assertEqual(CLUSTER_CREATED[0]._operation_id, op_id)
self.assertTrue(CLUSTER_CREATED[0]._operation_begin is op_begin)
mock_process_cluster_response.check_called(self, [(response_pb,)])
mock_process_operation.check_called(self, [(current_op,)])

def test_delete(self):
from gcloud_bigtable._generated import (
Expand Down Expand Up @@ -472,3 +470,46 @@ def result_method(client):
self._grpc_client_test_helper('DeleteCluster', result_method,
request_pb, response_pb, expected_result,
PROJECT_ID)

def test_undelete(self):
from gcloud_bigtable._generated import (
bigtable_cluster_service_messages_pb2 as messages_pb2)
from gcloud_bigtable._generated import operations_pb2
from gcloud_bigtable._testing import _MockCalled
from gcloud_bigtable._testing import _Monkey
from gcloud_bigtable import cluster_standalone as MUT

# Create request_pb
cluster_name = ('projects/' + PROJECT_ID + '/zones/' + ZONE +
'/clusters/' + CLUSTER_ID)
request_pb = messages_pb2.UndeleteClusterRequest(name=cluster_name)

# Create response_pb
response_pb = operations_pb2.Operation()

# Create expected_result.
expected_result = None

# We must create the cluster object with the client passed in.
TEST_CASE = self
CLUSTER_CREATED = []

def result_method(client):
cluster = TEST_CASE._makeOne(ZONE, CLUSTER_ID, client)
CLUSTER_CREATED.append(cluster)
return cluster.undelete()

op_id = 5678
op_begin = object()
mock_process_operation = _MockCalled((op_id, op_begin))
with _Monkey(MUT,
_process_operation=mock_process_operation):
self._grpc_client_test_helper('UndeleteCluster', result_method,
request_pb, response_pb,
expected_result, PROJECT_ID)

self.assertEqual(len(CLUSTER_CREATED), 1)
self.assertEqual(CLUSTER_CREATED[0]._operation_type, 'undelete')
self.assertEqual(CLUSTER_CREATED[0]._operation_id, op_id)
self.assertTrue(CLUSTER_CREATED[0]._operation_begin is op_begin)
mock_process_operation.check_called(self, [(response_pb,)])

0 comments on commit 5c29830

Please sign in to comment.