Esempio n. 1
0
def add_log_table(env, db):
    """Add a table for storing the builds logs."""
    from bitten.model import BuildLog, BuildStep
    cursor = db.cursor()

    connector, _ = DatabaseManager(env)._get_connector()
    for table in BuildLog._schema:
        for stmt in connector.to_sql(table):
            cursor.execute(stmt)

    cursor.execute("SELECT build,name,log FROM bitten_step "
                   "WHERE log IS NOT NULL")
    for build, step, log in cursor:
        build_log = BuildLog(env, build, step)
        build_log.messages = [(BuildLog.INFO, msg) for msg in log.splitlines()]
        build_log.insert(db)

    cursor.execute("CREATE TEMPORARY TABLE old_step AS SELECT * FROM bitten_step")
    cursor.execute("DROP TABLE bitten_step")
    for table in BuildStep._schema:
        for stmt in connector.to_sql(table):
            cursor.execute(stmt)
    cursor.execute("INSERT INTO bitten_step (build,name,description,status,"
                   "started,stopped) SELECT build,name,description,status,"
                   "started,stopped FROM old_step")
Esempio n. 2
0
def add_log_table(env, db):
    """Add a table for storing the builds logs."""
    from bitten.model import BuildLog, BuildStep
    cursor = db.cursor()

    connector, _ = DatabaseManager(env)._get_connector()
    for table in BuildLog._schema:
        for stmt in connector.to_sql(table):
            cursor.execute(stmt)

    cursor.execute("SELECT build,name,log FROM bitten_step "
                   "WHERE log IS NOT NULL")
    for build, step, log in cursor:
        build_log = BuildLog(env, build, step)
        build_log.messages = [(BuildLog.INFO, msg) for msg in log.splitlines()]
        build_log.insert(db)

    cursor.execute(
        "CREATE TEMPORARY TABLE old_step AS SELECT * FROM bitten_step")
    cursor.execute("DROP TABLE bitten_step")
    for table in BuildStep._schema:
        for stmt in connector.to_sql(table):
            cursor.execute(stmt)
    cursor.execute("INSERT INTO bitten_step (build,name,description,status,"
                   "started,stopped) SELECT build,name,description,status,"
                   "started,stopped FROM old_step")
Esempio n. 3
0
    def test_delete(self):
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute(
            "INSERT INTO bitten_log (build,step,generator,filename) "
            "VALUES (%s,%s,%s,%s)", (1, 'test', 'distutils', '1.log'))
        id = db.get_last_id(cursor, 'bitten_log')
        logs_dir = self.env.config.get("bitten", "logsdir", "log/bitten")
        if os.path.isabs(logs_dir):
            raise ValueError(
                "Should not have absolute logs directory for temporary test")
        logs_dir = os.path.join(self.env.path, logs_dir)
        full_file = os.path.join(logs_dir, "1.log")
        open(full_file, "wb").writelines(["running tests\n", "tests failed\n"])

        log = BuildLog.fetch(self.env, id=id, db=db)
        self.assertEqual(True, log.exists)
        log.delete()
        self.assertEqual(False, log.exists)

        cursor.execute("SELECT * FROM bitten_log WHERE id=%s", (id, ))
        self.assertEqual(True, not cursor.fetchall())
        file_exists = os.path.exists(full_file)
        if os.path.exists(full_file):
            os.remove(full_file)
        assert not file_exists
Esempio n. 4
0
 def get_all_log_messages_for_step(self, step):
     messages = []
     for log in BuildLog.select(self.env,
                                build=self.build.id,
                                step=step.name):
         messages.extend(log.messages)
     return messages
Esempio n. 5
0
    def test_select(self):
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("INSERT INTO bitten_log (build,step,generator,filename) "
                       "VALUES (%s,%s,%s,%s)", (1, 'test', 'distutils', '1.log'))
        id = db.get_last_id(cursor, 'bitten_log')
        logs_dir = self.env.config.get("bitten", "logsdir", "log/bitten")
        if os.path.isabs(logs_dir):
            raise ValueError("Should not have absolute logs directory for temporary test")
        logs_dir = os.path.join(self.env.path, logs_dir)
        full_file = os.path.join(logs_dir, "1.log")
        open(full_file, "wb").writelines(["running tests\n", "tests failed\n", u"test unicode\xbb\n".encode("UTF-8")])

        logs = BuildLog.select(self.env, build=1, step='test', db=db)
        log = logs.next()
        self.assertEqual(True, log.exists)
        self.assertEqual(id, log.id)
        self.assertEqual(1, log.build)
        self.assertEqual('test', log.step)
        self.assertEqual('distutils', log.generator)
        self.assertEqual((BuildLog.UNKNOWN, 'running tests'), log.messages[0])
        self.assertEqual((BuildLog.UNKNOWN, 'tests failed'), log.messages[1])
        self.assertEqual((BuildLog.UNKNOWN, u'test unicode\xbb'), log.messages[2])
        self.assertRaises(StopIteration, logs.next)
        if os.path.exists(full_file):
            os.remove(full_file)
