def test_get_jobs_deleted_target(self): user = self.guest_login() entity = Entity.objects.create(name='entity', created_user=user) entry = Entry.objects.create(name='entry', created_user=user, schema=entity) Job.new_create(user, entry) resp = self.client.get('/job/') self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.context['jobs']), 1) # check the case show jobs after deleting job target entry.delete() # Create delete job Job.new_delete(user, entry) resp = self.client.get('/job/') self.assertEqual(resp.status_code, 200) # Confirm that the delete job can be obtained self.assertEqual(len(resp.context['jobs']), 1) self.assertEqual(resp.context['jobs'][0]['operation'], JobOperation.DELETE_ENTRY.value)
def test_get_jobs_deleted_target(self): user = self.guest_login() entity = Entity.objects.create(name='entity', created_user=user) entry = Entry.objects.create(name='entry', created_user=user, schema=entity) Job.new_create(user, entry) resp = self.client.get('/job/') self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.context['jobs']), 1) # check the case show jobs after deleting job target entry.delete() # Create delete job Job.new_delete(user, entry) resp = self.client.get('/job/') self.assertEqual(resp.status_code, 200) # Confirm that the delete job can be obtained self.assertEqual(len(resp.context['jobs']), 1) self.assertEqual(resp.context['jobs'][0]['operation'], JobOperation.DELETE_ENTRY.value) # check respond HTML has expected elements which are specified of CSS selectors parser = HTML(html=resp.content.decode('utf-8')) job_elems = parser.find('#entry_container .job_info') self.assertEqual(len(job_elems), 1) for job_elem in job_elems: for _cls in ['target', 'status', 'execution_time', 'created_at', 'note', 'operation']: self.assertIsNotNone(job_elem.find('.%s' % _cls))
def test_get_non_target_job(self): user = self.guest_login() Job.new_create(user, None) resp = self.client.get('/job/api/v2/jobs') self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.json()), 0)
def test_get_non_target_job(self): user = self.guest_login() Job.new_create(user, None) resp = self.client.get("/job/") self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.context["jobs"]), 0)
def test_get_jobs(self): user = self.guest_login() entity = Entity.objects.create(name='entity', created_user=user) entry = Entry.objects.create(name='entry', created_user=user, schema=entity) # create three jobs [ Job.new_create(user, entry) for _ in range(0, _TEST_MAX_LIST_VIEW + 1) ] self.assertEqual( Job.objects.filter(user=user).count(), _TEST_MAX_LIST_VIEW + 1) # checks number of the returned objects are as expected resp = self.client.get('/job/') self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.context['jobs']), _TEST_MAX_LIST_VIEW) # checks all job objects will be returned resp = self.client.get('/job/?nolimit=1') self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.context['jobs']), _TEST_MAX_LIST_VIEW + 1) # checks no job object will be returned because of different user self.admin_login() resp = self.client.get('/job/?nolimit=1') self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.context['jobs']), 0)
def do_create(request, entity_id, recv_data): # get objects to be referred in the following processing user = User.objects.get(id=request.user.id) entity = Entity.objects.get(id=entity_id) # checks that a same name entry corresponding to the entity is existed, or not. if Entry.objects.filter(schema=entity_id, name=recv_data['entry_name']).exists(): return HttpResponse('Duplicate name entry is existed', status=400) # validate contexts of each attributes err = _validate_input(recv_data, entity) if err: return err if custom_view.is_custom("do_create_entry", entity.name): # resp is HttpReponse instance or its subclass (e.g. JsonResponse) resp = custom_view.call_custom( "do_create_entry", entity.name, request, recv_data, user, entity) if resp: return resp # Create a new Entry object entry = Entry.objects.create(name=recv_data['entry_name'], created_user=user, schema=entity, status=Entry.STATUS_CREATING) # Create a new job to create entry and run it job = Job.new_create(user, entry, params=recv_data) job.run() return JsonResponse({ 'entry_id': entry.id, 'entry_name': entry.name, })
def test_may_schedule(self): # This describes how many times run method of Job called. self.test_data = 0 def side_effect(): self.test_data += 1 [job1, job2] = [Job.new_create(self.guest, self.entry) for _ in range(2)] # Checks dependent_job parameters of both entries are set properly self.assertIsNone(job1.dependent_job) self.assertEqual(job2.dependent_job.id, job1.id) with mock.patch.object(Job, 'run') as mock_run: mock_run.side_effect = side_effect # job1 doesn't have dependent job and ready to run so this never be rescheduled self.assertTrue(job1.proceed_if_ready()) self.assertFalse(job1.may_schedule()) self.assertEqual(self.test_data, 0) # job2 depends on job1 so this will be rescheduled by calling run method self.assertTrue(job2.may_schedule()) self.assertEqual(self.test_data, 1) # This checks proceed_if_ready() method also call rescheduling method self.assertFalse(job2.proceed_if_ready()) self.assertEqual(self.test_data, 2)
def test_job_download_failure(self): user = self.guest_login() entity = Entity.objects.create(name="entity", created_user=user) job = Job.new_create(user, entity, "hoge") # When user send a download request of Job with invalid Job-id, then HTTP 400 is returned resp = self.client.get("/job/download/%d" % (job.id + 1)) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content.decode(), "Invalid Job-ID is specified") # When user send a download request of non export Job, then HTTP 400 is returned resp = self.client.get("/job/download/%d" % job.id) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content.decode(), "Target Job has no value to return") # The case user sends a download request for a job which doesn't have a result job = Job.new_export(user, text="fuga") resp = self.client.get("/job/download/%d" % job.id) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content.decode(), "This result is no longer available") # When user send a download request of export Job by differenct user from creating one, # then HTTP 400 is returned job = Job.new_export(user, text="fuga") user = self.admin_login() resp = self.client.get("/job/download/%d" % job.id) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content.decode(), "Target Job is executed by other people")
def test_get_jobs(self): user = self.guest_login() entity = Entity.objects.create(name="entity", created_user=user) entry = Entry.objects.create(name="entry", created_user=user, schema=entity) # create three jobs jobs = [Job.new_create(user, entry) for _ in range(0, 3)] resp = self.client.get("/api/v1/job/") self.assertEqual(resp.status_code, 200) # checks expected parameters are set correctly results = resp.json() self.assertEqual( results["constant"]["operation"], { "create": JobOperation.CREATE_ENTRY.value, "edit": JobOperation.EDIT_ENTRY.value, "delete": JobOperation.DELETE_ENTRY.value, "copy": JobOperation.COPY_ENTRY.value, "do_copy": JobOperation.DO_COPY_ENTRY.value, "import": JobOperation.IMPORT_ENTRY.value, "import_v2": JobOperation.IMPORT_ENTRY_V2.value, "export": JobOperation.EXPORT_ENTRY.value, "export_search_result": JobOperation.EXPORT_SEARCH_RESULT.value, "restore": JobOperation.RESTORE_ENTRY.value, "create_entity": JobOperation.CREATE_ENTITY.value, "edit_entity": JobOperation.EDIT_ENTITY.value, "delete_entity": JobOperation.DELETE_ENTITY.value, }, ) self.assertEqual( results["constant"]["status"], { "processing": Job.STATUS["PROCESSING"], "done": Job.STATUS["DONE"], "error": Job.STATUS["ERROR"], "timeout": Job.STATUS["TIMEOUT"], }, ) # checks the parameter MAXLIST_NAV is applied self.assertEqual(Job.objects.filter(user=user).count(), 3) self.assertEqual(len(results["result"]), _TEST_MAX_LIST_NAV) # After cheeting created_at time back to CONFIG.RECENT_SECONDS or more, # this checks that nothing result will be returned. for job in jobs: job.created_at = job.created_at - timedelta( seconds=(CONFIG.RECENT_SECONDS + 1)) job.save(update_fields=["created_at"]) resp = self.client.get("/api/v1/job/") self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.json()["result"]), 0)
def test_job_is_timeout(self): job = Job.new_create(self.guest, self.entity) self.assertFalse(job.is_timeout()) # overwrite timeout timeout value for testing settings.AIRONE['JOB_TIMEOUT'] = -1 self.assertTrue(job.is_timeout())
def test_hidden_jobs_is_not_shown(self): user = self.guest_login() entity = Entity.objects.create(name='entity', created_user=user) entry = Entry.objects.create(name='entry', schema=entity, created_user=user) # create a hidden job Job.new_register_referrals(user, entry) # create an unhidden job Job.new_create(user, entry) # access job list page and check only unhidden jobs are returned resp = self.client.get('/job/') self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.context['jobs']), 1) self.assertEqual(resp.context['jobs'][0]['operation'], JobOperation.CREATE_ENTRY.value)
def test_update_method(self): job = Job.new_create(self.guest, self.entry, 'original text') self.assertEqual(job.status, Job.STATUS['PREPARING']) self.assertEqual(job.operation, JobOperation.CREATE_ENTRY.value) last_updated_time = job.updated_at # When an invalid status value is specified, status value won't be changed job.update(9999) job.refresh_from_db() self.assertEqual(job.status, Job.STATUS['PREPARING']) self.assertEqual(job.text, 'original text') self.assertEqual(job.target.id, self.entry.id) self.assertEqual(job.operation, JobOperation.CREATE_ENTRY.value) self.assertGreater(job.updated_at, last_updated_time) last_updated_time = job.updated_at # update only status parameter job.update(Job.STATUS['PROCESSING']) job.refresh_from_db() self.assertEqual(job.status, Job.STATUS['PROCESSING']) self.assertEqual(job.text, 'original text') self.assertEqual(job.target.id, self.entry.id) self.assertEqual(job.operation, JobOperation.CREATE_ENTRY.value) self.assertGreater(job.updated_at, last_updated_time) last_updated_time = job.updated_at # update status and text parameters job.update(Job.STATUS['CANCELED'], 'changed message') job.refresh_from_db() self.assertEqual(job.status, Job.STATUS['CANCELED']) self.assertEqual(job.text, 'changed message') self.assertEqual(job.target.id, self.entry.id) self.assertEqual(job.operation, JobOperation.CREATE_ENTRY.value) self.assertGreater(job.updated_at, last_updated_time) last_updated_time = job.updated_at # update status, text and target parameters new_entry = Entry.objects.create(name='newone', created_user=self.guest, schema=self.entity) job.update(Job.STATUS['DONE'], 'further changed message', new_entry) job.refresh_from_db() self.assertEqual(job.status, Job.STATUS['DONE']) self.assertEqual(job.text, 'further changed message') self.assertEqual(job.target.id, new_entry.id) self.assertEqual(job.operation, JobOperation.CREATE_ENTRY.value) self.assertGreater(job.updated_at, last_updated_time) # update invalid operation, job operation parameter won't be changed job.update(operation=9999) self.assertEqual(job.operation, JobOperation.CREATE_ENTRY.value) # update valid operation, job operation parameter will be changed job.update(operation=JobOperation.EDIT_ENTRY.value) self.assertEqual(job.operation, JobOperation.EDIT_ENTRY.value)
def test_hidden_jobs_is_not_shown(self): user = self.guest_login() entity = Entity.objects.create(name="entity", created_user=user) entry = Entry.objects.create(name="entry", schema=entity, created_user=user) # create a hidden job Job.new_register_referrals(user, entry) # create an unhidden job Job.new_create(user, entry) resp = self.client.get("/api/v1/job/") self.assertEqual(resp.status_code, 200) # check API result doesn't contain hidden job resp_data = resp.json() self.assertEqual(len(resp_data["result"]), 1) self.assertEqual(resp_data["result"][0]["operation"], JobOperation.CREATE_ENTRY.value)
def test_get_jobs_deleted_target(self): user = self.guest_login() entity = Entity.objects.create(name='entity', created_user=user) entry = Entry.objects.create(name='entry', created_user=user, schema=entity) Job.new_create(user, entry) resp = self.client.get('/job/') self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.context['jobs']), 1) # check the case show jobs after deleting job target entry.delete() resp = self.client.get('/job/') self.assertEqual(resp.status_code, 200) self.assertEqual(resp.context['jobs'], [])
def test_is_finished(self): job = Job.new_create(self.guest, self.entity) for status in [ Job.STATUS['DONE'], Job.STATUS['ERROR'], Job.STATUS['TIMEOUT'], Job.STATUS['CANCELED'] ]: job.status = status job.save(update_fields=['status']) self.assertTrue(job.is_finished())
def test_is_canceled(self): job = Job.new_create(self.guest, self.entity) self.assertFalse(job.is_canceled()) # change status of target job job.set_status(Job.STATUS['CANCELED']) # confirms that is_canceled would be true by changing job status parameter self.assertTrue(job.is_canceled())
def test_get_jobs_deleted_target(self): user = self.guest_login() entity = Entity.objects.create(name="entity", created_user=user) entry = Entry.objects.create(name="entry", created_user=user, schema=entity) Job.new_create(user, entry) resp = self.client.get("/job/") self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.context["jobs"]), 1) # check the case show jobs after deleting job target entry.delete() # Create delete job Job.new_delete(user, entry) resp = self.client.get("/job/") self.assertEqual(resp.status_code, 200) # Confirm that the delete job can be obtained self.assertEqual(len(resp.context["jobs"]), 1) self.assertEqual(resp.context["jobs"][0]["operation"], JobOperation.DELETE_ENTRY.value) # check respond HTML has expected elements which are specified of CSS selectors parser = HTML(html=resp.content.decode("utf-8")) job_elems = parser.find("#entry_container .job_info") self.assertEqual(len(job_elems), 1) for job_elem in job_elems: for _cls in [ "target", "status", "execution_time", "created_at", "note", "operation", ]: self.assertIsNotNone(job_elem.find(".%s" % _cls))
def test_set_status(self): job = Job.new_create(self.guest, self.entity) self.assertEqual(job.status, Job.STATUS['PREPARING']) self.assertTrue(job.set_status(Job.STATUS['DONE'])) job.refresh_from_db(fields=['status']) self.assertEqual(job.status, Job.STATUS['DONE']) # When an invalid status value is specified, status value won't be changed self.assertFalse(job.set_status(9999)) job.refresh_from_db(fields=['status']) self.assertEqual(job.status, Job.STATUS['DONE'])
def test_is_finished(self): job = Job.new_create(self.guest, self.entry) for status in [ Job.STATUS["DONE"], Job.STATUS["ERROR"], Job.STATUS["TIMEOUT"], Job.STATUS["CANCELED"], ]: job.status = status job.save(update_fields=["status"]) self.assertTrue(job.is_finished())
def test_cache(self): job = Job.new_create(self.guest, self.entity) registering_values = [ 1234, 'foo\nbar\nbaz', ['foo', 'bar'], { 'hoge': 'fuga', 'foo': ['a', 'b'] } ] for value in registering_values: job.set_cache(json.dumps(value)) self.assertEqual(job.get_cache(), json.dumps(value))
def test_cache(self): job = Job.new_create(self.guest, self.entry) registering_values = [ 1234, "foo\nbar\nbaz", ["foo", "bar"], {"hoge": "fuga", "foo": ["a", "b"]}, ] for value in registering_values: job.set_cache(json.dumps(value)) self.assertEqual(job.get_cache(), json.dumps(value))
def test_get_jobs(self): user = self.guest_login() entity = Entity.objects.create(name='entity', created_user=user) entry = Entry.objects.create(name='entry', created_user=user, schema=entity) # create three jobs jobs = [Job.new_create(user, entry) for _ in range(0, 3)] resp = self.client.get('/api/v1/job/') self.assertEqual(resp.status_code, 200) # checks expected parameters are set correctly results = resp.json() self.assertEqual( results['constant']['operation'], { 'create': JobOperation.CREATE_ENTRY.value, 'edit': JobOperation.EDIT_ENTRY.value, 'delete': JobOperation.DELETE_ENTRY.value, 'copy': JobOperation.COPY_ENTRY.value, 'import': JobOperation.IMPORT_ENTRY.value, 'export': JobOperation.EXPORT_ENTRY.value, 'export_search_result': JobOperation.EXPORT_SEARCH_RESULT.value, 'restore': JobOperation.RESTORE_ENTRY.value, 'create_entity': JobOperation.CREATE_ENTITY.value, 'edit_entity': JobOperation.EDIT_ENTITY.value, 'delete_entity': JobOperation.DELETE_ENTITY.value, }) self.assertEqual( results['constant']['status'], { 'processing': Job.STATUS['PROCESSING'], 'done': Job.STATUS['DONE'], 'error': Job.STATUS['ERROR'], 'timeout': Job.STATUS['TIMEOUT'], }) # checks the parameter MAXLIST_NAV is applied self.assertEqual(Job.objects.filter(user=user).count(), 3) self.assertEqual(len(results['result']), _TEST_MAX_LIST_NAV) # After cheeting created_at time back to CONFIG.RECENT_SECONDS or more, # this checks that nothing result will be returned. for job in jobs: job.created_at = (job.created_at - timedelta(seconds=(CONFIG.RECENT_SECONDS + 1))) job.save(update_fields=['created_at']) resp = self.client.get('/api/v1/job/') self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.json()['result']), 0)
def test_rerun_deleted_job(self): user = self.guest_login() entity = Entity.objects.create(name='entity', created_user=user) entry = Entry.objects.create(name='entry', created_user=user, schema=entity) job = Job.new_create(user, entry) # delete target entry entry.delete() resp = self.client.post('/api/v1/job/run/%d' % job.id) self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content, b'"Job target has already been deleted"')
def test_is_ready_to_process(self): job = Job.new_create(self.guest, self.entity) for status in [ Job.STATUS['DONE'], Job.STATUS['ERROR'], Job.STATUS['TIMEOUT'], Job.STATUS['CANCELED'], Job.STATUS['PROCESSING'] ]: job.status = status job.save(update_fields=['status']) self.assertFalse(job.is_ready_to_process()) job.status = Job.STATUS['PREPARING'] job.save(update_fields=['status']) self.assertTrue(job.is_ready_to_process())
def test_get_jobs_deleted_target(self): user = self.guest_login() entity = Entity.objects.create(name="entity", created_user=user) entry = Entry.objects.create(name="entry", created_user=user, schema=entity) Job.new_create(user, entry) resp = self.client.get("/job/api/v2/jobs") self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.json()), 1) # check the case show jobs after deleting job target entry.delete() # Create delete job Job.new_delete(user, entry) resp = self.client.get("/job/api/v2/jobs") self.assertEqual(resp.status_code, 200) # Confirm that the delete job can be obtained body = resp.json() self.assertEqual(len(body), 1) self.assertEqual(body[0]["operation"], JobOperation.DELETE_ENTRY.value)
def test_get_jobs(self): user = self.guest_login() entity = Entity.objects.create(name="entity", created_user=user) entry = Entry.objects.create(name="entry", created_user=user, schema=entity) # create three jobs [ Job.new_create(user, entry) for _ in range(0, _TEST_MAX_LIST_VIEW + 1) ] self.assertEqual( Job.objects.filter(user=user).count(), _TEST_MAX_LIST_VIEW + 1) # checks number of the returned objects are as expected resp = self.client.get("/job/") self.assertEqual(resp.status_code, 200) self.assertTemplateUsed("list_jobs.html") self.assertEqual(len(resp.context["jobs"]), _TEST_MAX_LIST_VIEW) for i, job in enumerate( Job.objects.filter( user=user).order_by("-created_at")[:_TEST_MAX_LIST_VIEW]): self.assertEqual(resp.context["jobs"][i]["id"], job.id) self.assertEqual(resp.context["jobs"][i]["target"], job.target) self.assertEqual(resp.context["jobs"][i]["text"], job.text) self.assertEqual(resp.context["jobs"][i]["status"], job.status) self.assertEqual(resp.context["jobs"][i]["operation"], job.operation) self.assertEqual(resp.context["jobs"][i]["can_cancel"], True) self.assertEqual(resp.context["jobs"][i]["created_at"], job.created_at) self.assertEqual(resp.context["jobs"][i]["operation"], job.operation) self.assertGreaterEqual(resp.context["jobs"][i]["passed_time"], 0) # checks all job objects will be returned resp = self.client.get("/job/?nolimit=1") self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.context["jobs"]), _TEST_MAX_LIST_VIEW + 1) # checks no job object will be returned because of different user self.admin_login() resp = self.client.get("/job/?nolimit=1") self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.context["jobs"]), 0)
def test_proceed_if_ready(self): job = Job.new_create(self.guest, self.entry) for status in [ Job.STATUS["DONE"], Job.STATUS["ERROR"], Job.STATUS["TIMEOUT"], Job.STATUS["CANCELED"], Job.STATUS["PROCESSING"], ]: job.status = status job.save(update_fields=["status"]) self.assertFalse(job.proceed_if_ready()) job.status = Job.STATUS["PREPARING"] job.save(update_fields=["status"]) self.assertTrue(job.proceed_if_ready())
def test_waiting_job_until_dependent_one_is_finished(self, mock_sleep): # create two jobs which have dependency (job1, job2) = [Job.new_create(self.guest, self.entity) for _x in range(2)] self.assertFalse(job1.is_finished()) self.assertFalse(job2.is_finished()) def side_effect(*args, **kwargs): job1.text = 'finished manually from side_effect' job1.status = Job.STATUS['DONE'] job1.save(update_fields=['status', 'text']) mock_sleep.side_effect = side_effect job2.wait_dependent_job() self.assertTrue(job1.is_finished()) self.assertEqual(job1.text, 'finished manually from side_effect')
def test_task_module(self, mock_import_module): # This initializes test data that describes how many times does import_module is called # in the processing actually. self.test_data = 0 def side_effect(component): self.test_data += 1 mock_import_module.side_effect = side_effect # create a job and call get_task_module method many times job = Job.new_create(self.guest, self.entry) for _x in range(3): job.get_task_module('hoge') # This confirms import_module method is invoked just one time even through get_task_module # is called multiple times. self.assertEqual(self.test_data, 1)
def test_cancel_job(self): user = self.guest_login() entity = Entity.objects.create(name="entity", created_user=user) entry = Entry.objects.create(name="entry", schema=entity, created_user=user) # make a job job = Job.new_delete(user, entry) self.assertEqual(job.status, Job.STATUS["PREPARING"]) # send request without any parameters resp = self.client.delete("/api/v1/job/", json.dumps({}), "application/json") self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content, b'"Parameter job_id is required"') # send request with invalid job id resp = self.client.delete("/api/v1/job/", json.dumps({"job_id": 99999}), "application/json") self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content, b'"Failed to find Job(id=99999)"') # target jobs that cannot be canceled resp = self.client.delete("/api/v1/job/", json.dumps({"job_id": job.id}), "application/json") self.assertEqual(resp.status_code, 400) self.assertEqual(resp.content, b'"Target job cannot be canceled"') # send request with proper parameter job = Job.new_create(user, entry) self.assertEqual(job.status, Job.STATUS["PREPARING"]) resp = self.client.delete("/api/v1/job/", json.dumps({"job_id": job.id}), "application/json") self.assertEqual(resp.status_code, 200) self.assertEqual(resp.content, b'"Success to cancel job"') job.refresh_from_db() self.assertEqual(job.status, Job.STATUS["CANCELED"])