Exemple #1
0
    def test_promote_post(self):
        b = Build.create(self.project)
        db.session.add(Run(b, 'run0'))
        db.session.add(Run(b, 'run1'))

        url = 'http://localhost/projects/proj-1/builds/%d/promote' % b.build_id

        headers = {
            'Content-type': 'application/json',
        }
        data = {
            'name': 'release-x',
            'annotation': 'foo bar',
        }

        # you can't promote an in-progress build
        _sign(url, headers, 'POST')
        self._post(url, json.dumps(data), headers, 400)

        for r in b.runs:
            r.set_status(BuildStatus.PASSED)
        self._post(url, json.dumps(data), headers, 201)
        db.session.refresh(b)
        self.assertEqual(BuildStatus.PROMOTED, b.status)
        self.assertEqual(data['name'], b.name)
        self.assertEqual(data['annotation'], b.annotation)
Exemple #2
0
 def get_signed_json(self, url, status_code=200, query_string=None):
     headers = {}
     if not url.startswith('http://'):
         # signed url handling requires complete url
         url = 'http://localhost' + url
     permissions._sign(url, headers, 'GET')
     return self.get_json(url, status_code, query_string, headers)
Exemple #3
0
    def test_project_trigger_create(self):
        self.create_projects("proj-1")
        url = "http://localhost/projects/proj-1/triggers/"

        headers = {"Content-type": "application/json"}
        _sign(url, headers, "POST")
        data = {
            "owner": "gavin.gavel",
            "type": "git_poller",
            "secret1": "ThisIsThePassword",
        }
        r = self.client.post(url, headers=headers, data=json.dumps(data))
        self.assertEqual(201, r.status_code, r.data)
        p = Project.query.filter(Project.name == "proj-1").one()
        self.assertEqual(1, len(p.triggers))
        t = p.triggers[0]
        self.assertEqual(TriggerTypes.git_poller.value, t.type)
        self.assertEqual(data["owner"], t.user)
        self.assertEqual(data["secret1"], t.secret_data["secret1"])

        trigger = self.get_signed_json(url)[0]
        self.assertEqual([{"name": "secret1"}], trigger["secrets"])

        # now patch the secrets and make sure it works
        data = {
            "secrets": [
                {"name": "secret1", "value": "newval"},  # update one
                {"name": "secret2", "value": "hax0r"},  # add one
            ]
        }
        self.patch_signed_json(url + str(trigger["id"]) + "/", data)
        p = Project.query.filter(Project.name == "proj-1").one()
        t = p.triggers[0]
        self.assertEqual(t.secret_data["secret1"], "newval")
        self.assertEqual(t.secret_data["secret2"], "hax0r")
Exemple #4
0
    def test_promote_post(self):
        b = Build.create(self.project)
        db.session.add(Run(b, "run0"))
        db.session.add(Run(b, "run1"))

        url = "http://localhost/projects/proj-1/builds/%d/promote" % b.build_id

        headers = {
            "Content-type": "application/json",
        }
        data = {
            "name": "release-x",
            "annotation": "foo bar",
        }

        # you can't promote an in-progress build
        _sign(url, headers, "POST")
        self._post(url, json.dumps(data), headers, 400)

        for r in b.runs:
            r.set_status(BuildStatus.PASSED)
        self._post(url, json.dumps(data), headers, 201)
        db.session.refresh(b)
        self.assertEqual(BuildStatus.PROMOTED, b.status)
        self.assertEqual(data["name"], b.name)
        self.assertEqual(data["annotation"], b.annotation)
Exemple #5
0
 def test_build_unexpected(self, storage):
     """Ensure unexpected storage errors are handled gracefully."""
     storage().set_run_definition.side_effect = RuntimeError("edge case!!!")
     headers = {"Content-type": "application/json"}
     data = {
         "trigger-name": "git",
         "project-definition": {
             "timeout":
             5,
             "email": {
                 "users": "*****@*****.**",
             },
             "triggers": [
                 {
                     "name":
                     "git",
                     "type":
                     "git_poller",
                     "runs": [{
                         "name": "run0",
                         "host-tag": "foo*",
                         "container": "alpine",
                         "script": "test",
                     }],
                 },
             ],
             "scripts": {
                 "test": "#test#",
             },
         },
     }
     _sign("http://localhost/projects/proj-1/builds/", headers, "POST")
     self._post(self.urlbase, json.dumps(data), headers, 500)
     self.assertEqual([BuildStatus.FAILED], [x.status for x in Run.query])
