1#
2# Copyright (C) 2018 The Android Open Source Project
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15#
16
17import logging
18import os
19import time
20
21import environment_variables as env
22
23
24class SyzkallerTestCase(object):
25    """Represents syzkaller test case.
26
27    Attributes:
28        _env: dict, inverted map of environment varialbes for this test.
29        _device_target: string, OS of the target device.
30        _device_code: string, serial number of the target device.
31        _device_type: string, type of the target device.
32        _reproduce: boolean, whether or not to reproduce if a crash is found.
33        _http: integer, path to localhost where the test information will be shown.
34        _procs: integer, number of processes this test case will use if available.
35        _test_name: string, the unique name for this test case.
36        _work_dir_path: string, path to the work directory for this test case.
37        _config_file_path: string, path to the config file for this test case.
38    """
39
40    def __init__(self, env, device_target, device_code, device_type, reproduce,
41                 procs):
42        self._env = env
43        self._device_target = device_target
44        self._device_code = device_code
45        self._device_type = device_type
46        self._reproduce = reproduce
47        self._http = 'localhost:50000'
48        self._procs = procs
49        self._test_name = self.GenerateTestName()
50        self._work_dir_path = self.GenerateCorpusDir()
51        self._config_file_path = self.GenerateConfigFile()
52
53    def GenerateTestName(self):
54        """Uses device code and time to create unique name
55
56        Returns:
57            test_name, string, the unique test name for this test case.
58        """
59        test_name = '%s_%s_%d' % (time.strftime('%Y-%m-%d'), self._device_code,
60                                  int(time.time()))
61        return str(test_name)
62
63    def GenerateCorpusDir(self):
64        """Creates working directory for this test case.
65
66        Returns:
67            work_dir_path, string, path to the working directory for this test case.
68        """
69        work_dir_path = os.path.join(self._env['syzkaller_work_dir'],
70                                     self._test_name)
71        if not os.path.exists(work_dir_path):
72            os.makedirs(work_dir_path)
73        return work_dir_path
74
75    def GenerateConfigFile(self):
76        """Creates configuration file for this test case.
77
78        Returns:
79            config_file_path, string, path to the configuration file for this test case.
80        """
81
82        # read template config
83        with open(self._env['template_cfg'], 'r') as temp:
84            template_cfg = str(temp.read())
85
86        # fill out template
87        template_cfg = template_cfg.replace('{device_target}',
88                                            self._device_target)
89        template_cfg = template_cfg.replace('{reproduce}', self._reproduce)
90        template_cfg = template_cfg.replace('{work_dir_path}',
91                                            self._work_dir_path)
92        template_cfg = template_cfg.replace('{http}', self._http)
93        template_cfg = template_cfg.replace('{syzkaller_dir_path}',
94                                            self._env['syzkaller_dir'])
95        template_cfg = template_cfg.replace('{device_code}', self._device_code)
96        template_cfg = template_cfg.replace('{device_type}', self._device_type)
97        template_cfg = template_cfg.replace('{procs}', str(self._procs))
98
99        # save config file
100        config_file_path = self._work_dir_path + str('.cfg')
101        with open(config_file_path, 'w') as config_file:
102            config_file.write(template_cfg)
103        return config_file_path
104
105    def GetRunCommand(self):
106        """Creates test run command for this case.
107
108        Returns:
109            test_command, string, test run command for this test case.
110        """
111        syz_manager_path = os.path.join(self._env['syzkaller_bin_dir'],
112                                        'syz-manager')
113        test_command = '%s -config=%s' % (syz_manager_path,
114                                          self._config_file_path)
115        return test_command
116