Skip to content

Commit

Permalink
Removing cover.sh and folding into tox config.
Browse files Browse the repository at this point in the history
This is to make the tox config friendlier to Windows
and other non-bash shells.

Towards googleapis#1123.
  • Loading branch information
dhermes committed Nov 20, 2015
2 parents cec15ac + 9c18dad commit 77cbba0
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 36 deletions.
33 changes: 29 additions & 4 deletions gcloud/bigtable/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@
In the hierarchy of API concepts
* a :class:`Client` owns a :class:`.Cluster`
* a :class:`.Cluster` owns a :class:`Table <gcloud_bigtable.table.Table>`
* a :class:`Table <gcloud_bigtable.table.Table>` owns a
* a :class:`.Cluster` owns a :class:`Table <gcloud.bigtable.table.Table>`
* a :class:`Table <gcloud.bigtable.table.Table>` owns a
:class:`ColumnFamily <.column_family.ColumnFamily>`
* a :class:`Table <gcloud_bigtable.table.Table>` owns a :class:`Row <.row.Row>`
* a :class:`Table <gcloud.bigtable.table.Table>` owns a :class:`Row <.row.Row>`
(and all the cells in the row)
"""


import copy

from gcloud.bigtable._generated import bigtable_cluster_data_pb2 as data_pb2
from gcloud.bigtable._generated import bigtable_cluster_service_pb2
from gcloud.bigtable._generated import (
bigtable_cluster_service_messages_pb2 as messages_pb2)
from gcloud.bigtable._generated import bigtable_service_pb2
from gcloud.bigtable._generated import bigtable_table_service_pb2
from gcloud.bigtable._generated import operations_pb2
Expand Down Expand Up @@ -192,7 +195,7 @@ def project_name(self):
The project name is of the form
``"projects/{project_id}"``
``"projects/{project}"``
:rtype: str
:returns: The project name to be used with the Cloud Bigtable Admin
Expand Down Expand Up @@ -375,3 +378,25 @@ def cluster(self, zone, cluster_id, display_name=None, serve_nodes=3):
"""
return Cluster(zone, cluster_id, self,
display_name=display_name, serve_nodes=serve_nodes)

def list_zones(self):
"""Lists zones associated with project.
:rtype: list
:returns: The names (as :class:`str`) of the zones
:raises: :class:`ValueError <exceptions.ValueError>` if one of the
zones is not in ``OK`` state.
"""
request_pb = messages_pb2.ListZonesRequest(name=self.project_name)
response = self._cluster_stub.ListZones.async(request_pb,
self.timeout_seconds)
# We expect a `.messages_pb2.ListZonesResponse`
list_zones_response = response.result()

result = []
for zone in list_zones_response.zones:
if zone.status != data_pb2.Zone.OK:
raise ValueError('Zone %s not in OK state' % (
zone.display_name,))
result.append(zone.display_name)
return result
2 changes: 1 addition & 1 deletion gcloud/bigtable/column_family.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class ColumnFamily(object):
:param column_family_id: The ID of the column family. Must be of the
form ``[_a-zA-Z0-9][-_.a-zA-Z0-9]*``.
:type table: :class:`Table <gcloud_bigtable.table.Table>`
:type table: :class:`Table <gcloud.bigtable.table.Table>`
:param table: The table that owns the column family.
"""

Expand Down
2 changes: 1 addition & 1 deletion gcloud/bigtable/row.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Row(object):
:type row_key: bytes
:param row_key: The key for the current row.
:type table: :class:`Table <gcloud_bigtable.table.Table>`
:type table: :class:`Table <gcloud.bigtable.table.Table>`
:param table: The table that owns the row.
"""

Expand Down
93 changes: 92 additions & 1 deletion gcloud/bigtable/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,59 @@ def test_cluster_factory(self):
self.assertEqual(cluster.serve_nodes, serve_nodes)
self.assertTrue(cluster._client is client)

def _list_zones_helper(self, zone_status):
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)

credentials = _Credentials()
project = 'PROJECT'
timeout_seconds = 281330
client = self._makeOne(project=project, credentials=credentials,
admin=True, timeout_seconds=timeout_seconds)

# Create request_pb
request_pb = messages_pb2.ListZonesRequest(
name='projects/' + project,
)

# Create response_pb
zone1 = 'foo'
zone2 = 'bar'
response_pb = messages_pb2.ListZonesResponse(
zones=[
data_pb2.Zone(display_name=zone1, status=zone_status),
data_pb2.Zone(display_name=zone2, status=zone_status),
],
)

# Patch the stub used by the API method.
client._cluster_stub_internal = stub = _FakeStub(response_pb)

# Create expected_result.
expected_result = [zone1, zone2]

# Perform the method and check the result.
result = client.list_zones()
self.assertEqual(result, expected_result)
self.assertEqual(stub.method_calls, [(
'ListZones',
(request_pb, timeout_seconds),
{},
)])

def test_list_zones(self):
from gcloud.bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
self._list_zones_helper(data_pb2.Zone.OK)

def test_list_zones_failure(self):
from gcloud.bigtable._generated import (
bigtable_cluster_data_pb2 as data_pb2)
with self.assertRaises(ValueError):
self._list_zones_helper(data_pb2.Zone.EMERGENCY_MAINENANCE)


class _Credentials(object):

Expand All @@ -511,8 +564,11 @@ def __eq__(self, other):


class _FakeStub(object):
"""Acts as a gPRC stub."""

def __init__(self):
def __init__(self, *results):
self.results = results
self.method_calls = []
self._entered = 0
self._exited = []

Expand All @@ -523,3 +579,38 @@ def __enter__(self):
def __exit__(self, exc_type, exc_val, exc_tb):
self._exited.append((exc_type, exc_val, exc_tb))
return True

def __getattr__(self, name):
# We need not worry about attributes set in constructor
# since __getattribute__ will handle them.
return _MethodMock(name, self)


class _MethodMock(object):
"""Mock for :class:`grpc.framework.alpha._reexport._UnaryUnarySyncAsync`.
May need to be callable and needs to (in our use) have an
``async`` method.
"""

def __init__(self, name, factory):
self._name = name
self._factory = factory

def async(self, *args, **kwargs):
"""Async method meant to mock a gRPC stub request."""
self._factory.method_calls.append((self._name, args, kwargs))
curr_result, self._factory.results = (self._factory.results[0],
self._factory.results[1:])
return _AsyncResult(curr_result)


class _AsyncResult(object):
"""Result returned from a ``_MethodMock.async`` call."""

def __init__(self, result):
self._result = result

def result(self):
"""Result method on an asyc object."""
return self._result
27 changes: 0 additions & 27 deletions scripts/cover.sh

This file was deleted.

13 changes: 11 additions & 2 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,29 @@ deps =
protobuf>=3.0.0a3
setenv =
PYTHONPATH = {toxinidir}/_testing
covercmd =
nosetests \
--ignore-files=run_system_test\.py \
--with-coverage \
--cover-package=gcloud \
--cover-erase \
--cover-tests \
--cover-branches \
--nocapture

[testenv:cover]
basepython =
python2.7
commands =
{toxinidir}/scripts/cover.sh --cover-min-percentage=100
{[testenv]covercmd} --cover-min-percentage=100
deps =
{[testenv]deps}
coverage

[testenv:coveralls]
basepython = {[testenv:cover]basepython}
commands =
{toxinidir}/scripts/cover.sh
{[testenv]covercmd}
coveralls
deps =
{[testenv:cover]deps}
Expand Down

0 comments on commit 77cbba0

Please sign in to comment.