| # Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Mock out test results for puppylab. |
| """ |
| |
| |
| import logging |
| import os |
| import time |
| |
| import common |
| from autotest_lib.client.common_lib import time_utils |
| |
| # TODO(beeps): The right way to create these status logs is by creating a job |
| # object and invoking job.record on it. However we perform this template |
| # hack instead for the following reasons: |
| # * The templates are a lot easier to understand at first glance, which |
| # is really what one wants from a testing interface built for a |
| # framework like autotest. |
| # * Creating the job is wedged into core autotest code, so it has |
| # unintended consequences like checking for hosts/labels etc. |
| # * We are guaranteed to create the bare minimum by hand specifying the file |
| # to write, and their contents. Job.record ends up checking and creating |
| # several non-essential directoris in the process or recording status. |
| |
| _SUCCESS_TEST_TEMPLATE = ( |
| "\tSTART\t%(test_name)s\t%(test_name)s" |
| "\ttimestamp=%(timestamp)s\tlocaltime=%(date)s\n" |
| "\t\tGOOD\t%(test_name)s\t%(test_name)s\ttimestamp=%(timestamp)s\t" |
| "localtime=%(date)s\tcompleted successfully\n" |
| "\tEND GOOD\t%(test_name)s\t%(test_name)s\ttimestamp=%(timestamp)s\t" |
| "localtime=%(date)s") |
| |
| |
| _SUCCESS_JOB_TEMPLATE = ( |
| "START\t----\t----\ttimestamp=%(timestamp)s\tlocaltime=%(date)s" |
| "\n\tSTART\t%(test_name)s\t%(test_name)s\ttimestamp=%(timestamp)s\t" |
| "localtime=%(date)s\n\t\tGOOD\t%(test_name)s\t%(test_name)s" |
| "\ttimestamp=%(timestamp)s\tlocaltime=%(date)s\tcompleted " |
| "successfully\n\tEND GOOD\t%(test_name)s\t%(test_name)s" |
| "\ttimestamp=%(timestamp)s\tlocaltime=%(date)s\n" |
| "END GOOD\t----\t----\ttimestamp=%(timestamp)s\tlocaltime=%(date)s") |
| |
| |
| _JOB_KEYVALS_TEMPLATE = "hostname=%(hostname)s\nstatus_version=1\n" |
| |
| |
| class ResultsMocker(object): |
| """Class to mock out the results of a test.""" |
| |
| def _make_dirs(self): |
| """Create essential directories needed for faking test results. |
| |
| @raises ValueError: If the directories crucial to reporting |
| test status already exist. |
| @raises OSError: If we cannot make one of the directories for |
| an os related reason (eg: permissions). |
| @raises AssertionError: If one of the directories silently failed |
| creation. |
| """ |
| logging.info("creating dir %s, %s, %s", |
| self.results_dir, self.test_results, self.host_keyval_dir) |
| if not os.path.exists(self.results_dir): |
| os.makedirs(self.results_dir) |
| if not os.path.exists(self.test_results): |
| os.makedirs(self.test_results) |
| if not os.path.exists(self.host_keyval_dir): |
| os.makedirs(self.host_keyval_dir) |
| assert(os.path.exists(self.test_results) and |
| os.path.exists(self.results_dir) and |
| os.path.exists(self.host_keyval_dir)) |
| |
| |
| def __init__(self, test_name, results_dir, machine_name): |
| """Initialize a results mocker. |
| |
| @param test_name: The name of the test, eg: dummy_Pass. |
| @param results_dir: The results directory this test will use. |
| @param machine_name: A string representing the hostname the test will |
| run on. |
| """ |
| self.results_dir = results_dir |
| self.test_results = os.path.join(results_dir, test_name) |
| self.host_keyval_dir = os.path.join(self.results_dir, 'host_keyvals') |
| self.machine_name = machine_name |
| self.test_name = test_name |
| |
| self._make_dirs() |
| |
| # Status logs are used by the parser to declare a test as pass/fail. |
| self.job_status = os.path.join(self.results_dir, 'status') |
| self.job_status_log = os.path.join(self.results_dir, 'status.log') |
| self.test_status = os.path.join(self.test_results, 'status') |
| |
| # keyvals are used by the parser to figure out fine grained information |
| # about a test. Only job_keyvals are crucial to parsing. |
| self.test_keyvals = os.path.join(self.test_results, 'keyval') |
| self.job_keyvals = os.path.join(self.results_dir, 'keyval') |
| self.host_keyvals = os.path.join(self.results_dir, machine_name) |
| |
| |
| def _write(self, results_path, results): |
| """Write the content in results to the file in results_path. |
| |
| @param results_path: The path to the results file. |
| @param results: The content to write to the file. |
| """ |
| logging.info('Writing results to %s', results_path) |
| with open(results_path, 'w') as results_file: |
| results_file.write(results) |
| |
| |
| def generate_keyvals(self): |
| """Apply templates to keyval files. |
| |
| There are 3 important keyvals files, only one of which is actually |
| crucial to results parsing: |
| host_keyvals - information about the DUT |
| job_keyvals - information about the server_job |
| test_keyvals - information about the test |
| |
| Parsing cannot complete without the job_keyvals. Everything else is |
| optional. Keyvals are parsed into tko tables. |
| """ |
| #TODO(beeps): Include other keyvals. |
| self._write( |
| self.job_keyvals, |
| _JOB_KEYVALS_TEMPLATE % |
| {'hostname': self.machine_name}) |
| |
| |
| def generate_status(self): |
| """Generate status logs. |
| |
| 3 important status logs are required for successful parsing: |
| test_name/status - core test status |
| results_dir/status - server job status (has test status in it) |
| status.log - compiled final status log |
| """ |
| current_timestamp = int(time.time()) |
| test_info = { |
| 'test_name': self.test_name, |
| 'timestamp': current_timestamp, |
| 'date': time_utils.epoch_time_to_date_string( |
| current_timestamp, fmt_string='%b %d %H:%M:%S'), |
| } |
| self._write( |
| self.job_status, |
| _SUCCESS_JOB_TEMPLATE % test_info) |
| self._write( |
| self.job_status_log, |
| _SUCCESS_JOB_TEMPLATE % test_info) |
| self._write( |
| self.test_status, |
| _SUCCESS_TEST_TEMPLATE % test_info) |
| |
| |
| def mock_results(self): |
| """Create mock results in the directories used to init the instance.""" |
| self.generate_status() |
| self.generate_keyvals() |
| |
| |