xref: /aosp_15_r20/external/autotest/server/cros/pvs/sequence.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Copyright 2022 The Chromium OS Authors. All rights reserved.
2*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
3*9c5db199SXin Li# found in the LICENSE file.
4*9c5db199SXin Li
5*9c5db199SXin Liimport os
6*9c5db199SXin Liimport shutil
7*9c5db199SXin Li
8*9c5db199SXin Lifrom autotest_lib.server import autotest, test
9*9c5db199SXin Lifrom autotest_lib.client.common_lib import error
10*9c5db199SXin Li
11*9c5db199SXin Li
12*9c5db199SXin Liclass test_sequence(test.test):
13*9c5db199SXin Li    """
14*9c5db199SXin Li    test_sequence extends the base test implementation to allow for
15*9c5db199SXin Li    encapsulating a series of (client or server) tests which must
16*9c5db199SXin Li    be run in a given sequence.
17*9c5db199SXin Li    """
18*9c5db199SXin Li
19*9c5db199SXin Li    def initialize(self, sequence):
20*9c5db199SXin Li        """
21*9c5db199SXin Li        initialize implements the initialize call in test.test, is called before
22*9c5db199SXin Li        execution of the test
23*9c5db199SXin Li
24*9c5db199SXin Li        @param sequence: the sequence of tests constructed in the wrapper
25*9c5db199SXin Li        @param sequence_verdicts: verdicts from each executed test in the
26*9c5db199SXin Li                sequence. Passed by reference and used by the caller to
27*9c5db199SXin Li                annotate results.
28*9c5db199SXin Li        """
29*9c5db199SXin Li        self._sequenced_tests = sequence
30*9c5db199SXin Li        self._sequence_verdicts = {}
31*9c5db199SXin Li        self._results_path = self.job._server_offload_dir_path()
32*9c5db199SXin Li        self._wrapper_results_dir = os.path.join(self._results_path,
33*9c5db199SXin Li                                                 self.tagged_testname)
34*9c5db199SXin Li
35*9c5db199SXin Li    def process_test_results_post_hook(self):
36*9c5db199SXin Li        """
37*9c5db199SXin Li        process_test_results is used as a post_run_hook to record results to the
38*9c5db199SXin Li        status.log file following the execution of the run. For tests that were
39*9c5db199SXin Li        completed (i.e. no exceptions occurred to end the sequence), results are
40*9c5db199SXin Li        moved to the top level from the child results directory
41*9c5db199SXin Li        """
42*9c5db199SXin Li        for test, args, server_test in self._sequenced_tests:
43*9c5db199SXin Li            if test not in self._sequence_verdicts:
44*9c5db199SXin Li                continue
45*9c5db199SXin Li
46*9c5db199SXin Li            if server_test:
47*9c5db199SXin Li                self.surface_server_test_resultsdir(test)
48*9c5db199SXin Li            else:
49*9c5db199SXin Li                self.surface_client_test_resultsdir(test)
50*9c5db199SXin Li            annotated_testname = self.tagged_testname + "." + test
51*9c5db199SXin Li            self.job.record('START', None, annotated_testname)
52*9c5db199SXin Li            self.job.record('INFO', None, annotated_testname)
53*9c5db199SXin Li            if self._sequence_verdicts[test]:
54*9c5db199SXin Li                self.job.record('END GOOD', None, annotated_testname, "")
55*9c5db199SXin Li            else:
56*9c5db199SXin Li                self.job.record('END FAIL', None, annotated_testname, "")
57*9c5db199SXin Li
58*9c5db199SXin Li    def execute_sequenced_test(self, client, test, argv, server_test):
59*9c5db199SXin Li        """
60*9c5db199SXin Li        execute_sequenced_test runs a single test from the sequence with the
61*9c5db199SXin Li        given argument vector
62*9c5db199SXin Li
63*9c5db199SXin Li        @param test: test name (url) to run
64*9c5db199SXin Li        @param argv: argument dictionary to run the test with
65*9c5db199SXin Li
66*9c5db199SXin Li        @raises error.TestFail: on failure of the wrapped tests
67*9c5db199SXin Li        """
68*9c5db199SXin Li        try:
69*9c5db199SXin Li            self._sequence_verdicts[test] = True
70*9c5db199SXin Li            if server_test:
71*9c5db199SXin Li                err = self.job.run_test(test, **argv)
72*9c5db199SXin Li                if err == False:
73*9c5db199SXin Li                    raise error.TestFail()
74*9c5db199SXin Li            else:
75*9c5db199SXin Li                client.run_test(test, check_client_result=True, **argv)
76*9c5db199SXin Li        except:
77*9c5db199SXin Li            self._sequence_verdicts[test] = False
78*9c5db199SXin Li            self.postprocess()
79*9c5db199SXin Li            raise error.TestFail('Sequenced test %s failed, reason: ' % test)
80*9c5db199SXin Li
81*9c5db199SXin Li    def surface_client_test_resultsdir(self, test):
82*9c5db199SXin Li        """
83*9c5db199SXin Li        surface_client_test_resultsdir retrieves the child test results from a
84*9c5db199SXin Li        sequenced client job
85*9c5db199SXin Li
86*9c5db199SXin Li        @param test: the child test name to grab results from
87*9c5db199SXin Li        """
88*9c5db199SXin Li        wrapped_test_results_path = os.path.join(self._wrapper_results_dir,
89*9c5db199SXin Li                                                 test)
90*9c5db199SXin Li        tagged_destination = os.path.join(self._results_path,
91*9c5db199SXin Li                                          self.tagged_testname + "." + test)
92*9c5db199SXin Li        shutil.move(wrapped_test_results_path, tagged_destination)
93*9c5db199SXin Li
94*9c5db199SXin Li    def surface_server_test_resultsdir(self, test):
95*9c5db199SXin Li        """
96*9c5db199SXin Li        surface_server_test_resultsdir renames the server test results from a sequenced child
97*9c5db199SXin Li
98*9c5db199SXin Li        @param test: the child test name to grab results from
99*9c5db199SXin Li        """
100*9c5db199SXin Li        wrapped_test_results_path = os.path.join(self._results_path, test)
101*9c5db199SXin Li        tagged_destination = os.path.join(self._results_path,
102*9c5db199SXin Li                                          self.tagged_testname + "." + test)
103*9c5db199SXin Li        shutil.move(wrapped_test_results_path, tagged_destination)
104*9c5db199SXin Li
105*9c5db199SXin Li    def run_once(self, host=None):
106*9c5db199SXin Li        """
107*9c5db199SXin Li        run_once implements the run_once call in test.test, is called to begin
108*9c5db199SXin Li        execution of the test
109*9c5db199SXin Li
110*9c5db199SXin Li        @param host: host from control file with which to run the test
111*9c5db199SXin Li        """
112*9c5db199SXin Li        client_at = autotest.Autotest(host)
113*9c5db199SXin Li        for test, argv, server_test in self._sequenced_tests:
114*9c5db199SXin Li            self.execute_sequenced_test(client_at, test, argv, server_test)
115*9c5db199SXin Li
116*9c5db199SXin Li    def postprocess(self):
117*9c5db199SXin Li        """
118*9c5db199SXin Li        postprocess is the post routine for test.test. We must add our post_hook
119*9c5db199SXin Li        in this function (as opposed to the initialize call) because if added in
120*9c5db199SXin Li        initialize, this will be called after each child server test as well as
121*9c5db199SXin Li        at the end of the function
122*9c5db199SXin Li        """
123*9c5db199SXin Li        self.job.add_post_run_hook(self.process_test_results_post_hook)
124