freezer-api/freezer_api/tests/unit/test_jobs.py

571 lines
22 KiB
Python

"""Freezer swift.py related tests
Copyright 2015 Hewlett-Packard
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
import json
import random
import falcon
import mock
from mock import patch
from freezer_api.api.v1 import jobs as v1_jobs
from freezer_api.common import exceptions
from freezer_api.tests.unit import common
class TestJobsBaseResource(common.FreezerBaseTestCase):
def setUp(self):
super(TestJobsBaseResource, self).setUp()
self.mock_db = mock.Mock()
self.resource = v1_jobs.JobsBaseResource(self.mock_db)
def test_get_action_returns_found_action(self):
self.mock_db.get_action.return_value = 'awesome_result'
result = self.resource.get_action('user-id', 'action-id')
self.assertEqual('awesome_result', result)
def test_get_action_returns_none_when_action_not_found(self):
self.mock_db.get_action.side_effect = exceptions.DocumentNotFound(
'regular test failure')
result = self.resource.get_action('user-id', 'action-id')
self.assertIsNone(result)
def test_update_actions_in_job_no_action_id(self):
self.resource.get_action = mock.Mock()
self.resource.get_action.return_value = None
action_doc = {
# "action_id": "ottonero",
"freezer_action": {
"mode": "mysql",
"container": "freezer_backup_test"
},
"max_retries": 3
}
job_doc = {"job_actions": [action_doc.copy()],
"description": "three actions backup"
}
self.resource.update_actions_in_job('duder', job_doc=job_doc)
self.mock_db.add_action.assert_called_with(user_id='duder',
doc=action_doc)
def test_update_actions_in_job_action_id_not_found(self):
self.resource.get_action = mock.Mock()
self.resource.get_action.return_value = None
action_doc = {
"action_id": "ottonero",
"freezer_action": {
"mode": "mysql",
"container": "freezer_backup_test"
},
"max_retries": 3
}
job_doc = {"job_actions": [action_doc.copy()],
"description": "three actions backup"
}
self.resource.update_actions_in_job('duder', job_doc=job_doc)
self.mock_db.add_action.assert_called_with(user_id='duder',
doc=action_doc)
def test_update_actions_in_job_action_id_found_and_same_action(self):
self.resource.get_action = mock.Mock()
action_doc = {
"action_id": "ottonero",
"freezer_action": {
"mode": "mysql",
"container": "freezer_backup_test"
},
"max_retries": 3
}
job_doc = {"job_actions": [action_doc.copy()],
"description": "three actions backup"
}
self.resource.get_action.return_value = action_doc.copy()
self.resource.update_actions_in_job('duder', job_doc=job_doc)
self.mock_db.add_action.assert_not_called()
def test_update_actions_in_job_action_id_found_and_different_action(self):
self.resource.get_action = mock.Mock()
action_doc = {
"action_id": "ottonero",
"freezer_action": {
"mode": "mysql",
"container": "freezer_backup_test"
},
"max_retries": 3
}
job_doc = {"job_actions": [action_doc.copy()],
"description": "three actions backup"
}
found_action = {
"action_id": "ottonero",
"freezer_action": {
"mode": "mysql",
"container": "different_drum"
},
"max_retries": 4
}
new_doc = action_doc.copy()
new_doc['action_id'] = ''
self.resource.get_action.return_value = found_action
self.resource.update_actions_in_job('duder', job_doc=job_doc)
self.mock_db.add_action.assert_called_with(user_id='duder',
doc=new_doc)
class TestJobsCollectionResource(common.FreezerBaseTestCase):
def setUp(self):
super(TestJobsCollectionResource, self).setUp()
self.mock_json_body = mock.Mock()
self.mock_json_body.return_value = {}
self.mock_db = mock.Mock()
self.mock_req = mock.MagicMock()
self.mock_req.__getitem__.side_effect = common.get_req_items
self.mock_req.get_header.return_value = common.fake_job_0_user_id
self.mock_req.status = falcon.HTTP_200
self.resource = v1_jobs.JobsCollectionResource(self.mock_db)
self.resource.json_body = self.mock_json_body
def test_on_get_return_empty_list(self):
self.mock_db.search_job.return_value = []
expected_result = {'jobs': []}
self.resource.on_get(self.mock_req, self.mock_req)
result = self.mock_req.body
self.assertEqual(expected_result, result)
self.assertEqual(falcon.HTTP_200, self.mock_req.status)
def test_on_get_return_correct_list(self):
self.mock_db.search_job.return_value = [common.get_fake_job_0(),
common.get_fake_job_1()]
expected_result = {
'jobs': [common.get_fake_job_0(), common.get_fake_job_1()]}
self.resource.on_get(self.mock_req, self.mock_req)
result = self.mock_req.body
self.assertEqual(expected_result, result)
self.assertEqual(falcon.HTTP_200, self.mock_req.status)
def test_on_post_inserts_correct_data(self):
job = common.get_fake_job_0()
self.mock_json_body.return_value = job
self.mock_db.add_job.return_value = 'pjiofrdslaikfunr'
expected_result = {'job_id': 'pjiofrdslaikfunr'}
self.resource.on_post(self.mock_req, self.mock_req)
self.assertEqual(falcon.HTTP_201, self.mock_req.status)
self.assertEqual(expected_result, self.mock_req.body)
class TestJobsResource(common.FreezerBaseTestCase):
def setUp(self):
super(TestJobsResource, self).setUp()
self.mock_db = mock.Mock()
self.mock_req = mock.MagicMock()
self.mock_req.__getitem__.side_effect = common.get_req_items
self.mock_req.stream.read.return_value = {}
self.mock_req.get_header.return_value = common.fake_job_0_user_id
self.mock_req.status = falcon.HTTP_200
self.resource = v1_jobs.JobsResource(self.mock_db)
def test_create_resource(self):
self.assertIsInstance(self.resource, v1_jobs.JobsResource)
def test_on_get_return_no_result_and_404_when_not_found(self):
self.mock_req.body = None
self.mock_db.get_job.return_value = None
self.resource.on_get(self.mock_req, self.mock_req,
common.fake_job_0_job_id)
self.assertIsNone(self.mock_req.body)
self.assertEqual(falcon.HTTP_404, self.mock_req.status)
def test_on_get_return_correct_data(self):
self.mock_db.get_job.return_value = common.get_fake_job_0()
self.resource.on_get(self.mock_req, self.mock_req,
common.fake_job_0_job_id)
result = self.mock_req.body
self.assertEqual(common.get_fake_job_0(), result)
self.assertEqual(falcon.HTTP_200, self.mock_req.status)
def test_on_delete_removes_proper_data(self):
self.resource.on_delete(self.mock_req, self.mock_req,
common.fake_job_0_job_id)
result = self.mock_req.body
expected_result = {'job_id': common.fake_job_0_job_id}
self.assertEqual(falcon.HTTP_204, self.mock_req.status)
self.assertEqual(expected_result, result)
def test_on_patch_ok_with_some_fields(self):
new_version = random.randint(0, 99)
self.mock_db.update_job.return_value = new_version
patch_doc = {'some_field': 'some_value',
'because': 'size_matters',
'job_schedule': {}}
self.mock_req.stream.read.return_value = json.dumps(patch_doc)
expected_result = {'job_id': common.fake_job_0_job_id,
'version': new_version}
self.resource.update_actions_in_job = mock.Mock()
self.resource.on_patch(self.mock_req, self.mock_req,
common.fake_job_0_job_id)
self.mock_db.update_job.assert_called_with(
user_id=common.fake_job_0_user_id,
job_id=common.fake_job_0_job_id,
patch_doc=patch_doc)
self.assertEqual(falcon.HTTP_200, self.mock_req.status)
result = self.mock_req.body
self.assertEqual(expected_result, result)
def test_on_post_ok(self):
new_version = random.randint(0, 99)
self.mock_db.replace_job.return_value = new_version
job = common.get_fake_job_0()
self.mock_req.stream.read.return_value = json.dumps(job)
expected_result = {'job_id': common.fake_job_0_job_id,
'version': new_version}
self.resource.on_post(self.mock_req, self.mock_req,
common.fake_job_0_job_id)
self.assertEqual(falcon.HTTP_201, self.mock_req.status)
self.assertEqual(expected_result, self.mock_req.body)
def test_on_post_raises_when_db_replace_job_raises(self):
self.mock_db.replace_job.side_effect = exceptions.AccessForbidden(
'regular test failure')
job = common.get_fake_job_0()
self.mock_req.stream.read.return_value = json.dumps(job)
self.assertRaises(exceptions.AccessForbidden, self.resource.on_post,
self.mock_req,
self.mock_req,
common.fake_job_0_job_id)
class TestJobsEvent(common.FreezerBaseTestCase):
def setUp(self):
super(TestJobsEvent, self).setUp()
self.mock_db = mock.Mock()
self.mock_req = mock.MagicMock()
self.mock_req.__getitem__.side_effect = common.get_req_items
self.mock_req.get_header.return_value = common.fake_session_0[
'user_id']
self.mock_req.status = falcon.HTTP_200
self.resource = v1_jobs.JobsEvent(self.mock_db)
self.mock_json_body = mock.Mock()
self.mock_json_body.return_value = {}
self.resource.json_body = self.mock_json_body
def test_create_resource(self):
self.assertIsInstance(self.resource, v1_jobs.JobsEvent)
def test_on_post_raises_when_unable_to_read_event_from_body(self):
self.mock_json_body.return_value = {}
self.assertRaises(exceptions.BadDataFormat, self.resource.on_post,
self.mock_req,
self.mock_req,
'my_job_id')
def test_on_post_start_event_ok(self):
new_version = random.randint(0, 99)
self.mock_db.get_job.return_value = {
'job_schedule': {
'status': 'stop'
}
}
self.mock_db.replace_job.return_value = new_version
event = {"start": None}
self.mock_json_body.return_value = event
expected_result = {'result': 'success'}
self.resource.on_post(self.mock_req, self.mock_req, 'my_job_id')
self.assertEqual(falcon.HTTP_202, self.mock_req.status)
self.assertEqual(expected_result, self.mock_req.body)
class TestJobs(common.FreezerBaseTestCase):
def setUp(self):
super(TestJobs, self).setUp()
def _test_job_start(self, status, event, response, need_update):
job_schedule = {}
if status is not None:
job_schedule['status'] = status
if event is not None:
job_schedule['event'] = event
job = v1_jobs.Job({'job_schedule': job_schedule})
res = job.start()
self.assertEqual(response, res)
self.assertEqual(need_update, job.need_update)
def _test_job_stop(self, status, event, response, need_update):
job_schedule = {}
if status is not None:
job_schedule['status'] = status
if event is not None:
job_schedule['event'] = event
job = v1_jobs.Job({'job_schedule': job_schedule})
res = job.stop()
self.assertEqual(response, res)
self.assertEqual(need_update, job.need_update)
def _test_job_abort(self, status, event, response, need_update):
job_schedule = {}
if status is not None:
job_schedule['status'] = status
if event is not None:
job_schedule['event'] = event
job = v1_jobs.Job({'job_schedule': job_schedule})
res = job.abort()
self.assertEqual(response, res)
self.assertEqual(need_update, job.need_update)
def test_start_scheduled_unstarted_job(self):
self._test_job_start(status='scheduled',
event=None,
response='success',
need_update=True)
def test_start_scheduled_started_job(self):
self._test_job_start(status='scheduled',
event='start',
response='start already requested',
need_update=False)
def test_start_running_unstarted_job(self):
self._test_job_start(status='running',
event=None,
response='success',
need_update=True)
def test_start_running_started_job(self):
self._test_job_start(status='running',
event='start',
response='start already requested',
need_update=False)
def test_start_stopped_unstarted_job(self):
self._test_job_start(status='stop',
event=None,
response='success',
need_update=True)
def test_start_stopped_started_job(self):
self._test_job_start(status='stop',
event='start',
response='start already requested',
need_update=False)
def test_start_completed_unstarted_job(self):
self._test_job_start(status='completed',
event=None,
response='success',
need_update=True)
def test_start_completed_started_job(self):
self._test_job_start(status='completed',
event='start',
response='start already requested',
need_update=False)
def test_start_emptystatus_unstarted_job(self):
self._test_job_start(status='',
event=None,
response='success',
need_update=True)
def test_start_emptystatus_started_job(self):
self._test_job_start(status=None,
event='start',
response='start already requested',
need_update=False)
def test_start_nostatus_unstarted_job(self):
self._test_job_start(status=None,
event=None,
response='success',
need_update=True)
def test_stop_scheduled_unstopped_job(self):
self._test_job_stop(status='scheduled',
event=None,
response='success',
need_update=True)
def test_stop_scheduled_stopped_job(self):
self._test_job_stop(status='scheduled',
event='stop',
response='stop already requested',
need_update=False)
def test_stop_running_unstopped_job(self):
self._test_job_stop(status='running',
event=None,
response='success',
need_update=True)
def test_stop_running_stopped_job(self):
self._test_job_stop(status='running',
event='stop',
response='stop already requested',
need_update=False)
def test_stop_stopped_unstopped_job(self):
self._test_job_stop(status='stop',
event=None,
response='success',
need_update=True)
def test_stop_stopped_stopped_job(self):
self._test_job_stop(status='stop',
event='stop',
response='stop already requested',
need_update=False)
def test_stop_completed_unstopped_job(self):
self._test_job_stop(status='completed',
event=None,
response='success',
need_update=True)
def test_stop_completed_stopped_job(self):
self._test_job_stop(status='completed',
event='stop',
response='stop already requested',
need_update=False)
def test_stop_emptystatus_unstopped_job(self):
self._test_job_stop(status='',
event=None,
response='success',
need_update=True)
def test_stop_emptystatus_stopped_job(self):
self._test_job_stop(status=None,
event='stop',
response='stop already requested',
need_update=False)
def test_stop_nostatus_unstopped_job(self):
self._test_job_stop(status=None,
event=None,
response='success',
need_update=True)
def test_abort_scheduled_unaborted_job(self):
self._test_job_abort(status='scheduled',
event=None,
response='success',
need_update=True)
def test_abort_scheduled_abortped_job(self):
self._test_job_abort(status='scheduled',
event='abort',
response='abort already requested',
need_update=False)
def test_abort_running_unaborted_job(self):
self._test_job_abort(status='running',
event=None,
response='success',
need_update=True)
def test_abort_running_abortped_job(self):
self._test_job_abort(status='running',
event='abort',
response='abort already requested',
need_update=False)
def test_abort_abortped_unaborted_job(self):
self._test_job_abort(status='abort',
event=None,
response='success',
need_update=True)
def test_abort_abortped_abortped_job(self):
self._test_job_abort(status='abort',
event='abort',
response='abort already requested',
need_update=False)
def test_abort_completed_unaborted_job(self):
self._test_job_abort(status='completed',
event=None,
response='success',
need_update=True)
def test_abort_completed_abortped_job(self):
self._test_job_abort(status='completed',
event='abort',
response='abort already requested',
need_update=False)
def test_abort_emptystatus_unaborted_job(self):
self._test_job_abort(status='',
event=None,
response='success',
need_update=True)
def test_abort_emptystatus_abortped_job(self):
self._test_job_abort(status=None,
event='abort',
response='abort already requested',
need_update=False)
def test_abort_nostatus_unaborted_job(self):
self._test_job_abort(status=None,
event=None,
response='success',
need_update=True)
@patch.object(v1_jobs.Job, 'start')
def test_execute_start_event(self, mock_start):
job = v1_jobs.Job({})
job.execute_event('start', 'my_params')
mock_start.assert_called_once_with('my_params')
@patch.object(v1_jobs.Job, 'stop')
def test_execute_stop_event(self, mock_stop):
job = v1_jobs.Job({})
job.execute_event('stop', 'my_params')
mock_stop.assert_called_once_with('my_params')
@patch.object(v1_jobs.Job, 'abort')
def test_execute_abort_event(self, mock_abort):
job = v1_jobs.Job({})
job.execute_event('abort', 'my_params')
mock_abort.assert_called_once_with('my_params')
def test_execute_raises_BadDataFormat_when_event_not_implemented(self):
job = v1_jobs.Job({})
self.assertRaises(exceptions.BadDataFormat, job.execute_event, 'smile',
'my_params')
def test_expand_action_defaults(self):
job_doc = {
'action_defaults': {'that_field': 'that_value'},
'job_actions': [
{'freezer_action': {'not_that_field': 'some_value'}},
{'freezer_action': {'that_field': 'another_value'}}
]
}
expected_job_doc = {
'job_actions': [
{'freezer_action': {'not_that_field': 'some_value',
'that_field': 'that_value'}},
{'freezer_action': {'that_field': 'another_value'}}
],
'job_schedule': {}
}
job = v1_jobs.Job(job_doc)
self.assertEqual(expected_job_doc, job.doc)