Exemple #6
0
    def test_build_trigger_fails(self):
        # ensure we have a graceful failure when we are triggered
        headers = {}
        r = self.client.post(self.urlbase, data={}, headers=headers)
        self.assertEqual(401, r.status_code)  # not signed

        _sign('http://localhost/projects/proj-1/builds/', headers, 'POST')
        r = self.client.post(self.urlbase, data={}, headers=headers)
        self.assertEqual(500, r.status_code)
        data = json.loads(r.data.decode())
        self.assertEqual('error', data['status'])
Exemple #7
0
 def patch_signed_json(self, url, data, status_code=200):
     headers = {}
     if not url.startswith('http://'):
         # signed url handling requires complete url
         url = 'http://localhost' + url
     permissions._sign(url, headers, 'PATCH')
     resp = self.client.patch(url, headers=headers, json=data)
     if status_code != resp.status_code:
         print('response text:', resp.data)
     self.assertEqual(status_code, resp.status_code, resp.data)
     data = json.loads(resp.data)
     return data['data']
Exemple #8
0
    def test_run_rerun(self):
        r = Run(self.build, 'run0')
        r.status = BuildStatus.FAILED
        db.session.add(r)
        db.session.commit()

        url = 'http://localhost' + self.urlbase + 'run0/rerun'

        headers = {}
        self._post(url, 'message', headers, 401)

        permissions._sign(url, headers, 'POST')
        self._post(url, 'message', headers, 200)
Exemple #9
0
    def test_run_rerun(self):
        r = Run(self.build, "run0")
        r.status = BuildStatus.FAILED
        db.session.add(r)
        db.session.commit()

        url = "http://localhost" + self.urlbase + "run0/rerun"

        headers = {}
        self._post(url, "message", headers, 401)

        permissions._sign(url, headers, "POST")
        self._post(url, "message", headers, 200)
Exemple #10
0
    def test_build_trigger_simple(self, trigger_build):
        """Assert we can trigger a minimal build."""
        trigger_build.return_value.build_id = 1
        headers = {"Content-type": "application/json"}
        data = {}
        _sign("http://localhost/projects/proj-1/builds/", headers, "POST")
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual({}, trigger_build.call_args[0][4])

        trigger_build.reset_mock()
        data = {"secrets": {"foo": "bar"}}
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual(data["secrets"], trigger_build.call_args[0][4])
Exemple #11
0
    def test_build_trigger_simple(self, trigger_build):
        """Assert we can trigger a minimal build."""
        trigger_build.return_value.build_id = 1
        headers = {'Content-type': 'application/json'}
        data = {}
        _sign('http://localhost/projects/proj-1/builds/', headers, 'POST')
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual({}, trigger_build.call_args[0][4])

        trigger_build.reset_mock()
        data = {'secrets': {'foo': 'bar'}}
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual(data['secrets'], trigger_build.call_args[0][4])
Exemple #12
0
    def test_run_cancel(self, storage):
        r = Run(self.build, 'run0')
        db.session.add(r)
        db.session.commit()

        headers = {}
        url = 'http://localhost' + self.urlbase + 'run0/cancel'

        self._post(url, 'message', headers, 401)

        permissions._sign(url, headers, 'POST')
        self._post(url, '', headers, 202)
        db.session.refresh(r)
        self.assertEqual(BuildStatus.CANCELLING, r.status)
