blob: 965fbe9485950c67e413f318ab570c974239af69 [file] [log] [blame]
# Copyright (c) 2014-2015, Intel Corporation
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import json
import logging
class Scenario:
"""
Class which can handle several TestVectors and script
to play a complete scenario.
"""
def __init__(self,
consoleLogger,
scenarioFileName,
actionGathererFileName,
testFactory,
testLauncher):
"""
Init function
:param consoleLogger: console log handler
:type consoleLogger: Handler
:param scenarioFileName: name of file containing scenario description
:type scenarioFileName: string
:param actionGathererFileName: conf file which allows to reduce action repetition
:type actionGathererFileName: string
:param testFactory: the factory used to generate tests from setCriterion actions
:type testFactory: TestVectorFactory
:param testLauncher: object used to execute actions from scenarios
:type testLauncher: TestLauncher
"""
self.__logger = logging.getLogger(__name__)
self.__logger.addHandler(consoleLogger)
self.__testFactory = testFactory
self.__testLauncher = testLauncher
# Simplify the way to get an action behaviour
# Python way to replace switch statement but keeping the possibility
# to get keys (usefull in __parseScenarioActions)
self.__actionTypeBehaviour = {
"setCriterion":
lambda rawCriterions:
self.__testLauncher.executeTestVector(
self.__testFactory.generateTestVector(rawCriterions)),
"script":
self.__testLauncher.executeScript
}
self.__scenarioActions = self.__parseScenarioActions(
scenarioFileName,
actionGathererFileName)
def __parseScenarioActions(self, scenarioFileName, actionGathererFileName):
"""
Parse actions from a scenario.
Convert user-defined actions in system-known actions.
:param scenarioFileName: name of file containing scenario description
:type scenarioFileName: string
:param actionGathererFileName: conf file which allows to reduce action repetition
:type actionGathererFileName: string
:return: parsed scenario's actions with system-known types
:rtype: dict
"""
# Parsing of Json test file
with open(scenarioFileName, "r") as scenarioFile:
scenarioActions = json.load(scenarioFile)
# Parsing the action Gatherer file which allows defining new
# actions types
scenarioGatheredActions = {}
if actionGathererFileName:
with open(actionGathererFileName, "r") as actionGathererFile:
scenarioGatheredActions = json.load(actionGathererFile)
for action in scenarioActions:
actionDefinedType = self.__getActionType(action)
if actionDefinedType in self.__actionTypeBehaviour.keys():
continue
try:
actionValue = action.pop(actionDefinedType)
actionGatherer = scenarioGatheredActions[actionDefinedType]
except KeyError as e:
self.__logger.error(
"Actions {} from {} file is not valid".format(
actionDefinedType,
scenarioFileName))
raise e
if self.__getActionType(actionGatherer) == "script":
raise UngatherableTypeException(
"Unable to redefine {} type, please edit your {} file".format(
self.__getActionType(actionGatherer),
actionGathererFileName))
# Fusion of gathered Actions and other desired actions which
# are directly writed in the scenario's file
actionValue.update(self.__getActionValue(actionGatherer))
# Change the user defined key which was previously popped
# by the known one
action[self.__getActionType(actionGatherer)] = actionValue
return scenarioActions
def __getActionType(self, action):
"""
Return the type of an action (the key)
An action is a dictionary with only one element
:param action: the action you want to get the type
:type action: dict
:return: the type of the desired action
:rtype: string
"""
return list(action.keys())[0]
def __getActionValue(self, action):
"""
Return the Value of an action
An action is a dictionary with only one element
:param action: the action you want to get the type
:type action: dict
:return: the value of the desired action
:rtype: string or dict
"""
return list(action.values())[0]
def play(self):
"""
Execute a Scenario
"""
for action in self.__scenarioActions:
# Launch the adequate behaviour depending on the key of the action dict
# No need to try KeyError as it would have been raised during init
# process
self.__actionTypeBehaviour[self.__getActionType(action)](
self.__getActionValue(action))
class UngatherableTypeException(Exception):
"""
Exception raised in case of problem with a type that the
user try to personalize
"""
def __init__(self, msg):
self.__msg = msg
def __str__(self):
return "Ungatherable type Error : " + self.__msg