• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#      http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18import logging
19
20from vts.runners.host import asserts
21from vts.runners.host import base_test
22from vts.runners.host import const
23from vts.runners.host import keys
24from vts.runners.host import test_runner
25from vts.utils.python.controllers import android_device
26from vts.utils.python.os import path_utils
27
28from vts.testcases.kernel.linux_kselftest import kselftest_config as config
29
30class LinuxKselftestTest(base_test.BaseTestClass):
31    """Runs Linux Kselftest test cases against Android OS kernel.
32
33    Attributes:
34        _dut: AndroidDevice, the device under test as config
35        _shell: ShellMirrorObject, shell mirror
36        _testcases: string list, list of testcases to run
37    """
38    _32BIT = 32
39    _64BIT = 64
40
41    def setUpClass(self):
42        """Creates a remote shell instance, and copies data files."""
43        required_params = [
44            keys.ConfigKeys.IKEY_DATA_FILE_PATH,
45            config.ConfigKeys.TEST_TYPE
46        ]
47        self.getUserParams(required_params)
48
49        logging.info("%s: %s", keys.ConfigKeys.IKEY_DATA_FILE_PATH,
50            self.data_file_path)
51
52        self._dut = self.registerController(android_device)[0]
53        self._dut.shell.InvokeTerminal("one")
54        self._shell = self._dut.shell.one
55
56        if self.test_type == "presubmit":
57            self._testcases = config.KSFT_CASES_PRESUBMIT
58        elif self.test_type == "stable":
59            self._testcases = config.KSFT_CASES_STABLE
60        elif self.test_type == "staging":
61            self._testcases = config.KSFT_CASES_STAGING
62        else:
63            asserts.fail("Test config is incorrect!")
64
65    def tearDownClass(self):
66        """Deletes all copied data."""
67        self._shell.Execute("rm -rf %s" % config.KSFT_DIR)
68
69    def PushFiles(self, n_bit):
70        """adb pushes related file to target.
71
72        Args:
73            n_bit: _32BIT or 32 for 32-bit tests;
74                _64BIT or 64 for 64-bit tests;
75        """
76        self._shell.Execute("mkdir %s -p" % config.KSFT_DIR)
77        test_bit = 'nativetest'
78        if n_bit == self._64BIT:
79            test_bit += '64'
80        self._dut.adb.push("%s/DATA/%s/linux-kselftest/. %s" %
81            (self.data_file_path, test_bit, config.KSFT_DIR))
82
83    def PreTestSetup(self):
84        """Sets up test before running."""
85        # This sed command makes shell scripts compatible wiht android shell.
86        sed_pattern = [
87            's?/bin/echo?echo?',
88            's?#!/bin/sh?#!/system/bin/sh?',
89            's?#!/bin/bash?#!/system/bin/sh?'
90        ]
91        sed_cmd = 'sed %s' % ' '.join(
92            ['-i -e ' + ('"%s"' % p) for p in sed_pattern])
93
94        # This grep command is used to identify shell scripts.
95        grep_pattern = [
96           'bin/sh',
97           'bin/bash'
98        ]
99        grep_cmd = 'grep -l %s' % ' '.join(
100            ['-e ' + ('"%s"' % p) for p in grep_pattern])
101
102        # This applies sed_cmd to every shell script.
103        cmd = 'find %s -type f | xargs %s | xargs %s' % (
104            config.KSFT_DIR, grep_cmd, sed_cmd)
105        result = self._shell.Execute(cmd)
106
107        asserts.assertFalse(
108            any(result[const.EXIT_CODE]),
109            "Error: pre-test setup failed.")
110
111    def RunTestcase(self, testcase):
112        """Runs the given testcase and asserts the result.
113
114        Args:
115            testcase: string, format testsuite/testname, specifies which
116                test case to run.
117        """
118        if not testcase:
119            asserts.skip("Test is not supported on this abi.")
120
121        chmod_cmd = "chmod -R 755 %s" % path_utils.JoinTargetPath(
122            config.KSFT_DIR, testcase.testsuite)
123        cd_cmd = "cd %s" % path_utils.JoinTargetPath(
124            config.KSFT_DIR, testcase.testsuite)
125
126        cmd = [
127            chmod_cmd,
128            "%s && %s" % (cd_cmd, testcase.test_cmd)
129        ]
130        logging.info("Executing: %s", cmd)
131
132        result = self._shell.Execute(cmd)
133        logging.info("EXIT_CODE: %s:", result[const.EXIT_CODE])
134
135        asserts.assertFalse(
136            any(result[const.EXIT_CODE]),
137            "%s failed." % testcase.testname)
138
139    def TestNBits(self, n_bit):
140        """Runs all 32-bit or all 64-bit tests.
141
142        Args:
143            n_bit: _32BIT or 32 for 32-bit tests;
144                _64BIT or 64 for 64-bit tests;
145        """
146        self.PushFiles(n_bit)
147        self.PreTestSetup()
148
149        cpu_abi = self._dut.cpu_abi
150        relevant_testcases = filter(
151            lambda x: x.IsRelevant(cpu_abi, n_bit),
152            self._testcases)
153
154        self.runGeneratedTests(
155            test_func=self.RunTestcase,
156            settings=relevant_testcases,
157            name_func=lambda testcase: "%s_%sbit" % (
158                testcase.testname.replace('/','_'), n_bit))
159
160    def generate32BitTests(self):
161        """Runs all 32-bit tests."""
162        self.TestNBits(self._32BIT)
163
164    def generate64BitTests(self):
165        """Runs all 64-bit tests."""
166        if self._dut.is64Bit:
167            self.TestNBits(self._64BIT)
168
169if __name__ == "__main__":
170    test_runner.main()
171