Esempio n. 6
0
    def test_process_build_step_success_with_log(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] = '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:
            self.assertEqual(201, outheaders['Status'])
            self.assertEqual('20', outheaders['Content-Length'])
            self.assertEqual('text/plain', outheaders['Content-Type'])
            self.assertEqual('Build step processed', outbody.getvalue())

            build = Build.fetch(self.env, build.id)
            self.assertEqual(Build.SUCCESS, build.status)
            assert build.stopped
            assert build.stopped > build.started

            steps = list(BuildStep.select(self.env, build.id))
            self.assertEqual(1, len(steps))
            self.assertEqual('foo', steps[0].name)
            self.assertEqual(BuildStep.SUCCESS, steps[0].status)

            logs = list(BuildLog.select(self.env, build=build.id, step='foo'))
            self.assertEqual(1, len(logs))
            self.assertEqual('http://bitten.cmlenz.net/tools/python#unittest',
                             logs[0].generator)
            self.assertEqual(2, len(logs[0].messages))
            self.assertEqual((u'info', u'Doing stuff'), logs[0].messages[0])
            self.assertEqual((u'error', u'Ouch that hurt'), logs[0].messages[1])
Esempio n. 7
0
 def _render_log(self, req, build, formatters, step):
     items = []
     for log in BuildLog.select(self.env, build=build.id, step=step.name):
         for level, message in log.messages:
             for format in formatters:
                 message = format(step, log.generator, level, message)
             items.append({'level': level, 'message': message})
     return items
Esempio n. 8
0
 def _render_log(self, req, build, formatters, step):
     items = []
     for log in BuildLog.select(self.env, build=build.id, step=step.name):
         for level, message in log.messages:
             for format in formatters:
                 message = format(step, log.generator, level, message)
             items.append({'level': level, 'message': message})
     return items
Esempio n. 9
0
 def test_new(self):
     log = BuildLog(self.env)
     self.assertEqual(False, log.exists)
     self.assertEqual(None, log.id)
     self.assertEqual(None, log.build)
     self.assertEqual(None, log.step)
     self.assertEqual('', log.generator)
     self.assertEqual([], log.messages)
Esempio n. 10
0
 def get_faillog(self, build):
     faillog = ''
     for step in self.get_failed_steps(build):
         build_logs = BuildLog.select(self.env,
                 build=build.id,
                 step=step.name)
         for log in build_logs:
             faillog += '\n'.join(['%5s: %s' % (level, msg) \
                     for level, msg in log.messages])
     return faillog
Esempio n. 11
0
    def test_insert(self):
        log = BuildLog(self.env,
                       build=1,
                       step='test',
                       generator='distutils',
                       filename='1.log.gz')
        full_file = log.get_log_file('1.log.gz')
        if os.path.exists(full_file):
            os.remove(full_file)
        log.messages = [(BuildLog.INFO, 'running tests'),
                        (BuildLog.ERROR, 'tests failed')]
        log.insert()
        self.assertNotEqual(None, log.id)

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute(
            "SELECT build,step,generator,filename FROM bitten_log "
            "WHERE id=%s", (log.id, ))
        self.assertEqual((1, 'test', 'distutils', '1.log.gz'),
                         cursor.fetchone())
        lines = gzip.open(full_file, "rb").readlines()
        self.assertEqual('running tests\n', lines[0])
        self.assertEqual('tests failed\n', lines[1])
        if os.path.exists(full_file):
            os.remove(full_file)