Exemple #13
0
    def test_run_cancel(self, storage):
        r = Run(self.build, "run0")
        db.session.add(r)
        db.session.commit()

        headers = {}
        url = "http://localhost" + self.urlbase + "run0/cancel"

        self._post(url, "message", headers, 401)

        permissions._sign(url, headers, "POST")
        self._post(url, "", headers, 202)
        db.session.refresh(r)
        self.assertEqual(BuildStatus.CANCELLING, r.status)
    def test_build_trigger_with_secrets(self, trigger_build):
        """Assert we honor the trigger-type and trigger-id params."""
        trigger_build.return_value.build_id = 1
        pt = ProjectTrigger('user', TriggerTypes.simple.value, self.project,
                            None, None, {'foo': 'simple'})
        db.session.add(pt)
        db.session.commit()

        # try first trigger type
        headers = {'Content-type': 'application/json'}
        data = {'trigger-type': 'simple'}
        _sign('http://localhost/projects/proj-1/builds/', headers, 'POST')
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual({'foo': 'simple'}, trigger_build.call_args[0][4])

        # try "optional" trigger type (when there is no "optional")
        data = {'trigger-type': 'git-poller-optional'}
        _sign('http://localhost/projects/proj-1/builds/', headers, 'POST')
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual({}, trigger_build.call_args[0][4])

        # try override
        data = {'trigger-type': 'simple', 'secrets': {'foo': 'override'}}
        _sign('http://localhost/projects/proj-1/builds/', headers, 'POST')
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual({'foo': 'override'}, trigger_build.call_args[0][4])

        # try by trigger-id
        data = {'trigger-id': pt.id}
        _sign('http://localhost/projects/proj-1/builds/', headers, 'POST')
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual({'foo': 'simple'}, trigger_build.call_args[0][4])
Exemple #15
0
    def test_project_create(self):
        url = "http://localhost/projects/"
        headers = {"Content-type": "application/json"}
        _sign(url, headers, "POST")
        r = self.client.post(url, headers=headers, data=json.dumps({"name": "foo"}))
        self.assertEqual(201, r.status_code, r.data)
        Project.query.filter(Project.name == "foo").one()

        r = self.client.post(
            url,
            headers=headers,
            data=json.dumps({"name": "foo2", "synchronous-builds": True}),
        )
        self.assertEqual(201, r.status_code, r.data)
        p = Project.query.filter(Project.name == "foo2").one()
        self.assertTrue(p.synchronous_builds)
Exemple #16
0
    def test_project_delete_denied(self):
        self.create_projects("proj-1")
        url = "http://localhost/projects/proj-1/"
        r = self.client.delete(url)
        self.assertEqual(401, r.status_code)
        self.assertEqual("X-JobServ-Sig not provided", r.json["message"])

        headers = {"Content-type": "application/json"}
        _sign(url, headers, "DELETE")
        r = self.client.delete(url, headers=headers, data=json.dumps({}))
        self.assertEqual(401, r.status_code, r.data)

        headers = {"Content-type": "application/json"}
        _sign(url, headers, "DELETE")
        data = {"I_REALLY_MEAN_TO_DO_THIS": "YES"}
        r = self.client.delete(url, headers=headers, data=json.dumps(data))
        self.assertEqual(200, r.status_code, r.data)
Exemple #17
0
    def test_project_delete_denied(self):
        self.create_projects('proj-1')
        url = 'http://localhost/projects/proj-1/'
        r = self.client.delete(url)
        self.assertEqual(401, r.status_code)
        self.assertEqual('X-JobServ-Sig not provided', r.json['message'])

        headers = {'Content-type': 'application/json'}
        _sign(url, headers, 'DELETE')
        r = self.client.delete(url, headers=headers, data=json.dumps({}))
        self.assertEqual(401, r.status_code, r.data)

        headers = {'Content-type': 'application/json'}
        _sign(url, headers, 'DELETE')
        data = {'I_REALLY_MEAN_TO_DO_THIS': 'YES'}
        r = self.client.delete(url, headers=headers, data=json.dumps(data))
        self.assertEqual(200, r.status_code, r.data)
