コード例 #1
0
ファイル: version_1.py プロジェクト: yochow/autotest
    def is_successful_reboot(self, current_status):
        # make sure this is a reboot line
        if self.testname != "reboot":
            return False

        # make sure this was not a failure
        if status_lib.is_worse_than_or_equal_to(current_status, "FAIL"):
            return False

        # it must have been a successful reboot
        return True
コード例 #2
0
ファイル: version_1.py プロジェクト: sconklin/autotest
    def is_successful_reboot(self, current_status):
        # make sure this is a reboot line
        if self.testname != "reboot":
            return False

        # make sure this was not a failure
        if status_lib.is_worse_than_or_equal_to(current_status, "FAIL"):
            return False

        # it must have been a successful reboot
        return True
コード例 #3
0
ファイル: server_job.py プロジェクト: dgrnbrg/autotest
 def __insert_test(self, test):
     """
     An internal method to insert a new test result into the
     database. This method will not raise an exception, even if an
     error occurs during the insert, to avoid failing a test
     simply because of unexpected database issues."""
     self.num_tests_run += 1
     if status_lib.is_worse_than_or_equal_to(test.status, 'FAIL'):
         self.num_tests_failed += 1
     try:
         self.results_db.insert_test(self.job_model, test)
     except Exception:
         msg = ("WARNING: An unexpected error occured while "
                "inserting test results into the database. "
                "Ignoring error.\n" + traceback.format_exc())
         print >> sys.stderr, msg
コード例 #4
0
ファイル: server_job.py プロジェクト: Poohby/autotest
 def __insert_test(self, test):
     """
     An internal method to insert a new test result into the
     database. This method will not raise an exception, even if an
     error occurs during the insert, to avoid failing a test
     simply because of unexpected database issues."""
     self.num_tests_run += 1
     if status_lib.is_worse_than_or_equal_to(test.status, 'FAIL'):
         self.num_tests_failed += 1
     try:
         self.results_db.insert_test(self.job_model, test)
     except Exception:
         msg = ("WARNING: An unexpected error occured while "
                "inserting test results into the database. "
                "Ignoring error.\n" + traceback.format_exc())
         print >> sys.stderr, msg
コード例 #5
0
    def is_successful_reboot(self, current_status):
        """
        Checks whether the status represents a successful reboot.

        @param current_status: A string representing the current status.

        @return True, if the status represents a successful reboot, or False
            if not.

        """
        # Make sure this is a reboot line.
        if self.testname != 'reboot':
            return False

        # Make sure this was not a failure.
        if status_lib.is_worse_than_or_equal_to(current_status, 'FAIL'):
            return False

        # It must have been a successful reboot.
        return True
