1#!/usr/bin/python3 2# Copyright (c) 2014-2015, Intel Corporation 3# All rights reserved. 4# 5# Redistribution and use in source and binary forms, with or without modification, 6# are permitted provided that the following conditions are met: 7# 8# 1. Redistributions of source code must retain the above copyright notice, this 9# list of conditions and the following disclaimer. 10# 11# 2. Redistributions in binary form must reproduce the above copyright notice, 12# this list of conditions and the following disclaimer in the documentation and/or 13# other materials provided with the distribution. 14# 15# 3. Neither the name of the copyright holder nor the names of its contributors 16# may be used to endorse or promote products derived from this software without 17# specific prior written permission. 18# 19# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 20# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 23# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 26# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30from clientsimulator.criterion.CriterionClassFactory import CriterionClassFactory 31from clientsimulator.testGenerator.TestVectorFactory import TestVectorFactory 32from clientsimulator.testGenerator.TestLauncher import TestLauncher 33from clientsimulator.testGenerator.SubprocessLogger import SubprocessLoggerThread 34from clientsimulator.testGenerator.SubprocessLogger import ScriptLoggerThread 35from clientsimulator.configuration.ConfigParser import ConfigParser 36from clientsimulator.scenario.Scenario import Scenario 37from clientsimulator.userInteraction.UserInteractor import UserInteractor 38from clientsimulator.userInteraction.DynamicCallHelper import DynamicCallHelper 39import argparse 40import time 41import logging 42import os 43 44 45def close(logger, testLauncher, coverage): 46 """ SIGINT Handler which clean up processes """ 47 48 # Check if some scripts are running, if this is the case 49 # we warn the user. 50 if ScriptLoggerThread.getRunningInstances(): 51 try: 52 logger.info("{} \n {}".format( 53 "Some subprocesses are still running. The program will wait them before exiting.", 54 "If you really want to exit, please confirm by typing Ctrl+C again")) 55 56 # Wait for thread to terminate 57 while ScriptLoggerThread.getRunningInstances(): 58 time.sleep(1) 59 except KeyboardInterrupt as e: 60 pass 61 62 # Kill subprocess (at least test-platform one) 63 SubprocessLoggerThread.closeAll() 64 65 if coverage: 66 testLauncher.generateCoverage() 67 68 logger.info("Closing") 69 70 exit(0) 71 72 73def launchScenario( 74 logger, 75 consoleLogger, 76 actionGathererFileName, 77 scenarioFileName, 78 testFactory, 79 testLauncher): 80 81 logger.info("Launching {}".format(scenarioFileName)) 82 83 Scenario(consoleLogger, 84 scenarioFileName, 85 actionGathererFileName, 86 testFactory, 87 testLauncher).play() 88 89 logger.info("Scenario execution complete.") 90 91 92def main(): 93 94 # Handle Arguments 95 96 parser = argparse.ArgumentParser() 97 98 parser.add_argument("test_directory", type=str, default=None, 99 help="precise a test directory (required).") 100 101 parser.add_argument("-s", "--scenario", type=int, default=None, nargs='+', 102 help="precise one or more scenarios to launch.") 103 104 interactiveness = parser.add_mutually_exclusive_group() 105 interactiveness.add_argument("--no-exit", action='store_true', 106 help="lets you interactively select more scenarios (This is" 107 " implicit if neither '--scenario' nor '--interactive' are " 108 " passed).") 109 110 interactiveness.add_argument("--interactive", action='store_true', 111 help="run in interactive mode (lets you select actions and scripts" 112 " to run).") 113 114 parser.add_argument( 115 "-v", 116 "--verbose", 117 action='store_true', 118 help="display test-platform's and scripts' log on stdout.") 119 120 parser.add_argument("-c", "--coverage", action='store_true', 121 help="generate coverage file at end of script") 122 123 args = parser.parse_args() 124 125 # Logging Configuration 126 logger = logging.getLogger(__name__) 127 128 # Decide what to write in console depending on verbose argument 129 consoleLogger = logging.StreamHandler() 130 if args.verbose: 131 consoleLogger.setLevel(logging.DEBUG) 132 else: 133 consoleLogger.setLevel(logging.INFO) 134 logger.addHandler(consoleLogger) 135 136 # The given directory should have a conf.json file 137 if not os.path.isfile(os.path.join(args.test_directory, "conf.json")): 138 # This error will only be logged in the terminal 139 logger.error( 140 "Cannot find configuration file : conf.json in {} directory.".format( 141 args.test_directory)) 142 exit(1) 143 144 try: 145 configParser = ConfigParser( 146 os.path.join( 147 args.test_directory, 148 "conf.json"), 149 args.test_directory, 150 consoleLogger) 151 except KeyError as e: 152 logger.error( 153 "Missing mandatory configuration item {} in the" 154 " conf.json file".format(e)) 155 exit(1) 156 157 # Always write all log in the file 158 logging.basicConfig(level=logging.DEBUG, 159 format='%(name)-12s %(levelname)-8s %(message)s', 160 filename=configParser["LogFile"], 161 filemode='w') 162 163 # Parsing criterion file and classes generation 164 logger.info("Criterion analysis") 165 classFactory = CriterionClassFactory(configParser["CriterionFile"]) 166 criterionClasses = classFactory.generateCriterionClasses() 167 168 # Tests Handlers Generation 169 testFactory = TestVectorFactory( 170 criterionClasses, 171 consoleLogger) 172 173 testLauncher = TestLauncher( 174 criterionClasses, 175 configParser, 176 consoleLogger) 177 178 # Initialisation 179 testLauncher.init(criterionClasses, args.verbose) 180 181 # Launching 182 try: 183 if args.interactive: 184 # Launch Interactive Mode with default criterions values 185 UserInteractor( 186 testLauncher, 187 testFactory.generateTestVector()).launchInteractiveMode() 188 else: 189 scenarioOptions = [ 190 (scenarioFileName, 191 DynamicCallHelper( 192 launchScenario, 193 logger, 194 consoleLogger, 195 configParser["ActionGathererFile"], 196 os.path.join( 197 configParser["ScenariosDirectory"], scenarioFileName), 198 testFactory, 199 testLauncher 200 )) 201 for scenarioFileName in sorted(os.listdir(configParser["ScenariosDirectory"])) 202 ] 203 if args.scenario is not None: 204 for elem in args.scenario: 205 scenarioOptions[elem][1]() 206 if (args.scenario is None) or args.no_exit: 207 # Let the user choose more scenarios after the ones chosen by command line 208 # or if none was given on the command line. 209 UserInteractor.getMenu(scenarioOptions, "Quit") 210 except KeyboardInterrupt as e: 211 close(logger, testLauncher, args.coverage) 212 else: 213 close(logger, testLauncher, args.coverage) 214 215 216if __name__ == "__main__": 217 # Execute main if the script is running as main 218 main() 219