Exemple #18
0
    def test_project_create(self):
        url = 'http://localhost/projects/'
        headers = {'Content-type': 'application/json'}
        _sign(url, headers, 'POST')
        r = self.client.post(url,
                             headers=headers,
                             data=json.dumps({'name': 'foo'}))
        self.assertEqual(201, r.status_code, r.data)
        Project.query.filter(Project.name == 'foo').one()

        r = self.client.post(url,
                             headers=headers,
                             data=json.dumps({
                                 'name': 'foo2',
                                 'synchronous-builds': True
                             }))
        self.assertEqual(201, r.status_code, r.data)
        p = Project.query.filter(Project.name == 'foo2').one()
        self.assertTrue(p.synchronous_builds)
Exemple #19
0
    def test_project_trigger_secret_removal(self):
        project_name = 'projectUpdateTest'
        trigger_url = f'http://localhost/projects/{project_name}/triggers/'
        trigger_headers = {'Content-type': 'application/json'}
        _sign(trigger_url, trigger_headers, 'POST')
        secret_a = (str(uuid4()), str(uuid4()))  # (key, value) tuple
        secret_b = (str(uuid4()), str(uuid4()))
        secret_c = (str(uuid4()), str(uuid4()))
        secrets = dict([secret_a, secret_b, secret_c])
        create_data = {
            'owner': 'tester.testing',
            'type': TriggerTypes.git_poller.name,
            **secrets
        }
        self.create_projects(project_name)
        response = self.client.post(trigger_url,
                                    headers=trigger_headers,
                                    data=json.dumps(create_data))
        self.assertEqual(201, response.status_code, msg=response.data)
        actual_triggers = self.get_signed_json(url=trigger_url)
        self.assertEqual(1, len(actual_triggers))
        actual_trigger = actual_triggers[0]
        actual_secrets = [
            secret['name'] for secret in actual_trigger['secrets']
        ]
        self.assertEqual(3, len(actual_secrets))
        self.assertIn(secret_a[0], actual_secrets)
        self.assertIn(secret_b[0], actual_secrets)
        self.assertIn(secret_c[0], actual_secrets)
        remove_data = {'secrets': [{'name': secret_b[0], 'value': None}]}

        self.patch_signed_json(f"{trigger_url}{actual_trigger['id']}/",
                               remove_data)

        actual_trigger = self.get_signed_json(url=trigger_url)[0]
        actual_secrets = [
            secret['name'] for secret in actual_trigger['secrets']
        ]
        self.assertEqual(2, len(actual_secrets))
        self.assertIn(secret_a[0], actual_secrets)
        self.assertNotIn(secret_b[0], actual_secrets)
        self.assertIn(secret_c[0], actual_secrets)
Exemple #20
0
    def test_project_trigger_create(self):
        self.create_projects('proj-1')
        url = 'http://localhost/projects/proj-1/triggers/'

        headers = {'Content-type': 'application/json'}
        _sign(url, headers, 'POST')
        data = {
            'owner': 'gavin.gavel',
            'type': 'git_poller',
            'secret1': 'ThisIsThePassword',
        }
        r = self.client.post(url, headers=headers, data=json.dumps(data))
        self.assertEqual(201, r.status_code, r.data)
        p = Project.query.filter(Project.name == 'proj-1').one()
        self.assertEqual(1, len(p.triggers))
        t = p.triggers[0]
        self.assertEqual(TriggerTypes.git_poller.value, t.type)
        self.assertEqual(data['owner'], t.user)
        self.assertEqual(data['secret1'], t.secret_data['secret1'])

        trigger = self.get_signed_json(url)[0]
        self.assertEqual([{'name': 'secret1'}], trigger['secrets'])

        # now patch the secrets and make sure it works
        data = {
            'secrets': [
                {
                    'name': 'secret1',
                    'value': 'newval'
                },  # update one
                {
                    'name': 'secret2',
                    'value': 'hax0r'
                },  # add one
            ]
        }
        self.patch_signed_json(url + str(trigger['id']) + '/', data)
        p = Project.query.filter(Project.name == 'proj-1').one()
        t = p.triggers[0]
        self.assertEqual(t.secret_data['secret1'], 'newval')
        self.assertEqual(t.secret_data['secret2'], 'hax0r')
