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

Add 'BucketNotification.create' API wrapper. #3966

Merged
merged 1 commit into from
Sep 15, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add 'BucketNotification.create' API wrapper.
Toward #3956.
  • Loading branch information
tseaver committed Sep 15, 2017
commit 62e5c8005396a2046973d70f3d8d1e5dc60c52af
47 changes: 47 additions & 0 deletions storage/google/cloud/storage/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
JSON_API_V1_PAYLOAD_FORMAT = 'JSON_API_V1'
NONE_PAYLOAD_FORMAT = 'NONE'

_TOPIC_REF = '//pubsub.googleapis.com/projects/{}/topics/{}'

This comment was marked as spam.

This comment was marked as spam.



class BucketNotification(object):
"""Represent a single notification resource for a bucket.
Expand Down Expand Up @@ -133,3 +135,48 @@ def etag(self):
def self_link(self):
"""Server-set ETag of notification resource."""
return self._properties.get('selfLink')

@property
def client(self):
"""The client bound to this notfication."""
return self.bucket.client

def _require_client(self, client):
"""Check client or verify over-ride.

:type client: :class:`~google.cloud.storage.client.Client` or
``NoneType``
:param client: the client to use.

:rtype: :class:`google.cloud.storage.client.Client`
:returns: The client passed in or the bucket's client.
"""
if client is None:
client = self.client
return client

def create(self, client=None):
"""API wrapper: create the notification.

See:
https://cloud.google.com/storage/docs/json_api/v1/notifications/insert

