blob: 2fdee615220dffeefa262d32860d4a7be263bf94 [file] [log] [blame]
# 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()