Esempio n. 12
0
    def test_insert_and_delete_files(self):
        # create - files should be created automatically
        build_log = BuildLog(self.env, build=1, step='test', generator='make')
        build_log.messages = [(BuildLog.INFO, 'running')]
        build_log.insert()

        # fetch it fresh - check object and files
        build_log = BuildLog.fetch(self.env, id=build_log.id)
        self.assertEquals(build_log.filename, "%s.log.gz" % build_log.id)
        log_file = build_log.get_log_file(build_log.filename)
        levels_file = build_log.get_level_file(build_log.filename)
        self.failUnless(os.path.exists(log_file), 'log_file does not exist')
        self.failUnless(os.path.exists(levels_file),
                                                'levels_file does not exist')
        self.assertEquals(build_log.messages, [(BuildLog.INFO, 'running')])

        # delete - object and file should be gone
        build_log.delete()
        self.assertEquals(None, BuildLog.fetch(self.env, id=build_log.id))
        self.failIf(os.path.exists(log_file), 'log_file exists after delete()')
        self.failIf(os.path.exists(levels_file),
                                        'levels_file exists after delete()')
Esempio n. 13
0
    def test_insert_and_delete_files(self):
        # create - files should be created automatically
        build_log = BuildLog(self.env, build=1, step='test', generator='make')
        build_log.messages = [(BuildLog.INFO, 'running')]
        build_log.insert()

        # fetch it fresh - check object and files
        build_log = BuildLog.fetch(self.env, id=build_log.id)
        self.assertEquals(build_log.filename, "%s.log" % build_log.id)
        log_file = build_log.get_log_file(build_log.filename)
        levels_file = log_file+'.levels'
        self.failUnless(os.path.exists(log_file), 'log_file does not exist')
        self.failUnless(os.path.exists(levels_file),
                                                'levels_file does not exist')
        self.assertEquals(build_log.messages, [(BuildLog.INFO, 'running')])

        # delete - object and file should be gone
        build_log.delete()
        self.assertEquals(None, BuildLog.fetch(self.env, id=build_log.id))
        self.failIf(os.path.exists(log_file), 'log_file exists after delete()')
        self.failIf(os.path.exists(levels_file),
                                        'levels_file exists after delete()')
Esempio n. 14
0
    def test_insert(self):
        log = BuildLog(self.env, build=1, step='test', generator='distutils', filename='1.log')
        full_file = log.get_log_file('1.log')
        if os.path.exists(full_file):
            os.remove(full_file)
        log.messages = [
            (BuildLog.INFO, 'running tests'),
            (BuildLog.ERROR, 'tests failed')
        ]
        log.insert()
        self.assertNotEqual(None, log.id)

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("SELECT build,step,generator,filename FROM bitten_log "
                       "WHERE id=%s", (log.id,))
        self.assertEqual((1, 'test', 'distutils', '1.log'), cursor.fetchone())
        lines = open(full_file, "rb").readlines()
        self.assertEqual('running tests\n', lines[0])
        self.assertEqual('tests failed\n', lines[1])
        if os.path.exists(full_file):
            os.remove(full_file)
Esempio n. 15
0
    def test_insert_empty(self):
        log = BuildLog(self.env, build=1, step='test', generator='distutils', filename="1.log")
        full_file = log.get_log_file('1.log')
        if os.path.exists(full_file):
            os.remove(full_file)
        log.messages = []
        log.insert()
        self.assertNotEqual(None, log.id)

        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("SELECT build,step,generator,filename FROM bitten_log "
                       "WHERE id=%s", (log.id,))
        self.assertEqual((1, 'test', 'distutils', '1.log'), cursor.fetchone())
        file_exists = os.path.exists(full_file)
        if file_exists:
            os.remove(full_file)
        assert not file_exists
Esempio n. 16
0
    def test_delete(self):
        db = self.env.get_db_cnx()
        cursor = db.cursor()
        cursor.execute("INSERT INTO bitten_log (build,step,generator,filename) "
                       "VALUES (%s,%s,%s,%s)", (1, 'test', 'distutils', '1.log'))
        id = db.get_last_id(cursor, 'bitten_log')
        logs_dir = self.env.config.get("bitten", "logsdir", "log/bitten")
        if os.path.isabs(logs_dir):
            raise ValueError("Should not have absolute logs directory for temporary test")
        logs_dir = os.path.join(self.env.path, logs_dir)
        full_file = os.path.join(logs_dir, "1.log")
        open(full_file, "wb").writelines(["running tests\n", "tests failed\n"])

        log = BuildLog.fetch(self.env, id=id, db=db)
        self.assertEqual(True, log.exists)
        log.delete()
        self.assertEqual(False, log.exists)

        cursor.execute("SELECT * FROM bitten_log WHERE id=%s", (id,))
        self.assertEqual(True, not cursor.fetchall())
        file_exists = os.path.exists(full_file)
        if os.path.exists(full_file):
            os.remove(full_file)
        assert not file_exists
