def test_check_automerge(self, mock_get): mock_get.return_value = utils.Response() e0 = utils.create_event(cause=models.Event.PUSH) e0.cause = models.Event.PULL_REQUEST e0.status = models.JobStatus.SUCCESS e0.pull_request = utils.create_pr() e0.save() with self.settings( INSTALLED_GITSERVERS=[utils.github_config( remote_update=True)]): # Not configured for automerge UpdateRemoteStatus.check_automerge(e0) self.assertEqual(mock_get.call_count, 0) auto_merge_settings = { "auto_merge_label": "Auto Merge", "auto_merge_require_review": False, "auto_merge_enabled": True, } repo = e0.base.branch.repository repo_settings = { "%s/%s" % (repo.user.name, repo.name): auto_merge_settings } git_config = utils.github_config(remote_update=True, repo_settings=repo_settings) with self.settings(INSTALLED_GITSERVERS=[git_config]): # Only works for pull requests e0.cause = models.Event.PUSH e0.save() UpdateRemoteStatus.check_automerge(e0) self.assertEqual(mock_get.call_count, 0) # Only works if the event status is SUCCESS e0.cause = models.Event.PULL_REQUEST e0.status = models.JobStatus.FAILED_OK e0.pull_request = utils.create_pr() e0.save() UpdateRemoteStatus.check_automerge(e0) self.assertEqual(mock_get.call_count, 0) e0.status = models.JobStatus.SUCCESS e0.save() # Should try to auto merge UpdateRemoteStatus.check_automerge(e0) self.assertEqual(mock_get.call_count, 1)
def test_get_pr_changed_files(self, mock_get): api = self.server.api() pr = utils.create_pr(repo=self.repo) mock_get.return_value = utils.Response({"changes": []}) files = api._get_pr_changed_files(self.repo.user.name, self.repo.name, pr.number) # shouldn't be any files self.assertEqual(len(files), 0) file_json = self.get_json_file("files.json") file_data = json.loads(file_json) mock_get.return_value = utils.Response(file_data) files = api._get_pr_changed_files(self.repo.user.name, self.repo.name, pr.number) self.assertEqual(["other/path/to/file1", "path/to/file0"], files) # simulate a bad request mock_get.return_value = utils.Response(file_data, status_code=400) files = api._get_pr_changed_files(self.repo.user.name, self.repo.name, pr.number) self.assertEqual(files, []) # simulate a request timeout mock_get.side_effect = Exception("Bam!") files = api._get_pr_changed_files(self.repo.user.name, self.repo.name, pr.number) self.assertEqual(files, [])
def create_event_with_jobs(self, commit='1234', user=None, branch1=None, branch2=None, cause=models.Event.PULL_REQUEST): ev = utils.create_event(commit2=commit, user=user, branch1=branch1, branch2=branch2, cause=cause) ev.base.branch.repository.active = True ev.base.branch.repository.save() alt_recipe = utils.create_recipe( name="alt recipe", cause=models.Recipe.CAUSE_PULL_REQUEST_ALT) utils.create_step(name="step0_alt", recipe=alt_recipe, position=0) utils.create_step(name="step1_alt", recipe=alt_recipe, position=1) if cause == models.Event.PULL_REQUEST: pr = utils.create_pr(title="Foo {a, b} & <bar> …") pr.alternate_recipes.add(alt_recipe) ev.pull_request = pr ev.save() r0 = utils.create_recipe(name="r0", cause=cause) utils.create_step(name="step1_r0", recipe=r0, position=1) utils.create_step(name="step2_r0", recipe=r0, position=2) r1 = utils.create_recipe(name="r1", cause=cause) utils.create_step(name="step1_r1", recipe=r1, position=1) utils.create_step(name="step2_r1", recipe=r1, position=2) r1.depends_on.add(r1) utils.create_job(event=ev, recipe=r0) utils.create_job(event=ev, recipe=r1) return ev
def test_repo_prs_status(self): # bad repo url = reverse('ci:ajax:repo_prs_status', args=["foo", "bar"]) response = self.client.get(url) self.assertEqual(response.status_code, 404) # not open pr = utils.create_pr() pr.closed = True pr.save() url = reverse('ci:ajax:repo_prs_status', args=[pr.repository.user.name, pr.repository.name]) response = self.client.get(url) self.assertEqual(response.status_code, 200) json_data = response.json() self.assertEqual(len(json_data["prs"]), 0) # should be OK pr.closed = False pr.save() response = self.client.get(url) self.assertEqual(response.status_code, 200) json_data = response.json() self.assertEqual(len(json_data["prs"]), 1) self.assertEqual(json_data["prs"][0]["number"], pr.number) self.assertEqual(json_data["prs"][0]["status"], pr.status_slug())
def setUp(self): self.client = Client() self.factory = RequestFactory() for i in range(5): repo = utils.create_repo(name="repo%s" % i) repo.active = True repo.status = models.JobStatus.SUCCESS repo.save() for j in range(2): b = utils.create_branch(name="branch%s" % j, repo=repo) b.status = models.JobStatus.SUCCESS b.save() for j in range(3): b = repo.branches.first() pr = utils.create_pr(title="pr%s" % j, number=j+1, repo=repo) pr.closed = False pr.status = models.JobStatus.SUCCESS pr.save() ev = utils.create_event(user=repo.user, branch1=b, branch2=b, commit1="%s" % j) ev.pull_request = pr ev.save() for k in range(3): r = utils.create_recipe(name="%s%s" % (repo.name, k), repo=repo, branch=b) r.private = False r.save() job = utils.create_job(recipe=r, event=ev) job.status = models.JobStatus.SUCCESS job.client = utils.create_client(name="client%s/%s" % (repo.name, k)) job.save() utils.create_step_result(job=job) utils.create_osversion() utils.create_loadedmodule()
def test_mooseframework(self): # no moose repo response = self.client.get(reverse('ci:mooseframework')) self.assertEqual(response.status_code, 200) user = utils.create_user(name='idaholab') repo = utils.create_repo(name='moose', user=user) utils.create_pr(repo=repo) # no master/devel branches response = self.client.get(reverse('ci:mooseframework')) self.assertEqual(response.status_code, 200) utils.create_branch(name='master', repo=repo) utils.create_branch(name='devel', repo=repo) # should be good response = self.client.get(reverse('ci:mooseframework')) self.assertEqual(response.status_code, 200)
def test_repo_update(self): url = reverse('ci:ajax:repo_update') # no parameters response = self.client.get(url) self.assertEqual(response.status_code, 400) pr_open = utils.create_pr(title='Foo <type> & bar …', number=1) ev_open = utils.create_event() pr_open.closed = False pr_open.save() ev_open.pull_request = pr_open ev_open.save() pr_closed = utils.create_pr(title='closed_pr', number=2) pr_closed.closed = True pr_closed.save() ev_closed = utils.create_event(commit1='2345') ev_closed.pull_request = pr_closed ev_closed.save() pr_open.repository.active = True pr_open.repository.save() ev_branch = utils.create_event(commit1='1', commit2='2', cause=models.Event.PUSH) ev_branch.base.branch.status = models.JobStatus.RUNNING ev_branch.base.branch.save() recipe, depends_on = utils.create_recipe_dependency() utils.create_job(recipe=recipe) utils.create_job(recipe=depends_on) data = {'last_request': 10, 'limit': 30} # missing repo id response = self.client.get(url, data) self.assertEqual(response.status_code, 400) data["repo_id"] = pr_open.repository.pk response = self.client.get(url, data) self.assertEqual(response.status_code, 200) json_data = response.json() self.assertIn('repo_status', json_data) self.assertIn('closed', json_data) self.assertEqual(len(json_data['repo_status']), 1) self.assertEqual(len(json_data['repo_status'][0]['prs']), 1) self.assertIn(escape(pr_open.title), json_data['repo_status'][0]['prs'][0]['description']) self.assertEqual(pr_closed.pk, json_data['closed'][0]['id'])
def test_invalidate(self, mock_collab): # only post is allowed url = reverse('ci:invalidate', args=[1000]) self.set_counts() response = self.client.get(url) self.assertEqual(response.status_code, 405) # not allowed self.compare_counts() # invalid job self.set_counts() response = self.client.post(url) self.assertEqual(response.status_code, 404) # not found self.compare_counts() # can't invalidate step_result = utils.create_step_result() job = step_result.job job.event.pull_request = utils.create_pr() job.event.comments_url = "some url" job.event.save() mock_collab.return_value = False url = reverse('ci:invalidate', args=[job.pk]) self.set_counts() response = self.client.post(url) self.assertEqual(response.status_code, 403) # forbidden self.compare_counts() # valid client = utils.create_client() job.client = client job.save() post_data = {"post_to_pr": "on", "comment": "some comment", "same_client": None, } mock_collab.return_value = True self.set_counts() response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, 302) #redirect self.compare_counts(ready=1, invalidated=1, num_changelog=1) job.refresh_from_db() redir_url = reverse('ci:view_job', args=[job.pk]) self.assertRedirects(response, redir_url) self.check_job_invalidated(job) post_data["same_client"] = "on" utils.create_step_result(job=job) job.client = client job.save() self.set_counts() response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, 302) #redirect self.compare_counts(num_changelog=1) job.refresh_from_db() self.assertRedirects(response, redir_url) self.check_job_invalidated(job, True, client)
def test_disable_repo(self): out = StringIO() with self.assertRaises(CommandError): management.call_command("disable_repo", "--dry-run", stdout=out) with self.assertRaises(CommandError): management.call_command("disable_repo", "--dry-run", "--owner", "foo", stdout=out) repo = utils.create_repo() with self.assertRaises(CommandError): management.call_command("disable_repo", "--dry-run", "--owner", repo.user.name, "--repo", "<repo>", stdout=out) repo.active = True repo.save() branch = utils.create_branch(repo=repo) branch.status = models.JobStatus.SUCCESS branch.save() pr = utils.create_pr(repo=repo) pr.closed = False pr.save() management.call_command("disable_repo", "--dry-run", "--owner", repo.user.name, "--repo", repo.name, stdout=out) repo.refresh_from_db() self.assertIs(repo.active, True) branch.refresh_from_db() self.assertEqual(branch.status, models.JobStatus.SUCCESS) pr.refresh_from_db() self.assertIs(pr.closed, False) management.call_command("disable_repo", "--owner", repo.user.name, "--repo", repo.name, stdout=out) repo.refresh_from_db() self.assertIs(repo.active, False) branch.refresh_from_db() self.assertEqual(branch.status, models.JobStatus.NOT_STARTED) pr.refresh_from_db() self.assertIs(pr.closed, True)
def create_step_result(self, output): result = utils.create_step_result() result.output = output result.save() ev = result.job.event ev.pull_request = utils.create_pr() ev.pull_request.review_comments_url = "review_comments" ev.pull_request.save() ev.comments_url = "url" ev.save() return result
def create_repo_with_prs(self, name="Repo0"): repo = utils.create_repo(name=name) branch = utils.create_branch(name="branch1", repo=repo) repo.active = True repo.save() branch.status = models.JobStatus.RUNNING branch.save() for i in range(3): pr = utils.create_pr(title="Foo {a, b} & <bar> … %s" % i, repo=repo, number=i+1) pr.status = models.JobStatus.RUNNING pr.save() return repo, branch
def test_pr_update(self): url = reverse('ci:ajax:pr_update', args=[1000]) # bad pr response = self.client.get(url) self.assertEqual(response.status_code, 404) pr = utils.create_pr(title="Foo <type> & bar …") url = reverse('ci:ajax:pr_update', args=[pr.pk]) response = self.client.get(url) self.assertEqual(response.status_code, 200) json_data = response.json() self.assertIn('events', json_data)
def test_new_pr(self): repo, branch = self.create_repo_with_prs() self.get() self.check_repos() self.check_events() pr = utils.create_pr(repo=repo, number=200) pr.status = models.JobStatus.RUNNING pr.save() self.wait_for_js() self.check_js_error() self.check_repos() self.check_events()
def test_new_pr(self): repo, branch = self.create_repo_with_prs() url = reverse('ci:view_repo', args=[repo.pk]) self.get(url) self.check_repos() self.check_events() pr = utils.create_pr(repo=repo, number=100) pr.status = models.JobStatus.RUNNING pr.save() self.wait_for_js() self.check_js_error() self.check_repos() self.check_events()
def test_update_pr_status(self, mock_post): mock_post.return_value = utils.Response() ev = utils.create_event(user=self.build_user) pr = utils.create_pr(server=self.server) ev.pull_request = pr ev.save() # no state is set so just run for coverage with self.settings( INSTALLED_GITSERVERS=[utils.gitlab_config( remote_update=True)]): mock_post.return_value = utils.Response(status_code=200, content="some content") api = self.server.api() api.update_pr_status(ev.base, ev.head, api.PENDING, 'event', 'desc', 'context', api.STATUS_JOB_STARTED) self.assertEqual(mock_post.call_count, 1) api.update_pr_status(ev.base, ev.head, api.PENDING, 'event', 'desc', 'context', api.STATUS_CONTINUE_RUNNING) self.assertEqual(mock_post.call_count, 1) # Not updated api.update_pr_status(ev.base, ev.head, api.PENDING, 'event', 'desc', 'context', api.STATUS_START_RUNNING) self.assertEqual(mock_post.call_count, 1) mock_post.return_value = utils.Response( json_data={"error": "some error"}, status_code=404) api.update_pr_status(ev.base, ev.head, api.PENDING, 'event', 'desc', 'context', api.STATUS_JOB_STARTED) self.assertEqual(mock_post.call_count, 2) mock_post.return_value = utils.Response( json_data={"error": "some error"}, status_code=205) api.update_pr_status(ev.base, ev.head, api.PENDING, 'event', 'desc', 'context', api.STATUS_JOB_STARTED) self.assertEqual(mock_post.call_count, 3) mock_post.side_effect = Exception('BAM!') api.update_pr_status(ev.base, ev.head, api.PENDING, 'event', 'desc', 'context', api.STATUS_JOB_STARTED) self.assertEqual(mock_post.call_count, 4) # This should just return api = self.server.api() api.update_pr_status(ev.base, ev.head, api.PENDING, 'event', 'desc', 'context', api.STATUS_JOB_STARTED) self.assertEqual(mock_post.call_count, 4)
def create_events(self): self.set_counts() self.build_user = utils.create_user_with_token(name="moosebuild") self.owner = utils.create_user(name="idaholab") self.repo = utils.create_repo(name="civet", user=self.owner) self.branch = utils.create_branch(name="devel", repo=self.repo) pre = utils.create_recipe(name="Precheck", user=self.build_user, repo=self.repo) test = utils.create_recipe(name="Test", user=self.build_user, repo=self.repo) test1 = utils.create_recipe(name="Test1", user=self.build_user, repo=self.repo) test.depends_on.add(pre) test1.depends_on.add(pre) merge = utils.create_recipe(name="Merge", user=self.build_user, repo=self.repo) merge.depends_on.add(test) merge.depends_on.add(test1) pr = utils.create_pr(title="{a, b} & <c> … somereallylongwordthatshouldgettruncated", repo=self.repo) pr.username = '******' pr.save() for commit in ['1234', '2345', '3456']: e = utils.create_event(user=self.owner, commit1=commit, branch1=self.branch, branch2=self.branch) e.pull_request = pr e.description = "some description" e.save() j = utils.create_job(recipe=pre, event=e, user=self.build_user) j.seconds = datetime.timedelta(seconds=10) j.failed_step = 'failed step' j.running_step = '3/5' j.save() utils.create_job(recipe=test, event=e, user=self.build_user) utils.create_job(recipe=test1, event=e, user=self.build_user) utils.create_job(recipe=merge, event=e, user=self.build_user) self.compare_counts(recipes=4, deps=4, current=4, jobs=12, active=12, num_pr_recipes=4, events=3, users=2, repos=1, branches=1, commits=3, prs=1)
def test_event_status_incomplete(self): self.create_jobs() # All jobs are NOT_STARTED ev = self.job0.event self.assertEqual(ev.jobs.count(), 4) ev.set_status() self.assertEqual(ev.status, models.JobStatus.NOT_STARTED) self.assertEqual(ev.base.branch.status, models.JobStatus.NOT_STARTED) # 1 SUCCESS but not all of them self.job0.status = models.JobStatus.SUCCESS self.job0.save() ev.set_status() self.assertEqual(ev.status, models.JobStatus.RUNNING) self.assertEqual(ev.base.branch.status, models.JobStatus.RUNNING) self.job1.status = models.JobStatus.FAILED self.job1.save() ev.set_status() self.assertEqual(ev.status, models.JobStatus.RUNNING) self.job2.status = models.JobStatus.ACTIVATION_REQUIRED self.job2.save() self.job3.status = models.JobStatus.ACTIVATION_REQUIRED self.job3.save() ev.set_status() self.assertEqual(ev.status, models.JobStatus.ACTIVATION_REQUIRED) self.assertEqual(ev.base.branch.status, models.JobStatus.ACTIVATION_REQUIRED) self.job2.status = models.JobStatus.RUNNING self.job2.save() ev.set_status() self.assertEqual(ev.status, models.JobStatus.RUNNING) self.assertEqual(ev.base.branch.status, models.JobStatus.RUNNING) # try again with on a pull request event ev.pull_request = utils.create_pr() ev.save() self.assertEqual(ev.pull_request.status, models.JobStatus.NOT_STARTED) ev.set_status() self.assertEqual(ev.status, models.JobStatus.RUNNING) self.assertEqual(ev.pull_request.status, models.JobStatus.RUNNING)
def test_repo_prs(self): repo0 = utils.create_repo(name="repo0") repo0.active = True repo0.save() utils.create_pr(title="pr0", number=1, repo=repo0) utils.create_pr(title="pr1", number=2, repo=repo0) repo1 = utils.create_repo(name="repo1") repo1.active = True repo1.save() utils.create_pr(repo=repo1) repo2 = utils.create_repo(name="repo2") repo2.active = True repo2.save() response = self.client.get(reverse('ci:num_prs')) self.assertEqual(response.status_code, 200)
def test_cancel_event(self, mock_collab): # only post is allowed url = reverse('ci:cancel_event', args=[1000]) self.set_counts() response = self.client.get(url) self.assertEqual(response.status_code, 405) # not allowed self.compare_counts() # invalid event self.set_counts() response = self.client.post(url) self.assertEqual(response.status_code, 404) # not found self.compare_counts() # can't cancel step_result = utils.create_step_result() job = step_result.job job.event.pull_request = utils.create_pr() job.event.comments_url = "some url" job.event.save() mock_collab.return_value = False url = reverse('ci:cancel_event', args=[job.event.pk]) self.set_counts() response = self.client.post(url) self.assertEqual(response.status_code, 302) # redirect with error message self.compare_counts() # valid mock_collab.return_value = True post_data = {"post_to_pr": "on", "comment": "some comment" } self.set_counts() response = self.client.post(url, post_data) self.compare_counts(canceled=1, events_canceled=1, num_events_completed=1, num_jobs_completed=1, num_changelog=1) self.assertEqual(response.status_code, 302) #redirect ev_url = reverse('ci:view_event', args=[job.event.pk]) self.assertRedirects(response, ev_url) job = models.Job.objects.get(pk=job.pk) self.assertEqual(job.status, models.JobStatus.CANCELED) self.assertEqual(job.event.status, models.JobStatus.CANCELED)
def test_view_user(self): user = utils.create_user() url = reverse('ci:view_user', args=["no_exist"]) response = self.client.get(url) self.assertEqual(response.status_code, 404) url = reverse('ci:view_user', args=[user.name]) response = self.client.get(url) self.assertEqual(response.status_code, 200) ev = utils.create_event() pr = utils.create_pr() pr.closed = True pr.username = user.name pr.save() ev.pull_request = pr ev.save() utils.create_job(event=ev) response = self.client.get(url) self.assertEqual(response.status_code, 200)
def test_close_pr(self): user = utils.get_test_user(server=self.server) repo = utils.create_repo(user=user) pr = utils.create_pr(repo=repo, number=1) pr.closed = False pr.save() views.close_pr('foo', 'bar', 1, user.server) pr.refresh_from_db() self.assertFalse(pr.closed) views.close_pr(user.name, 'bar', 1, user.server) pr.refresh_from_db() self.assertFalse(pr.closed) views.close_pr(user.name, repo.name, 0, user.server) pr.refresh_from_db() self.assertFalse(pr.closed) views.close_pr(user.name, repo.name, 1, user.server) pr.refresh_from_db() self.assertTrue(pr.closed)
def test_update_pull_requests(self): with test_utils.RecipeDir() as recipes_dir: creator = self.create_valid_with_check(recipes_dir) self.set_counts() creator._update_pull_requests() self.compare_counts() # update_pull_requests doesn't depend on recipes in the filesystem build_user = models.GitUser.objects.get(name="moosebuild") pr = test_utils.create_pr() self.assertEqual( build_user.recipes.filter( cause=models.Recipe.CAUSE_PULL_REQUEST_ALT).count(), 2) r1_orig = build_user.recipes.filter( cause=models.Recipe.CAUSE_PULL_REQUEST_ALT).first() r1 = test_utils.create_recipe(name="alt_pr", user=r1_orig.build_user, repo=r1_orig.repository, cause=r1_orig.cause) r1.filename = r1_orig.filename r1.save() r1_orig.current = False r1_orig.save() self.assertEqual(pr.alternate_recipes.count(), 0) pr.alternate_recipes.add(r1_orig) # There is an old alt recipe on the PR, it should be removed and replaced with the new one self.set_counts() creator._update_pull_requests() self.compare_counts() self.assertEqual(pr.alternate_recipes.count(), 1) self.assertEqual(pr.alternate_recipes.first().pk, r1.pk) r1.current = False r1.save() self.set_counts() # Now there are not current alt PR recipes creator._update_pull_requests() self.compare_counts(num_pr_alts=-1) self.assertEqual(pr.alternate_recipes.count(), 0)
def test_job_finished_status(self): user = utils.get_test_user() recipe = utils.create_recipe(user=user) job = utils.create_job(recipe=recipe, user=user) step0 = utils.create_step(name='step0', recipe=recipe) step1 = utils.create_step(name='step1', recipe=recipe, position=1) step0_result = utils.create_step_result(step=step0, job=job) step1_result = utils.create_step_result(step=step1, job=job) step0_result.status = models.JobStatus.FAILED_OK step0_result.save() step1_result.status = models.JobStatus.SUCCESS step1_result.save() client = utils.create_client() job.client = client job.save() job.event.comments_url = 'http://localhost' job.event.pull_request = utils.create_pr() job.event.save() url = reverse('ci:client:job_finished', args=[user.build_key, client.name, job.pk]) # A step has FAILED_OK # So final status is FAILED_OK and we update the PR post_data = {'seconds': 0, 'complete': True} with patch('ci.github.api.GitHubAPI') as mock_api: self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts(num_events_completed=1, num_jobs_completed=1) self.assertEqual(response.status_code, 200) self.assertTrue(mock_api.called) self.assertTrue(mock_api.return_value.update_pr_status.called) job.refresh_from_db() self.assertEqual(job.status, models.JobStatus.FAILED_OK) os_obj = models.OSVersion.objects.get(name="Other") self.assertEqual(job.operating_system.pk, os_obj.pk) self.assertEqual(job.loaded_modules.count(), 1) self.assertEqual(job.loaded_modules.first().name, "None") # A step FAILED # So final status is FAILED and we update the PR step0_result.status = models.JobStatus.FAILED step0_result.save() with patch('ci.github.api.GitHubAPI') as mock_api: self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 200) self.assertTrue(mock_api.called) self.assertTrue(mock_api.return_value.update_pr_status.called) job.refresh_from_db() self.assertEqual(job.status, models.JobStatus.FAILED) step0_result.status = models.JobStatus.SUCCESS step0_result.save() # All steps passed # So final status is SUCCESS and we update the PR with patch('ci.github.api.GitHubAPI') as mock_api: self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 200) self.assertTrue(mock_api.called) self.assertTrue(mock_api.return_value.update_pr_status.called) job.refresh_from_db() self.assertEqual(job.status, models.JobStatus.SUCCESS) step0_result.status = models.JobStatus.FAILED step0_result.save() # A step FAILED # So final status is FAILED and we update the PR with patch('ci.github.api.GitHubAPI') as mock_api: self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 200) self.assertTrue(mock_api.called) self.assertTrue(mock_api.return_value.update_pr_status.called) job.refresh_from_db() self.assertEqual(job.status, models.JobStatus.FAILED)
def test_event_complete(self, mock_del, mock_get, mock_post): ev = utils.create_event(cause=models.Event.PUSH) ev.comments_url = 'url' ev.save() git_config = utils.github_config(post_event_summary=False, failed_but_allowed_label_name=None, remote_update=True) with self.settings(INSTALLED_GITSERVERS=[git_config]): # Not complete, shouldn't do anything UpdateRemoteStatus.event_complete(ev) self.assertEqual(mock_get.call_count, 0) self.assertEqual(mock_post.call_count, 0) self.assertEqual(mock_del.call_count, 0) ev.complete = True ev.save() # event isn't a pull request, so we shouldn't do anything UpdateRemoteStatus.event_complete(ev) self.assertEqual(mock_get.call_count, 0) self.assertEqual(mock_post.call_count, 0) self.assertEqual(mock_del.call_count, 0) ev.cause = models.Event.PULL_REQUEST ev.status = models.JobStatus.SUCCESS ev.pull_request = utils.create_pr() ev.save() # No label so we shouldn't do anything UpdateRemoteStatus.event_complete(ev) self.assertEqual(mock_get.call_count, 0) self.assertEqual(mock_post.call_count, 0) self.assertEqual(mock_del.call_count, 0) git_config = utils.github_config(post_event_summary=False, failed_but_allowed_label_name='foo', remote_update=True) with self.settings(INSTALLED_GITSERVERS=[git_config]): # event is SUCCESS, so we shouldn't add a label but # we will try to remove an existing label UpdateRemoteStatus.event_complete(ev) self.assertEqual(mock_get.call_count, 0) self.assertEqual(mock_post.call_count, 0) self.assertEqual(mock_del.call_count, 1) # removing the label ev.status = models.JobStatus.FAILED ev.save() # Don't put anything if the event is FAILED UpdateRemoteStatus.event_complete(ev) self.assertEqual(mock_get.call_count, 0) self.assertEqual(mock_post.call_count, 0) self.assertEqual(mock_del.call_count, 2) ev.status = models.JobStatus.FAILED_OK ev.save() # should try to add a label UpdateRemoteStatus.event_complete(ev) self.assertEqual(mock_get.call_count, 0) self.assertEqual(mock_post.call_count, 1) # add the label self.assertEqual(mock_del.call_count, 2)
def test_event_status_complete(self): self.create_jobs() # All jobs are NOT_STARTED ev = self.job0.event self.assertEqual(ev.jobs.count(), 4) ev.set_complete() self.assertEqual(ev.status, models.JobStatus.NOT_STARTED) # 1 SUCCESS but none of them are ready self.job0.status = models.JobStatus.SUCCESS self.job0.complete = True self.job0.save() self.job1.complete = True self.job1.save() self.job2.complete = True self.job2.save() self.job3.complete = True self.job3.save() ev.set_complete() ev.refresh_from_db() self.assertEqual(ev.status, models.JobStatus.SUCCESS) self.assertEqual(ev.base.branch.status, models.JobStatus.SUCCESS) # 1 SUCCESS, 1 CANCELED self.job1.status = models.JobStatus.CANCELED self.job1.save() ev.set_complete() ev.refresh_from_db() self.assertEqual(ev.status, models.JobStatus.CANCELED) self.assertEqual(ev.base.branch.status, models.JobStatus.CANCELED) # 1 SUCCESS, 1 CANCELED, 1 FAILED_OK self.job2.status = models.JobStatus.FAILED_OK self.job2.save() ev.set_complete() ev.refresh_from_db() self.assertEqual(ev.status, models.JobStatus.CANCELED) self.assertEqual(ev.base.branch.status, models.JobStatus.CANCELED) # 1 SUCCESS, 1 CANCELED, 1 FAILED_OK, 1 FAILED self.job3.status = models.JobStatus.FAILED self.job3.save() ev.set_complete() ev.refresh_from_db() # Since jobs are j0 -> j1,j2 ->j3 j3 is unrunnable # and not counted self.assertEqual(ev.status, models.JobStatus.CANCELED) self.assertEqual(ev.base.branch.status, models.JobStatus.CANCELED) # 2 SUCCESS, 1 FAILED_OK, 1 FAILED self.job1.status = models.JobStatus.SUCCESS self.job1.save() ev.set_complete() ev.refresh_from_db() self.assertEqual(ev.status, models.JobStatus.FAILED) self.assertEqual(ev.base.branch.status, models.JobStatus.FAILED) # 2 SUCCESS, 1 FAILED_OK, 1 RUNNING self.job3.status = models.JobStatus.RUNNING self.job3.save() ev.set_complete() ev.refresh_from_db() self.assertEqual(ev.status, models.JobStatus.RUNNING) self.assertEqual(ev.base.branch.status, models.JobStatus.RUNNING) # 3 SUCCESS, 1 FAILED_OK self.job3.status = models.JobStatus.SUCCESS self.job3.save() ev.set_complete() ev.refresh_from_db() self.assertEqual(ev.status, models.JobStatus.FAILED_OK) self.assertEqual(ev.base.branch.status, models.JobStatus.FAILED_OK) # try again with on a pull request event ev.pull_request = utils.create_pr() ev.save() self.assertEqual(ev.pull_request.status, models.JobStatus.NOT_STARTED) ev.set_complete() self.assertEqual(ev.status, models.JobStatus.FAILED_OK) self.assertEqual(ev.pull_request.status, models.JobStatus.FAILED_OK)
def test_view_pr(self, mock_collab): """ testing ci:view_pr """ # bad pr url = reverse('ci:view_pr', args=[1000,]) response = self.client.get(url) self.assertEqual(response.status_code, 404) pr = utils.create_pr() ev = utils.create_event() ev.pull_request = pr ev.save() utils.create_job(event=ev) user = utils.get_test_user() utils.simulate_login(self.client.session, user) # user not a collaborator, no alternate recipe form mock_collab.return_value = False url = reverse('ci:view_pr', args=[pr.pk,]) self.set_counts() response = self.client.get(url) self.compare_counts() self.assertEqual(response.status_code, 200) # user a collaborator, they get alternate recipe form mock_collab.return_value = True r0 = utils.create_recipe(name="Recipe 0", repo=ev.base.branch.repository, cause=models.Recipe.CAUSE_PULL_REQUEST_ALT) r1 = utils.create_recipe(name="Recipe 1", repo=ev.base.branch.repository, cause=models.Recipe.CAUSE_PULL_REQUEST_ALT) self.set_counts() response = self.client.get(url) self.compare_counts() self.assertEqual(response.status_code, 200) self.set_counts() # post an invalid alternate recipe form response = self.client.post(url, {}) self.assertEqual(response.status_code, 200) self.assertEqual(pr.alternate_recipes.count(), 0) self.compare_counts() utils.simulate_login(self.client.session, user) # post a valid alternate recipe form self.set_counts() response = self.client.post(url, {"recipes": [r0.pk, r1.pk]}) self.assertEqual(response.status_code, 200) self.assertEqual(pr.alternate_recipes.count(), 2) # The original job plus the two alternate jobs are ready self.compare_counts(jobs=2, ready=3, active=2, num_pr_alts=2) # post again with the same recipes self.set_counts() response = self.client.post(url, {"recipes": [r0.pk, r1.pk]}) self.assertEqual(response.status_code, 200) self.assertEqual(pr.alternate_recipes.count(), 2) self.compare_counts() # post again different recipes. We don't auto cancel jobs. self.set_counts() response = self.client.post(url, {"recipes": [r0.pk]}) self.assertEqual(response.status_code, 200) self.assertEqual(pr.alternate_recipes.count(), 1) self.compare_counts(num_pr_alts=-1) # clear alt recipes self.set_counts() response = self.client.post(url, {"recipes": []}) self.assertEqual(response.status_code, 200) self.assertEqual(pr.alternate_recipes.count(), 0) self.compare_counts(num_pr_alts=-1)
def test_user_open_prs(self): user = utils.create_user() url = reverse('ci:ajax:user_open_prs', args=["no_exist"]) response = self.client.get(url) self.assertEqual(response.status_code, 400) url = reverse('ci:ajax:user_open_prs', args=[user.name]) response = self.client.get(url) self.assertEqual(response.status_code, 400) get_data = {'last_request': 10} response = self.client.get(url, get_data) self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(len(data["repos"]), 0) self.assertEqual(len(data["prs"]), 0) self.assertEqual(len(data["events"]), 0) self.assertEqual(len(data["changed_events"]), 0) self.assertEqual(len(data["repo_status"]), 0) ev = utils.create_event() pr = utils.create_pr() pr.closed = True pr.username = user.name pr.save() ev.pull_request = pr ev.save() utils.create_job(event=ev) # not open response = self.client.get(url, get_data) self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(len(data["repos"]), 0) self.assertEqual(len(data["prs"]), 0) self.assertEqual(len(data["events"]), 0) self.assertEqual(len(data["changed_events"]), 0) self.assertEqual(len(data["repo_status"]), 0) # should be OK pr.closed = False pr.save() response = self.client.get(url, get_data) self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(len(data["repos"]), 1) self.assertEqual(len(data["prs"]), 1) self.assertEqual(len(data["events"]), 1) self.assertEqual(len(data["changed_events"]), 1) self.assertEqual(len(data["repo_status"]), 1) # use the last request. The changed_* shouldn't be set get_data["last_request"] = data["last_request"] + 10 response = self.client.get(url, get_data) self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(len(data["repos"]), 1) self.assertEqual(len(data["prs"]), 1) self.assertEqual(len(data["events"]), 1) self.assertEqual(len(data["changed_events"]), 0) self.assertEqual(len(data["repo_status"]), 0)
def test_claim_job(self): post_data = {'job_id': 0} user = utils.get_test_user() url = reverse('ci:client:claim_job', args=[user.build_key, 'testconfig', 'testClient']) # only post allowed self.set_counts() response = self.client.get(url) self.compare_counts() self.assertEqual(response.status_code, 405) # not allowed # setup a ready job job = utils.create_job(user=user) job.ready = True job.active = True job.event.cause = models.Event.PULL_REQUEST pr = utils.create_pr() job.event.pull_request = pr job.event.save() job.status = models.JobStatus.NOT_STARTED job_id = job.pk job.save() # bad config post_data = {'job_id': job_id} self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 400) # bad request # config different than job utils.create_build_config(name="otherBuildConfig") config2 = models.BuildConfig.objects.exclude(pk=job.config.pk).first() url = reverse('ci:client:claim_job', args=[user.build_key, config2.name, 'testClient']) post_data = {'job_id': job_id} self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 400) # bad request # bad job url = reverse('ci:client:claim_job', args=[user.build_key, job.config.name, 'testClient']) post_data = {'job_id': 0} self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 400) # bad request # valid job, should be ok post_data = {'job_id': job_id} self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts(num_clients=1) self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(data['job_id'], job_id) self.assertEqual(data['status'], 'OK') job.refresh_from_db() job.event.refresh_from_db() job.event.pull_request.refresh_from_db() self.assertEqual(job.status, models.JobStatus.RUNNING) self.assertEqual(job.event.status, models.JobStatus.RUNNING) self.assertEqual(job.event.pull_request.status, models.JobStatus.RUNNING) # create a job with a newer event. # This allows to test the update_status() function event2 = utils.create_event(commit1="2345", commit2="2345") job2 = utils.create_job(user=user, event=event2) job2.ready = True job2.active = True job2.event.cause = models.Event.PULL_REQUEST job2.event.pull_request = pr job2.event.save() job2.status = models.JobStatus.NOT_STARTED job2.save() job.status = models.JobStatus.NOT_STARTED job.client = None job.save() job.event.status = models.JobStatus.SUCCESS job.event.save() job.event.pull_request.status = models.JobStatus.SUCCESS job.event.pull_request.save() # valid job, should be ok, shouldn't update the status since # there is a newer event self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(data['job_id'], job_id) self.assertEqual(data['status'], 'OK') job.refresh_from_db() job.event.refresh_from_db() job.event.pull_request.refresh_from_db() self.assertEqual(job.status, models.JobStatus.RUNNING) self.assertEqual(job.event.status, models.JobStatus.RUNNING) # there is a newer event so this event doesn't update the PullRequest status self.assertEqual(job.event.pull_request.status, models.JobStatus.SUCCESS) # valid job, but wrong client job.invalidated = True job.same_client = True job.status = models.JobStatus.NOT_STARTED client = utils.create_client(name='old_client') job.client = client job.save() self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 400) # valid job, and correct client url = reverse('ci:client:claim_job', args=[user.build_key, job.config.name, client.name]) self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(data['job_id'], job_id) self.assertEqual(data['status'], 'OK') # valid job, and job client was null, should go through job.client = None job.save() url = reverse('ci:client:claim_job', args=[user.build_key, job.config.name, 'new_client']) self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts(num_clients=1) self.assertEqual(response.status_code, 200) data = response.json() self.assertEqual(data['job_id'], job_id) self.assertEqual(data['status'], 'OK') job.refresh_from_db() job.event.refresh_from_db() job.event.pull_request.refresh_from_db() self.assertEqual(job.status, models.JobStatus.RUNNING) self.assertEqual(job.event.status, models.JobStatus.RUNNING) # there is a newer event so this event doesn't update the PullRequest status self.assertEqual(job.event.pull_request.status, models.JobStatus.SUCCESS)
def test_start_step_result(self): user = utils.get_test_user() job = utils.create_job(user=user) result = utils.create_step_result(job=job) client = utils.create_client() client2 = utils.create_client(name='other_client') job.client = client job.event.cause = models.Event.PULL_REQUEST job.event.pr = utils.create_pr() job.event.save() job.save() post_data = { 'step_num': result.position, 'output': 'output', 'time': 5, 'complete': True, 'exit_status': 0 } url = reverse('ci:client:start_step_result', args=[user.build_key, client.name, result.pk]) # only post allowed self.set_counts() response = self.client.get(url) self.compare_counts() self.assertEqual(response.status_code, 405) # not allowed # bad step result url = reverse('ci:client:start_step_result', args=[user.build_key, client.name, 0]) self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 400) # bad request # unknown client url = reverse('ci:client:start_step_result', args=[user.build_key, 'unknown_client', result.pk]) self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 400) # bad request # bad client url = reverse('ci:client:start_step_result', args=[user.build_key, client2.name, result.pk]) self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 400) # bad request # ok url = reverse('ci:client:start_step_result', args=[user.build_key, client.name, result.pk]) self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 200) result.refresh_from_db() self.assertEqual(result.status, models.JobStatus.RUNNING) data = response.json() self.assertEqual(data["command"], None) self.assertEqual(data["status"], "OK") # If a job got canceled, make sure it sends the command to the client job.status = models.JobStatus.CANCELED job.save() self.set_counts() response = self.client_post_json(url, post_data) self.compare_counts() self.assertEqual(response.status_code, 200) result.refresh_from_db() self.assertEqual(result.status, models.JobStatus.CANCELED) data = response.json() self.assertEqual(data["command"], "cancel") self.assertEqual(data["status"], "OK")
def test_sync_open_prs(self, mock_get): r = models.Recipe.objects.first() repo = r.repository repo.active = True repo.save() pr = utils.create_pr(title="TESTPR") pr.closed = False pr.save() pr0 = {"number": pr.number, "title": "PR 1", "html_url": "first_url"} pr1 = { "number": pr.number + 1, "title": "PR 2", "html_url": "second_url" } mock_get.return_value = utils.Response([pr1]) # A PR with recipe but its repository isn't active out = StringIO() management.call_command("sync_open_prs", stdout=out) self.assertEqual('', self._split_output(out)[0]) pr.repository = repo pr.save() # A PR with a good repo, should be closed out = StringIO() management.call_command("sync_open_prs", stdout=out) self.assertIn(pr.title, out.getvalue()) self.assertIn(str(pr.number), out.getvalue()) self.assertIn(str(pr.repository), out.getvalue()) pr.refresh_from_db() self.assertEqual(pr.closed, True) # Try to sync a specific repository that exists out = StringIO() pr.closed = False pr.save() management.call_command("sync_open_prs", "--dryrun", "--repo", str(repo), stdout=out) self.assertIn(pr.title, out.getvalue()) self.assertIn(str(pr.number), out.getvalue()) self.assertIn(str(pr.repository), out.getvalue()) pr.refresh_from_db() self.assertEqual(pr.closed, False) # Try to sync a specific repository that exists out = StringIO() management.call_command("sync_open_prs", "--repo", str(repo), stdout=out) self.assertIn(pr.title, out.getvalue()) self.assertIn(str(pr.number), out.getvalue()) self.assertIn(str(pr.repository), out.getvalue()) pr.refresh_from_db() self.assertEqual(pr.closed, True) # Make sure dry run doesn't change anything out = StringIO() pr.closed = False pr.save() management.call_command("sync_open_prs", "--dryrun", stdout=out) self.assertIn(pr.title, out.getvalue()) self.assertIn(str(pr.number), out.getvalue()) self.assertIn(str(pr.repository), out.getvalue()) pr.refresh_from_db() self.assertEqual(pr.closed, False) mock_get.return_value = utils.Response([pr0, pr1]) # Server has other PRs that CIVET doesn't have out = StringIO() management.call_command("sync_open_prs", "--dryrun", stdout=out) self.assertNotIn(pr.title, out.getvalue()) self.assertNotIn("#%s" % pr.number, out.getvalue()) self.assertIn("PRs open on server but not open on CIVET", out.getvalue()) self.assertIn("PR 2", out.getvalue()) self.assertIn("second_url", out.getvalue()) self.assertIn("#%s" % (pr.number + 1), out.getvalue()) pr.refresh_from_db() self.assertEqual(pr.closed, False) # Try to sync a specific repository that doesn't exist out = StringIO() management.call_command("sync_open_prs", "--dryrun", "--repo", "foo/bar", stdout=out) self.assertEqual("", out.getvalue()) # If the git server encounters an error then it shouldn't do anything mock_get.return_value = utils.Response(status_code=404) out = StringIO() management.call_command("sync_open_prs", stdout=out) self.assertIn("Error getting open PRs for %s" % repo, out.getvalue()) pr.refresh_from_db() self.assertEqual(pr.closed, False)