1*f86d0556SBrad Bishopimport unittest
2*f86d0556SBrad Bishopimport pprint
3*f86d0556SBrad Bishop
4eb8dc403SDave Cobbleyfrom oeqa.runtime.case import OERuntimeTestCase
5eb8dc403SDave Cobbleyfrom oeqa.core.decorator.depends import OETestDepends
6eb8dc403SDave Cobbleyfrom oeqa.core.decorator.oeid import OETestID
7eb8dc403SDave Cobbleyfrom oeqa.core.decorator.data import skipIfNotFeature
8eb8dc403SDave Cobbleyfrom oeqa.utils.logparser import Lparser, Result
9eb8dc403SDave Cobbley
10eb8dc403SDave Cobbleyclass PtestRunnerTest(OERuntimeTestCase):
11eb8dc403SDave Cobbley
12eb8dc403SDave Cobbley    # a ptest log parser
13eb8dc403SDave Cobbley    def parse_ptest(self, logfile):
14eb8dc403SDave Cobbley        parser = Lparser(test_0_pass_regex="^PASS:(.+)",
15eb8dc403SDave Cobbley                         test_0_fail_regex="^FAIL:(.+)",
16eb8dc403SDave Cobbley                         test_0_skip_regex="^SKIP:(.+)",
17eb8dc403SDave Cobbley                         section_0_begin_regex="^BEGIN: .*/(.+)/ptest",
18eb8dc403SDave Cobbley                         section_0_end_regex="^END: .*/(.+)/ptest")
19eb8dc403SDave Cobbley        parser.init()
20eb8dc403SDave Cobbley        result = Result()
21eb8dc403SDave Cobbley
22eb8dc403SDave Cobbley        with open(logfile, errors='replace') as f:
23eb8dc403SDave Cobbley            for line in f:
24eb8dc403SDave Cobbley                result_tuple = parser.parse_line(line)
25eb8dc403SDave Cobbley                if not result_tuple:
26eb8dc403SDave Cobbley                    continue
27eb8dc403SDave Cobbley                result_tuple = line_type, category, status, name = parser.parse_line(line)
28eb8dc403SDave Cobbley
29eb8dc403SDave Cobbley                if line_type == 'section' and status == 'begin':
30eb8dc403SDave Cobbley                    current_section = name
31eb8dc403SDave Cobbley                    continue
32eb8dc403SDave Cobbley
33eb8dc403SDave Cobbley                if line_type == 'section' and status == 'end':
34eb8dc403SDave Cobbley                    current_section = None
35eb8dc403SDave Cobbley                    continue
36eb8dc403SDave Cobbley
37eb8dc403SDave Cobbley                if line_type == 'test' and status == 'pass':
38eb8dc403SDave Cobbley                    result.store(current_section, name, status)
39eb8dc403SDave Cobbley                    continue
40eb8dc403SDave Cobbley
41eb8dc403SDave Cobbley                if line_type == 'test' and status == 'fail':
42eb8dc403SDave Cobbley                    result.store(current_section, name, status)
43eb8dc403SDave Cobbley                    continue
44eb8dc403SDave Cobbley
45eb8dc403SDave Cobbley                if line_type == 'test' and status == 'skip':
46eb8dc403SDave Cobbley                    result.store(current_section, name, status)
47eb8dc403SDave Cobbley                    continue
48eb8dc403SDave Cobbley
49eb8dc403SDave Cobbley        result.sort_tests()
50eb8dc403SDave Cobbley        return result
51eb8dc403SDave Cobbley
52eb8dc403SDave Cobbley    @OETestID(1600)
53eb8dc403SDave Cobbley    @skipIfNotFeature('ptest', 'Test requires ptest to be in DISTRO_FEATURES')
54eb8dc403SDave Cobbley    @OETestDepends(['ssh.SSHTest.test_ssh'])
55*f86d0556SBrad Bishop    @unittest.expectedFailure
56eb8dc403SDave Cobbley    def test_ptestrunner(self):
57eb8dc403SDave Cobbley        status, output = self.target.run('which ptest-runner', 0)
58eb8dc403SDave Cobbley        if status != 0:
59eb8dc403SDave Cobbley            self.skipTest("No -ptest packages are installed in the image")
60eb8dc403SDave Cobbley
61eb8dc403SDave Cobbley        import datetime
62eb8dc403SDave Cobbley
63eb8dc403SDave Cobbley        test_log_dir = self.td.get('TEST_LOG_DIR', '')
64eb8dc403SDave Cobbley        # The TEST_LOG_DIR maybe NULL when testimage is added after
65eb8dc403SDave Cobbley        # testdata.json is generated.
66eb8dc403SDave Cobbley        if not test_log_dir:
67eb8dc403SDave Cobbley            test_log_dir = os.path.join(self.td.get('WORKDIR', ''), 'testimage')
68eb8dc403SDave Cobbley        # Don't use self.td.get('DATETIME'), it's from testdata.json, not
69eb8dc403SDave Cobbley        # up-to-date, and may cause "File exists" when re-reun.
70eb8dc403SDave Cobbley        datetime = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
71eb8dc403SDave Cobbley        ptest_log_dir_link = os.path.join(test_log_dir, 'ptest_log')
72eb8dc403SDave Cobbley        ptest_log_dir = '%s.%s' % (ptest_log_dir_link, datetime)
73eb8dc403SDave Cobbley        ptest_runner_log = os.path.join(ptest_log_dir, 'ptest-runner.log')
74eb8dc403SDave Cobbley
75eb8dc403SDave Cobbley        status, output = self.target.run('ptest-runner', 0)
76eb8dc403SDave Cobbley        os.makedirs(ptest_log_dir)
77eb8dc403SDave Cobbley        with open(ptest_runner_log, 'w') as f:
78eb8dc403SDave Cobbley            f.write(output)
79eb8dc403SDave Cobbley
80eb8dc403SDave Cobbley        # status != 0 is OK since some ptest tests may fail
81eb8dc403SDave Cobbley        self.assertTrue(status != 127, msg="Cannot execute ptest-runner!")
82eb8dc403SDave Cobbley
83*f86d0556SBrad Bishop        if not hasattr(self.tc, "extraresults"):
84*f86d0556SBrad Bishop            self.tc.extraresults = {}
85*f86d0556SBrad Bishop        extras = self.tc.extraresults
86*f86d0556SBrad Bishop        extras['ptestresult.rawlogs'] = {'log': output}
87*f86d0556SBrad Bishop
88eb8dc403SDave Cobbley        # Parse and save results
89eb8dc403SDave Cobbley        parse_result = self.parse_ptest(ptest_runner_log)
90eb8dc403SDave Cobbley        parse_result.log_as_files(ptest_log_dir, test_status = ['pass','fail', 'skip'])
91eb8dc403SDave Cobbley        if os.path.exists(ptest_log_dir_link):
92eb8dc403SDave Cobbley            # Remove the old link to create a new one
93eb8dc403SDave Cobbley            os.remove(ptest_log_dir_link)
94eb8dc403SDave Cobbley        os.symlink(os.path.basename(ptest_log_dir), ptest_log_dir_link)
95eb8dc403SDave Cobbley
96*f86d0556SBrad Bishop        trans = str.maketrans("()", "__")
97*f86d0556SBrad Bishop        resmap = {'pass': 'PASSED', 'skip': 'SKIPPED', 'fail': 'FAILED'}
98*f86d0556SBrad Bishop        for section in parse_result.result_dict:
99*f86d0556SBrad Bishop            for test, result in parse_result.result_dict[section]:
100*f86d0556SBrad Bishop                testname = "ptestresult." + section + "." + "_".join(test.translate(trans).split())
101*f86d0556SBrad Bishop                extras[testname] = {'status': resmap[result]}
102*f86d0556SBrad Bishop
103eb8dc403SDave Cobbley        failed_tests = {}
104eb8dc403SDave Cobbley        for section in parse_result.result_dict:
105*f86d0556SBrad Bishop            failed_testcases = [ "_".join(test.translate(trans).split()) for test, result in parse_result.result_dict[section] if result == 'fail' ]
106eb8dc403SDave Cobbley            if failed_testcases:
107eb8dc403SDave Cobbley                failed_tests[section] = failed_testcases
108eb8dc403SDave Cobbley
109*f86d0556SBrad Bishop        if failed_tests:
110*f86d0556SBrad Bishop            self.fail("Failed ptests:\n%s" % pprint.pformat(failed_tests))
111