# 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()
|