コード例 #6
0
    def state_iterator(self, buffer):
        """
        Yields a list of tests out of the buffer.

        @param buffer: a buffer object

        """
        line = None
        new_tests = []
        job_count, boot_count = 0, 0
        min_stack_size = 0
        stack = status_lib.status_stack()
        current_kernel = kernel("", [])  # UNKNOWN
        current_status = status_lib.statuses[-1]
        current_reason = None
        started_time_stack = [None]
        subdir_stack = [None]
        testname_stack = [None]
        running_test = None
        running_reasons = set()
        ignored_lines = []
        yield []  # We're ready to start running.

        def print_ignored_lines():
            """
            Prints the ignored_lines using tko_utils.dprint method.
            """
            tko_utils.dprint('The following lines were ignored:')
            for line in ignored_lines:
                tko_utils.dprint(line)
            tko_utils.dprint('---------------------------------')

        # Create a RUNNING SERVER_JOB entry to represent the entire test.
        running_job = test.parse_partial_test(self.job, '----', 'SERVER_JOB',
                                              '', current_kernel,
                                              self.job.started_time)
        new_tests.append(running_job)

        while True:
            # Are we finished with parsing?
            if buffer.size() == 0 and self.finished:
                if ignored_lines:
                    print_ignored_lines()
                    ignored_lines = []
                if stack.size() == 0:
                    break
                # We have status lines left on the stack;
                # we need to implicitly abort them first.
                tko_utils.dprint('\nUnexpected end of job, aborting')
                abort_subdir_stack = list(subdir_stack)
                if self.job.aborted_by:
                    reason = 'Job aborted by %s' % self.job.aborted_by
                    reason += self.job.aborted_on.strftime(
                        ' at %b %d %H:%M:%S')
                else:
                    reason = 'Job aborted unexpectedly'

                timestamp = line.optional_fields.get('timestamp')
                for i in reversed(xrange(stack.size())):
                    if abort_subdir_stack:
                        subdir = abort_subdir_stack.pop()
                    else:
                        subdir = None
                    abort = self.make_dummy_abort(i, subdir, subdir, timestamp,
                                                  reason)
                    buffer.put(abort)

            # Stop processing once the buffer is empty.
            if buffer.size() == 0:
                yield new_tests
                new_tests = []
                continue

            # Reinitialize the per-iteration state.
            started_time = None
            finished_time = None

            # Get the next line.
            raw_line = status_lib.clean_raw_line(buffer.get())
            line = status_line.parse_line(raw_line)
            if line is None:
                ignored_lines.append(raw_line)
                continue
            elif ignored_lines:
                print_ignored_lines()
                ignored_lines = []

            # Do an initial sanity check of the indentation.
            expected_indent = stack.size()
            if line.type == 'END':
                expected_indent -= 1
            if line.indent < expected_indent:
                # ABORT the current level if indentation was unexpectedly low.
                self.put_back_line_and_abort(
                    buffer, raw_line,
                    stack.size() - 1, subdir_stack[-1], testname_stack[-1],
                    line.optional_fields.get('timestamp'), line.reason)
                continue
            elif line.indent > expected_indent:
                # Ignore the log if the indent was unexpectedly high.
                tko_utils.dprint('ignoring line because of extra indentation')
                continue

            # Initial line processing.
            if line.type == 'START':
                stack.start()
                started_time = line.get_timestamp()
                testname = None
                if (line.testname is None and line.subdir is None
                        and not running_test):
                    # We just started a client; all tests are relative to here.
                    min_stack_size = stack.size()
                    # Start a "RUNNING" CLIENT_JOB entry.
                    job_name = 'CLIENT_JOB.%d' % job_count
                    running_client = test.parse_partial_test(
                        self.job, None, job_name, '', current_kernel,
                        started_time)
                    msg = 'RUNNING: %s\n%s\n'
                    msg %= (running_client.status, running_client.testname)
                    tko_utils.dprint(msg)
                    new_tests.append(running_client)
                    testname = running_client.testname
                elif stack.size() == min_stack_size + 1 and not running_test:
                    # We just started a new test; insert a running record.
                    running_reasons = set()
                    if line.reason:
                        running_reasons.add(line.reason)
                    running_test = test.parse_partial_test(
                        self.job, line.subdir, line.testname, line.reason,
                        current_kernel, started_time)
                    msg = 'RUNNING: %s\nSubdir: %s\nTestname: %s\n%s'
                    msg %= (running_test.status, running_test.subdir,
                            running_test.testname, running_test.reason)
                    tko_utils.dprint(msg)
                    new_tests.append(running_test)
                    testname = running_test.testname
                started_time_stack.append(started_time)
                subdir_stack.append(line.subdir)
                testname_stack.append(testname)
                continue
            elif line.type == 'INFO':
                fields = line.optional_fields
                # Update the current kernel if one is defined in the info.
                if 'kernel' in fields:
                    current_kernel = line.get_kernel()
                # Update the SERVER_JOB reason if one was logged for an abort.
                if 'job_abort_reason' in fields:
                    running_job.reason = fields['job_abort_reason']
                    new_tests.append(running_job)
                continue
            elif line.type == 'STATUS':
                # Update the stacks.
                if line.subdir and stack.size() > min_stack_size:
                    subdir_stack[-1] = line.subdir
                    testname_stack[-1] = line.testname
                # Update the status, start and finished times.
                stack.update(line.status)
                if status_lib.is_worse_than_or_equal_to(
                        line.status, current_status):
                    if line.reason:
                        # Update the status of a currently running test.
                        if running_test:
                            running_reasons.add(line.reason)
                            running_reasons = tko_utils.drop_redundant_messages(
                                running_reasons)
                            sorted_reasons = sorted(running_reasons)
                            running_test.reason = ', '.join(sorted_reasons)
                            current_reason = running_test.reason
                            new_tests.append(running_test)
                            msg = 'update RUNNING reason: %s' % line.reason
                            tko_utils.dprint(msg)
                        else:
                            current_reason = line.reason
                    current_status = stack.current_status()
                started_time = None
                finished_time = line.get_timestamp()
                # If this is a non-test entry there's nothing else to do.
                if line.testname is None and line.subdir is None:
                    continue
            elif line.type == 'END':
                # Grab the current subdir off of the subdir stack, or, if this
                # is the end of a job, just pop it off.
                if (line.testname is None and line.subdir is None
                        and not running_test):
                    min_stack_size = stack.size() - 1
                    subdir_stack.pop()
                    testname_stack.pop()
                else:
                    line.subdir = subdir_stack.pop()
                    testname_stack.pop()
                    if not subdir_stack[-1] and stack.size() > min_stack_size:
                        subdir_stack[-1] = line.subdir
                # Update the status, start and finished times.
                stack.update(line.status)
                current_status = stack.end()
                if stack.size() > min_stack_size:
                    stack.update(current_status)
                    current_status = stack.current_status()
                started_time = started_time_stack.pop()
                finished_time = line.get_timestamp()
                # Update the current kernel.
                if line.is_successful_reboot(current_status):
                    current_kernel = line.get_kernel()
                # Adjust the testname if this is a reboot.
                if line.testname == 'reboot' and line.subdir is None:
                    line.testname = 'boot.%d' % boot_count
            else:
                assert False

            # Have we just finished a test?
            if stack.size() <= min_stack_size:
                # If there was no testname, just use the subdir.
                if line.testname is None:
                    line.testname = line.subdir
                # If there was no testname or subdir, use 'CLIENT_JOB'.
                if line.testname is None:
                    line.testname = 'CLIENT_JOB.%d' % job_count
                    running_test = running_client
                    job_count += 1
                    if not status_lib.is_worse_than_or_equal_to(
                            current_status, 'ABORT'):
                        # A job hasn't really failed just because some of the
                        # tests it ran have.
                        current_status = 'GOOD'

                if not current_reason:
                    current_reason = line.reason
                new_test = test.parse_test(self.job, line.subdir,
                                           line.testname, current_status,
                                           current_reason, current_kernel,
                                           started_time, finished_time,
                                           running_test)
                running_test = None
                current_status = status_lib.statuses[-1]
                current_reason = None
                if new_test.testname == ('boot.%d' % boot_count):
                    boot_count += 1
                msg = 'ADD: %s\nSubdir: %s\nTestname: %s\n%s'
                msg %= (new_test.status, new_test.subdir, new_test.testname,
                        new_test.reason)
                tko_utils.dprint(msg)
                new_tests.append(new_test)

        # The job is finished; produce the final SERVER_JOB entry and exit.
        final_job = test.parse_test(self.job, '----', 'SERVER_JOB',
                                    self.job.exit_status(), running_job.reason,
                                    current_kernel, self.job.started_time,
                                    self.job.finished_time, running_job)
        new_tests.append(final_job)
        yield new_tests
