kunit_tool: Move log printing out of kunit_parser

Currently, kunit_parser will print a test log in parse_run_tests. This
means that, in kunit_test, there is a lot of confusing output from the
included test logs.

This change makes kunit_parser write its log to a string, which may then
optinally be printed by its caller. In this case, we make the main
'kunit.py' print out the test log when running tests, but to not make
kunit_test do so, as to not clutter the unittest output.

In doing this, the kunit_parser.TestResult type is changed to a class
(with an additional 'pretty_log' function which writes to
TestResult.log_lines), replacing the old namedtuple
implemenatation. There is also an additional
TestResult.print_pretty_log() function to print this log.

Signed-off-by: David Gow <davidgow@google.com>
Change-Id: Ib6c70f9749cf3daf513c150d472b58903aff0202
diff --git a/tools/testing/kunit/kunit.py b/tools/testing/kunit/kunit.py
index dc4d14d..2536c74 100755
--- a/tools/testing/kunit/kunit.py
+++ b/tools/testing/kunit/kunit.py
@@ -55,6 +55,7 @@
 				kunit_parser.isolate_kunit_output(
 				  linux.run_kernel(timeout=request.timeout)))
 	test_end = time.time()
+	test_result.print_pretty_log()
 
 	print(kunit_parser.timestamp((
 		'Elapsed time: %.3fs total, %.3fs configuring, %.3fs ' +
diff --git a/tools/testing/kunit/kunit_parser.py b/tools/testing/kunit/kunit_parser.py
index 02b4abe..4d65e0a 100644
--- a/tools/testing/kunit/kunit_parser.py
+++ b/tools/testing/kunit/kunit_parser.py
@@ -3,12 +3,6 @@
 
 from collections import namedtuple
 
-TestResult = namedtuple('TestResult', ['status','modules','log'])
-
-TestModule = namedtuple('TestModule', ['status','name','cases'])
-
-TestCase = namedtuple('TestCase', ['status','name','log'])
-
 class TestStatus(object):
 	SUCCESS = 'SUCCESS'
 	FAILURE = 'FAILURE'
@@ -16,6 +10,24 @@
 	TIMED_OUT = 'TIMED_OUT'
 	KERNEL_CRASHED = 'KERNEL_CRASHED'
 
+class TestResult(object):
+	def __init__(self, status=TestStatus.SUCCESS, modules=None, kernel_log='',
+			log_lines=None):
+		self.status = status
+		self.modules = modules or []
+		self.kernel_log = kernel_log
+		self.log_lines = log_lines or []
+
+	def pretty_log(self, msg):
+		self.log_lines.append(msg)
+
+	def print_pretty_log(self):
+		print('\n'.join(self.log_lines))
+
+TestModule = namedtuple('TestModule', ['status','name','cases'])
+
+TestCase = namedtuple('TestCase', ['status','name','log'])
+
 kunit_start_re = re.compile('console .* enabled')
 kunit_end_re = re.compile('List of all partitions:')
 
@@ -75,8 +87,7 @@
 	failed_tests = set()
 	crashed_tests = set()
 
-	test_status = TestStatus.SUCCESS
-	modules = []
+	test_result = TestResult()
 	log_list = []
 
 	def get_test_module_name(match):
@@ -96,7 +107,7 @@
 		del log[:]
 		total_tests.add(get_test_name(match))
 
-	print(timestamp(DIVIDER))
+	test_result.pretty_log(timestamp(DIVIDER))
 	try:
 		for line in kernel_output:
 			log_list.append(line)
@@ -104,8 +115,8 @@
 			# Ignore module output:
 			module_success = test_module_success.match(line)
 			if module_success:
-				print(timestamp(DIVIDER))
-				modules.append(
+				test_result.pretty_log(timestamp(DIVIDER))
+				test_result.modules.append(
 				  TestModule(TestStatus.SUCCESS,
 					     get_test_module_name(module_success),
 					     current_module_cases))
@@ -113,8 +124,8 @@
 				continue
 			module_fail = test_module_fail.match(line)
 			if module_fail:
-				print(timestamp(DIVIDER))
-				modules.append(
+				test_result.pretty_log(timestamp(DIVIDER))
+				test_result.modules.append(
 				  TestModule(TestStatus.FAILURE,
 					     get_test_module_name(module_fail),
 					     current_module_cases))
@@ -123,7 +134,8 @@
 
 			match = re.match(test_case_success, line)
 			if match:
-				print(timestamp(green("[PASSED] ") + get_test_name(match)))
+				test_result.pretty_log(timestamp(green("[PASSED] ") +
+									get_test_name(match)))
 				current_module_cases.append(
 					TestCase(TestStatus.SUCCESS,
 						 get_test_case_name(match),
@@ -136,38 +148,41 @@
 			# want to show and count it once.
 			if match and get_test_name(match) not in crashed_tests:
 				failed_tests.add(get_test_name(match))
-				print(timestamp(red("[FAILED] " + get_test_name(match))))
+				test_result.pretty_log(timestamp(red("[FAILED] " +
+									get_test_name(match))))
 				for out in timestamp_log(map(yellow, current_case_log)):
-					print(out)
-				print(timestamp(""))
+					test_result.pretty_log(out)
+				test_result.pretty_log(timestamp(""))
 				current_module_cases.append(
 					TestCase(TestStatus.FAILURE,
 						 get_test_case_name(match),
 						 '\n'.join(current_case_log)))
-				if test_status != TestStatus.TEST_CRASHED:
-					test_status = TestStatus.FAILURE
+				if test_result.status != TestStatus.TEST_CRASHED:
+					test_result.status = TestStatus.FAILURE
 				end_one_test(match, current_case_log)
 				continue
 
 			match = re.match(test_case_crash, line)
 			if match:
 				crashed_tests.add(get_test_name(match))
-				print(timestamp(yellow("[CRASH] " + get_test_name(match))))
+				test_result.pretty_log(timestamp(yellow("[CRASH] " +
+									get_test_name(match))))
 				for out in timestamp_log(current_case_log):
-					print(out)
-				print(timestamp(""))
+					test_result.pretty_log(out)
+				test_result.pretty_log(timestamp(""))
 				current_module_cases.append(
 					TestCase(TestStatus.TEST_CRASHED,
 						 get_test_case_name(match),
 						 '\n'.join(current_case_log)))
-				test_status = TestStatus.TEST_CRASHED
+				test_result.status = TestStatus.TEST_CRASHED
 				end_one_test(match, current_case_log)
 				continue
 
 			if line.strip() == TIMED_OUT_LOG_ENTRY:
-				print(timestamp(red("[TIMED-OUT] Process Terminated")))
+				test_result.pretty_log(timestamp(red("[TIMED-OUT] " +
+									 "Process Terminated")))
 				did_timeout = True
-				test_status = TestStatus.TIMED_OUT
+				test_result.status = TestStatus.TIMED_OUT
 				break
 
 			# Strip off the `kunit module-name:` prefix
@@ -178,15 +193,16 @@
 				current_case_log.append(line)
 	except KernelCrashException:
 		did_kernel_crash = True
-		test_status = TestStatus.KERNEL_CRASHED
-		print(timestamp(red("The KUnit kernel crashed unexpectedly and was " +
+		test_result.status = TestStatus.KERNEL_CRASHED
+		test_result.pretty_log(timestamp(red("The KUnit kernel crashed " +
+							"unexpectedly and was unable " +
 							"unable to finish running tests!")))
-		print(timestamp(red("These are the logs from the most " +
+		test_result.pretty_log(timestamp(red("These are the logs from the most " +
 							"recently running test:")))
-		print(timestamp(DIVIDER))
+		test_result.pretty_log(timestamp(DIVIDER))
 		for out in timestamp_log(current_case_log):
-			print(out)
-		print(timestamp(DIVIDER))
+			test_result.pretty_log(out)
+		test_result.pretty_log(timestamp(DIVIDER))
 
 	fmt = green if (len(failed_tests) + len(crashed_tests) == 0
 			and not did_kernel_crash and not did_timeout) else red
@@ -196,7 +212,8 @@
 	elif did_timeout:
 		message = "Before timing out:"
 
-	print(timestamp(fmt(message + " %d tests run. %d failed. %d crashed." %
+	test_result.pretty_log(timestamp(fmt(message + " %d tests run. %d failed. %d crashed." %
 				(len(total_tests), len(failed_tests), len(crashed_tests)))))
 
-	return TestResult(test_status, modules, '\n'.join(log_list))
+	test_result.kernel_log = '\n'.join(log_list)
+	return test_result