Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for instance labels #193

Merged
merged 7 commits into from Dec 15, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions google/cloud/spanner_v1/client.py
Expand Up @@ -289,6 +289,7 @@ def instance(
configuration_name=None,
display_name=None,
node_count=DEFAULT_NODE_COUNT,
labels=None,
):
"""Factory to create a instance associated with this client.

Expand All @@ -313,6 +314,9 @@ def instance(
:param node_count: (Optional) The number of nodes in the instance's
cluster; used to set up the instance's cluster.

:type labels: str
larkee marked this conversation as resolved.
Show resolved Hide resolved
:param labels: (Optional) User-assigned labels for this instance.

:rtype: :class:`~google.cloud.spanner_v1.instance.Instance`
:returns: an instance owned by this client.
"""
Expand All @@ -323,6 +327,7 @@ def instance(
node_count,
display_name,
self._emulator_host,
labels,
)

def list_instances(self, filter_="", page_size=None):
Expand Down
20 changes: 18 additions & 2 deletions google/cloud/spanner_v1/instance.py
Expand Up @@ -99,6 +99,15 @@ class Instance(object):
Cloud Console UI. (Must be between 4 and 30
characters.) If this value is not set in the
constructor, will fall back to the instance ID.

:type emulator_host: str
:param emulator_host: (Optional) The address for the Cloud Spanner emulator
that the database of this instance should connect to.
If this value is not set, the instance will connect
to the Cloud Spanner endpoint.
larkee marked this conversation as resolved.
Show resolved Hide resolved

:type labels: str
:param labels: (Optional) User-assigned labels for this instance.
"""

def __init__(
Expand All @@ -109,13 +118,17 @@ def __init__(
node_count=DEFAULT_NODE_COUNT,
display_name=None,
emulator_host=None,
labels=None,
):
self.instance_id = instance_id
self._client = client
self.configuration_name = configuration_name
self.node_count = node_count
self.display_name = display_name or instance_id
self.emulator_host = emulator_host
if labels is None:
labels = {}
self.labels = labels

def _update_from_pb(self, instance_pb):
"""Refresh self from the server-provided protobuf.
Expand All @@ -127,6 +140,7 @@ def _update_from_pb(self, instance_pb):
self.display_name = instance_pb.display_name
self.configuration_name = instance_pb.config
self.node_count = instance_pb.node_count
self.labels = instance_pb.labels

@classmethod
def from_pb(cls, instance_pb, client):
Expand Down Expand Up @@ -242,6 +256,7 @@ def create(self):
config=self.configuration_name,
display_name=self.display_name,
node_count=self.node_count,
labels=self.labels,
)
metadata = _metadata_with_prefix(self.name)

Expand Down Expand Up @@ -296,7 +311,7 @@ def update(self):

.. note::

Updates the ``display_name`` and ``node_count``. To change those
Updates the ``display_name``, ``node_count`` and ``labels``. To change those
values before updating, set them via

.. code:: python
Expand All @@ -316,8 +331,9 @@ def update(self):
config=self.configuration_name,
display_name=self.display_name,
node_count=self.node_count,
labels=self.labels,
)
field_mask = FieldMask(paths=["config", "display_name", "node_count"])
field_mask = FieldMask(paths=["config", "display_name", "node_count", "labels"])
metadata = _metadata_with_prefix(self.name)

future = api.update_instance(
Expand Down
4 changes: 4 additions & 0 deletions tests/unit/test_client.py
Expand Up @@ -37,6 +37,7 @@ class TestClient(unittest.TestCase):
INSTANCE_NAME = "%s/instances/%s" % (PATH, INSTANCE_ID)
DISPLAY_NAME = "display-name"
NODE_COUNT = 5
LABELS = {"test": "true"}
TIMEOUT_SECONDS = 80

def _get_target_class(self):
Expand Down Expand Up @@ -518,6 +519,7 @@ def test_instance_factory_defaults(self):
self.assertIsNone(instance.configuration_name)
self.assertEqual(instance.display_name, self.INSTANCE_ID)
self.assertEqual(instance.node_count, DEFAULT_NODE_COUNT)
self.assertEqual(instance.labels, {})
self.assertIs(instance._client, client)

def test_instance_factory_explicit(self):
Expand All @@ -531,13 +533,15 @@ def test_instance_factory_explicit(self):
self.CONFIGURATION_NAME,
display_name=self.DISPLAY_NAME,
node_count=self.NODE_COUNT,
labels=self.LABELS,
)

self.assertIsInstance(instance, Instance)
self.assertEqual(instance.instance_id, self.INSTANCE_ID)
self.assertEqual(instance.configuration_name, self.CONFIGURATION_NAME)
self.assertEqual(instance.display_name, self.DISPLAY_NAME)
self.assertEqual(instance.node_count, self.NODE_COUNT)
self.assertEqual(instance.labels, self.LABELS)
self.assertIs(instance._client, client)

def test_list_instances(self):
Expand Down
28 changes: 26 additions & 2 deletions tests/unit/test_instance.py
Expand Up @@ -38,6 +38,7 @@ class TestInstance(unittest.TestCase):
TIMEOUT_SECONDS = 1
DATABASE_ID = "database_id"
DATABASE_NAME = "%s/databases/%s" % (INSTANCE_NAME, DATABASE_ID)
LABELS = {"test": "true"}