コード例 #7
0
ファイル: version_1.py プロジェクト: yochow/autotest
    def state_iterator(self, buffer):
        line = None
        new_tests = []
        job_count, boot_count = 0, 0
        min_stack_size = 0
        stack = status_lib.status_stack()
        current_kernel = kernel("", [])  # UNKNOWN
        current_status = status_lib.statuses[-1]
        current_reason = None
        started_time_stack = [None]
        subdir_stack = [None]
        running_test = None
        running_reasons = set()
        yield []   # we're ready to start running

        # create a RUNNING SERVER_JOB entry to represent the entire test
        running_job = test.parse_partial_test(self.job, "----", "SERVER_JOB",
                                              "", current_kernel,
                                              self.job.started_time)
        new_tests.append(running_job)

        while True:
            # are we finished with parsing?
            if buffer.size() == 0 and self.finished:
                if stack.size() == 0:
                    break
                # we have status lines left on the stack,
                # we need to implicitly abort them first
                tko_utils.dprint('\nUnexpected end of job, aborting')
                abort_subdir_stack = list(subdir_stack)
                if self.job.aborted_by:
                    reason = "Job aborted by %s" % self.job.aborted_by
                    reason += self.job.aborted_on.strftime(
                        " at %b %d %H:%M:%S")
                else:
                    reason = "Job aborted unexpectedly"

                timestamp = line.optional_fields.get('timestamp')
                for i in reversed(xrange(stack.size())):
                    if abort_subdir_stack:
                        subdir = abort_subdir_stack.pop()
                    else:
                        subdir = None
                    abort = self.make_dummy_abort(
                        i, subdir, subdir, timestamp, reason)
                    buffer.put(abort)

            # stop processing once the buffer is empty
            if buffer.size() == 0:
                yield new_tests
                new_tests = []
                continue

            # reinitialize the per-iteration state
            started_time = None
            finished_time = None

            # get the next line
            raw_line = status_lib.clean_raw_line(buffer.get())
            tko_utils.dprint('\nSTATUS: ' + raw_line.strip())
            line = status_line.parse_line(raw_line)
            if line is None:
                tko_utils.dprint('non-status line, ignoring')
                continue

            # do an initial sanity check of the indentation
            expected_indent = stack.size()
            if line.type == "END":
                expected_indent -= 1
            if line.indent < expected_indent:
                # ABORT the current level if indentation was unexpectedly low
                self.put_back_line_and_abort(
                    buffer, raw_line, stack.size() - 1, subdir_stack[-1],
                    line.optional_fields.get("timestamp"), line.reason)
                continue
            elif line.indent > expected_indent:
                # ignore the log if the indent was unexpectedly high
                tko_utils.dprint("unexpected extra indentation, ignoring")
                continue


            # initial line processing
            if line.type == "START":
                stack.start()
                started_time = line.get_timestamp()
                if (line.testname is None and line.subdir is None
                    and not running_test):
                    # we just started a client, all tests are relative to here
                    min_stack_size = stack.size()
                elif stack.size() == min_stack_size + 1 and not running_test:
                    # we just started a new test, insert a running record
                    running_reasons = set()
                    if line.reason:
                        running_reasons.add(line.reason)
                    running_test = test.parse_partial_test(self.job,
                                                           line.subdir,
                                                           line.testname,
                                                           line.reason,
                                                           current_kernel,
                                                           started_time)
                    msg = "RUNNING: %s\nSubdir: %s\nTestname: %s\n%s"
                    msg %= (running_test.status, running_test.subdir,
                            running_test.testname, running_test.reason)
                    tko_utils.dprint(msg)
                    new_tests.append(running_test)
                started_time_stack.append(started_time)
                subdir_stack.append(line.subdir)
                continue
            elif line.type == "INFO":
                # update the current kernel if one is defined in the info
                if "kernel" in line.optional_fields:
                    current_kernel = line.get_kernel()
                continue
            elif line.type == "STATUS":
                # update the stacks
                if line.subdir and stack.size() > min_stack_size:
                    subdir_stack[-1] = line.subdir
                # update the status, start and finished times
                stack.update(line.status)
                if status_lib.is_worse_than_or_equal_to(line.status,
                                                        current_status):
                    if line.reason:
                        # update the status of a currently running test
                        if running_test:
                            running_reasons.add(line.reason)
                            running_reasons = tko_utils.drop_redundant_messages(
                                    running_reasons)
                            sorted_reasons = sorted(running_reasons)
                            running_test.reason = ", ".join(sorted_reasons)
                            current_reason = running_test.reason
                            new_tests.append(running_test)
                            msg = "update RUNNING reason: %s" % line.reason
                            tko_utils.dprint(msg)
                        else:
                            current_reason = line.reason
                    current_status = stack.current_status()
                started_time = None
                finished_time = line.get_timestamp()
                # if this is a non-test entry there's nothing else to do
                if line.testname is None and line.subdir is None:
                    continue
            elif line.type == "END":
                # grab the current subdir off of the subdir stack, or, if this
                # is the end of a job, just pop it off
                if (line.testname is None and line.subdir is None
                    and not running_test):
                    min_stack_size = stack.size() - 1
                    subdir_stack.pop()
                else:
                    line.subdir = subdir_stack.pop()
                    if not subdir_stack[-1] and stack.size() > min_stack_size:
                        subdir_stack[-1] = line.subdir
                # update the status, start and finished times
                stack.update(line.status)
                current_status = stack.end()
                if stack.size() > min_stack_size:
                    stack.update(current_status)
                    current_status = stack.current_status()
                started_time = started_time_stack.pop()
                finished_time = line.get_timestamp()
                # update the current kernel
                if line.is_successful_reboot(current_status):
                    current_kernel = line.get_kernel()
                # adjust the testname if this is a reboot
                if line.testname == "reboot" and line.subdir is None:
                    line.testname = "boot.%d" % boot_count
            else:
                assert False

            # have we just finished a test?
            if stack.size() <= min_stack_size:
                # if there was no testname, just use the subdir
                if line.testname is None:
                    line.testname = line.subdir
                # if there was no testname or subdir, use 'CLIENT_JOB'
                if line.testname is None:
                    line.testname = "CLIENT_JOB.%d" % job_count
                    job_count += 1
                    if not status_lib.is_worse_than_or_equal_to(
                        current_status, "ABORT"):
                        # a job hasn't really failed just because some of the
                        # tests it ran have
                        current_status = "GOOD"

                if not current_reason:
                    current_reason = line.reason
                new_test = test.parse_test(self.job,
                                           line.subdir,
                                           line.testname,
                                           current_status,
                                           current_reason,
                                           current_kernel,
                                           started_time,
                                           finished_time,
                                           running_test)
                running_test = None
                current_status = status_lib.statuses[-1]
                current_reason = None
                if new_test.testname == ("boot.%d" % boot_count):
                    boot_count += 1
                msg = "ADD: %s\nSubdir: %s\nTestname: %s\n%s"
                msg %= (new_test.status, new_test.subdir,
                        new_test.testname, new_test.reason)
                tko_utils.dprint(msg)
                new_tests.append(new_test)

        # the job is finished, produce the final SERVER_JOB entry and exit
        final_job = test.parse_test(self.job, "----", "SERVER_JOB",
                                    self.job.exit_status(), "",
                                    current_kernel,
                                    self.job.started_time,
                                    self.job.finished_time,
                                    running_job)
        new_tests.append(final_job)
        yield new_tests