Esempio n. 17
0
 def get_all_log_messages_for_step(self, step):
     messages = []
     for log in BuildLog.select(self.env, build=self.build.id,
                                step=step.name):
         messages.extend(log.messages)
     return messages
Esempio n. 18
0
            step.status = BuildStep.FAILURE
            if current_step.onerror == 'fail':
                last_step = True
        else:
            step.status = BuildStep.SUCCESS
        step.errors += [error.gettext() for error in elem.children('error')]

        # TODO: step.update(db=db)
        step.delete(db=db)
        step.insert(db=db)

        # Collect log messages from the request body
        for idx, log_elem in enumerate(elem.children('log')):
            build_log = BuildLog(self.env,
                                 build=build.id,
                                 step=stepname,
                                 generator=log_elem.attr.get('generator'),
                                 orderno=idx)
            for message_elem in log_elem.children('message'):
                build_log.messages.append(
                    (message_elem.attr['level'], message_elem.gettext()))
            build_log.insert(db=db)

        # Collect report data from the request body
        for report_elem in elem.children('report'):
            report = Report(self.env,
                            build=build.id,
                            step=stepname,
                            category=report_elem.attr.get('category'),
                            generator=report_elem.attr.get('generator'))
            for item_elem in report_elem.children():
Esempio n. 19
0
 def test_delete_new(self):
     log = BuildLog(self.env, build=1, step='test', generator='foo')
     self.assertRaises(AssertionError, log.delete)
Esempio n. 20
0
    def test_insert_no_build_or_step(self):
        log = BuildLog(self.env, step='test')
        self.assertRaises(AssertionError, log.insert) # No build

        step = BuildStep(self.env, build=1)
        self.assertRaises(AssertionError, log.insert) # No step
Esempio n. 21
0
    def test_process_build_step_success_with_log(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.TOKEN] = '123'
        build.insert()

        inbody = StringIO("""<result step="foo" status="success"
                                     time="2007-04-01T15:30:00.0000"
                                     duration="3.45">
    <log generator="http://bitten.edgewall.org/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,
                   incookie=Cookie('trac_auth=123'))
        module = BuildMaster(self.env)

        module._start_new_step(build, 'foo').insert()

        assert module.match_request(req)

        self.assertRaises(RequestDone, module.process_request, req)

        self.assertEqual(201, outheaders['Status'])
        self.assertEqual('20', outheaders['Content-Length'])
        self.assertEqual('text/plain', outheaders['Content-Type'])
        self.assertEqual('Build step processed', outbody.getvalue())

        build = Build.fetch(self.env, build.id)
        self.assertEqual(Build.SUCCESS, build.status)
        assert build.stopped
        assert build.stopped > build.started

        steps = list(BuildStep.select(self.env, build.id))
        self.assertEqual(1, len(steps))
        self.assertEqual('foo', steps[0].name)
        self.assertEqual(BuildStep.SUCCESS, steps[0].status)

        logs = list(BuildLog.select(self.env, build=build.id, step='foo'))
        self.assertEqual(1, len(logs))
        self.assertEqual('http://bitten.edgewall.org/tools/python#unittest',
                         logs[0].generator)
        self.assertEqual(2, len(logs[0].messages))
        self.assertEqual((u'info', u'Doing stuff'), logs[0].messages[0])
        self.assertEqual((u'error', u'Ouch that hurt'), logs[0].messages[1])
Esempio n. 22
0
            self.log.warning('Build %s step %s failed', build.id, stepname)
            step.status = BuildStep.FAILURE
            if current_step.onerror == 'fail':
                last_step = True
        else:
            step.status = BuildStep.SUCCESS
        step.errors += [error.gettext() for error in elem.children('error')]

        # TODO: step.update(db=db)
        step.delete(db=db)
        step.insert(db=db)

        # Collect log messages from the request body
        for idx, log_elem in enumerate(elem.children('log')):
            build_log = BuildLog(self.env, build=build.id, step=stepname,
                                 generator=log_elem.attr.get('generator'),
                                 orderno=idx)
            for message_elem in log_elem.children('message'):
                build_log.messages.append((message_elem.attr['level'],
                                           message_elem.gettext()))
            build_log.insert(db=db)

        # Collect report data from the request body
        for report_elem in elem.children('report'):
            report = Report(self.env, build=build.id, step=stepname,
                            category=report_elem.attr.get('category'),
                            generator=report_elem.attr.get('generator'))
            for item_elem in report_elem.children():
                item = {'type': item_elem.name}
                item.update(item_elem.attr)
                for child_elem in item_elem.children():