1# Copyright (c) 2014-2015, Intel Corporation 2# All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without modification, 5# are permitted provided that the following conditions are met: 6# 7# 1. Redistributions of source code must retain the above copyright notice, this 8# list of conditions and the following disclaimer. 9# 10# 2. Redistributions in binary form must reproduce the above copyright notice, 11# this list of conditions and the following disclaimer in the documentation and/or 12# other materials provided with the distribution. 13# 14# 3. Neither the name of the copyright holder nor the names of its contributors 15# may be used to endorse or promote products derived from this software without 16# specific prior written permission. 17# 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29import json 30import logging 31 32 33class Scenario: 34 35 """ 36 Class which can handle several TestVectors and script 37 to play a complete scenario. 38 """ 39 40 def __init__(self, 41 consoleLogger, 42 scenarioFileName, 43 actionGathererFileName, 44 testFactory, 45 testLauncher): 46 """ 47 Init function 48 49 :param consoleLogger: console log handler 50 :type consoleLogger: Handler 51 :param scenarioFileName: name of file containing scenario description 52 :type scenarioFileName: string 53 :param actionGathererFileName: conf file which allows to reduce action repetition 54 :type actionGathererFileName: string 55 :param testFactory: the factory used to generate tests from setCriterion actions 56 :type testFactory: TestVectorFactory 57 :param testLauncher: object used to execute actions from scenarios 58 :type testLauncher: TestLauncher 59 """ 60 self.__logger = logging.getLogger(__name__) 61 self.__logger.addHandler(consoleLogger) 62 63 self.__testFactory = testFactory 64 self.__testLauncher = testLauncher 65 66 # Simplify the way to get an action behaviour 67 # Python way to replace switch statement but keeping the possibility 68 # to get keys (usefull in __parseScenarioActions) 69 self.__actionTypeBehaviour = { 70 "setCriterion": 71 lambda rawCriterions: 72 self.__testLauncher.executeTestVector( 73 self.__testFactory.generateTestVector(rawCriterions)), 74 "script": 75 self.__testLauncher.executeScript 76 } 77 78 self.__scenarioActions = self.__parseScenarioActions( 79 scenarioFileName, 80 actionGathererFileName) 81 82 def __parseScenarioActions(self, scenarioFileName, actionGathererFileName): 83 """ 84 Parse actions from a scenario. 85 Convert user-defined actions in system-known actions. 86 87 :param scenarioFileName: name of file containing scenario description 88 :type scenarioFileName: string 89 :param actionGathererFileName: conf file which allows to reduce action repetition 90 :type actionGathererFileName: string 91 92 :return: parsed scenario's actions with system-known types 93 :rtype: dict 94 """ 95 96 # Parsing of Json test file 97 with open(scenarioFileName, "r") as scenarioFile: 98 scenarioActions = json.load(scenarioFile) 99 100 # Parsing the action Gatherer file which allows defining new 101 # actions types 102 scenarioGatheredActions = {} 103 if actionGathererFileName: 104 with open(actionGathererFileName, "r") as actionGathererFile: 105 scenarioGatheredActions = json.load(actionGathererFile) 106 107 for action in scenarioActions: 108 actionDefinedType = self.__getActionType(action) 109 if actionDefinedType in self.__actionTypeBehaviour.keys(): 110 continue 111 112 try: 113 actionValue = action.pop(actionDefinedType) 114 actionGatherer = scenarioGatheredActions[actionDefinedType] 115 except KeyError as e: 116 self.__logger.error( 117 "Actions {} from {} file is not valid".format( 118 actionDefinedType, 119 scenarioFileName)) 120 raise e 121 122 if self.__getActionType(actionGatherer) == "script": 123 raise UngatherableTypeException( 124 "Unable to redefine {} type, please edit your {} file".format( 125 self.__getActionType(actionGatherer), 126 actionGathererFileName)) 127 128 # Fusion of gathered Actions and other desired actions which 129 # are directly writed in the scenario's file 130 actionValue.update(self.__getActionValue(actionGatherer)) 131 132 # Change the user defined key which was previously popped 133 # by the known one 134 action[self.__getActionType(actionGatherer)] = actionValue 135 136 return scenarioActions 137 138 def __getActionType(self, action): 139 """ 140 Return the type of an action (the key) 141 An action is a dictionary with only one element 142 143 :param action: the action you want to get the type 144 :type action: dict 145 146 :return: the type of the desired action 147 :rtype: string 148 """ 149 return list(action.keys())[0] 150 151 def __getActionValue(self, action): 152 """ 153 Return the Value of an action 154 An action is a dictionary with only one element 155 156 :param action: the action you want to get the type 157 :type action: dict 158 159 :return: the value of the desired action 160 :rtype: string or dict 161 """ 162 return list(action.values())[0] 163 164 def play(self): 165 """ 166 Execute a Scenario 167 """ 168 169 for action in self.__scenarioActions: 170 # Launch the adequate behaviour depending on the key of the action dict 171 # No need to try KeyError as it would have been raised during init 172 # process 173 self.__actionTypeBehaviour[self.__getActionType(action)]( 174 self.__getActionValue(action)) 175 176 177class UngatherableTypeException(Exception): 178 179 """ 180 Exception raised in case of problem with a type that the 181 user try to personalize 182 """ 183 184 def __init__(self, msg): 185 self.__msg = msg 186 187 def __str__(self): 188 return "Ungatherable type Error : " + self.__msg 189