def setUp(self): self.request_mock = Mock() self.ts_epoch = 1451606400000 self.ts_dt = datetime.datetime(2016, 1, 1) self.request_dict = { "children": [], "parent": None, "system": "system_name", "system_version": "0.0.1", "instance_name": "default", "command": "say", "id": "58542eb571afd47ead90d25f", "parameters": {}, "comment": "bye!", "output": "nested output", "output_type": "STRING", "status": "IN_PROGRESS", "command_type": "ACTION", "created_at": self.ts_epoch, "updated_at": self.ts_epoch, "error_class": None, "metadata": {}, "has_parent": True, "requester": None, } self.job_dict = { "name": "job_name", "trigger_type": "date", "trigger": {"run_date": self.ts_epoch, "timezone": "utc"}, "request_template": { "system": "system", "system_version": "1.0.0", "instance_name": "default", "command": "speak", "parameters": {"message": "hey!"}, "comment": "hi!", "metadata": {"request": "stuff"}, }, "misfire_grace_time": 3, "coalesce": True, "next_run_time": self.ts_epoch, "success_count": 0, "error_count": 0, } db_dict = copy.deepcopy(self.job_dict) db_dict["request_template"] = RequestTemplate(**db_dict["request_template"]) db_dict["trigger"]["run_date"] = self.ts_dt db_dict["trigger"] = DateTrigger(**db_dict["trigger"]) db_dict["next_run_time"] = self.ts_dt self.job = Job(**db_dict) db_dict = copy.deepcopy(self.request_dict) db_dict["created_at"] = self.ts_dt db_dict["updated_at"] = self.ts_dt self.request = Request(**db_dict) super(RequestAPITest, self).setUp()
def get_next_run_time(self): """Get the next run time as a localized datetime.""" try: document = (BGJob.objects( next_run_time__ne=None).order_by("next_run_time").fields( next_run_time=1).first()) if document: return utc.localize(document.next_run_time) except DoesNotExist: return None
def setUp(self): self.ts_epoch = 1451606400000 self.ts_dt = datetime(2016, 1, 1) self.job_dict = { "name": "job_name", "trigger_type": "date", "trigger": { "run_date": self.ts_epoch, "timezone": "utc" }, "request_template": { "system": "system", "system_version": "1.0.0", "instance_name": "default", "command": "speak", "parameters": { "message": "hey!" }, "comment": "hi!", "metadata": { "request": "stuff" }, }, "misfire_grace_time": 3, "coalesce": True, "next_run_time": self.ts_epoch, "success_count": 0, "error_count": 0, "status": "RUNNING", "max_instances": 3, } db_dict = copy.deepcopy(self.job_dict) db_dict["request_template"] = RequestTemplate( **db_dict["request_template"]) db_dict["trigger"]["run_date"] = self.ts_dt db_dict["trigger"] = DateTrigger(**db_dict["trigger"]) db_dict["next_run_time"] = self.ts_dt self.job = Job(**db_dict) super(JobListAPITest, self).setUp()
def _get_jobs(self, conditions): jobs = [] failed_jobs = [] for document in BGJob.objects(**conditions).order_by("next_run_time"): try: jobs.append( db_to_scheduler(document, self._scheduler, self._alias)) except Exception: logger.exception( "Removing job %s, exception occurred while restoring:" % document.id) failed_jobs.append(document) # Remove all the jobs we failed to restore if failed_jobs: for document in failed_jobs: document.delete() return jobs
class JobListAPITest(TestHandlerBase): def setUp(self): self.ts_epoch = 1451606400000 self.ts_dt = datetime(2016, 1, 1) self.job_dict = { "name": "job_name", "trigger_type": "date", "trigger": { "run_date": self.ts_epoch, "timezone": "utc" }, "request_template": { "system": "system", "system_version": "1.0.0", "instance_name": "default", "command": "speak", "parameters": { "message": "hey!" }, "comment": "hi!", "metadata": { "request": "stuff" }, }, "misfire_grace_time": 3, "coalesce": True, "next_run_time": self.ts_epoch, "success_count": 0, "error_count": 0, "status": "RUNNING", "max_instances": 3, } db_dict = copy.deepcopy(self.job_dict) db_dict["request_template"] = RequestTemplate( **db_dict["request_template"]) db_dict["trigger"]["run_date"] = self.ts_dt db_dict["trigger"] = DateTrigger(**db_dict["trigger"]) db_dict["next_run_time"] = self.ts_dt self.job = Job(**db_dict) super(JobListAPITest, self).setUp() def tearDown(self): Job.objects.delete() def test_get(self): self.job.save() self.job_dict["id"] = str(self.job.id) response = self.fetch("/api/v1/jobs") self.assertEqual(200, response.code) self.assertEqual(json.loads(response.body.decode("utf-8")), [self.job_dict]) def test_get_with_filter_param(self): self.job.save() self.job_dict["id"] = str(self.job.id) response = self.fetch("/api/v1/jobs?name=DOES_NOT_EXIST") self.assertEqual(200, response.code) self.assertEqual(json.loads(response.body.decode("utf-8")), []) response = self.fetch("/api/v1/jobs?name=job_name") self.assertEqual(200, response.code) self.assertEqual(json.loads(response.body.decode("utf-8")), [self.job_dict]) @patch("brew_view.request_scheduler") def test_post(self, scheduler_mock): body = json.dumps(self.job_dict) self.job_dict["id"] = None response = self.fetch("/api/v1/jobs", method="POST", body=body) self.assertEqual(response.code, 201) data_without_id = json.loads(response.body.decode("utf-8")) data_without_id["id"] = None self.assertEqual(data_without_id, self.job_dict) self.assertEqual(scheduler_mock.add_job.call_count, 1) @patch("brew_view.request_scheduler") def test_post_error_delete(self, scheduler_mock): body = json.dumps(self.job_dict) self.job_dict["id"] = None scheduler_mock.add_job.side_effect = ValueError response = self.fetch("/api/v1/jobs", method="POST", body=body) self.assertGreaterEqual(response.code, 500)
class RequestAPITest(TestHandlerBase): def setUp(self): self.request_mock = Mock() self.ts_epoch = 1451606400000 self.ts_dt = datetime.datetime(2016, 1, 1) self.request_dict = { "children": [], "parent": None, "system": "system_name", "system_version": "0.0.1", "instance_name": "default", "command": "say", "id": "58542eb571afd47ead90d25f", "parameters": {}, "comment": "bye!", "output": "nested output", "output_type": "STRING", "status": "IN_PROGRESS", "command_type": "ACTION", "created_at": self.ts_epoch, "updated_at": self.ts_epoch, "error_class": None, "metadata": {}, "has_parent": True, "requester": None, } self.job_dict = { "name": "job_name", "trigger_type": "date", "trigger": {"run_date": self.ts_epoch, "timezone": "utc"}, "request_template": { "system": "system", "system_version": "1.0.0", "instance_name": "default", "command": "speak", "parameters": {"message": "hey!"}, "comment": "hi!", "metadata": {"request": "stuff"}, }, "misfire_grace_time": 3, "coalesce": True, "next_run_time": self.ts_epoch, "success_count": 0, "error_count": 0, } db_dict = copy.deepcopy(self.job_dict) db_dict["request_template"] = RequestTemplate(**db_dict["request_template"]) db_dict["trigger"]["run_date"] = self.ts_dt db_dict["trigger"] = DateTrigger(**db_dict["trigger"]) db_dict["next_run_time"] = self.ts_dt self.job = Job(**db_dict) db_dict = copy.deepcopy(self.request_dict) db_dict["created_at"] = self.ts_dt db_dict["updated_at"] = self.ts_dt self.request = Request(**db_dict) super(RequestAPITest, self).setUp() def tearDown(self): Request.objects.delete() Job.objects.delete() def test_get(self): self.request.save() response = self.fetch("/api/v1/requests/" + str(self.request.id)) self.assertEqual(200, response.code) data = json.loads(response.body.decode("utf-8")) data.pop("updated_at") self.request_dict.pop("updated_at") self.assertEqual(self.request_dict, data) def test_patch_replace_duplicate(self): self.request.status = "SUCCESS" self.request.output = "output" self.request.save() body = json.dumps( { "operations": [ {"operation": "replace", "path": "/output", "value": "output"}, {"operation": "replace", "path": "/status", "value": "SUCCESS"}, ] } ) response = self.fetch( "/api/v1/requests/" + str(self.request.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertEqual(200, response.code) self.request.reload() self.assertEqual("SUCCESS", self.request.status) self.assertEqual("output", self.request.output) def test_patch_replace_status(self): self.request.save() body = json.dumps( { "operations": [ {"operation": "replace", "path": "/status", "value": "SUCCESS"} ] } ) response = self.fetch( "/api/v1/requests/" + str(self.request.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertEqual(200, response.code) self.request.reload() self.assertEqual("SUCCESS", self.request.status) def test_patch_replace_output(self): self.request.output = "old_output_but_not_done_with_progress" self.request.save() body = json.dumps( { "operations": [ {"operation": "replace", "path": "/output", "value": "output"} ] } ) response = self.fetch( "/api/v1/requests/" + str(self.request.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertEqual(200, response.code) self.request.reload() self.assertEqual("output", self.request.output) def test_patch_replace_error_class(self): self.request.error_class = "Klazz1" body = json.dumps( { "operations": [ {"operation": "replace", "path": "/error_class", "value": "error"} ] } ) self.request.save() response = self.fetch( "/api/v1/requests/" + str(self.request.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.request.reload() self.assertEqual(200, response.code) self.assertEqual("error", self.request.error_class) def test_patch_replace_bad_status(self): self.request.save() body = json.dumps( { "operations": [ {"operation": "replace", "path": "/status", "value": "bad"} ] } ) response = self.fetch( "/api/v1/requests/" + str(self.request.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertGreaterEqual(response.code, 400) def test_patch_update_output_for_complete_request(self): self.request.status = "SUCCESS" self.request.output = "old_value" self.request.save() body = json.dumps( { "operations": [ { "operation": "replace", "path": "/output", "value": "shouldnt work", } ] } ) response = self.fetch( "/api/v1/requests/" + str(self.request.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.request.reload() self.assertGreaterEqual(response.code, 400) self.assertEqual(self.request.output, "old_value") def test_patch_no_system(self): good_id_does_not_exist = "".join("1" for _ in range(24)) response = self.fetch( "/api/v1/requests/" + good_id_does_not_exist, method="PATCH", body='{"operations": [{"operation": "fake"}]}', headers={"content-type": "application/json"}, ) self.assertEqual(response.code, 404) def test_patch_replace_bad_path(self): self.request.save() body = json.dumps( {"operations": [{"operation": "replace", "path": "/bad", "value": "error"}]} ) response = self.fetch( "/api/v1/requests/" + str(self.request.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertGreaterEqual(response.code, 400) def test_patch_bad_operation(self): self.request.save() response = self.fetch( "/api/v1/requests/" + str(self.request.id), method="PATCH", body='{"operations": [{"operation": "fake"}]}', headers={"content-type": "application/json"}, ) self.assertGreaterEqual(response.code, 400) def test_prometheus_endpoint(self): handler = self.app.find_handler(request=Mock(path="/api/v1/requests")) c = handler.handler_class( self.app, Mock(path="/api/v1/requests/111111111111111111111111") ) assert c.prometheus_endpoint == "/api/v1/requests/<ID>" def test_update_job_numbers(self): self.job.save() self.request.metadata["_bg_job_id"] = str(self.job.id) self.request.save() body = json.dumps( { "operations": [ {"operation": "replace", "path": "/status", "value": "SUCCESS"} ] } ) response = self.fetch( "/api/v1/requests/" + str(self.request.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertEqual(response.code, 200) self.job.reload() self.assertEqual(self.job.success_count, 1) self.assertEqual(self.job.error_count, 0) def test_update_job_numbers_error(self): self.job.save() self.request.metadata["_bg_job_id"] = str(self.job.id) self.request.save() body = json.dumps( { "operations": [ {"operation": "replace", "path": "/status", "value": "ERROR"} ] } ) response = self.fetch( "/api/v1/requests/" + str(self.request.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertEqual(response.code, 200) self.job.reload() self.assertEqual(self.job.success_count, 0) self.assertEqual(self.job.error_count, 1) def test_update_job_invalid_id(self): self.request.metadata["_bg_job_id"] = "".join(["1" for _ in range(24)]) self.request.save() body = json.dumps( { "operations": [ {"operation": "replace", "path": "/status", "value": "ERROR"} ] } ) response = self.fetch( "/api/v1/requests/" + str(self.request.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertEqual(response.code, 200)
class JobAPITest(TestHandlerBase): def setUp(self): self.ts_epoch = 1451606400000 self.ts_dt = datetime(2016, 1, 1) self.job_dict = { "name": "job_name", "trigger_type": "date", "trigger": { "run_date": self.ts_epoch, "timezone": "utc" }, "request_template": { "system": "system", "system_version": "1.0.0", "instance_name": "default", "command": "speak", "parameters": { "message": "hey!" }, "comment": "hi!", "metadata": { "request": "stuff" }, }, "misfire_grace_time": 3, "coalesce": True, "next_run_time": self.ts_epoch, "success_count": 0, "error_count": 0, "status": "RUNNING", "max_instances": 3, } db_dict = copy.deepcopy(self.job_dict) db_dict["request_template"] = RequestTemplate( **db_dict["request_template"]) db_dict["trigger"]["run_date"] = self.ts_dt db_dict["trigger"] = DateTrigger(**db_dict["trigger"]) db_dict["next_run_time"] = self.ts_dt self.job = Job(**db_dict) super(JobAPITest, self).setUp() def tearDown(self): Job.objects.delete() def test_get_404(self): self.job.save() bad_id = "".join(["1" for _ in range(24)]) if bad_id == self.job.id: bad_id = "".join(["2" for _ in range(24)]) response = self.fetch("/api/v1/jobs/" + bad_id) self.assertEqual(404, response.code) def test_get(self): self.job.save() self.job_dict["id"] = str(self.job.id) response = self.fetch("/api/v1/jobs/" + str(self.job.id)) self.assertEqual(200, response.code) self.assertEqual(json.loads(response.body.decode("utf-8")), self.job_dict) @patch("brew_view.request_scheduler") def test_delete(self, scheduler_mock): self.job.save() response = self.fetch("/api/v1/jobs/" + str(self.job.id), method="DELETE") self.assertEqual(204, response.code) scheduler_mock.remove_job.assert_called_with(str(self.job.id), jobstore="beer_garden") @patch("brew_view.request_scheduler") def test_pause(self, scheduler_mock): self.job.save() body = json.dumps({ "operations": [{ "operation": "update", "path": "/status", "value": "PAUSED" }] }) response = self.fetch( "/api/v1/jobs/" + str(self.job.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertEqual(200, response.code) scheduler_mock.pause_job.assert_called_with(str(self.job.id), jobstore="beer_garden") self.job.reload() self.assertEqual(self.job.status, "PAUSED") @patch("brew_view.request_scheduler") def test_resume(self, scheduler_mock): self.job.status = "PAUSED" self.job.save() body = json.dumps({ "operations": [{ "operation": "update", "path": "/status", "value": "RUNNING" }] }) response = self.fetch( "/api/v1/jobs/" + str(self.job.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertEqual(200, response.code) scheduler_mock.resume_job.assert_called_with(str(self.job.id), jobstore="beer_garden") self.job.reload() self.assertEqual(self.job.status, "RUNNING") def test_invalid_operation(self): self.job.save() body = json.dumps({ "operations": [{ "operation": "INVALID", "path": "/status", "value": "RUNNING" }] }) response = self.fetch( "/api/v1/jobs/" + str(self.job.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertGreaterEqual(400, response.code) def test_invalid_path(self): self.job.save() body = json.dumps({ "operations": [{ "operation": "update", "path": "/INVALID", "value": "RUNNING" }] }) response = self.fetch( "/api/v1/jobs/" + str(self.job.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertGreaterEqual(400, response.code) def test_invalid_value(self): self.job.save() body = json.dumps({ "operations": [{ "operation": "update", "path": "/status", "value": "INVALID" }] }) response = self.fetch( "/api/v1/jobs/" + str(self.job.id), method="PATCH", body=body, headers={"content-type": "application/json"}, ) self.assertGreaterEqual(400, response.code)
def drop_systems(self, app): Job.drop_collection()
def test_trigger_mismatch(self): date_trigger = DateTrigger() job = Job(trigger_type="cron", trigger=date_trigger) with self.assertRaises(ModelValidationError): job.clean()
def test_invalid_trigger_type(self): job = Job(trigger_type="INVALID_TRIGGER_TYPE") with self.assertRaises(ModelValidationError): job.clean()