Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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, [])
Ejemplo n.º 3
0
 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
Ejemplo n.º 4
0
    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())
Ejemplo n.º 5
0
 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()
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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'])
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
 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
Ejemplo n.º 11
0
 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
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
    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()
Ejemplo n.º 14
0
    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()
Ejemplo n.º 15
0
    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)
Ejemplo n.º 16
0
    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)
Ejemplo n.º 17
0
    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)
Ejemplo n.º 18
0
 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)
Ejemplo n.º 19
0
    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)
Ejemplo n.º 20
0
    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)
Ejemplo n.º 21
0
    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)
Ejemplo n.º 22
0
    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)
Ejemplo n.º 23
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)
Ejemplo n.º 24
0
    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)
Ejemplo n.º 25
0
    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)
Ejemplo n.º 26
0
    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)
Ejemplo n.º 27
0
    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)
Ejemplo n.º 28
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)
Ejemplo n.º 29
0
    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")
Ejemplo n.º 30
0
    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)