コード例 #8
0
ファイル: version_1.py プロジェクト: sconklin/autotest
    def state_iterator(self, buffer):
        line = None
        new_tests = []
        job_count, boot_count = 0, 0
        min_stack_size = 0
        stack = status_lib.status_stack()
        current_kernel = kernel("", [])  # UNKNOWN
        current_status = status_lib.statuses[-1]
        current_reason = None
        started_time_stack = [None]
        subdir_stack = [None]
        running_test = None
        running_reasons = set()
        yield []   # we're ready to start running

        # create a RUNNING SERVER_JOB entry to represent the entire test
        running_job = test.parse_partial_test(self.job, "----", "SERVER_JOB",
                                              "", current_kernel,
                                              self.job.started_time)
        new_tests.append(running_job)

        while True:
            # are we finished with parsing?
            if buffer.size() == 0 and self.finished:
                if stack.size() == 0:
                    break
                # we have status lines left on the stack,
                # we need to implicitly abort them first
                tko_utils.dprint('\nUnexpected end of job, aborting')
                abort_subdir_stack = list(subdir_stack)
                if self.job.aborted_by:
                    reason = "Job aborted by %s" % self.job.aborted_by
                    reason += self.job.aborted_on.strftime(
                        " at %b %d %H:%M:%S")
                else:
                    reason = "Job aborted unexpectedly"

                timestamp = line.optional_fields.get('timestamp')
                for i in reversed(xrange(stack.size())):
                    if abort_subdir_stack:
                        subdir = abort_subdir_stack.pop()
                    else:
                        subdir = None
                    abort = self.make_dummy_abort(
                        i, subdir, subdir, timestamp, reason)
                    buffer.put(abort)

            # stop processing once the buffer is empty
            if buffer.size() == 0:
                yield new_tests
                new_tests = []
                continue

            # reinitialize the per-iteration state
            started_time = None
            finished_time = None

            # get the next line
            raw_line = status_lib.clean_raw_line(buffer.get())
            tko_utils.dprint('\nSTATUS: ' + raw_line.strip())
            line = status_line.parse_line(raw_line)
            if line is None:
                tko_utils.dprint('non-status line, ignoring')
                continue

            # do an initial sanity check of the indentation
            expected_indent = stack.size()
            if line.type == "END":
                expected_indent -= 1
            if line.indent < expected_indent:
                # ABORT the current level if indentation was unexpectedly low
                self.put_back_line_and_abort(
                    buffer, raw_line, stack.size() - 1, subdir_stack[-1],
                    line.optional_fields.get("timestamp"), line.reason)
                continue
            elif line.indent > expected_indent:
                # ignore the log if the indent was unexpectedly high
                tko_utils.dprint("unexpected extra indentation, ignoring")
                continue


            # initial line processing
            if line.type == "START":
                stack.start()
                started_time = line.get_timestamp()
                if (line.testname is None and line.subdir is None
                    and not running_test):
                    # we just started a client, all tests are relative to here
                    min_stack_size = stack.size()
                    # start a "RUNNING" CLIENT_JOB entry
                    job_name = "CLIENT_JOB.%d" % job_count
                    running_client = test.parse_partial_test(self.job, None,
                                                             job_name,
                                                             "", current_kernel,
                                                             started_time)
                    msg = "RUNNING: %s\n%s\n"
                    msg %= (running_client.status, running_client.testname)
                    tko_utils.dprint(msg)
                    new_tests.append(running_client)
                elif stack.size() == min_stack_size + 1 and not running_test:
                    # we just started a new test, insert a running record
                    running_reasons = set()
                    if line.reason:
                        running_reasons.add(line.reason)
                    running_test = test.parse_partial_test(self.job,
                                                           line.subdir,
                                                           line.testname,
                                                           line.reason,
                                                           current_kernel,
                                                           started_time)
                    msg = "RUNNING: %s\nSubdir: %s\nTestname: %s\n%s"
                    msg %= (running_test.status, running_test.subdir,
                            running_test.testname, running_test.reason)
                    tko_utils.dprint(msg)
                    new_tests.append(running_test)
                started_time_stack.append(started_time)
                subdir_stack.append(line.subdir)
                continue
            elif line.type == "INFO":
                fields = line.optional_fields
                # update the current kernel if one is defined in the info
                if "kernel" in fields:
                    current_kernel = line.get_kernel()
                # update the SERVER_JOB reason if one was logged for an abort
                if "job_abort_reason" in fields:
                    running_job.reason = fields["job_abort_reason"]
                    new_tests.append(running_job)
                continue
            elif line.type == "STATUS":
                # update the stacks
                if line.subdir and stack.size() > min_stack_size:
                    subdir_stack[-1] = line.subdir
                # update the status, start and finished times
                stack.update(line.status)
                if status_lib.is_worse_than_or_equal_to(line.status,
                                                        current_status):
                    if line.reason:
                        # update the status of a currently running test
                        if running_test:
                            running_reasons.add(line.reason)
                            running_reasons = tko_utils.drop_redundant_messages(
                                    running_reasons)
                            sorted_reasons = sorted(running_reasons)
                            running_test.reason = ", ".join(sorted_reasons)
                            current_reason = running_test.reason
                            new_tests.append(running_test)
                            msg = "update RUNNING reason: %s" % line.reason
                            tko_utils.dprint(msg)
                        else:
                            current_reason = line.reason
                    current_status = stack.current_status()
                started_time = None
                finished_time = line.get_timestamp()
                # if this is a non-test entry there's nothing else to do
                if line.testname is None and line.subdir is None:
                    continue
            elif line.type == "END":
                # grab the current subdir off of the subdir stack, or, if this
                # is the end of a job, just pop it off
                if (line.testname is None and line.subdir is None
                    and not running_test):
                    min_stack_size = stack.size() - 1
                    subdir_stack.pop()
                else:
                    line.subdir = subdir_stack.pop()
                    if not subdir_stack[-1] and stack.size() > min_stack_size:
                        subdir_stack[-1] = line.subdir
                # update the status, start and finished times
                stack.update(line.status)
                current_status = stack.end()
                if stack.size() > min_stack_size:
                    stack.update(current_status)
                    current_status = stack.current_status()
                started_time = started_time_stack.pop()
                finished_time = line.get_timestamp()
                # update the current kernel
                if line.is_successful_reboot(current_status):
                    current_kernel = line.get_kernel()
                # adjust the testname if this is a reboot
                if line.testname == "reboot" and line.subdir is None:
                    line.testname = "boot.%d" % boot_count
            else:
                assert False

            # have we just finished a test?
            if stack.size() <= min_stack_size:
                # if there was no testname, just use the subdir
                if line.testname is None:
                    line.testname = line.subdir
                # if there was no testname or subdir, use 'CLIENT_JOB'
                if line.testname is None:
                    line.testname = "CLIENT_JOB.%d" % job_count
                    running_test = running_client
                    job_count += 1
                    if not status_lib.is_worse_than_or_equal_to(
                        current_status, "ABORT"):
                        # a job hasn't really failed just because some of the
                        # tests it ran have
                        current_status = "GOOD"

                if not current_reason:
                    current_reason = line.reason
                new_test = test.parse_test(self.job,
                                           line.subdir,
                                           line.testname,
                                           current_status,
                                           current_reason,
                                           current_kernel,
                                           started_time,
                                           finished_time,
                                           running_test)
                running_test = None
                current_status = status_lib.statuses[-1]
                current_reason = None
                if new_test.testname == ("boot.%d" % boot_count):
                    boot_count += 1
                msg = "ADD: %s\nSubdir: %s\nTestname: %s\n%s"
                msg %= (new_test.status, new_test.subdir,
                        new_test.testname, new_test.reason)
                tko_utils.dprint(msg)
                new_tests.append(new_test)

        # the job is finished, produce the final SERVER_JOB entry and exit
        final_job = test.parse_test(self.job, "----", "SERVER_JOB",
                                    self.job.exit_status(), running_job.reason,
                                    current_kernel,
                                    self.job.started_time,
                                    self.job.finished_time,
                                    running_job)
        new_tests.append(final_job)
        yield new_tests