Exemple #21
0
    def test_cancel(self):
        b = Build.create(self.project)
        db.session.add(Run(b, "run0"))
        r = Run(b, "run1")
        r.status = BuildStatus.RUNNING
        db.session.add(r)

        url = "http://localhost/projects/proj-1/builds/%d/cancel" % b.build_id

        headers = {
            "Content-type": "application/json",
        }
        _sign(url, headers, "POST")
        self._post(url, "", headers, 202)

        expected = [BuildStatus.FAILED, BuildStatus.CANCELLING]
        if db.engine.dialect.name == "sqlite":
            # sqlite doesn't handle the query properly
            expected[0] = BuildStatus.CANCELLING

        self.assertEqual(expected, [x.status for x in b.runs])
Exemple #22
0
    def test_project_trigger_secret_removal(self):
        project_name = "projectUpdateTest"
        trigger_url = f"http://localhost/projects/{project_name}/triggers/"
        trigger_headers = {"Content-type": "application/json"}
        _sign(trigger_url, trigger_headers, "POST")
        secret_a = (str(uuid4()), str(uuid4()))  # (key, value) tuple
        secret_b = (str(uuid4()), str(uuid4()))
        secret_c = (str(uuid4()), str(uuid4()))
        secrets = dict([secret_a, secret_b, secret_c])
        create_data = {
            "owner": "tester.testing",
            "type": TriggerTypes.git_poller.name,
            **secrets,
        }
        self.create_projects(project_name)
        response = self.client.post(
            trigger_url, headers=trigger_headers, data=json.dumps(create_data)
        )
        self.assertEqual(201, response.status_code, msg=response.data)
        actual_triggers = self.get_signed_json(url=trigger_url)
        self.assertEqual(1, len(actual_triggers))
        actual_trigger = actual_triggers[0]
        actual_secrets = [secret["name"] for secret in actual_trigger["secrets"]]
        self.assertEqual(3, len(actual_secrets))
        self.assertIn(secret_a[0], actual_secrets)
        self.assertIn(secret_b[0], actual_secrets)
        self.assertIn(secret_c[0], actual_secrets)
        remove_data = {"secrets": [{"name": secret_b[0], "value": None}]}

        self.patch_signed_json(f"{trigger_url}{actual_trigger['id']}/", remove_data)

        actual_trigger = self.get_signed_json(url=trigger_url)[0]
        actual_secrets = [secret["name"] for secret in actual_trigger["secrets"]]
        self.assertEqual(2, len(actual_secrets))
        self.assertIn(secret_a[0], actual_secrets)
        self.assertNotIn(secret_b[0], actual_secrets)
        self.assertIn(secret_c[0], actual_secrets)
Exemple #23
0
    def test_build_trigger_with_secrets(self, trigger_build):
        """Assert we honor the trigger-type and trigger-id params."""
        trigger_build.return_value.build_id = 1
        pt = ProjectTrigger(
            "user",
            TriggerTypes.simple.value,
            self.project,
            None,
            None,
            {"foo": "simple"},
        )
        db.session.add(pt)
        db.session.commit()

        # try first trigger type
        headers = {"Content-type": "application/json"}
        data = {"trigger-type": "simple"}
        _sign("http://localhost/projects/proj-1/builds/", headers, "POST")
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual({"foo": "simple"}, trigger_build.call_args[0][4])

        # try "optional" trigger type (when there is no "optional")
        data = {"trigger-type": "git-poller-optional"}
        _sign("http://localhost/projects/proj-1/builds/", headers, "POST")
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual({}, trigger_build.call_args[0][4])

        # try override
        data = {"trigger-type": "simple", "secrets": {"foo": "override"}}
        _sign("http://localhost/projects/proj-1/builds/", headers, "POST")
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual({"foo": "override"}, trigger_build.call_args[0][4])

        # try by trigger-id
        data = {"trigger-id": pt.id}
        _sign("http://localhost/projects/proj-1/builds/", headers, "POST")
        self._post(self.urlbase, json.dumps(data), headers, 201)
        self.assertEqual({"foo": "simple"}, trigger_build.call_args[0][4])