Home | History | Annotate | Download | only in server
      1 # Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 """Mock out test results for puppylab.
      6 """
      7 
      8 
      9 import logging
     10 import os
     11 import time
     12 
     13 import common
     14 from autotest_lib.client.common_lib import time_utils
     15 
     16 # TODO(beeps): The right way to create these status logs is by creating a job
     17 # object and invoking job.record on it. However we perform this template
     18 # hack instead for the following reasons:
     19 #   * The templates are a lot easier to understand at first glance, which
     20 #     is really what one wants from a testing interface built for a
     21 #     framework like autotest.
     22 #   * Creating the job is wedged into core autotest code, so it has
     23 #     unintended consequences like checking for hosts/labels etc.
     24 #   * We are guaranteed to create the bare minimum by hand specifying the file
     25 #     to write, and their contents. Job.record ends up checking and creating
     26 #     several non-essential directoris in the process or recording status.
     27 
     28 _SUCCESS_TEST_TEMPLATE = (
     29         "\tSTART\t%(test_name)s\t%(test_name)s"
     30         "\ttimestamp=%(timestamp)s\tlocaltime=%(date)s\n"
     31         "\t\tGOOD\t%(test_name)s\t%(test_name)s\ttimestamp=%(timestamp)s\t"
     32         "localtime=%(date)s\tcompleted successfully\n"
     33         "\tEND GOOD\t%(test_name)s\t%(test_name)s\ttimestamp=%(timestamp)s\t"
     34         "localtime=%(date)s")
     35 
     36 
     37 _SUCCESS_JOB_TEMPLATE = (
     38         "START\t----\t----\ttimestamp=%(timestamp)s\tlocaltime=%(date)s"
     39         "\n\tSTART\t%(test_name)s\t%(test_name)s\ttimestamp=%(timestamp)s\t"
     40         "localtime=%(date)s\n\t\tGOOD\t%(test_name)s\t%(test_name)s"
     41         "\ttimestamp=%(timestamp)s\tlocaltime=%(date)s\tcompleted "
     42         "successfully\n\tEND GOOD\t%(test_name)s\t%(test_name)s"
     43         "\ttimestamp=%(timestamp)s\tlocaltime=%(date)s\n"
     44         "END GOOD\t----\t----\ttimestamp=%(timestamp)s\tlocaltime=%(date)s")
     45 
     46 
     47 _JOB_KEYVALS_TEMPLATE = "hostname=%(hostname)s\nstatus_version=1\n"
     48 
     49 
     50 class ResultsMocker(object):
     51     """Class to mock out the results of a test."""
     52 
     53     def _make_dirs(self):
     54         """Create essential directories needed for faking test results.
     55 
     56         @raises ValueError: If the directories crucial to reporting
     57             test status already exist.
     58         @raises OSError: If we cannot make one of the directories for
     59             an os related reason (eg: permissions).
     60         @raises AssertionError: If one of the directories silently failed
     61             creation.
     62         """
     63         logging.info("creating dir %s, %s, %s",
     64                 self.results_dir, self.test_results, self.host_keyval_dir)
     65         if not os.path.exists(self.results_dir):
     66             os.makedirs(self.results_dir)
     67         if not os.path.exists(self.test_results):
     68             os.makedirs(self.test_results)
     69         if not os.path.exists(self.host_keyval_dir):
     70             os.makedirs(self.host_keyval_dir)
     71         assert(os.path.exists(self.test_results) and
     72                os.path.exists(self.results_dir) and
     73                os.path.exists(self.host_keyval_dir))
     74 
     75 
     76     def __init__(self, test_name, results_dir, machine_name):
     77         """Initialize a results mocker.
     78 
     79         @param test_name: The name of the test, eg: dummy_Pass.
     80         @param results_dir: The results directory this test will use.
     81         @param machine_name: A string representing the hostname the test will
     82             run on.
     83         """
     84         self.results_dir = results_dir
     85         self.test_results = os.path.join(results_dir, test_name)
     86         self.host_keyval_dir = os.path.join(self.results_dir, 'host_keyvals')
     87         self.machine_name = machine_name
     88         self.test_name = test_name
     89 
     90         self._make_dirs()
     91 
     92         # Status logs are used by the parser to declare a test as pass/fail.
     93         self.job_status = os.path.join(self.results_dir, 'status')
     94         self.job_status_log = os.path.join(self.results_dir, 'status.log')
     95         self.test_status = os.path.join(self.test_results, 'status')
     96 
     97         # keyvals are used by the parser to figure out fine grained information
     98         # about a test. Only job_keyvals are crucial to parsing.
     99         self.test_keyvals = os.path.join(self.test_results, 'keyval')
    100         self.job_keyvals = os.path.join(self.results_dir, 'keyval')
    101         self.host_keyvals = os.path.join(self.results_dir, machine_name)
    102 
    103 
    104     def _write(self, results_path, results):
    105         """Write the content in results to the file in results_path.
    106 
    107         @param results_path: The path to the results file.
    108         @param results: The content to write to the file.
    109         """
    110         logging.info('Writing results to %s', results_path)
    111         with open(results_path, 'w') as results_file:
    112             results_file.write(results)
    113 
    114 
    115     def generate_keyvals(self):
    116         """Apply templates to keyval files.
    117 
    118         There are 3 important keyvals files, only one of which is actually
    119         crucial to results parsing:
    120             host_keyvals - information about the DUT
    121             job_keyvals - information about the server_job
    122             test_keyvals - information about the test
    123 
    124         Parsing cannot complete without the job_keyvals. Everything else is
    125         optional. Keyvals are parsed into tko tables.
    126         """
    127         #TODO(beeps): Include other keyvals.
    128         self._write(
    129                 self.job_keyvals,
    130                 _JOB_KEYVALS_TEMPLATE %
    131                         {'hostname': self.machine_name})
    132 
    133 
    134     def generate_status(self):
    135         """Generate status logs.
    136 
    137         3 important status logs are required for successful parsing:
    138             test_name/status - core test status
    139             results_dir/status - server job status (has test status in it)
    140             status.log - compiled final status log
    141         """
    142         current_timestamp = int(time.time())
    143         test_info = {
    144             'test_name': self.test_name,
    145             'timestamp': current_timestamp,
    146             'date': time_utils.epoch_time_to_date_string(
    147                             current_timestamp, fmt_string='%b %d %H:%M:%S'),
    148         }
    149         self._write(
    150                 self.job_status,
    151                 _SUCCESS_JOB_TEMPLATE % test_info)
    152         self._write(
    153                 self.job_status_log,
    154                 _SUCCESS_JOB_TEMPLATE % test_info)
    155         self._write(
    156                 self.test_status,
    157                 _SUCCESS_TEST_TEMPLATE % test_info)
    158 
    159 
    160     def mock_results(self):
    161         """Create mock results in the directories used to init the instance."""
    162         self.generate_status()
    163         self.generate_keyvals()
    164 
    165 
    166