diff options
author | Milo Casagrande <milo.casagrande@linaro.org> | 2015-03-09 10:17:05 +0100 |
---|---|---|
committer | Milo Casagrande <milo.casagrande@linaro.org> | 2015-03-09 10:17:05 +0100 |
commit | 29b49b434ab2df60fd422616d6c8a2b0248bb311 (patch) | |
tree | 9d716f8201b3f21688843a5e645ece2b86740410 | |
parent | 7e5d4a29da65b9bda84ec249db82a8053547ba02 (diff) |
Remove references to subscription handlers.
* We do not use nor plan to implement the subscription
mechanism, at least for now.
-rw-r--r-- | app/handlers/subscription.py | 95 | ||||
-rw-r--r-- | app/handlers/tests/test_subscription_handler.py | 172 | ||||
-rw-r--r-- | app/models/subscription.py | 181 | ||||
-rw-r--r-- | app/models/tests/test_subscription_model.py | 107 | ||||
-rw-r--r-- | app/tests/__init__.py | 1 | ||||
-rw-r--r-- | app/urls.py | 7 | ||||
-rw-r--r-- | app/utils/subscription.py | 120 |
7 files changed, 0 insertions, 683 deletions
diff --git a/app/handlers/subscription.py b/app/handlers/subscription.py deleted file mode 100644 index a6bd578..0000000 --- a/app/handlers/subscription.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (C) 2014 Linaro Ltd. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -"""The RequetHandler for /subscription URLs.""" - -try: - import simplejson as json -except ImportError: - import json - -from handlers.base import BaseHandler -from handlers.response import HandlerResponse -from handlers.common import SUBSCRIPTION_VALID_KEYS -from models import ( - EMAIL_KEY, - SUBSCRIPTION_COLLECTION, -) -from utils.subscription import ( - subscribe, - unsubscribe, -) -from utils.validator import is_valid_json -from utils.db import delete - - -class SubscriptionHandler(BaseHandler): - """Handle the /subscription URLs.""" - - def __init__(self, application, request, **kwargs): - super(SubscriptionHandler, self).__init__( - application, request, **kwargs - ) - - @property - def collection(self): - return self.db[SUBSCRIPTION_COLLECTION] - - @staticmethod - def _valid_keys(method): - return SUBSCRIPTION_VALID_KEYS.get(method, None) - - def _post(self, *args, **kwargs): - response = HandlerResponse() - - response.status_code = subscribe(self.db, kwargs['json_obj']) - response.result = None - response.reason = self._get_status_message(response.status_code) - - return response - - def _delete(self, doc_id): - response = HandlerResponse() - response.result = None - - if self.request.body: - try: - json_obj = json.loads(self.request.body.decode('utf8')) - - valid, reason = is_valid_json( - json_obj, self._valid_keys('DELETE') - ) - - if valid: - response.status_code = unsubscribe( - self.collection, doc_id, json_obj[EMAIL_KEY] - ) - response.reason = self._get_status_message( - response.status_code - ) - else: - response.status_code = 400 - response.reason = reason - except ValueError: - response.status_code = 420 - response.reason = "No JSON data found in the DELETE request" - else: - response.status_code = delete(self.collection, doc_id) - if response.status_code == 200: - response.reason = ( - "Subscriptsions for resource %s deleted" % doc_id - ) - - return response diff --git a/app/handlers/tests/test_subscription_handler.py b/app/handlers/tests/test_subscription_handler.py deleted file mode 100644 index bdfaa76..0000000 --- a/app/handlers/tests/test_subscription_handler.py +++ /dev/null @@ -1,172 +0,0 @@ -# Copyright (C) 2014 Linaro Ltd. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -"""Test module for the DefConfHandler handler..""" - -import json -import mongomock - -from concurrent.futures import ThreadPoolExecutor -from mock import ( - MagicMock, - patch, -) -from tornado import ( - ioloop, - testing, - web, -) - -from handlers.app import AppHandler -from urls import _SUBSCRIPTION_URL - -# Default Content-Type header returned by Tornado. -DEFAULT_CONTENT_TYPE = 'application/json; charset=UTF-8' - - -class TestSubscriptionHandler( - testing.AsyncHTTPTestCase, testing.LogTrapTestCase): - - def setUp(self): - self.mongodb_client = mongomock.Connection() - - super(TestSubscriptionHandler, self).setUp() - - patched_find_token = patch("handlers.base.BaseHandler._find_token") - self.find_token = patched_find_token.start() - self.find_token.return_value = "token" - - patched_validate_token = patch("handlers.base.validate_token") - self.validate_token = patched_validate_token.start() - self.validate_token.return_value = True - - self.addCleanup(patched_find_token.stop) - self.addCleanup(patched_validate_token.stop) - - def get_app(self): - dboptions = { - 'dbpassword': "", - 'dbuser': "" - } - - settings = { - 'dboptions': dboptions, - 'client': self.mongodb_client, - 'executor': ThreadPoolExecutor(max_workers=2), - 'default_handler_class': AppHandler, - 'debug': False, - } - - return web.Application([_SUBSCRIPTION_URL], **settings) - - def get_new_ioloop(self): - return ioloop.IOLoop.instance() - - @patch('utils.db.find') - @patch('utils.db.count') - def test_get(self, mock_count, mock_find): - mock_count.return_value = 0 - mock_find.return_value = [] - - expected_body = ( - '{"count": 0, "code": 200, "limit": 0, "result": []}' - ) - - headers = {'Authorization': 'foo'} - response = self.fetch('/subscription', headers=headers) - - self.assertEqual(response.code, 200) - self.assertEqual( - response.headers['Content-Type'], DEFAULT_CONTENT_TYPE) - self.assertEqual(response.body, expected_body) - - @patch('handlers.subscription.SubscriptionHandler.collection') - def test_get_by_id_not_found(self, mock_collection): - mock_collection.find_one = MagicMock() - mock_collection.find_one.return_value = None - - headers = {'Authorization': 'foo'} - response = self.fetch('/subscription/sub', headers=headers) - - self.assertEqual(response.code, 404) - self.assertEqual( - response.headers['Content-Type'], DEFAULT_CONTENT_TYPE) - - def test_post_without_token(self): - - body = json.dumps(dict(job='job', kernel='kernel')) - - response = self.fetch('/subscription', method='POST', body=body) - - self.assertEqual(response.code, 403) - self.assertEqual( - response.headers['Content-Type'], DEFAULT_CONTENT_TYPE) - - def test_post_not_json(self): - headers = {'Authorization': 'foo'} - - response = self.fetch( - '/subscription', method='POST', body='', headers=headers - ) - - self.assertEqual(response.code, 415) - self.assertEqual( - response.headers['Content-Type'], DEFAULT_CONTENT_TYPE) - - @patch('utils.subscription.find_one') - def test_post_valid(self, mock_find_one): - mock_find_one.return_value = dict(_id='sub', job_id='job', emails=[]) - - headers = {'Authorization': 'foo', 'Content-Type': 'application/json'} - - body = json.dumps(dict(job='job', email='email')) - - response = self.fetch( - '/subscription', method='POST', body=body, headers=headers - ) - - self.assertEqual(response.code, 201) - self.assertEqual( - response.headers['Content-Type'], DEFAULT_CONTENT_TYPE) - - @patch('utils.subscription.find_one') - def test_delete_valid_with_payload(self, mock_find_one): - mock_find_one.return_value = dict( - _id='sub', emails=['email'], job_id='job' - ) - - headers = {'Authorization': 'foo', 'Content-Type': 'application/json'} - - body = json.dumps(dict(email='email')) - - response = self.fetch( - '/subscription/sub', method='DELETE', body=body, - headers=headers, allow_nonstandard_methods=True, - ) - - self.assertEqual(response.code, 200) - self.assertEqual( - response.headers['Content-Type'], DEFAULT_CONTENT_TYPE) - - def test_delete_valid_without_payload(self): - headers = {'Authorization': 'foo'} - - response = self.fetch( - '/subscription/sub', method='DELETE', headers=headers, - ) - - self.assertEqual(response.code, 200) - self.assertEqual( - response.headers['Content-Type'], DEFAULT_CONTENT_TYPE) diff --git a/app/models/subscription.py b/app/models/subscription.py deleted file mode 100644 index b63182c..0000000 --- a/app/models/subscription.py +++ /dev/null @@ -1,181 +0,0 @@ -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -""" -The model that represents a subscription document in the mongodb collection. -""" - -import types - -import models -import models.base as modb - - -class SubscriptionDocument(modb.BaseDocument): - """This class represents a subscription document in the mongodb database. - - A subscription document contains a list of emails that shoule be notified. - It contains an external ID that points to the job ID. - """ - - def __init__(self, job, kernel): - doc_name = { - models.JOB_KEY: job, - models.KERNEL_KEY: kernel - } - self._name = models.SUBSCRIPTION_DOCUMENT_NAME % doc_name - self._created_on = None - self._id = None - self._job_id = None - self._job = job - self._kernel = kernel - self._emails = [] - self._version = None - - @property - def collection(self): - return models.SUBSCRIPTION_COLLECTION - - @property - def name(self): - """The name of the object.""" - return self._name - - @name.setter - def name(self, value): - """Set the name of the document.""" - self._name = value - - @property - def id(self): - """The ID of this object as returned by mongodb.""" - return self._id - - @id.setter - def id(self, value): - """Set the ID of this object with the ObjectID from mongodb. - - :param value: The ID of this object. - :type value: str - """ - self._id = value - - @property - def job(self): - """The real job name as found on the file system.""" - return self._job - - @property - def kernel(self): - """The real kernel name as found on the file system.""" - return self._kernel - - @property - def created_on(self): - """When this object was created.""" - return self._created_on - - @created_on.setter - def created_on(self, value): - """Set the creation date of this object. - - :param value: The lab creation date, in UTC time zone. - :type value: datetime - """ - self._created_on = value - - @property - def job_id(self): - """The job ID this subscriptions belong to.""" - return self._job_id - - @job_id.setter - def job_id(self, value): - """Set the ID of the associated job.""" - self._job_id = value - - @property - def emails(self): - """The list of emails subscribed.""" - return self._emails - - @emails.setter - def emails(self, value): - """Set the emails subscribed.""" - if not isinstance(value, types.ListType): - if isinstance(value, types.StringTypes): - value = [value] - else: - value = list(value) - - self._emails.extend(value) - # Make sure the list is unique. - self._emails = list(set(self._emails)) - - @property - def version(self): - """The schema version of this object.""" - return self._version - - @version.setter - def version(self, value): - """Set the schema version of this object. - - :param value: The schema string. - :type param: str - """ - self._version = value - - def to_dict(self): - sub_dict = { - models.CREATED_KEY: self.created_on, - models.EMAIL_LIST_KEY: self.emails, - models.JOB_ID_KEY: self.job_id, - models.JOB_KEY: self.job, - models.KERNEL_KEY: self.kernel, - models.NAME_KEY: self.name, - models.VERSION_KEY: self.version, - } - - if self.id: - sub_dict[models.ID_KEY] = self.id - - return sub_dict - - @staticmethod - def from_json(json_obj): - """Build a document from a JSON object. - - :param json_obj: The JSON object to start from. - :return An instance of `SubscriptionDocument`. - """ - sub_doc = None - if isinstance(json_obj, types.DictionaryType): - json_pop = json_obj.pop - job = json_pop(models.JOB_KEY) - kernel = json_pop(models.KERNEL_KEY) - doc_id = json_pop(models.ID_KEY) - # Remove the name key. - json_pop(models.NAME_KEY) - - sub_doc = SubscriptionDocument(job, kernel) - sub_doc.id = doc_id - sub_doc.version = json_pop(models.VERSION_KEY, "1.0") - - for key, value in json_obj.iteritems(): - try: - setattr(sub_doc, key, value) - except AttributeError: - print key - - return sub_doc diff --git a/app/models/tests/test_subscription_model.py b/app/models/tests/test_subscription_model.py deleted file mode 100644 index 2b5a6b9..0000000 --- a/app/models/tests/test_subscription_model.py +++ /dev/null @@ -1,107 +0,0 @@ -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import types -import unittest - -from bson import json_util - -import models.base as modb -import models.subscription as mods - - -class TestSubscriptionModel(unittest.TestCase): - - def test_subscription_document_emails_attribute(self): - sub_doc = mods.SubscriptionDocument("job", "kernel") - self.assertIsInstance(sub_doc.emails, types.ListType) - self.assertItemsEqual([], sub_doc.emails) - - def test_subscription_document_emails_attribute_set(self): - sub_doc = mods.SubscriptionDocument("job", "kernel") - - self.assertIsInstance(sub_doc.emails, types.ListType) - self.assertNotIsInstance(sub_doc.emails, types.StringTypes) - - def test_subscription_document_emails_extended(self): - sub_doc = mods.SubscriptionDocument("job", "kernel") - sub_doc.emails = "email2" - - self.assertIsInstance(sub_doc.emails, types.ListType) - self.assertEquals(["email2"], sub_doc.emails) - - def test_subscription_document_emails_setter_str(self): - sub_doc = mods.SubscriptionDocument("job", "kernel") - sub_doc.emails = "an_email" - - self.assertIsInstance(sub_doc.emails, types.ListType) - self.assertEqual(["an_email"], sub_doc.emails) - - def test_subscription_document_emails_setter_tuple(self): - sub_doc = mods.SubscriptionDocument("sub", "job") - sub_doc.emails = ("an_email", "another_email") - - self.assertIsInstance(sub_doc.emails, types.ListType) - self.assertEqual(["an_email", "another_email"], sub_doc.emails) - - def test_subscription_document_to_dict(self): - expected = { - "job": "job", - "kernel": "kernel", - "name": "sub-job-kernel", - "emails": [], - "job_id": None, - "created_on": None, - "version": None, - } - sub_doc = mods.SubscriptionDocument("job", "kernel") - - self.assertEqual(expected, sub_doc.to_dict()) - - def test_subscription_document_from_json(self): - json_obj = { - "_id": "id", - "name": "sub-job-kernel", - "job": "job", - "kernel": "kernel", - "emails": [], - "job_id": "job-id", - "cerated_on": "now" - } - - sub_doc = mods.SubscriptionDocument.from_json(json_obj) - - self.assertIsInstance(sub_doc, mods.SubscriptionDocument) - self.assertIsInstance(sub_doc, modb.BaseDocument) - - self.assertEqual(sub_doc.name, 'sub-job-kernel') - self.assertEqual(sub_doc.job_id, 'job-id') - self.assertIsInstance(sub_doc.emails, types.ListType) - - def test_subscription_document_from_json_with_emails(self): - json_obj = { - "_id": "id", - "job_id": "job-id", - "name": "sub-job-kernel", - "job": "job", - "kernel": "kernel", - "created_on": None, - "emails": [ - "a@example.org", "b@example.org" - ] - } - - sub_doc = mods.SubscriptionDocument.from_json(json_obj) - - self.assertIsInstance(sub_doc.emails, types.ListType) - self.assertEqual(len(sub_doc.emails), 2) diff --git a/app/tests/__init__.py b/app/tests/__init__.py index 67cb946..a47fb03 100644 --- a/app/tests/__init__.py +++ b/app/tests/__init__.py @@ -41,7 +41,6 @@ def test_modules(): "models.tests.test_job_model", "models.tests.test_lab_model", "models.tests.test_report_model", - "models.tests.test_subscription_model", "models.tests.test_test_suite_model", "models.tests.test_token_model", "utils.batch.tests.test_batch_common", diff --git a/app/urls.py b/app/urls.py index c06d228..043d63c 100644 --- a/app/urls.py +++ b/app/urls.py @@ -24,7 +24,6 @@ import handlers.job import handlers.lab import handlers.report import handlers.send -import handlers.subscription import handlers.test_suite import handlers.token import handlers.upload @@ -39,11 +38,6 @@ _DEFCONF_URL = tornado.web.url( handlers.defconf.DefConfHandler, name="defconf" ) -_SUBSCRIPTION_URL = tornado.web.url( - r"/subscription[s]?/?(?P<id>.*)", - handlers.subscription.SubscriptionHandler, - name="subscription", -) _BOOT_URL = tornado.web.url( r"/boot[s]?/?(?P<id>.*)", handlers.boot.BootHandler, name="boot" ) @@ -96,7 +90,6 @@ APP_URLS = [ _DEFCONF_URL, _JOB_URL, _LAB_URL, - _SUBSCRIPTION_URL, _TOKEN_URL, _VERSION_URL, _REPORT_URL, diff --git a/app/utils/subscription.py b/app/utils/subscription.py deleted file mode 100644 index 83e1903..0000000 --- a/app/utils/subscription.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright (C) 2014 Linaro Ltd. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -"""Collection of utilities to handle subscriptions.""" - -import pymongo - -import models -import models.subscription as mods -from utils import LOG -from utils.db import ( - find_one, - save, - update, -) - - -def subscribe(database, json_obj): - """Subscribe an email to a job. - - It accepts a dict-like object that should contain at least the `job_id' and - `email' keys. All other keys will not be considered. - - At the moment no validation is run on the email provided. - - :param database: The database where to store the data. - :param json_obj: A dict-like object with `job_id' and `email' fields. - :return This function return 201 when the subscription has been performed, - 404 if the job to subscribe to does not exist, or 500 in case of - an internal database error. - """ - ret_val = 404 - - job = json_obj['job'] - emails = json_obj['email'] - - job_doc = find_one(database[models.JOB_COLLECTION], job) - if job_doc: - job_id = job_doc[models.ID_KEY] - subscription = find_one( - database[models.SUBSCRIPTION_COLLECTION], - job_id, - 'job_id' - ) - - if subscription: - sub_obj = mods.SubscriptionDocument.from_json(subscription) - sub_obj.emails = emails - else: - sub_id = ( - models.SUBSCRIPTION_DOCUMENT_NAME % job_id - ) - sub_obj = mods.SubscriptionDocument(sub_id, job_id) - sub_obj.emails = emails - - ret_val = save(database, sub_obj) - - return ret_val - - -def unsubscribe(collection, doc_id, email): - """Unsubscribe an email from a job. - - :param collection: The collection where operation will be performed. - :param doc_id: The job ID from which the email should be unsubscribed. - :type str - :param email: The email to unsubscribe. - :type str - :return 200 on success, 400 if there is an error removing an email, 500 - in case of a database error. - """ - ret_val = 400 - - subscription = find_one(collection, doc_id) - - if subscription: - emails = subscription['emails'] - try: - emails.remove(email) - ret_val = update( - collection, {'_id': doc_id}, {'emails': emails} - ) - except ValueError, ex: - LOG.error( - "Error removing email address from subscription with " - "'_id': %s" % (doc_id) - ) - LOG.exception(str(ex)) - - return ret_val - - -def send(job_id): - """Send emails to the subscribers. - - :param job_id: The job ID for which to send notifications. - """ - # TODO: add logic to make sure we can send the notifications. - # We should store the job status. - database = pymongo.MongoClient()[models.DB_NAME] - - subscription = find_one( - database[models.SUBSCRIPTION_COLLECTION], job_id, 'job_id' - ) - - if subscription: - emails = subscription['emails'] - LOG.info("Sending emails to: %s" % (str(emails))) |