def _getTargetClass(self):
from google.cloud.spanner_v1.instance import Instance
Expand All @@ -57,6 +58,7 @@ def test_constructor_defaults(self):
self.assertIs(instance.configuration_name, None)
self.assertEqual(instance.node_count, DEFAULT_NODE_COUNT)
self.assertEqual(instance.display_name, self.INSTANCE_ID)
self.assertEqual(instance.labels, {})

def test_constructor_non_default(self):
DISPLAY_NAME = "display_name"
Expand All @@ -68,12 +70,14 @@ def test_constructor_non_default(self):
configuration_name=self.CONFIG_NAME,
node_count=self.NODE_COUNT,
display_name=DISPLAY_NAME,
labels=self.LABELS,
)
self.assertEqual(instance.instance_id, self.INSTANCE_ID)
self.assertIs(instance._client, client)
self.assertEqual(instance.configuration_name, self.CONFIG_NAME)
self.assertEqual(instance.node_count, self.NODE_COUNT)
self.assertEqual(instance.display_name, DISPLAY_NAME)
self.assertEqual(instance.labels, self.LABELS)

def test_copy(self):
DISPLAY_NAME = "display_name"
Expand Down Expand Up @@ -145,6 +149,7 @@ def test_from_pb_success(self):
name=self.INSTANCE_NAME,
config=self.CONFIG_NAME,
display_name=self.INSTANCE_ID,
labels=self.LABELS,
)

klass = self._getTargetClass()
Expand All @@ -153,13 +158,22 @@ def test_from_pb_success(self):
self.assertEqual(instance._client, client)
self.assertEqual(instance.instance_id, self.INSTANCE_ID)
self.assertEqual(instance.configuration_name, self.CONFIG_NAME)
self.assertEqual(instance.labels, self.LABELS)

def test_name_property(self):
client = _Client(project=self.PROJECT)

instance = self._make_one(self.INSTANCE_ID, client, self.CONFIG_NAME)
self.assertEqual(instance.name, self.INSTANCE_NAME)

def test_labels_property(self):
client = _Client(project=self.PROJECT)

instance = self._make_one(
self.INSTANCE_ID, client, self.CONFIG_NAME, labels=self.LABELS
)
self.assertEqual(instance.labels, self.LABELS)

def test___eq__(self):
client = object()
instance1 = self._make_one(self.INSTANCE_ID, client, self.CONFIG_NAME)
Expand Down Expand Up @@ -231,6 +245,7 @@ def test_create_success(self):
configuration_name=self.CONFIG_NAME,
display_name=self.DISPLAY_NAME,
node_count=self.NODE_COUNT,
labels=self.LABELS,
)

future = instance.create()
Expand All @@ -244,6 +259,7 @@ def test_create_success(self):
self.assertEqual(instance.config, self.CONFIG_NAME)
self.assertEqual(instance.display_name, self.DISPLAY_NAME)
self.assertEqual(instance.node_count, self.NODE_COUNT)
self.assertEqual(instance.labels, self.LABELS)
self.assertEqual(metadata, [("google-cloud-resource-prefix", instance.name)])

def test_exists_instance_grpc_error(self):
Expand Down Expand Up @@ -327,6 +343,7 @@ def test_reload_success(self):
config=self.CONFIG_NAME,
display_name=self.DISPLAY_NAME,
node_count=self.NODE_COUNT,
labels=self.LABELS,
)
api = client.instance_admin_api = _FauxInstanceAdminAPI(
_get_instance_response=instance_pb
Expand All @@ -338,6 +355,7 @@ def test_reload_success(self):
self.assertEqual(instance.configuration_name, self.CONFIG_NAME)
self.assertEqual(instance.node_count, self.NODE_COUNT)
self.assertEqual(instance.display_name, self.DISPLAY_NAME)
self.assertEqual(instance.labels, self.LABELS)

name, metadata = api._got_instance
self.assertEqual(name, self.INSTANCE_NAME)
Expand Down Expand Up @@ -371,7 +389,9 @@ def test_update_not_found(self):
instance.update()

instance, field_mask, metadata = api._updated_instance
self.assertEqual(field_mask.paths, ["config", "display_name", "node_count"])
self.assertEqual(
field_mask.paths, ["config", "display_name", "node_count", "labels"]
)
self.assertEqual(instance.name, self.INSTANCE_NAME)
self.assertEqual(instance.config, self.CONFIG_NAME)
self.assertEqual(instance.display_name, self.INSTANCE_ID)
Expand All @@ -390,18 +410,22 @@ def test_update_success(self):
configuration_name=self.CONFIG_NAME,
node_count=self.NODE_COUNT,
display_name=self.DISPLAY_NAME,
labels=self.LABELS,
)

future = instance.update()

self.assertIs(future, op_future)

instance, field_mask, metadata = api._updated_instance
self.assertEqual(field_mask.paths, ["config", "display_name", "node_count"])
self.assertEqual(
field_mask.paths, ["config", "display_name", "node_count", "labels"]
)
self.assertEqual(instance.name, self.INSTANCE_NAME)
self.assertEqual(instance.config, self.CONFIG_NAME)
self.assertEqual(instance.display_name, self.DISPLAY_NAME)
self.assertEqual(instance.node_count, self.NODE_COUNT)
self.assertEqual(instance.labels, self.LABELS)
self.assertEqual(metadata, [("google-cloud-resource-prefix", instance.name)])

def test_delete_grpc_error(self):
Expand Down