Mercurial > bitten > bitten-test
changeset 479:07148aa7667e
Don't accept build step results for invalidated builds or from the wrong slave. Remerge of [520] with fixed tests and new functional tests.
author | wbell |
---|---|
date | Thu, 13 Mar 2008 23:24:32 +0000 |
parents | 6718f9a5c1f1 |
children | 5181353ccb41 |
files | bitten/master.py bitten/tests/master.py |
diffstat | 2 files changed, 147 insertions(+), 7 deletions(-) [+] |
line wrap: on
line diff
--- a/bitten/master.py +++ b/bitten/master.py @@ -193,6 +193,9 @@ raise HTTPBadRequest('XML parser error') stepname = elem.attr['step'] + # make sure it's the right slave. + if build.status != Build.IN_PROGRESS or build.slave_info.get(Build.IP_ADDRESS) != req.remote_addr: + raise HTTPForbidden('Build %s has been invalidated for host %s.' % (build.id, req.remote_addr)) step = BuildStep.fetch(self.env, build=build.id, name=stepname) if step:
--- a/bitten/tests/master.py +++ b/bitten/tests/master.py @@ -18,7 +18,7 @@ from trac.perm import PermissionCache, PermissionSystem from trac.test import EnvironmentStub, Mock from trac.web.api import HTTPBadRequest, HTTPMethodNotAllowed, HTTPNotFound, \ - RequestDone + HTTPForbidden, RequestDone from trac.web.href import Href from bitten.master import BuildMaster @@ -267,7 +267,8 @@ BuildConfig(self.env, 'test', path='somepath', active=True, recipe=recipe).insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, - started=42) + started=42, status=Build.IN_PROGRESS) + build.slave_info[Build.IP_ADDRESS] = '127.0.0.1'; build.insert() inbody = StringIO("""<result step="foo" status="success" @@ -314,7 +315,8 @@ BuildConfig(self.env, 'test', path='somepath', active=True, recipe=recipe).insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, - started=42) + started=42, status=Build.IN_PROGRESS) + build.slave_info[Build.IP_ADDRESS] = '127.0.0.1'; build.insert() inbody = StringIO("""<result step="foo" status="success" @@ -373,7 +375,8 @@ BuildConfig(self.env, 'test', path='somepath', active=True, recipe=recipe).insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, - started=42) + started=42, status=Build.IN_PROGRESS) + build.slave_info[Build.IP_ADDRESS] = '127.0.0.1'; build.insert() inbody = StringIO("""<result step="foo" status="success" @@ -431,6 +434,136 @@ 'type': 'test', }, reports[0].items[0]) + def test_process_build_step_wrong_slave(self): + recipe = """<build> + <step id="foo"> + </step> +</build>""" + BuildConfig(self.env, 'test', path='somepath', active=True, + recipe=recipe).insert() + build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, + started=42, status=Build.IN_PROGRESS) + build.slave_info[Build.IP_ADDRESS] = '192.168.1.1'; + build.insert() + + inbody = StringIO("""<result step="foo" status="success" + time="2007-04-01T15:30:00.0000" + duration="3.45"> + <log generator="http://bitten.cmlenz.net/tools/python#unittest"> + <message level="info">Doing stuff</message> + <message level="error">Ouch that hurt</message> + </log> +</result>""") + outheaders = {} + outbody = StringIO() + req = Mock(method='POST', base_path='', + path_info='/builds/%d/steps/' % build.id, + href=Href('/trac'), abs_href=Href('http://example.org/trac'), + remote_addr='127.0.0.1', args={}, + perm=PermissionCache(self.env, 'hal'), + read=inbody.read, + send_response=lambda x: outheaders.setdefault('Status', x), + send_header=lambda x, y: outheaders.setdefault(x, y), + write=outbody.write) + module = BuildMaster(self.env) + assert module.match_request(req) + try: + module.process_request(req) + self.fail('Expected HTTPForbidden') + except HTTPForbidden, e: + self.assertEqual('Build 1 has been invalidated for host 127.0.0.1.', e.detail) + + build = Build.fetch(self.env, build.id) + self.assertEqual(Build.IN_PROGRESS, build.status) + assert not build.stopped + + steps = list(BuildStep.select(self.env, build.id)) + self.assertEqual(0, len(steps)) + + + def test_process_build_step_invalidated_build(self): + recipe = """<build> + <step id="foo"> + </step> + <step id="foo2"> + </step> +</build>""" + BuildConfig(self.env, 'test', path='somepath', active=True, + recipe=recipe).insert() + build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, + started=42, status=Build.IN_PROGRESS) + build.slave_info[Build.IP_ADDRESS] = '127.0.0.1'; + build.insert() + + inbody = StringIO("""<result step="foo" status="success" + time="2007-04-01T15:30:00.0000" + duration="3.45"> + <log generator="http://bitten.cmlenz.net/tools/python#unittest"> + <message level="info">Doing stuff</message> + <message level="error">Ouch that hurt</message> + </log> +</result>""") + outheaders = {} + outbody = StringIO() + req = Mock(method='POST', base_path='', + path_info='/builds/%d/steps/' % build.id, + href=Href('/trac'), abs_href=Href('http://example.org/trac'), + remote_addr='127.0.0.1', args={}, + perm=PermissionCache(self.env, 'hal'), + read=inbody.read, + send_response=lambda x: outheaders.setdefault('Status', x), + send_header=lambda x, y: outheaders.setdefault(x, y), + write=outbody.write) + module = BuildMaster(self.env) + assert module.match_request(req) + try: + module.process_request(req) + self.fail('Expected RequestDone') + except RequestDone: + build = Build.fetch(self.env, build.id) + self.assertEqual(Build.IN_PROGRESS, build.status) + assert not build.stopped + + steps = list(BuildStep.select(self.env, build.id)) + self.assertEqual(1, len(steps)) + + # invalidate the build. + + build = Build.fetch(self.env, build.id) + build.slave = None + build.status = Build.PENDING + build.update() + + # have this slave submit more data. + inbody = StringIO("""<result step="foo2" status="success" + time="2007-04-01T15:45:00.0000" + duration="4"> + <log generator="http://bitten.cmlenz.net/tools/python#unittest"> + <message level="info">This is a step after invalidation</message> + </log> +</result>""") + outheaders = {} + outbody = StringIO() + req = Mock(method='POST', base_path='', + path_info='/builds/%d/steps/' % build.id, + href=Href('/trac'), abs_href=Href('http://example.org/trac'), + remote_addr='127.0.0.1', args={}, + perm=PermissionCache(self.env, 'hal'), + read=inbody.read, + send_response=lambda x: outheaders.setdefault('Status', x), + send_header=lambda x, y: outheaders.setdefault(x, y), + write=outbody.write) + module = BuildMaster(self.env) + assert module.match_request(req) + try: + module.process_request(req) + self.fail('Build was invalidated. Should fail.'); + except HTTPForbidden, e: + self.assertEqual('Build 1 has been invalidated for host 127.0.0.1.', e.detail) + + build = Build.fetch(self.env, build.id) + self.assertEqual(Build.PENDING, build.status) + def test_process_build_step_failure(self): recipe = """<build> <step id="foo"> @@ -439,7 +572,8 @@ BuildConfig(self.env, 'test', path='somepath', active=True, recipe=recipe).insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, - started=42) + started=42, status=Build.IN_PROGRESS) + build.slave_info[Build.IP_ADDRESS] = '127.0.0.1'; build.insert() inbody = StringIO("""<result step="foo" status="failure" @@ -486,7 +620,9 @@ BuildConfig(self.env, 'test', path='somepath', active=True, recipe=recipe).insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, - started=42) + started=42, status=Build.IN_PROGRESS) + build.slave_info[Build.IP_ADDRESS] = '127.0.0.1'; + build.insert() inbody = StringIO("""<result step="foo" status="failure" @@ -559,7 +695,8 @@ BuildConfig(self.env, 'test', path='somepath', active=True, recipe=recipe).insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, - started=42) + started=42, status=Build.IN_PROGRESS) + build.slave_info[Build.IP_ADDRESS] = '127.0.0.1'; build.insert() inbody = StringIO("""<result step="foo" status="success"