Skip to content

Commit

Permalink
Add 'BucketNotification.{reload,exists}' API wrappers. (#3986)
Browse files Browse the repository at this point in the history
Toward #3956.
  • Loading branch information
tseaver committed Sep 18, 2017
1 parent 0a2a40f commit 7190c86
Show file tree
Hide file tree
Showing 2 changed files with 194 additions and 43 deletions.
61 changes: 61 additions & 0 deletions storage/google/cloud/storage/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

"""Support for bucket notification resources."""

from google.api.core.exceptions import NotFound


OBJECT_FINALIZE_EVENT_TYPE = 'OBJECT_FINALIZE'
OBJECT_METADATA_UPDATE_EVENT_TYPE = 'OBJECT_METADATA_UPDATE'
OBJECT_DELETE_EVENT_TYPE = 'OBJECT_DELETE'
Expand Down Expand Up @@ -161,6 +164,15 @@ def _require_client(self, client):
client = self.client
return client

def _set_properties(self, response):
"""Helper for :meth:`reload`.
:type response: dict
:param response: resource mapping from server
"""
self._properties.clear()
self._properties.update(response)

def create(self, client=None):
"""API wrapper: create the notification.
Expand All @@ -187,6 +199,54 @@ def create(self, client=None):
data=properties,
)

def exists(self, client=None):
"""Test whether this notification exists.
See:
https://cloud.google.com/storage/docs/json_api/v1/notifications/get
:type client: :class:`~google.cloud.storage.client.Client` or
``NoneType``
:param client: Optional. The client to use. If not passed, falls back
to the ``client`` stored on the current bucket.
:rtype: bool
:returns: True, if the notification exists, else False.
:raises ValueError: if the notification has no ID.
"""
if self.notification_id is None:
raise ValueError("Notification not intialized by server")

client = self._require_client(client)
try:
client._connection.api_request(method='GET', path=self.path)
except NotFound:
return False
else:
return True

def reload(self, client=None):
"""Update this notification from the server configuration.
See:
https://cloud.google.com/storage/docs/json_api/v1/notifications/get
:type client: :class:`~google.cloud.storage.client.Client` or
``NoneType``
:param client: Optional. The client to use. If not passed, falls back
to the ``client`` stored on the current bucket.
:rtype: bool
:returns: True, if the notification exists, else False.
:raises ValueError: if the notification has no ID.
"""
if self.notification_id is None:
raise ValueError("Notification not intialized by server")

client = self._require_client(client)
response = client._connection.api_request(method='GET', path=self.path)
self._set_properties(response)

def delete(self, client=None):
"""Delete this notification.
Expand All @@ -200,6 +260,7 @@ def delete(self, client=None):
:raises: :class:`google.api.core.exceptions.NotFound`:
if the notification does not exist.
:raises ValueError: if the notification has no ID.
"""
if self.notification_id is None:
raise ValueError("Notification not intialized by server")
Expand Down
176 changes: 133 additions & 43 deletions storage/tests/unit/test_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ class TestBucketNotification(unittest.TestCase):
'attr2': 'value2',
}
BLOB_NAME_PREFIX = 'blob-name-prefix/'
NOTIFICATION_ID = '123'
SELF_LINK = 'https://example.com/notification/123'
ETAG = 'DEADBEEF'
CREATE_PATH = '/b/{}/notificationConfigs'.format(BUCKET_NAME)
NOTIFICATION_PATH = '/b/{}/notificationConfigs/{}'.format(
BUCKET_NAME, NOTIFICATION_ID)

@staticmethod
def event_types():
Expand Down Expand Up @@ -108,93 +114,82 @@ def test_ctor_explicit(self):
def test_notification_id(self):
client = self._make_client()
bucket = self._make_bucket(client)
NOTIFICATION_ID = '123'

notification = self._make_one(
bucket, self.TOPIC_NAME)

self.assertIsNone(notification.notification_id)

notification._properties['id'] = NOTIFICATION_ID
self.assertEqual(notification.notification_id, NOTIFICATION_ID)
notification._properties['id'] = self.NOTIFICATION_ID
self.assertEqual(notification.notification_id, self.NOTIFICATION_ID)

def test_etag(self):
client = self._make_client()
bucket = self._make_bucket(client)
ETAG = 'DEADBEEF'

notification = self._make_one(
bucket, self.TOPIC_NAME)

self.assertIsNone(notification.etag)

notification._properties['etag'] = ETAG
self.assertEqual(notification.etag, ETAG)
notification._properties['etag'] = self.ETAG
self.assertEqual(notification.etag, self.ETAG)

def test_self_link(self):
client = self._make_client()
bucket = self._make_bucket(client)
SELF_LINK = 'https://example.com/notification/123'

notification = self._make_one(
bucket, self.TOPIC_NAME)

self.assertIsNone(notification.self_link)

notification._properties['selfLink'] = SELF_LINK
self.assertEqual(notification.self_link, SELF_LINK)
notification._properties['selfLink'] = self.SELF_LINK
self.assertEqual(notification.self_link, self.SELF_LINK)

def test_create_w_existing_notification_id(self):
NOTIFICATION_ID = '123'
client = self._make_client()
bucket = self._make_bucket(client)
notification = self._make_one(
bucket, self.TOPIC_NAME)
notification._properties['id'] = NOTIFICATION_ID
notification._properties['id'] = self.NOTIFICATION_ID

with self.assertRaises(ValueError):
notification.create()

def test_create_w_defaults(self):
NOTIFICATION_ID = '123'
ETAG = 'DEADBEEF'
SELF_LINK = 'https://example.com/notification/123'
client = self._make_client()
bucket = self._make_bucket(client)
notification = self._make_one(
bucket, self.TOPIC_NAME)
api_request = client._connection.api_request
api_request.return_value = {
'topic': self.TOPIC_REF,
'id': NOTIFICATION_ID,
'etag': ETAG,
'selfLink': SELF_LINK,
'id': self.NOTIFICATION_ID,
'etag': self.ETAG,
'selfLink': self.SELF_LINK,
}

notification.create()

self.assertEqual(notification.notification_id, NOTIFICATION_ID)
self.assertEqual(notification.etag, ETAG)
self.assertEqual(notification.self_link, SELF_LINK)
self.assertEqual(notification.notification_id, self.NOTIFICATION_ID)
self.assertEqual(notification.etag, self.ETAG)
self.assertEqual(notification.self_link, self.SELF_LINK)
self.assertIsNone(notification.custom_attributes)
self.assertIsNone(notification.event_types)
self.assertIsNone(notification.blob_name_prefix)
self.assertIsNone(notification.payload_format)

path = '/b/{}/notificationConfigs'.format(self.BUCKET_NAME)
data = {
'topic': self.TOPIC_REF,
}
api_request.assert_called_once_with(
method='POST',
path=path,
path=self.CREATE_PATH,
data=data,
)

def test_create_w_explicit_client(self):
NOTIFICATION_ID = '123'
ETAG = 'DEADBEEF'
SELF_LINK = 'https://example.com/notification/123'
client = self._make_client()
alt_client = self._make_client()
bucket = self._make_bucket(client)
Expand All @@ -213,9 +208,9 @@ def test_create_w_explicit_client(self):
'event_types': self.event_types(),
'blob_name_prefix': self.BLOB_NAME_PREFIX,
'payload_format': self.payload_format(),
'id': NOTIFICATION_ID,
'etag': ETAG,
'selfLink': SELF_LINK,
'id': self.NOTIFICATION_ID,
'etag': self.ETAG,
'selfLink': self.SELF_LINK,
}

notification.create(client=alt_client)
Expand All @@ -226,11 +221,10 @@ def test_create_w_explicit_client(self):
self.assertEqual(notification.blob_name_prefix, self.BLOB_NAME_PREFIX)
self.assertEqual(
notification.payload_format, self.payload_format())
self.assertEqual(notification.notification_id, NOTIFICATION_ID)
self.assertEqual(notification.etag, ETAG)
self.assertEqual(notification.self_link, SELF_LINK)
self.assertEqual(notification.notification_id, self.NOTIFICATION_ID)
self.assertEqual(notification.etag, self.ETAG)
self.assertEqual(notification.self_link, self.SELF_LINK)

path = '/b/{}/notificationConfigs'.format(self.BUCKET_NAME)
data = {
'topic': self.TOPIC_ALT_REF,
'custom_attributes': self.CUSTOM_ATTRIBUTES,
Expand All @@ -240,10 +234,112 @@ def test_create_w_explicit_client(self):
}
api_request.assert_called_once_with(
method='POST',
path=path,
path=self.CREATE_PATH,
data=data,
)

def test_exists_wo_notification_id(self):
client = self._make_client()
bucket = self._make_bucket(client)
notification = self._make_one(
bucket, self.TOPIC_NAME)

with self.assertRaises(ValueError):
notification.exists()

def test_exists_miss(self):
from google.cloud.exceptions import NotFound

client = self._make_client()
bucket = self._make_bucket(client)
notification = self._make_one(bucket, self.TOPIC_NAME)
notification._properties['id'] = self.NOTIFICATION_ID
api_request = client._connection.api_request
api_request.side_effect = NotFound('testing')

self.assertFalse(notification.exists())

api_request.assert_called_once_with(
method='GET',
path=self.NOTIFICATION_PATH,
)

def test_exists_hit(self):
client = self._make_client()
bucket = self._make_bucket(client)
alt_client = self._make_client()
notification = self._make_one(bucket, self.TOPIC_NAME)
notification._properties['id'] = self.NOTIFICATION_ID
api_request = client._connection.api_request
api_request.return_value = {
'topic': self.TOPIC_REF,
'id': self.NOTIFICATION_ID,
'etag': self.ETAG,
'selfLink': self.SELF_LINK,
}

self.assertTrue(notification.exists(client=client))

api_request.assert_called_once_with(
method='GET',
path=self.NOTIFICATION_PATH,
)

def test_reload_wo_notification_id(self):
client = self._make_client()
bucket = self._make_bucket(client)
notification = self._make_one(
bucket, self.TOPIC_NAME)

with self.assertRaises(ValueError):
notification.reload()

def test_reload_miss(self):
from google.cloud.exceptions import NotFound

client = self._make_client()
bucket = self._make_bucket(client)
notification = self._make_one(bucket, self.TOPIC_NAME)
notification._properties['id'] = self.NOTIFICATION_ID
api_request = client._connection.api_request
api_request.side_effect = NotFound('testing')

with self.assertRaises(NotFound):
notification.reload()

api_request.assert_called_once_with(
method='GET',
path=self.NOTIFICATION_PATH,
)

def test_reload_hit(self):
client = self._make_client()
bucket = self._make_bucket(client)
alt_client = self._make_client()
notification = self._make_one(bucket, self.TOPIC_NAME)
notification._properties['id'] = self.NOTIFICATION_ID
api_request = client._connection.api_request
api_request.return_value = {
'topic': self.TOPIC_REF,
'id': self.NOTIFICATION_ID,
'etag': self.ETAG,
'selfLink': self.SELF_LINK,
}

notification.reload(client=client)

self.assertEqual(notification.etag, self.ETAG)
self.assertEqual(notification.self_link, self.SELF_LINK)
self.assertIsNone(notification.custom_attributes)
self.assertIsNone(notification.event_types)
self.assertIsNone(notification.blob_name_prefix)
self.assertIsNone(notification.payload_format)

api_request.assert_called_once_with(
method='GET',
path=self.NOTIFICATION_PATH,
)

def test_delete_wo_notification_id(self):
client = self._make_client()
bucket = self._make_bucket(client)
Expand All @@ -256,39 +352,33 @@ def test_delete_wo_notification_id(self):
def test_delete_miss(self):
from google.cloud.exceptions import NotFound

NOTIFICATION_ID = '123'
client = self._make_client()
bucket = self._make_bucket(client)
notification = self._make_one(bucket, self.TOPIC_NAME)
notification._properties['id'] = NOTIFICATION_ID
notification._properties['id'] = self.NOTIFICATION_ID
api_request = client._connection.api_request
api_request.side_effect = NotFound('testing')

with self.assertRaises(NotFound):
notification.delete()

path = '/b/{}/notificationConfigs/{}'.format(
self.BUCKET_NAME, NOTIFICATION_ID)
api_request.assert_called_once_with(
method='DELETE',
path=path,
path=self.NOTIFICATION_PATH,
)

def test_delete_hit(self):
NOTIFICATION_ID = '123'
client = self._make_client()
bucket = self._make_bucket(client)
alt_client = self._make_client()
notification = self._make_one(bucket, self.TOPIC_NAME)
notification._properties['id'] = NOTIFICATION_ID
notification._properties['id'] = self.NOTIFICATION_ID
api_request = client._connection.api_request
api_request.return_value = None

notification.delete(client=client)

path = '/b/{}/notificationConfigs/{}'.format(
self.BUCKET_NAME, NOTIFICATION_ID)
api_request.assert_called_once_with(
method='DELETE',
path=path,
path=self.NOTIFICATION_PATH,
)

0 comments on commit 7190c86

Please sign in to comment.