:type client: :class:`~google.cloud.storage.client.Client`
:param client: (Optional) the client to use. If not passed, falls back
to the ``client`` stored on the notification's bucket.
"""
if self.notification_id is not None:
raise ValueError("Notification already exists w/ id: {}".format(
self.notification_id))

client = self._require_client(client)

path = '/b/{}/notificationConfigs'.format(self.bucket.name)
properties = self._properties.copy()
properties['topic'] = _TOPIC_REF.format(
self.topic_project, self.topic_name)
self._properties = client._connection.api_request(
method='POST',
path=path,
data=properties,
)
158 changes: 136 additions & 22 deletions storage/tests/unit/test_notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,29 @@ class TestBucketNotification(unittest.TestCase):
BUCKET_PROJECT = 'bucket-project-123'
TOPIC_NAME = 'test-topic'
TOPIC_ALT_PROJECT = 'topic-project-456'
TOPIC_REF_FMT = '//pubsub.googleapis.com/projects/{}/topics/{}'
TOPIC_REF = TOPIC_REF_FMT.format(BUCKET_PROJECT, TOPIC_NAME)
TOPIC_ALT_REF = TOPIC_REF_FMT.format(TOPIC_ALT_PROJECT, TOPIC_NAME)
CUSTOM_ATTRIBUTES = {
'attr1': 'value1',
'attr2': 'value2',
}
BLOB_NAME_PREFIX = 'blob-name-prefix/'

@staticmethod
def event_types():
from google.cloud.storage.notification import (
OBJECT_FINALIZE_EVENT_TYPE,
OBJECT_DELETE_EVENT_TYPE)

return [OBJECT_FINALIZE_EVENT_TYPE, OBJECT_DELETE_EVENT_TYPE]

@staticmethod
def payload_format():
from google.cloud.storage.notification import (
JSON_API_V1_PAYLOAD_FORMAT)

return JSON_API_V1_PAYLOAD_FORMAT

@staticmethod
def _get_target_class():
Expand All @@ -39,9 +62,10 @@ def _make_client(self, project=BUCKET_PROJECT):
return mock.Mock(project=project, spec=Client)

def _make_bucket(self, client, name=BUCKET_NAME):
from google.cloud.storage.bucket import Bucket

return mock.Mock(client=client, name=name, spec=Bucket)
bucket = mock.Mock(spec=['client', 'name'])
bucket.client= client
bucket.name = name
return bucket

def test_ctor_defaults(self):
client = self._make_client()
Expand All @@ -59,37 +83,27 @@ def test_ctor_defaults(self):
self.assertIsNone(notification.payload_format)

def test_ctor_explicit(self):
from google.cloud.storage.notification import (
OBJECT_FINALIZE_EVENT_TYPE,
OBJECT_DELETE_EVENT_TYPE,
JSON_API_V1_PAYLOAD_FORMAT)

client = self._make_client()
bucket = self._make_bucket(client)
CUSTOM_ATTRIBUTES = {
'attr1': 'value1',
'attr2': 'value2',
}
EVENT_TYPES = [OBJECT_FINALIZE_EVENT_TYPE, OBJECT_DELETE_EVENT_TYPE]
BLOB_NAME_PREFIX = 'blob-name-prefix/'

notification = self._make_one(
bucket, self.TOPIC_NAME,
topic_project=self.TOPIC_ALT_PROJECT,
custom_attributes=CUSTOM_ATTRIBUTES,
event_types=EVENT_TYPES,
blob_name_prefix=BLOB_NAME_PREFIX,
payload_format=JSON_API_V1_PAYLOAD_FORMAT,
custom_attributes=self.CUSTOM_ATTRIBUTES,
event_types=self.event_types(),
blob_name_prefix=self.BLOB_NAME_PREFIX,
payload_format=self.payload_format(),
)

self.assertIs(notification.bucket, bucket)
self.assertEqual(notification.topic_name, self.TOPIC_NAME)
self.assertEqual(notification.topic_project, self.TOPIC_ALT_PROJECT)
self.assertEqual(notification.custom_attributes, CUSTOM_ATTRIBUTES)
self.assertEqual(notification.event_types, EVENT_TYPES)
self.assertEqual(notification.blob_name_prefix, BLOB_NAME_PREFIX)
self.assertEqual(
notification.payload_format, JSON_API_V1_PAYLOAD_FORMAT)
notification.custom_attributes, self.CUSTOM_ATTRIBUTES)
self.assertEqual(notification.event_types, self.event_types())
self.assertEqual(notification.blob_name_prefix, self.BLOB_NAME_PREFIX)
self.assertEqual(
notification.payload_format, self.payload_format())

def test_notification_id(self):
client = self._make_client()
Expand Down Expand Up @@ -129,3 +143,103 @@ def test_self_link(self):

notification._properties['selfLink'] = SELF_LINK
self.assertEqual(notification.self_link, 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

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,
}

notification.create()

self.assertEqual(notification.notification_id, NOTIFICATION_ID)
self.assertEqual(notification.etag, ETAG)
self.assertEqual(notification.self_link, 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,
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)
notification = self._make_one(
bucket, self.TOPIC_NAME,
topic_project=self.TOPIC_ALT_PROJECT,
custom_attributes=self.CUSTOM_ATTRIBUTES,
event_types=self.event_types(),
blob_name_prefix=self.BLOB_NAME_PREFIX,
payload_format=self.payload_format(),
)
api_request = alt_client._connection.api_request
api_request.return_value = {
'topic': self.TOPIC_ALT_REF,
'custom_attributes': self.CUSTOM_ATTRIBUTES,
'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,
}

notification.create(client=alt_client)

self.assertEqual(
notification.custom_attributes, self.CUSTOM_ATTRIBUTES)
self.assertEqual(notification.event_types, self.event_types())
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)

path = '/b/{}/notificationConfigs'.format(self.BUCKET_NAME)
data = {
'topic': self.TOPIC_ALT_REF,
'custom_attributes': self.CUSTOM_ATTRIBUTES,
'event_types': self.event_types(),
'blob_name_prefix': self.BLOB_NAME_PREFIX,
'payload_format': self.payload_format(),
}
api_request.assert_called_once_with(
method='POST',
path=path,
data=data,
)