def test_view_config_paging(self): config = BuildConfig(self.env, name='test', path='trunk') config.insert() platform = TargetPlatform(self.env, config='test', name='any') platform.insert() PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW') req = Mock(method='GET', base_path='', cgi_location='', path_info='/build/test', href=Href('/trac'), args={}, chrome={}, authname='joe', perm=PermissionCache(self.env, 'joe')) root = Mock(get_entries=lambda: ['foo'], get_history=lambda: [('trunk', rev, 'edit') for rev in range(123, 110, -1)]) self.repos = Mock(get_node=lambda path, rev=None: root, sync=lambda: None, normalize_path=lambda path: path, normalize_rev=lambda rev: rev, youngest_rev=123) self.repos.authz = Mock(has_permission=lambda path: True, assert_permission=lambda path: None) module = BuildConfigController(self.env) assert module.match_request(req) _, data, _ = module.process_request(req) if req.chrome: self.assertEqual('/trac/build/test?page=2', req.chrome['links']['next'][0]['href'])
def test_view_config_paging(self): config = BuildConfig(self.env, name='test', path='trunk') config.insert() platform = TargetPlatform(self.env, config='test', name='any') platform.insert() PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW') req = Mock(method='GET', base_path='', cgi_location='', path_info='/build/test', href=Href('/trac'), args={}, chrome={}, authname='joe', perm=PermissionCache(self.env, 'joe')) root = Mock(get_entries=lambda: ['foo'], get_history=lambda: [('trunk', rev, 'edit') for rev in range(123, 110, -1)]) self.repos = Mock(get_node=lambda path, rev=None: root, sync=lambda: None, normalize_path=lambda path: path) self.repos.authz = Mock(has_permission=lambda path: True, assert_permission=lambda path: None) module = BuildConfigController(self.env) assert module.match_request(req) _, data, _ = module.process_request(req) if req.chrome: self.assertEqual('/trac/build/test?page=2', req.chrome['links']['next'][0]['href'])
def test_should_delete_build_outside_revision_range(self): messages = [] self.env.log = Mock(info=lambda msg, *args: messages.append(msg)) self.repos.rev_older_than = lambda rev1, rev2: rev1 < rev2 config = BuildConfig(self.env, 'test', active=True, min_rev=120, max_rev=123) config.insert() platform = TargetPlatform(self.env, config='test', name='stuff') platform.insert() build1 = Build(self.env, config=config.name, rev=42, platform=platform.id, rev_time=123456) build1.insert() build2 = Build(self.env, config=config.name, rev=10042, platform=platform.id, rev_time=123456) build2.insert() queue = BuildQueue(self.env, build_all=True) self.assertEqual(True, queue.should_delete_build(build1, self.repos)) self.assertEqual(True, queue.should_delete_build(build2, self.repos)) self.assert_("outside of the revision range" in messages[0]) self.assert_("outside of the revision range" in messages[1])
def test_cancel_build(self): config = BuildConfig(self.env, 'test', path='somepath', active=True, recipe='<build></build>') config.insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, status=Build.IN_PROGRESS, started=42) build.insert() outheaders = {} outbody = StringIO() req = Mock(method='DELETE', base_path='', path_info='/builds/%d' % build.id, href=Href('/trac'), remote_addr='127.0.0.1', args={}, perm=PermissionCache(self.env, 'hal'), send_response=lambda x: outheaders.setdefault('Status', x), send_header=lambda x, y: outheaders.setdefault(x, y), write=outbody.write, incookie=Cookie('trac_auth=')) module = BuildMaster(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) self.assertEqual(204, outheaders['Status']) self.assertEqual('', outbody.getvalue()) # Make sure the started timestamp has been set build = Build.fetch(self.env, build.id) self.assertEqual(Build.PENDING, build.status) assert not build.started
def test_bitten_keeps_order_of_revisions_from_versioncontrol(self): # Trac's API specifies that they are sorted chronological (backwards) # We must not assume that these revision numbers can be sorted later on, # for example the mercurial plugin will return the revisions as strings # (e.g. '880:4c19fa95fb9e') config = BuildConfig(self.env, name='test', path='trunk') config.insert() platform = TargetPlatform(self.env, config='test', name='any') platform.insert() PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW') req = Mock(method='GET', base_path='', cgi_location='', path_info='/build/'+config.name, href=Href('/trac'), args={}, chrome={}, authname='joe', perm=PermissionCache(self.env, 'joe')) # revisions are intentionally not sorted in any way - bitten should just keep them! revision_ids = [5, 8, 2] revision_list = [('trunk', revision, 'edit') for revision in revision_ids] root = Mock(get_entries=lambda: ['foo'], get_history=lambda: revision_list) self.repos.get_node=lambda path, rev=None: root self.repos.youngest_rev=5 self.repos.get_changeset=lambda rev: Mock(author='joe', date=99) module = BuildConfigController(self.env) assert module.match_request(req) _, data, _ = module.process_request(req) actual_revision_ids = data['config']['revisions'] self.assertEquals(revision_ids, actual_revision_ids)
def test_view_config(self): config = BuildConfig(self.env, name='test', path='trunk') config.insert() platform = TargetPlatform(self.env, config='test', name='any') platform.insert() PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW') req = Mock(method='GET', base_path='', cgi_location='', path_info='/build/test', href=Href('/trac'), args={}, chrome={}, authname='joe', perm=PermissionCache(self.env, 'joe')) root = Mock(get_entries=lambda: ['foo'], get_history=lambda: [('trunk', rev, 'edit') for rev in range(123, 111, -1)]) self.repos.get_node=lambda path, rev=None: root self.repos.youngest_rev=123 self.repos.get_changeset=lambda rev: Mock(author='joe', date=99) module = BuildConfigController(self.env) assert module.match_request(req) _, data, _ = module.process_request(req) self.assertEqual('view_config', data['page_mode']) assert not 'next' in req.chrome['links'] self.assertEquals(Resource('build', 'test'), data['context'].resource) self.assertEquals([], data['config']['attachments']['attachments']) self.assertEquals('/trac/attachment/build/test/', data['config']['attachments']['attach_href'])
def test_insert(self): config = BuildConfig(self.env, name='test', path='trunk', label='Test') config.insert() db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute("SELECT name,path,label,active,description " "FROM bitten_config") self.assertEqual(('test', 'trunk', 'Test', 0, ''), cursor.fetchone())
def test_initiate_build(self): config = BuildConfig(self.env, 'test', path='somepath', active=True, recipe='<build><step id="s1"></step></build>') config.insert() platform = TargetPlatform(self.env, config='test', name="Unix") platform.rules.append(('family', 'posix')) platform.insert() build = Build(self.env, 'test', '123', platform.id, slave='hal', rev_time=42) build.insert() outheaders = {} outbody = StringIO() req = Mock(method='GET', base_path='', path_info='/builds/%d' % build.id, href=Href('/trac'), remote_addr='127.0.0.1', args={}, authname='hal', perm=PermissionCache(self.env, 'hal'), send_response=lambda x: outheaders.setdefault('Status', x), send_header=lambda x, y: outheaders.setdefault(x, y), write=outbody.write, form_token="12345", incookie=Cookie('trac_auth=')) module = BuildMaster(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) self.assertEqual(200, outheaders['Status']) self.assertEqual('163', outheaders['Content-Length']) self.assertEqual('application/x-bitten+xml', outheaders['Content-Type']) self.assertEqual('attachment; filename=recipe_test_r123.xml', outheaders['Content-Disposition']) self.assertEqual( '<build build="1" config="test" form_token="12345" ' 'name="hal" path="somepath" platform="Unix" ' 'reponame="" repopath="somepath" ' 'revision="123"><step id="s1"/></build>', outbody.getvalue()) # Make sure the started timestamp has been set build = Build.fetch(self.env, build.id) assert build.started
def test_should_delete_build_platform_dont_exist(self): messages = [] self.env.log = Mock(info=lambda msg, *args: messages.append(msg)) config = BuildConfig(self.env, 'test', active=True) config.insert() build = Build(self.env, config=config.name, rev=42, platform="no-stuff", rev_time=123456) build.insert() queue = BuildQueue(self.env, build_all=True) self.assertEqual(True, queue.should_delete_build(build, self.repos)) self.assert_("platform no longer exists" in messages[0])
def test_should_delete_build_config_deactivated(self): messages = [] self.env.log = Mock(info=lambda msg, *args: messages.append(msg)) config = BuildConfig(self.env, 'test', active=False) config.insert() platform = TargetPlatform(self.env, config='test', name='stuff') platform.insert() build = Build(self.env, config=config.name, rev=42, platform=platform.id, rev_time=123456) build.insert() queue = BuildQueue(self.env, build_all=True) self.assertEqual(True, queue.should_delete_build(build, self.repos)) self.assert_("configuration is deactivated" in messages[0])
def test_process_attach_build(self): body, content_type = encode_multipart_formdata({ 'description': 'baz baz', 'file': ('baz.txt', 'hello baz'), '__FORM_TOKEN': '123456'}) args = {} for k, v in dict(cgi.FieldStorage(fp=StringIO(body), environ={ 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': content_type}) ).items(): if v.filename: args[k] = v else: args[k] = v.value args.update({'collection': 'attach', 'member': 'build'}) self.assertTrue('file' in args) outheaders = {} outbody = StringIO() req = Mock(args=args, form_token='123456', authname='hal', remote_addr='127.0.0.1', send_response=lambda x: outheaders.setdefault('Status', x), send_header=lambda x, y: outheaders.setdefault(x, y), write=outbody.write) config = BuildConfig(self.env, 'test', path='somepath', active=True, recipe='') config.insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, started=42, status=Build.IN_PROGRESS) build.insert() module = BuildMaster(self.env) self.assertRaises(RequestDone, module._process_attachment, req, config, build) self.assertEqual(201, outheaders['Status']) self.assertEqual('18', outheaders['Content-Length']) self.assertEqual('text/plain', outheaders['Content-Type']) self.assertEqual('Attachment created', outbody.getvalue()) build_atts = list(Attachment.select(self.env, 'build', 'test/1')) self.assertEquals(1, len(build_atts)) self.assertEquals('hal', build_atts[0].author) self.assertEquals('baz baz', build_atts[0].description) self.assertEquals('baz.txt', build_atts[0].filename) self.assertEquals('hello baz', build_atts[0].open().read())
def test_view_build(self): config = BuildConfig(self.env, name='test', path='trunk') config.insert() platform = TargetPlatform(self.env, config='test', name='any') platform.insert() build = Build(self.env, config='test', platform=1, rev=123, rev_time=42, status=Build.SUCCESS, slave='hal') build.insert() PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW') req = Mock(method='GET', base_path='', cgi_location='', path_info='/build/test/1', href=Href('/trac'), args={}, chrome={}, authname='joe', perm=PermissionCache(self.env, 'joe')) root = Mock(get_entries=lambda: ['foo'], get_history=lambda: [('trunk', rev, 'edit') for rev in range(123, 111, -1)]) self.repos = Mock(get_node=lambda path, rev=None: root, sync=lambda: None, normalize_path=lambda path: path, normalize_rev=lambda rev: rev, get_changeset=lambda rev: Mock(author='joe')) self.repos.authz = Mock(has_permission=lambda path: True, assert_permission=lambda path: None) module = BuildController(self.env) assert module.match_request(req) _, data, _ = module.process_request(req) self.assertEqual('view_build', data['page_mode']) from trac.resource import Resource self.assertEquals(Resource('build', 'test/1'), data['context'].resource) self.assertEquals([], data['build']['attachments']['attachments']) self.assertEquals('/trac/attachment/build/test/1/', data['build']['attachments']['attach_href'])
def test_raise_404(self): PermissionSystem(self.env).grant_permission('joe', 'BUILD_VIEW') module = BuildController(self.env) config = BuildConfig(self.env, name='existing', path='trunk') config.insert() req = Mock(method='GET', base_path='', cgi_location='', path_info='/build/existing/42', href=Href('/trac'), args={}, chrome={}, authname='joe', perm=PermissionCache(self.env, 'joe')) self.failUnless(module.match_request(req)) try: module.process_request(req) except Exception, e: self.failUnless(isinstance(e, HTTPNotFound)) self.assertEquals(str(e), "404 Not Found (Build '42' does not exist.)") return
def test_should_delete_build_old_with_not_buildall(self): messages = [] self.env.log = Mock(info=lambda msg, *args: messages.append(msg)) config = BuildConfig(self.env, 'test', active=True) config.insert() platform = TargetPlatform(self.env, config='test', name='stuff') platform.insert() build1 = Build(self.env, config=config.name, rev=42, platform=platform.id, rev_time=123456) build1.insert() build2 = Build(self.env, config=config.name, rev=43, platform=platform.id, rev_time=123457, slave='slave') build2.insert() queue = BuildQueue(self.env, build_all=False) self.assertEqual(True, queue.should_delete_build(build1, self.repos)) self.assert_("more recent build exists" in messages[0])
def test_initiate_build(self): config = BuildConfig(self.env, 'test', path='somepath', active=True, recipe='<build><step id="s1"></step></build>') config.insert() platform = TargetPlatform(self.env, config='test', name="Unix") platform.rules.append(('family', 'posix')) platform.insert() build = Build(self.env, 'test', '123', platform.id, slave='hal', rev_time=42) build.insert() outheaders = {} outbody = StringIO() req = Mock(method='GET', base_path='', path_info='/builds/%d' % build.id, href=Href('/trac'), remote_addr='127.0.0.1', args={}, authname='hal', perm=PermissionCache(self.env, 'hal'), send_response=lambda x: outheaders.setdefault('Status', x), send_header=lambda x, y: outheaders.setdefault(x, y), write=outbody.write, form_token="12345", incookie=Cookie('trac_auth=')) module = BuildMaster(self.env) assert module.match_request(req) self.assertRaises(RequestDone, module.process_request, req) self.assertEqual(200, outheaders['Status']) self.assertEqual('163', outheaders['Content-Length']) self.assertEqual('application/x-bitten+xml', outheaders['Content-Type']) self.assertEqual('attachment; filename=recipe_test_r123.xml', outheaders['Content-Disposition']) self.assertEqual('<build build="1" config="test" form_token="12345" ' 'name="hal" path="somepath" platform="Unix" ' 'reponame="" repopath="somepath" ' 'revision="123"><step id="s1"/></build>', outbody.getvalue()) # Make sure the started timestamp has been set build = Build.fetch(self.env, build.id) assert build.started
class CollectChangesTestCase(unittest.TestCase): """ Unit tests for the `bitten.queue.collect_changes` function. """ def setUp(self): self.env = EnvironmentStub() self.env.path = tempfile.mkdtemp() db = self.env.get_db_cnx() cursor = db.cursor() connector, _ = DatabaseManager(self.env)._get_connector() for table in schema: for stmt in connector.to_sql(table): cursor.execute(stmt) self.config = BuildConfig(self.env, name='test', path='somepath') self.config.insert(db=db) self.platform = TargetPlatform(self.env, config='test', name='Foo') self.platform.insert(db=db) db.commit() def tearDown(self): shutil.rmtree(self.env.path) def test_stop_on_copy(self): self.env.get_repository = lambda authname=None: Mock( get_node=lambda path, rev=None: Mock( get_history=lambda: [('otherpath', 123, 'copy')] ), normalize_path=lambda path: path ) retval = list(collect_changes(self.env.get_repository(), self.config)) self.assertEqual(0, len(retval)) def test_stop_on_minrev(self): self.env.get_repository = lambda authname=None: Mock( get_node=lambda path, rev=None: Mock( get_entries=lambda: [Mock(), Mock()], get_history=lambda: [('somepath', 123, 'edit'), ('somepath', 121, 'edit'), ('somepath', 120, 'edit')] ), normalize_path=lambda path: path, rev_older_than=lambda rev1, rev2: rev1 < rev2 ) self.config.min_rev = 123 self.config.update() retval = list(collect_changes(self.env.get_repository(), self.config)) self.assertEqual(1, len(retval)) self.assertEqual(123, retval[0][1]) def test_skip_until_maxrev(self): self.env.get_repository = lambda authname=None: Mock( get_node=lambda path, rev=None: Mock( get_entries=lambda: [Mock(), Mock()], get_history=lambda: [('somepath', 123, 'edit'), ('somepath', 121, 'edit'), ('somepath', 120, 'edit')] ), normalize_path=lambda path: path, rev_older_than=lambda rev1, rev2: rev1 < rev2 ) self.config.max_rev=121 self.config.update() retval = list(collect_changes(self.env.get_repository(), self.config)) self.assertEqual(2, len(retval)) self.assertEqual(121, retval[0][1]) self.assertEqual(120, retval[1][1]) def test_skip_empty_dir(self): def _mock_get_node(path, rev=None): if rev and rev == 121: return Mock( get_entries=lambda: [] ) else: return Mock( get_entries=lambda: [Mock(), Mock()], get_history=lambda: [('somepath', 123, 'edit'), ('somepath', 121, 'edit'), ('somepath', 120, 'edit')] ) self.env.get_repository = lambda authname=None: Mock( get_node=_mock_get_node, normalize_path=lambda path: path, rev_older_than=lambda rev1, rev2: rev1 < rev2 ) retval = list(collect_changes(self.env.get_repository(), self.config)) self.assertEqual(2, len(retval)) self.assertEqual(123, retval[0][1]) self.assertEqual(120, retval[1][1])
def test_process_attach_build(self): body, content_type = encode_multipart_formdata({ 'description': 'baz baz', 'file': ('baz.txt', 'hello baz'), '__FORM_TOKEN': '123456' }) args = {} for k, v in dict( cgi.FieldStorage(fp=StringIO(body), environ={ 'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': content_type })).items(): if v.filename: args[k] = v else: args[k] = v.value args.update({'collection': 'attach', 'member': 'build'}) self.assertTrue('file' in args) outheaders = {} outbody = StringIO() req = Mock(args=args, form_token='123456', authname='hal', remote_addr='127.0.0.1', send_response=lambda x: outheaders.setdefault('Status', x), send_header=lambda x, y: outheaders.setdefault(x, y), write=outbody.write) config = BuildConfig(self.env, 'test', path='somepath', active=True, recipe='') config.insert() build = Build(self.env, 'test', '123', 1, slave='hal', rev_time=42, started=42, status=Build.IN_PROGRESS) build.insert() module = BuildMaster(self.env) self.assertRaises(RequestDone, module._process_attachment, req, config, build) self.assertEqual(201, outheaders['Status']) self.assertEqual('18', outheaders['Content-Length']) self.assertEqual('text/plain', outheaders['Content-Type']) self.assertEqual('Attachment created', outbody.getvalue()) build_atts = list(Attachment.select(self.env, 'build', 'test/1')) self.assertEquals(1, len(build_atts)) self.assertEquals('hal', build_atts[0].author) self.assertEquals('baz baz', build_atts[0].description) self.assertEquals('baz.txt', build_atts[0].filename) self.assertEquals('hello baz', build_atts[0].open().read())
class CollectChangesTestCase(unittest.TestCase): """ Unit tests for the `bitten.queue.collect_changes` function. """ def setUp(self): self.env = EnvironmentStub(enable=['trac.*', 'bitten.*']) self.env.path = tempfile.mkdtemp() db = self.env.get_db_cnx() cursor = db.cursor() connector, _ = DatabaseManager(self.env)._get_connector() for table in schema: for stmt in connector.to_sql(table): cursor.execute(stmt) self.config = BuildConfig(self.env, name='test', path='somepath') self.config.insert(db=db) self.platform = TargetPlatform(self.env, config='test', name='Foo') self.platform.insert(db=db) db.commit() # Hook up a dummy repository self.repos = Mock() self.env.get_repository = lambda authname=None: self.repos # 0.11 try: # 0.12+ from trac.core import Component, implements from trac.versioncontrol.api import IRepositoryConnector, \ IRepositoryProvider class DummyRepos(Component): implements(IRepositoryConnector, IRepositoryProvider) def get_supported_types(self): yield ('dummy', 9) def get_repository(this, repos_type, repos_dir, params): return self.repos # Note: 'this' vs 'self' usage def get_repositories(self): yield ('', {'dir': 'dummy_dir', 'type': 'dummy'}) self.dummy = DummyRepos except ImportError: self.dummy = None # not supported, will use get_repository() def tearDown(self): if self.dummy: # remove from components list + interfaces dict self.env.__metaclass__._components.remove(self.dummy) for key in self.env.__metaclass__._registry.keys(): if self.dummy in self.env.__metaclass__._registry[key]: self.env.__metaclass__._registry[key].remove(self.dummy) shutil.rmtree(self.env.path) def test_stop_on_copy(self): self.repos.get_node=lambda path, rev=None: Mock( get_history=lambda: [('otherpath', 123, 'copy')]) self.repos.normalize_path=lambda path: path retval = list(collect_changes(self.config)) self.assertEqual(0, len(retval)) def test_stop_on_minrev(self): self.repos.get_node=lambda path, rev=None: Mock( get_entries=lambda: [Mock(), Mock()], get_history=lambda: [('somepath', 123, 'edit'), ('somepath', 121, 'edit'), ('somepath', 120, 'edit')]) self.repos.normalize_path=lambda path: path self.repos.rev_older_than=lambda rev1, rev2: rev1 < rev2 self.config.min_rev = 123 self.config.update() retval = list(collect_changes(self.config)) self.assertEqual(1, len(retval)) self.assertEqual(123, retval[0][1]) def test_skip_until_maxrev(self): self.repos.get_node=lambda path, rev=None: Mock( get_entries=lambda: [Mock(), Mock()], get_history=lambda: [('somepath', 123, 'edit'), ('somepath', 121, 'edit'), ('somepath', 120, 'edit')]) self.repos.normalize_path=lambda path: path self.repos.rev_older_than=lambda rev1, rev2: rev1 < rev2 self.config.max_rev=121 self.config.update() retval = list(collect_changes(self.config)) self.assertEqual(2, len(retval)) self.assertEqual(121, retval[0][1]) self.assertEqual(120, retval[1][1]) def test_skip_empty_dir(self): def _mock_get_node(path, rev=None): if rev and rev == 121: return Mock( get_entries=lambda: [] ) else: return Mock( get_entries=lambda: [Mock(), Mock()], get_history=lambda: [('somepath', 123, 'edit'), ('somepath', 121, 'edit'), ('somepath', 120, 'edit')] ) self.repos.get_node=_mock_get_node self.repos.normalize_path=lambda path: path self.repos.rev_older_than=lambda rev1, rev2: rev1 < rev2 retval = list(collect_changes(self.config)) self.assertEqual(2, len(retval)) self.assertEqual(123, retval[0][1]) self.assertEqual(120, retval[1][1])