adding TestON
diff --git a/TestON/core/__init__.py b/TestON/core/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/TestON/core/__init__.py
diff --git a/TestON/core/ast.py b/TestON/core/ast.py
new file mode 100644
index 0000000..fd5dfdb
--- /dev/null
+++ b/TestON/core/ast.py
@@ -0,0 +1,311 @@
+# -*- coding: utf-8 -*-
+"""
+ ast
+ ~~~
+
+ The `ast` module helps Python applications to process trees of the Python
+ abstract syntax grammar. The abstract syntax itself might change with
+ each Python release; this module helps to find out programmatically what
+ the current grammar looks like and allows modifications of it.
+
+ An abstract syntax tree can be generated by passing `ast.PyCF_ONLY_AST` as
+ a flag to the `compile()` builtin function or by using the `parse()`
+ function from this module. The result will be a tree of objects whose
+ classes all inherit from `ast.AST`.
+
+ A modified abstract syntax tree can be compiled into a Python code object
+ using the built-in `compile()` function.
+
+ Additionally various helper functions are provided that make working with
+ the trees simpler. The main intention of the helper functions and this
+ module in general is to provide an easy to use interface for libraries
+ that work tightly with the python syntax (template engines for example).
+
+
+ :copyright: Copyright 2008 by Armin Ronacher.
+ :license: Python License.
+"""
+from _ast import *
+from _ast import __version__
+
+
+def parse(source, filename='<unknown>', mode='exec'):
+ """
+ Parse the source into an AST node.
+ Equivalent to compile(source, filename, mode, PyCF_ONLY_AST).
+ """
+ return compile(source, filename, mode, PyCF_ONLY_AST)
+
+
+def literal_eval(node_or_string):
+ """
+ Safely evaluate an expression node or a string containing a Python
+ expression. The string or node provided may only consist of the following
+ Python literal structures: strings, numbers, tuples, lists, dicts, booleans,
+ and None.
+ """
+ _safe_names = {'None': None, 'True': True, 'False': False}
+ if isinstance(node_or_string, basestring):
+ node_or_string = parse(node_or_string, mode='eval')
+ if isinstance(node_or_string, Expression):
+ node_or_string = node_or_string.body
+ def _convert(node):
+ if isinstance(node, Str):
+ return node.s
+ elif isinstance(node, Num):
+ return node.n
+ elif isinstance(node, Tuple):
+ return tuple(map(_convert, node.elts))
+ elif isinstance(node, List):
+ return list(map(_convert, node.elts))
+ elif isinstance(node, Dict):
+ return dict((_convert(k), _convert(v)) for k, v
+ in zip(node.keys, node.values))
+ elif isinstance(node, Name):
+ if node.id in _safe_names:
+ return _safe_names[node.id]
+ elif isinstance(node, BinOp) and \
+ isinstance(node.op, (Add, Sub)) and \
+ isinstance(node.right, Num) and \
+ isinstance(node.right.n, complex) and \
+ isinstance(node.left, Num) and \
+ isinstance(node.left.n, (int, long, float)):
+ left = node.left.n
+ right = node.right.n
+ if isinstance(node.op, Add):
+ return left + right
+ else:
+ return left - right
+ raise ValueError('malformed string')
+ return _convert(node_or_string)
+
+
+def dump(node, annotate_fields=True, include_attributes=False):
+ """
+ Return a formatted dump of the tree in *node*. This is mainly useful for
+ debugging purposes. The returned string will show the names and the values
+ for fields. This makes the code impossible to evaluate, so if evaluation is
+ wanted *annotate_fields* must be set to False. Attributes such as line
+ numbers and column offsets are not dumped by default. If this is wanted,
+ *include_attributes* can be set to True.
+ """
+ def _format(node):
+ if isinstance(node, AST):
+ fields = [(a, _format(b)) for a, b in iter_fields(node)]
+ rv = '%s(%s' % (node.__class__.__name__, ', '.join(
+ ('%s=%s' % field for field in fields)
+ if annotate_fields else
+ (b for a, b in fields)
+ ))
+ if include_attributes and node._attributes:
+ rv += fields and ', ' or ' '
+ rv += ', '.join('%s=%s' % (a, _format(getattr(node, a)))
+ for a in node._attributes)
+ return rv + ')'
+ elif isinstance(node, list):
+ return '[%s]' % ', '.join(_format(x) for x in node)
+ return repr(node)
+ if not isinstance(node, AST):
+ raise TypeError('expected AST, got %r' % node.__class__.__name__)
+ return _format(node)
+
+
+def copy_location(new_node, old_node):
+ """
+ Copy source location (`lineno` and `col_offset` attributes) from
+ *old_node* to *new_node* if possible, and return *new_node*.
+ """
+ for attr in 'lineno', 'col_offset':
+ if attr in old_node._attributes and attr in new_node._attributes \
+ and hasattr(old_node, attr):
+ setattr(new_node, attr, getattr(old_node, attr))
+ return new_node
+
+
+def fix_missing_locations(node):
+ """
+ When you compile a node tree with compile(), the compiler expects lineno and
+ col_offset attributes for every node that supports them. This is rather
+ tedious to fill in for generated nodes, so this helper adds these attributes
+ recursively where not already set, by setting them to the values of the
+ parent node. It works recursively starting at *node*.
+ """
+ def _fix(node, lineno, col_offset):
+ if 'lineno' in node._attributes:
+ if not hasattr(node, 'lineno'):
+ node.lineno = lineno
+ else:
+ lineno = node.lineno
+ if 'col_offset' in node._attributes:
+ if not hasattr(node, 'col_offset'):
+ node.col_offset = col_offset
+ else:
+ col_offset = node.col_offset
+ for child in iter_child_nodes(node):
+ _fix(child, lineno, col_offset)
+ _fix(node, 1, 0)
+ return node
+
+
+def increment_lineno(node, n=1):
+ """
+ Increment the line number of each node in the tree starting at *node* by *n*.
+ This is useful to "move code" to a different location in a file.
+ """
+ for child in walk(node):
+ if 'lineno' in child._attributes:
+ child.lineno = getattr(child, 'lineno', 0) + n
+ return node
+
+
+def iter_fields(node):
+ """
+ Yield a tuple of ``(fieldname, value)`` for each field in ``node._fields``
+ that is present on *node*.
+ """
+ for field in node._fields:
+ try:
+ yield field, getattr(node, field)
+ except AttributeError:
+ pass
+
+
+def iter_child_nodes(node):
+ """
+ Yield all direct child nodes of *node*, that is, all fields that are nodes
+ and all items of fields that are lists of nodes.
+ """
+ for name, field in iter_fields(node):
+ if isinstance(field, AST):
+ yield field
+ elif isinstance(field, list):
+ for item in field:
+ if isinstance(item, AST):
+ yield item
+
+
+def get_docstring(node, clean=True):
+ """
+ Return the docstring for the given node or None if no docstring can
+ be found. If the node provided does not have docstrings a TypeError
+ will be raised.
+ """
+ if not isinstance(node, (FunctionDef, ClassDef, Module)):
+ raise TypeError("%r can't have docstrings" % node.__class__.__name__)
+ if node.body and isinstance(node.body[0], Expr) and \
+ isinstance(node.body[0].value, Str):
+ if clean:
+ import inspect
+ return inspect.cleandoc(node.body[0].value.s)
+ return node.body[0].value.s
+
+
+def walk(node):
+ """
+ Recursively yield all descendant nodes in the tree starting at *node*
+ (including *node* itself), in no specified order. This is useful if you
+ only want to modify nodes in place and don't care about the context.
+ """
+ from collections import deque
+ todo = deque([node])
+ while todo:
+ node = todo.popleft()
+ todo.extend(iter_child_nodes(node))
+ yield node
+
+
+class NodeVisitor(object):
+ """
+ A node visitor base class that walks the abstract syntax tree and calls a
+ visitor function for every node found. This function may return a value
+ which is forwarded by the `visit` method.
+
+ This class is meant to be subclassed, with the subclass adding visitor
+ methods.
+
+ Per default the visitor functions for the nodes are ``'visit_'`` +
+ class name of the node. So a `TryFinally` node visit function would
+ be `visit_TryFinally`. This behavior can be changed by overriding
+ the `visit` method. If no visitor function exists for a node
+ (return value `None`) the `generic_visit` visitor is used instead.
+
+ Don't use the `NodeVisitor` if you want to apply changes to nodes during
+ traversing. For this a special visitor exists (`NodeTransformer`) that
+ allows modifications.
+ """
+
+ def visit(self, node):
+ """Visit a node."""
+ method = 'visit_' + node.__class__.__name__
+ visitor = getattr(self, method, self.generic_visit)
+ return visitor(node)
+
+ def generic_visit(self, node):
+ """Called if no explicit visitor function exists for a node."""
+ for field, value in iter_fields(node):
+ if isinstance(value, list):
+ for item in value:
+ if isinstance(item, AST):
+ self.visit(item)
+ elif isinstance(value, AST):
+ self.visit(value)
+
+
+class NodeTransformer(NodeVisitor):
+ """
+ A :class:`NodeVisitor` subclass that walks the abstract syntax tree and
+ allows modification of nodes.
+
+ The `NodeTransformer` will walk the AST and use the return value of the
+ visitor methods to replace or remove the old node. If the return value of
+ the visitor method is ``None``, the node will be removed from its location,
+ otherwise it is replaced with the return value. The return value may be the
+ original node in which case no replacement takes place.
+
+ Here is an example transformer that rewrites all occurrences of name lookups
+ (``foo``) to ``data['foo']``::
+
+ class RewriteName(NodeTransformer):
+
+ def visit_Name(self, node):
+ return copy_location(Subscript(
+ value=Name(id='data', ctx=Load()),
+ slice=Index(value=Str(s=node.id)),
+ ctx=node.ctx
+ ), node)
+
+ Keep in mind that if the node you're operating on has child nodes you must
+ either transform the child nodes yourself or call the :meth:`generic_visit`
+ method for the node first.
+
+ For nodes that were part of a collection of statements (that applies to all
+ statement nodes), the visitor may also return a list of nodes rather than
+ just a single node.
+
+ Usually you use the transformer like this::
+
+ node = YourTransformer().visit(node)
+ """
+
+ def generic_visit(self, node):
+ for field, old_value in iter_fields(node):
+ old_value = getattr(node, field, None)
+ if isinstance(old_value, list):
+ new_values = []
+ for value in old_value:
+ if isinstance(value, AST):
+ value = self.visit(value)
+ if value is None:
+ continue
+ elif not isinstance(value, AST):
+ new_values.extend(value)
+ continue
+ new_values.append(value)
+ old_value[:] = new_values
+ elif isinstance(old_value, AST):
+ new_node = self.visit(old_value)
+ if new_node is None:
+ delattr(node, field)
+ else:
+ setattr(node, field, new_node)
+ return node
diff --git a/TestON/core/dicttoobject.py b/TestON/core/dicttoobject.py
new file mode 100644
index 0000000..82e2828
--- /dev/null
+++ b/TestON/core/dicttoobject.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python
+
+class DictToObject( dict ):
+ def __init__( self, data = None ):
+ super( DictToObject, self ).__init__()
+ if data:
+ self.__update( data, {} )
+
+ def __update( self, data, did ):
+ dataid = id(data)
+ did[ dataid ] = self
+
+ for k in data:
+ dkid = id(data[k])
+ if did.has_key(dkid):
+ self[k] = did[dkid]
+ elif isinstance( data[k], DictToObject ):
+ self[k] = data[k]
+ elif isinstance( data[k], dict ):
+ obj = DictToObject()
+ obj.__update( data[k], did )
+ self[k] = obj
+ obj = None
+ else:
+ self[k] = data[k]
+
+ def __getattr__( self, key ):
+ return self.get( key, None )
+
+ def __setattr__( self, key, value ):
+ if isinstance(value,dict):
+ self[key] = DictToObject( value )
+ else:
+ self[key] = value
+
+ def update( self, *args ):
+ for obj in args:
+ for k in obj:
+ if isinstance(obj[k],dict):
+ self[k] = DictToObject( obj[k] )
+ else:
+ self[k] = obj[k]
+ return self
+
+ def merge( self, *args ):
+ for obj in args:
+ for k in obj:
+ if self.has_key(k):
+ if isinstance(self[k],list) and isinstance(obj[k],list):
+ self[k] += obj[k]
+ elif isinstance(self[k],list):
+ self[k].append( obj[k] )
+ elif isinstance(obj[k],list):
+ self[k] = [self[k]] + obj[k]
+ elif isinstance(self[k],DictToObject) and isinstance(obj[k],Object):
+ self[k].merge( obj[k] )
+ elif isinstance(self[k],DictToObject) and isinstance(obj[k],dict):
+ self[k].merge( obj[k] )
+ else:
+ self[k] = [ self[k], obj[k] ]
+ else:
+ if isinstance(obj[k],dict):
+ self[k] = DictToObject( obj[k] )
+ else:
+ self[k] = obj[k]
+ return self
+
diff --git a/TestON/core/iniparser.py b/TestON/core/iniparser.py
new file mode 100644
index 0000000..b952f2d
--- /dev/null
+++ b/TestON/core/iniparser.py
@@ -0,0 +1,77 @@
+#/usr/bin/env python
+'''
+Created on 07-Jan-2013
+
+@author: Raghav Kashyap(raghavkashyap@paxterrasolutions.com)
+
+ TestON is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ TestON is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TestON. If not, see <http://www.gnu.org/licenses/>.
+
+
+'''
+
+import re
+from configobj import ConfigObj
+class iniparser:
+ '''
+ Manages authoring, parsing and execution of the test. Sub components are
+ Test-Topology parser
+ Module that parses the test from plain English and topology
+ from a specification file and prepares for execution.
+ Test sequencer
+ Module that executes the tests case by case,
+ step by step adding ability for step by step pause and debug later.
+ Object loader
+ Module that connects and loads all the component connection objects
+ for access in the test
+ '''
+ def __init__(self) :
+ self.default = ''
+
+ def parse(self,fileName):
+ '''
+ This will parse the params or topo or cfg file and return content in the file as Dictionary
+ '''
+ self.fileName = fileName
+ matchFileName = re.match(r'(.*)\.(params|topo)',self.fileName,re.M|re.I)
+ if matchFileName:
+ try :
+ parsedInfo = ConfigObj(self.fileName)
+ return parsedInfo
+ except :
+ print "There is no such file to parse "+fileName
+ else:
+ return 0
+
+ def parseParams(self,paramsPath):
+ '''
+ It will take the params file path and will return the params dictionary
+ '''
+
+ paramsPath = re.sub("\.","/",paramsPath)
+ paramsPath = re.sub("tests|examples","",paramsPath)
+ #print main.tests_path+"/"+paramsPath+".params"
+ params = self.parse(main.tests_path+paramsPath+".params")
+ paramsAsString = str(params)
+ return eval(paramsAsString)
+
+ def parseTopology(self,topologyPath):
+ '''
+ It will take topology file path and will return topology dictionary
+ '''
+ topologyPath = re.sub("\.","/",topologyPath)
+ topologyPath = re.sub("tests|examples","",topologyPath)
+ topology = self.parse(main.tests_path+"/"+topologyPath+".topo")
+ topoAsString = str(topology)
+ return eval(topoAsString)
+
diff --git a/TestON/core/jsonparser.py b/TestON/core/jsonparser.py
new file mode 100644
index 0000000..8726e87
--- /dev/null
+++ b/TestON/core/jsonparser.py
@@ -0,0 +1,56 @@
+#/usr/bin/env python
+'''
+Created on 07-Jan-2013
+
+@author: Raghav Kashyap(raghavkashyap@paxterrasolutions.com)
+
+ TestON is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ TestON is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+
+ You should have received a copy of the GNU General Public License
+ along with TestON. If not, see <http://www.gnu.org/licenses/>.
+
+
+'''
+
+import re
+import json
+class JsonParser:
+ '''
+ Module that parses the response Json to Dictionary and Vice versa.
+ '''
+ def __init__(self) :
+ self.default = ''
+
+ def response_parse(self,json_response):
+ '''
+ This will parse the json formatted string and return content as Dictionary
+ '''
+ response_dict = {}
+ try :
+ response_dict = json.loads(json_response)
+ except :
+ main.log.error("Json Parser is unable to parse the string")
+ return response_dict
+
+ '''
+
+ def dict_json(self,response_dict):
+
+ # This will parse the Python Dictionary and return content as Json string.
+
+ json_response = {}
+ try :
+ json_response = json.dumps(response_dict)
+ except :
+ main.log.error("Json Parser is unable to parse the string")
+ return json_response
+ '''
diff --git a/TestON/core/logger.py b/TestON/core/logger.py
new file mode 100644
index 0000000..44a70b8
--- /dev/null
+++ b/TestON/core/logger.py
@@ -0,0 +1,249 @@
+#/usr/bin/env python
+'''
+Created on 07-Jan-2013
+
+@author: Raghav Kashyap(raghavkashyap@paxterrasolutions.com)
+
+ TestON is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ TestON is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TestON. If not, see <http://www.gnu.org/licenses/>.
+
+
+'''
+
+import logging
+import datetime
+import re
+import os
+class Logger:
+ '''
+ Add continuous logs and reports of the test.
+
+ @author: Raghav Kashyap(raghavkashyap@paxterrasolutions.com)
+ '''
+ def _printHeader(self,main) :
+ '''
+ Log's header will be append to the Log file
+ '''
+ logmsg = "\n"+" " * 32+"+----------------+\n" +"-" * 30+" { Script And Files } "+"-" * 30+"\n" +" " * 32+"+----------------+\n";
+ logmsg = logmsg + "\n\tScript Log File : " + main.LogFileName + ""
+ logmsg = logmsg + "\n\tReport Log File : " + main.ReportFileName + ""
+ for component in main.componentDictionary.keys():
+ logmsg = logmsg + "\n\t"+component+" Session Log : " + main.logdir+"/"+component+".session" + ""
+
+ logmsg = logmsg + "\n\tTest Script :" + path + "Tests/" + main.TEST + ".py"+ ""
+ logmsg = logmsg + "\n\tTest Params : " + path + "Tests/" + main.TEST + ".params" + ""
+ logmsg = logmsg + "\n\tTopology : " + path + "Tests/" +main.TEST + ".tpl" + ""
+ logmsg = logmsg + "\n"+" " * 30+"+" +"-" * 18+"+" +"\n" +"-" * 27+" { Script Exec Params } "+"-" * 27 +"\n" +" " * 30 +"+"+"-" * 18 +"+\n";
+ values = "\n\t" + str(main.params)
+ values = re.sub(",", "\n\t", values)
+ values = re.sub("{", "\n\t", values)
+ values = re.sub("}", "\n\t", values)
+ logmsg = logmsg + values
+
+ logmsg = logmsg + "\n\n"+" " * 31+"+---------------+\n" +"-" * 29+" { Components Used } " +"-" * 29+"\n"+" " * 31+"+---------------+\n"
+ component_list = []
+ component_list.append(None)
+
+ # Listing the components in the order of test_target component should be first.
+ if type(main.componentDictionary) == dict:
+ for key in main.componentDictionary.keys():
+ if main.test_target == key :
+ component_list[0] = key+"-Test Target"
+ else :
+ component_list.append(key)
+
+ for index in range(len(component_list)) :
+ if index==0:
+ if component_list[index]:
+ logmsg+="\t"+component_list[index]+"\n"
+ elif index > 0 :
+ logmsg+="\t"+str(component_list[index])+"\n"
+
+
+
+ logmsg = logmsg + "\n\n"+" " * 30+"+--------+\n" +"-" * 28+" { Topology } "+"-" * 28 +"\n" +" " * 30+"+--------+\n"
+ values = "\n\t" + str(main.topology['COMPONENT'])
+ values = re.sub(",", "\n\t", values)
+ values = re.sub("{", "\n\t", values)
+ values = re.sub("}", "\n\t", values)
+ logmsg = logmsg + values
+
+ logmsg = logmsg + "\n"+"-" * 60+"\n"
+
+ # enter into log file all headers
+ logfile = open(main.LogFileName,"w+")
+ logfile.write (logmsg)
+ print logmsg
+ main.logHeader = logmsg
+
+ logfile.close()
+
+ #enter into report file all headers
+ main.reportFile = open(main.ReportFileName,"w+")
+ main.reportFile.write(logmsg)
+ main.reportFile.close()
+
+ def initlog(self,main):
+ '''
+ Initialise all the log handles.
+ '''
+ main._getTest()
+ main.STARTTIME = datetime.datetime.now()
+
+ currentTime = re.sub("-|\s|:|\.", "_", str(main.STARTTIME.strftime("%d %b %Y %H:%M:%S")))
+ if main.logdir:
+ main.logdir = main.logdir+ "/"+main.TEST + "_" + currentTime
+ else:
+ main.logdir = main.logs_path + main.TEST + "_" + currentTime
+
+ os.mkdir(main.logdir)
+
+ main.LogFileName = main.logdir + "/" + main.TEST + "_" +str(currentTime) + ".log"
+ main.ReportFileName = main.logdir + "/" + main.TEST + "_" + str(currentTime) + ".rpt"
+
+ #### Add log-level - Report
+ logging.addLevelName(9, "REPORT")
+ logging.addLevelName(7, "EXACT")
+ logging.addLevelName(10, "CASE")
+ logging.addLevelName(11, "STEP")
+ main.log = logging.getLogger(main.TEST)
+ def report (msg):
+ '''
+ Will append the report message to the logs.
+ '''
+ main.log._log(9,msg,"OpenFlowAutoMattion","OFAutoMation")
+ currentTime = datetime.datetime.now()
+ currentTime = currentTime.strftime("%d %b %Y %H:%M:%S")
+ newmsg = "\n[REPORT] " +"["+ str(currentTime)+"] "+msg
+ print newmsg
+ main.reportFile = open(main.ReportFileName,"a+")
+ main.reportFile.write(newmsg)
+ main.reportFile.close()
+
+
+ main.log.report = report
+
+ def exact (exmsg):
+ '''
+ Will append the raw formatted message to the logs
+ '''
+ main.log._log(7,exmsg,"OpenFlowAutoMattion","OFAutoMation")
+ main.reportFile = open(main.ReportFileName,"a+")
+ main.reportFile.write(exmsg)
+ main.reportFile.close()
+ logfile = open(main.LogFileName,"a")
+ logfile.write("\n"+ str(exmsg) +"\n")
+ logfile.close()
+ print exmsg
+
+ main.log.exact = exact
+
+
+ def case(msg):
+ '''
+ Format of the case type log defined here.
+ '''
+ main.log._log(9,msg,"OpenFlowAutoMattion","OFAutoMation")
+ currentTime = datetime.datetime.now()
+ newmsg = "["+str(currentTime)+"] " + "["+main.TEST+"] " + "[CASE] " +msg
+ logfile = open(main.LogFileName,"a")
+ logfile.write("\n"+ str(newmsg) +"\n")
+ logfile.close()
+ print newmsg
+
+ main.log.case = case
+
+ def step (msg):
+ '''
+ Format of the step type log defined here.
+ '''
+ main.log._log(9,msg,"OpenFlowAutoMattion","OFAutoMation")
+ currentTime = datetime.datetime.now()
+ newmsg = "["+str(currentTime)+"] " + "["+main.TEST+"] " + "[STEP] " +msg
+ logfile = open(main.LogFileName,"a")
+ logfile.write("\n"+ str(newmsg) +"\n")
+ logfile.close()
+ print newmsg
+
+ main.log.step = step
+
+ main.LogFileHandler = logging.FileHandler(main.LogFileName)
+ self._printHeader(main)
+
+ ### initializing logging module and settig log level
+ main.log.setLevel(logging.INFO)
+ main.LogFileHandler.setLevel(logging.INFO)
+
+ # create console handler with a higher log level
+ main.ConsoleHandler = logging.StreamHandler()
+ main.ConsoleHandler.setLevel(logging.INFO)
+ # create formatter and add it to the handlers
+ formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
+ main.ConsoleHandler.setFormatter(formatter)
+ main.LogFileHandler.setFormatter(formatter)
+
+ # add the handlers to logger
+ main.log.addHandler(main.ConsoleHandler)
+ main.log.addHandler(main.LogFileHandler)
+
+ def testSummary(self,main):
+ '''
+ testSummary will take care about the Summary of test.
+ '''
+
+ main.ENDTIME = datetime.datetime.now()
+ main.EXECTIME = main.ENDTIME - main.STARTTIME
+ if (main.TOTAL_TC_PASS == 0):
+ main.TOTAL_TC_SUCCESS = 0
+ else:
+ main.TOTAL_TC_SUCCESS = str((main.TOTAL_TC_PASS*100)/main.TOTAL_TC_RUN)
+
+ if (main.TOTAL_TC_RUN == 0) :
+ main.TOTAL_TC_EXECPERCENT = 0
+ else :
+ main.TOTAL_TC_EXECPERCENT = str((main.TOTAL_TC_RUN*100)/main.TOTAL_TC_PLANNED)
+
+ testResult = "\n\n"+"*" * 37+"\n" + "\tTest Execution Summary\n" + "\n"+"*" * 37+" \n"
+ testResult = testResult + "\n Test Start : " + str(main.STARTTIME.strftime("%d %b %Y %H:%M:%S"))
+ testResult = testResult + "\n Test End : " + str(main.ENDTIME.strftime("%d %b %Y %H:%M:%S"))
+ testResult = testResult + "\n Execution Time : " + str(main.EXECTIME)
+ testResult = testResult + "\n Total tests planned : " + str(main.TOTAL_TC_PLANNED)
+ testResult = testResult + "\n Total tests RUN : " + str(main.TOTAL_TC_RUN)
+ testResult = testResult + "\n Total Pass : " + str(main.TOTAL_TC_PASS)
+ testResult = testResult + "\n Total Fail : " + str(main.TOTAL_TC_FAIL)
+ testResult = testResult + "\n Total No Result : " + str(main.TOTAL_TC_NORESULT)
+ testResult = testResult + "\n Success Percentage : " + str(main.TOTAL_TC_SUCCESS) + "%"
+ testResult = testResult + "\n Execution Result : " + str(main.TOTAL_TC_EXECPERCENT) + "%"
+
+ #main.log.report(testResult)
+ main.testResult = testResult
+ main.log.exact(testResult)
+
+ def updateCaseResults(self,main):
+ '''
+ Update the case result based on the steps execution and asserting each step in the test-case
+ '''
+ case = str(main.CurrentTestCaseNumber)
+
+ if main.testCaseResult[case] == 2:
+ main.TOTAL_TC_RUN = main.TOTAL_TC_RUN + 1
+ main.TOTAL_TC_NORESULT = main.TOTAL_TC_NORESULT + 1
+ main.log.exact("\n "+"*" * 29+"\n" + "\n Result: No Assertion Called \n"+"*" * 29+"\n")
+ elif main.testCaseResult[case] == 1:
+ main.TOTAL_TC_RUN = main.TOTAL_TC_RUN + 1
+ main.TOTAL_TC_PASS = main.TOTAL_TC_PASS + 1
+ main.log.exact("\n"+"*" * 29+"\n Result: Pass \n"+"*" * 29+"\n")
+ elif main.testCaseResult[case] == 0:
+ main.TOTAL_TC_RUN = main.TOTAL_TC_RUN + 1
+ main.TOTAL_TC_FAIL = main.TOTAL_TC_FAIL + 1
+ main.log.exact("\n"+"*" * 29+"\n Result: Failed \n"+"*" * 29+"\n")
diff --git a/TestON/core/openspeak.py b/TestON/core/openspeak.py
new file mode 100644
index 0000000..59f2769
--- /dev/null
+++ b/TestON/core/openspeak.py
@@ -0,0 +1,815 @@
+#/usr/bin/env python
+'''
+Created on 20-Dec-2012
+
+@author: Raghav Kashyap(raghavkashyap@paxterrasolutions.com)
+
+
+ TestON is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ TestON is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TestON. If not, see <http://www.gnu.org/licenses/>.
+
+
+'''
+import re
+import inspect
+
+
+class OpenSpeak:
+
+ def __init__(self):
+ self.default = ''
+ self.flag = 0
+ self.CurrentStep = 0
+ self.grtrOrLssr = 0
+
+ def compiler(self,**compileParameters):
+ '''
+ This method will parse the openspeak file and will write to a python module with the equivalent translations.
+ It can accept OpenSpeak syntax in string or an OpenSpeak file as an input parameter.
+ Translated form can be written into python module if attribute "WRITETOFILE" is set to 1.
+ '''
+
+ args = self.parse_args(["OPENSPEAKFILE","TEXT","WRITETOFILE","FILEHANDLE"],**compileParameters)
+ resultString = ''
+ Test = "Mininet"
+ args["WRITETOFILE"] = args["WRITETOFILE"] if args["WRITETOFILE"] != None else 1
+ self.CurrentStep = 0
+ self.CurrentCase = ''
+
+ ## here Open Speak file will be parsed by each line and translated.
+ if args["OPENSPEAKFILE"] !=None and args["TEXT"] ==None and args["FILEHANDLE"] == None:
+ self.openspeakfile = args["OPENSPEAKFILE"]
+ openSpeakFile = open(args["OPENSPEAKFILE"],"r").readlines()
+
+ elif args["OPENSPEAKFILE"] ==None and args["TEXT"] and args["FILEHANDLE"] == None:
+ openSpeakFile = args["TEXT"].split("\n")
+ elif args["FILEHANDLE"] and args["OPENSPEAKFILE"] ==None and args["TEXT"] ==None:
+ openSpeakFile = args["FILEHANDLE"].readlines()
+
+ index = 0
+ outputFile = []
+ testName = re.search("\/(.*)\.ospk$",self.openspeakfile,0)
+ testName = testName.group(1)
+ testName = testName.split("/")
+ testName = testName[len(testName)-1]
+ outputFile.append("\nclass " + testName + " :" + "\n")
+ outputFile.append("\n" + " " * 4 + "def __init__(self) :")
+ outputFile.append("\n" + " " * 8 + "self.default = \'\'" + "\n")
+
+ while index < len(openSpeakFile):
+ ifelseMatch = re.match("\s+IF|\s+ELSE|\s+ELIF",openSpeakFile[index],flags=0)
+ line = openSpeakFile[index]
+ repeatMatch = re.match("\s*REPEAT", openSpeakFile[index], flags=0)
+ if ifelseMatch :
+ result = self.verify_and_translate(line)
+ initialSpaces = len(line) -len(line.lstrip())
+ self.outLoopSpace = initialSpaces
+ nextLine = openSpeakFile[index+1]
+ nextinitialSpaces = len(nextLine) -len(nextLine.lstrip())
+
+
+ while nextinitialSpaces > initialSpaces :
+ try :
+ elseMatch = re.match("\s*ELSE|\s*ELIF",nextLine,flags=0)
+ if elseMatch :
+ self.flag = self.flag -1
+ result = result + self.verify_and_translate(nextLine)
+ nextLine = openSpeakFile[index + 1]
+ nextinitialSpaces = len(nextLine) -len(nextLine.lstrip())
+ except IndexError:
+ pass
+ index = index + 1
+ self.flag = 0
+ elif repeatMatch:
+ self.flag = 0
+ result = self.verify_and_translate(line)
+ index = index + 1
+ endMatch = re.match("\s*END",openSpeakFile[index],flags=0)
+ while not endMatch :
+ try :
+
+ self.flag = self.flag + 1
+ result = result + self.verify_and_translate(openSpeakFile[index])
+ index = index + 1
+
+ except IndexError :
+ pass
+
+
+ else :
+ self.flag = 0
+ result = self.verify_and_translate(line)
+ index = index + 1
+ outputFile.append(result)
+
+ if args["WRITETOFILE"] == 1 :
+ testscript = re.sub("ospk","py",self.openspeakfile,0)
+ testScript = open(testscript,"w")
+ for lines in outputFile :
+ testScript.write(lines)
+ testScript.close()
+ return resultString
+
+ def verify_and_translate(self,line):
+ '''
+ It will accept the each line and calls the suitable API to conver into pyton equivalent syntax .
+ It will return the translated python syntax .
+ '''
+ lineSpace = re.match("^\s+",line,flags=0)
+ initialSpaces = len(line) -len(line.lstrip())
+ line = re.sub("^\s+","",line) if lineSpace else line
+
+
+ resultString = None
+ resultString = "\n" + " " * 4 if str(inspect.stack()[1][3]) == "compiler" else "\n"
+ indent = " " *(4 + 4 * self.flag) if self.flag > 0 else " " * 4
+ caseMatch = re.search("^CASE\s+(\d+)",line,flags=0)
+ nameMatch = re.match("^NAME\s+\"(.*)\"",line,flags=0)
+ commentMatch = re.match("^COMMENT\s+\"(.*)\"",line,flags=0)
+ stepMatch = re.match("^STEP\s+\"(.*)\"",line,flags=0)
+ connectMatch = re.match("^CONNECT\s+(\w+)\s+USING\s+(.*)",line,flags=0)
+ disconnectMatch = re.match("^DISCONNECT\s+(.*)",line,flags=0)
+ ondoMatch = re.match("^ON\s+(.*)\s+DO\s+(.*)",line,flags=0)
+
+ storeMatch = re.match("^STORE\s+(.*)\s+IN\s+(.*)",line,flags=0)
+ variableMatch = re.match("^(.*)\s+=\s+(.*)",line,flags=0)
+ assertMatch = re.match("^ASSERT\s+(\w+)\s+(.*)\s+(.*)\s+ONPASS\s+(.*)\s+ONFAIL\s+(.*)",line,flags=0)
+ logMatch = re.match("^(ERROR|INFO|DEBUG|CRITICAL|REPORT|EXACT|WARN)\s+(.*)",line,flags=0)
+ ifloop = re.match("IF\s+(\w+)\s*(..|\w+)\s*(.*)",line,flags=0)
+ elseloopMatch = re.match("ELSE\s*$",line,flags=0)
+ elifloop = re.match("ELSE\sIF\s+(\w+)\s*(..|\w+)\s*(.*)",line,flags=0)
+ forloopMatch = re.match("\s*REPEAT\s+(/d+)\s+TIMES",line,flags=0)
+ experimentalMatch = re.match("EXPERIMENTAL\s+MODE\s+(\w+)",line,flags=0)
+ repeatMatch = re.match("\s*REPEAT\s+(\d+)\s+TIMES", line, flags=0)
+
+ response_pasrse = re.match("\s*PARSE\s+(\w+)\s+AS\s+(\w+)\s+INTO\s+(\w+)", line, flags=0)
+
+ if caseMatch :
+ self.CurrentStep = 0
+ self.CurrentCase = "CASE" + caseMatch.group(1)
+ resultString = resultString + self.translate_case_block(casenumber=caseMatch.group(1))
+ elif repeatMatch:
+ resultString = resultString + indent + self.translate_repeat(repeat=repeatMatch.group(1))
+ elif nameMatch :
+ resultString = resultString + indent + self.translate_testcase_name(testname=nameMatch.group(1))
+ elif commentMatch :
+ resultString = resultString + indent + self.translate_comment(comment=commentMatch.group(1))
+ elif stepMatch :
+ self.CurrentStep = self.CurrentStep + 1
+ resultString = resultString + indent + self.translate_step(step=stepMatch.group(1))
+ elif connectMatch :
+ resultString = resultString + indent + self.translate_connect(component=connectMatch.group(1),
+ arguments=connectMatch.group(2) )
+ elif disconnectMatch :
+ resultString = resultString + indent + self.translate_disconnect(component=disconnectMatch.group(1))
+ elif ondoMatch :
+ resultString = resultString + indent + self.translate_onDOAs(component=ondoMatch.group(1),action=ondoMatch.group(2))
+ elif storeMatch :
+ resultString = resultString + indent + self.translate_store(variable=storeMatch.group(2),
+ value=storeMatch.group(1))
+ elif variableMatch :
+ resultString = resultString + indent + self.translate_store(variable=variableMatch.group(1),
+ value=variableMatch.group(2))
+ elif assertMatch :
+ resultString = resultString + indent + self.translate_assertion(leftvalue=assertMatch.group(1),
+ operator=assertMatch.group(2),
+ rightvalue=assertMatch.group(3),
+ onpass=assertMatch.group(4),
+ onfail=assertMatch.group(5))
+ elif logMatch :
+ resultString = resultString + indent + self.translate_logs(loglevel=logMatch.group(1),
+ message=logMatch.group(2))
+ elif ifloop :
+
+ self.initSpace = initialSpaces
+ operand = ifloop.group(1)
+ operator = ifloop.group(2)
+ value = ifloop.group(3)
+ resultString = resultString + indent + "if " + operand + self.translate_if_else_operator(conditionoperator=operator) + value + ":"
+ self.flag = self.flag + 1
+ elif experimentalMatch :
+ resultString = resultString + indent + self.translate_experimental_mode(mode=experimentalMatch.group(1))
+
+ elif elseloopMatch :
+ if initialSpaces == self.initSpace or initialSpaces == self.outLoopSpace:
+ resultString = resultString + indent + "else :"
+ self.flag = self.flag + 1
+ else :
+ indent = " " *(4 + 4 * (self.flag-1))
+ resultString = resultString + indent + "else :"
+ self.flag = self.flag + 1
+
+ elif elifloop :
+
+ operand = elifloop.group(1)
+ operator = elifloop.group(2)
+ value = elifloop.group(3)
+ if initialSpaces == self.initSpace or initialSpaces == self.outLoopSpace:
+ resultString = resultString + indent + "elif " + operand + self.translate_if_else_operator(conditionoperator=operator) + value + ":"
+ self.flag = self.flag + 1
+ else :
+ indent = " " *(4 + 4 * (self.flag-1))
+ resultString = resultString + indent + "elif " + operand + self.translate_if_else_operator(conditionoperator=operator) + value + ":"
+ self.flag = self.flag + 1
+ elif response_pasrse :
+ output_string = response_pasrse.group(1)
+ req_format = response_pasrse.group(2)
+ store_in = response_pasrse.group(3)
+ resultString = resultString + indent + store_in +'= main.response_parser('+output_string+",\""+req_format+"\")"
+ self.flag = self.flag + 1
+
+ return resultString
+
+ def translate_repeat(self,**repeatStatement):
+ '''
+ this will transalte the repeat statement into a python equivalen while loop
+ '''
+
+ args = self.parse_args(["REPEAT"],**repeatStatement)
+ resultString = ''
+
+ resultString = "i = 0"
+ resultString = resultString + "\n" + " " * 8 +"while i<" + args["REPEAT"] + " :"
+ return resultString
+
+ def translate_if_else_operator(self,**loopBlock):
+ '''
+ This method will translate if-else loop block into its equivalent python code.
+ Whole loop block will be passed into loopBlock List.
+ It returns the transalted reuslt as a string.
+ '''
+ args = self.parse_args(["CONDITIONOPERATOR"],**loopBlock)
+ resultString = ''
+ # process the loopBlock List translate all statements underlying the given loop block
+ equalsMatch = re.match("EQUALS$|==\s*$",args["CONDITIONOPERATOR"],flags=0)
+ greaterMatch = re.match("GREATER\s+THAN$|>\s*$",args["CONDITIONOPERATOR"],flags=0)
+ lesserMatch = re.match("LESSER\s+THAN$|<\s*$",args["CONDITIONOPERATOR"],flags=0)
+ greaterEqualMatch = re.match("GREATER\s+THAN\s+OR\s+EQUALS$|>=\s*$",args["CONDITIONOPERATOR"],flags=0)
+ lesserEqualMatch = re.match("LESSER\s+THAN\s+OR\s+EQUALS$|<=\s*$",args["CONDITIONOPERATOR"],flags=0)
+ if equalsMatch :
+ resultString = resultString + " == "
+ elif greaterMatch :
+ resultString = resultString + " > "
+ elif lesserMatch :
+ resultString = resultString + " < "
+ elif greaterEqualMatch:
+ resultString = resultString + " >= "
+ elif lesserEqualMatch :
+ resultString = resultString + " <= "
+ else :
+ print "\n Error: Given Operator is not listed "
+
+ return resultString
+
+ def translate_experimental_mode(self,**modeType):
+ '''
+ This API will translate statment EXPERIMENTAL MODE ON/OFF into python equivalent.
+ It will return the transalted value.
+ '''
+ args = self.parse_args(["MODE"],**modeType)
+ resultString = ''
+ ONmatch = re.match("\s*ON",args["MODE"],flags=0)
+ OFFmatch = re.match("\sOFF",args["MODE"],flags=0)
+
+ if ONmatch :
+ resultString = "main.EXPERIMENTAL_MODE = main.TRUE"
+ elif OFFmatch :
+ resultString = "main.EXPERIMENTAL_MODE = main.FALSE"
+
+ return resultString
+
+ def interpret(self,**interpetParameters):
+ '''
+ This method will accept the OpenSpeak syntax into a string and will return
+ a python equivalent translations statement
+ '''
+
+ args = self.parse_args(["TEXT","WRITETOFILE"],**interpetParameters)
+ resultString = ''
+ ## here Open Speak syntax will be translated into python equivalent.
+ resultString = self.verify_and_translate(args["TEXT"])
+ lineSpace = re.match("^\s+",resultString,flags=0)
+
+ resultString = re.sub("^\s+","",resultString) if lineSpace else resultString
+ return resultString
+
+ def translate_logs(self,**logStatement):
+ '''
+ This will translate the OpenSpeak log message statements into python equivalent
+ to resultString and returns resultString
+ '''
+ args = self.parse_args(["LOGLEVEL","MESSAGE"],**logStatement)
+ resultString = ''
+ # convert the statement here
+ message = self.translate_log_message(message=args["MESSAGE"])
+ if args["LOGLEVEL"] == "INFO" :
+ resultString = resultString + "main.log.info(" + message + ")"
+ elif args["LOGLEVEL"] == "ERROR" :
+ resultString = resultString + "main.log.error(" + message + ")"
+ elif args["LOGLEVEL"] == "DEBUG" :
+ resultString = resultString + "main.log.debug(" + message + ")"
+ elif args["LOGLEVEL"] == "REPORT" :
+ resultString = resultString + "main.log.report(" + message + ")"
+ elif args["LOGLEVEL"] == "CRITICAL" :
+ resultString = resultString + "main.log.critical(" + message + ")"
+ elif args["LOGLEVEL"] == "WARN" :
+ resultString = resultString + "main.log.warn(" + args["MESSAGE"] + ")"
+ elif args["LOGLEVEL"] == "EXACT" :
+ resultString = resultString + "main.log.exact(" + args["MESSAGE"] + ")"
+
+
+ return resultString
+
+ def translate_log_message(self,**messageStatement) :
+ '''
+ This API will translate log messages if it is a string or Variable or combination
+ of string and variable.
+ It will return the analysed and translate message.
+ '''
+ args = self.parse_args(["MESSAGE"],**messageStatement)
+ resultString = ''
+
+ paramsMatch = re.match("PARAMS\[(.*)\]|STEP\[(.*)\]|TOPO\[(.*)\]|CASE\[(.*)\]|LAST_RESULT|LAST_RESPONSE",args["MESSAGE"],flags=0)
+ stringMatch = re.match("\s*\"(.*)\"\s*$",args["MESSAGE"],flags=0)
+ stringWidVariableMatch = re.match("\"(.*)\"\s+\+\s+(.*)",args["MESSAGE"],flags=0)
+ varRefMatch = re.search("\<(\w+)\>",args["MESSAGE"],flags=0)
+ if paramsMatch :
+ resultString = resultString + self.translate_parameters(parameters=args["MESSAGE"])
+ elif stringMatch :
+ resultString = resultString + args["MESSAGE"]
+ elif stringWidVariableMatch:
+ quoteWord = stringWidVariableMatch.group(1)
+ variableRef = stringWidVariableMatch.group(2)
+ varMatch = re.search("PARAMS\[(.*)\]|STEP\[(.*)\]|TOPO\[(.*)\]|CASE\[(.*)\]",variableRef,flags=0)
+ varRefMatch = re.search("\<(\w+)\>",variableRef,flags=0)
+ if varMatch :
+ resultString = resultString + "\"" + quoteWord + "\"" + " + " + self.translate_parameters(parameters=variableRef)
+ elif varRefMatch :
+ resultString = resultString + "\"" + quoteWord + "\"" + " + " + varRefMatch.group(1)
+ elif varRefMatch:
+ resultString = resultString + varRefMatch.group(1)
+ else :
+ print "\nError : Syntax error , Not defined way to give log message" + args["MESSAGE"]
+
+ return resultString
+
+ def translate_assertion(self,**assertStatement):
+ '''
+ This will translate the ASSERT <value1> <COMPARISON OPERATOR> <value2> into python
+ equivalent to resultString and returns resultString
+ '''
+ args = self.parse_args(["LEFTVALUE","OPERATOR","RIGHTVALUE","ONPASS","ONFAIL"],**assertStatement)
+ resultString = ''
+ # convert the statement here
+ notOperatorMatch = re.search("NOT\s+(.*)",args["OPERATOR"],flags=0)
+ notOperatorSymbMatch = re.search("\!(.*)",args["OPERATOR"],flags=0)
+ operator = ''
+ lastresultMatch = re.match("LAST_RESULT",args["RIGHTVALUE"],flags=0)
+ lastresponseMatch = re.match("LAST_RESPONSE",args["RIGHTVALUE"],flags=0)
+ if lastresultMatch :
+ operator = "main.last_result"
+ elif lastresponseMatch :
+ operator = "main.last_response"
+ else :
+ operator = args["RIGHTVALUE"]
+
+ if args["OPERATOR"] == None or args["OPERATOR"] == "" :
+ print "\n Error : Operator has not been specified !!!"
+ elif notOperatorMatch or notOperatorSymbMatch:
+
+ operators = notOperatorMatch.group(1) if notOperatorMatch else notOperatorSymbMatch.group(1)
+ operators = self.translate_operator(operator=operators)
+ if self.grtrOrLssr == 0 :
+ resultString = resultString + "utilities.assert_not_" + operators + "(expect=" +\
+ self.translate_response_result(operator=args["RIGHTVALUE"]) + ",actual=" + self.translate_response_result(operator=args["LEFTVALUE"]) +\
+ ",onpass=" + self.translate_assertMessage(message=args["ONPASS"]) +\
+ ",onfail=" + self.translate_assertMessage(message=args["ONFAIL"]) + ")"
+ else :
+ resultString = resultString + "utilities.assert_not_" + operators + "(expect=" +\
+ self.translate_response_result(operator=args["LEFTVALUE"]) + ",actual=" + self.translate_response_result(operator=args["RIGHTVALUE"]) +\
+ ",onpass=" + self.translate_assertMessage(message=args["ONPASS"]) +\
+ ",onfail=" + self.translate_assertMessage(message=args["ONFAIL"]) + ")"
+
+ else :
+ operators = self.translate_operator(operator=args["OPERATOR"])
+ if self.grtrOrLssr == 0 :
+ resultString = resultString + "utilities.assert_" + operators + "(expect=" +\
+ self.translate_response_result(operator=args["RIGHTVALUE"]) +\
+ ",actual=" + self.translate_response_result(operator=args["LEFTVALUE"]) +\
+ ",onpass=" + self.translate_assertMessage(message=args["ONPASS"]) +\
+ ",onfail=" + self.translate_assertMessage(message=args["ONFAIL"]) + ")"
+ else :
+ resultString = resultString + "utilities.assert_" + operators + "(expect=" +\
+ self.translate_response_result(operator=args["LEFTVALUE"]) +\
+ ",actual=" + self.translate_response_result(operator=args["RIGHTVALUE"]) +\
+ ",onpass=" + self.translate_assertMessage(message=args["ONPASS"]) +\
+ ",onfail=" + self.translate_assertMessage(message=args["ONFAIL"]) + ")"
+
+
+ return resultString
+
+ def translate_response_result(self,**operatorStatement):
+ '''
+ It will translate the LAST_RESPONSE or LAST_RESULT statement into its equivalent.
+ It returns the translate form in resulString.
+ '''
+ args = self.parse_args(["OPERATOR"],**operatorStatement)
+ resultString = ''
+ lastResultMatch = re.match("LAST_RESULT",args["OPERATOR"],flags=0)
+ lastResponseMatch = re.match("LAST_RESPONSE",args["OPERATOR"],flags=0)
+ if lastResultMatch :
+ resultString = resultString + "main.last_result"
+ elif lastResponseMatch:
+ resultString = resultString + "main.last_response"
+ else :
+ resultString = resultString + args["OPERATOR"]
+ return resultString
+
+
+ def translate_assertMessage(self,**messageStatement) :
+ '''
+ This API will facilitate the translation of assert ONPASS or ONFAIL messages . The message can be
+ a string or calling another API in OpenSpeak syntax.
+ It will return the translated message
+ '''
+ args = self.parse_args(["MESSAGE"],**messageStatement)
+
+ connectMatch = re.search("CONNECT\s+(\w+)\s+USING\s+(.*)",args["MESSAGE"],flags=0)
+ disconnectMatch = re.search("DISCONNECT\s+(.*)",args["MESSAGE"],flags=0)
+ ondoMatch = re.search("ON\s+(.*)\s+DO\s+(.*)",args["MESSAGE"],flags=0)
+ paramsMatch = re.search("PARAMS\[(.*)\]|STEP\[(.*)\]|TOPO\[(.*)\]|CASE\[(.*)\]",args["MESSAGE"],flags=0)
+ stringMatch = re.search("\"(.*)\"|\'(.*)\'",args["MESSAGE"],flags=0)
+ variableMatch = re.search("\<(.*)\>",args["MESSAGE"],flags=0)
+
+ resultString = ''
+ if connectMatch :
+ resultString = resultString + self.translate_connect(component=connectMatch.group(1),
+ arguments=connectMatch.group(2) )
+ elif disconnectMatch :
+ resultString = resultString + self.translate_disconnect(component=disconnectMatch.group(1))
+ elif ondoMatch :
+ resultString = resultString + self.translate_onDOAs(component=ondoMatch.group(1),
+ action=ondoMatch.group(2))
+ elif paramsMatch :
+ resultString = resultString + self.translate_parameters(parameters=args["MESSAGE"])
+ elif stringMatch :
+ resultString = resultString + "\"" + stringMatch.group(1) + "\""
+ elif variableMatch :
+ resultString = resultString + variableMatch.group(1)
+ elif args["MESSAGE"] == None :
+ print "\n Error : Please pass a message or action for assertion "
+
+ return resultString
+
+ def translate_operator(self,**operatorStatement) :
+ '''
+ It will translate the operator for assertion , by ensuring against given arguments.
+ It will return the translated assertion operator.
+ '''
+ args = self.parse_args(["OPERATOR"],**operatorStatement)
+
+ resultString = ''
+ equalsMatch = re.match("EQUALS$|==$",args["OPERATOR"],flags=0)
+ greaterMatch = re.match("GREATER\s+THAN$|>$",args["OPERATOR"],flags=0)
+ lesserMatch = re.match("LESSER\s+THAN$|<$",args["OPERATOR"],flags=0)
+ stringMatch = re.match("MATCHES|~$",args["OPERATOR"],flags=0)
+ greaterEqualMatch = re.match("GREATER\s+THAN\s+OR\s+EQUALS$|>=$",args["OPERATOR"],flags=0)
+ lesserEqualMatch = re.match("LESSER\s+THAN\s+OR\s+EQUALS$|<=$",args["OPERATOR"],flags=0)
+ if equalsMatch :
+
+ resultString = resultString + "equals"
+ elif greaterMatch :
+ self.grtrOrLssr = self.grtrOrLssr + 1
+ resultString = resultString + "greater"
+ elif lesserMatch :
+ self.grtrOrLssr = self.grtrOrLssr + 1
+ resultString = resultString + "lesser"
+ elif stringMatch :
+
+ resultString = resultString + "matches"
+ elif greaterEqualMatch:
+
+ resultString = resultString + "greater_equals"
+ elif lesserEqualMatch :
+
+ resultString = resultString + "lesser_equals"
+ else :
+ print "\n Error: Given Operator is not listed for assertion"
+ return resultString
+
+ def translate_store(self,**storeStatement):
+ '''
+ This will translate the STORE <variable> IN <value> or <variable> = <value>
+ into python equivalent to resultString and returns resultString
+ '''
+ args = self.parse_args(["VARIABLE","VALUE"],**storeStatement)
+ resultString = ''
+ # convert the statement here
+ ondoMatch = re.match("^\s*ON\s+(.*)\s+DO\s+(.*)",args["VALUE"],flags=0)
+ paramsMatch = re.match("^\s*PARAMS\[(.*)\]|STEP\[(.*)\]|TOPO\[(.*)\]|CASE\[(.*)\]|LAST_RESULT|LAST_RESPONSE",args["VALUE"],flags=0)
+ if paramsMatch :
+ argString = self.translate_parameters(parameters=args["VALUE"])
+ resultString = args["VARIABLE"] + " = " + argString
+ elif ondoMatch :
+ resultString = args["VARIABLE"] + " = " + self.translate_onDOAs(component=ondoMatch.group(1),action=ondoMatch.group(2))
+ else :
+ resultString = args["VARIABLE"] + " = " + args["VALUE"]
+
+
+ return resultString
+
+ def translate_disconnect(self,**disconnectStatement):
+ '''
+ This will translate the DISCONNECT <component_name> into python
+ equivalent to resultString and returns resultString
+ '''
+ args = self.parse_args(["COMPONENT"],**disconnectStatement)
+ resultString = ''
+ # convert the statement here
+ resultString = "main." + args["COMPONENT"] + ".disconnect()"
+ return resultString
+
+ def translate_onDOAs(self,**onDoStatement):
+ '''
+ This will translate the ON <component> DO <action> USING <arg1> AS <value1>,<arg2> AS <value2>
+ into python equivalent to resultString and returns resultString
+ '''
+ args = self.parse_args(["COMPONENT","ACTION","ARGUMENTS"],**onDoStatement)
+ subString = ''
+
+ usingMatch = re.match("\s*(.*)\s+USING\s+(.*)",args["ACTION"],flags=0)
+ action = ''
+ if usingMatch :
+ action = usingMatch.group(1)
+ arguments = usingMatch.group(2)
+ subString = self.translate_usingas(arguments=arguments)
+
+ else :
+ andCheck = re.search ("(.*)\s+AND\s+(.*)",args["ACTION"],flags=0)
+
+ action = action + "()"
+ if andCheck:
+ action = andCheck.group(1) + "()"
+ subString = subString + self.handle_conjuction(statement=andCheck.group(2))
+ else :
+ action = args["ACTION"]
+ action = action + "()"
+ # convert the statement here
+ resultString = "main." + args["COMPONENT"] + "." + action + subString
+ return resultString
+
+
+ def handle_conjuction(self,**conjuctStatement):
+ '''
+ This will handle the conjuctions
+ '''
+
+ args = self.parse_args(["STATEMENT"],**conjuctStatement)
+ subSentence = ''
+
+ storeMatch = re.match("\s*STORE\s+(.*)\s+IN\s+(.*)",args["STATEMENT"],flags=0)
+ assertMatch = re.match("\s*ASSERT\s+(\w+)\s+(.*)\s+(.*)\s+ONPASS\s+(.*)\s+ONFAIL\s+(.*)",args["STATEMENT"],flags=0)
+ if storeMatch :
+ subSentence = "\n" + " " * 8 + self.translate_store(variable=storeMatch.group(2),
+ value=storeMatch.group(1))
+ elif assertMatch :
+ subSentence = "\n" + " " * 8 + self.translate_assertion(leftvalue=assertMatch.group(1),
+ operator=assertMatch.group(2),
+ rightvalue=assertMatch.group(3),
+ onpass=assertMatch.group(4),
+ onfail=assertMatch.group(5))
+ return subSentence
+
+ def translate_usingas(self,**argumentAS) :
+ '''
+ This will tranlate USING argument AS value Statement into equivalent argument passing.
+ It will return translated form into resultString
+ '''
+ args = self.parse_args(["ARGUMENTS"],**argumentAS)
+ resultString = ''
+ argsList = []
+ subString = ''
+ subSentence = ''
+ line = ''
+ andCheck = re.search ("(.*)\s+AND\s+(.*)",args["ARGUMENTS"],flags=0)
+ if andCheck:
+ line = andCheck.group(1)
+ subSentence = self.handle_conjuction(statement=andCheck.group(2))
+ else :
+ line = args["ARGUMENTS"]
+
+
+
+ argsMatch = re.search("(.*),(.*)",line,flags=0)
+
+
+ if args["ARGUMENTS"] == None or args["ARGUMENTS"] == '' :
+ subString = ''
+ elif argsMatch :
+
+ argsList = line.split(",")
+ for index, arguments in enumerate(argsList):
+ argMatch = re.search("(.*)\s+AS\s+(.*)",arguments,flags=0)
+ if argMatch:
+ argsKey = argMatch.group(1)
+ argsValue = argMatch.group(2)
+ paramsMatch = re.search("PARAMS\[(.*)\]|STEP\[(.*)\]|TOPO\[(.*)\]|CASE\[(.*)\]|LAST_RESPONSE|LAST_RESULT",argsValue,flags=0)
+ if not paramsMatch :
+ if index == len(argsList) - 1 :
+ subString = subString + argsKey + "=" + argsValue
+ else :
+ subString = subString + argsKey + "=" + argsValue + ","
+ else :
+ argString = self.translate_parameters(parameters=argsValue)
+ if index == len(argsList) - 1 :
+ subString = subString + argsKey + "=" + argString
+ else :
+ subString = subString + argsKey + "=" + argString + ","
+ else :
+ if index == len(argsList) - 1 :
+ subString = subString + arguments
+ else :
+ subString = subString + arguments + ","
+ else :
+ argMatch = re.search("(.*)\s+AS\s+(.*)",args["ARGUMENTS"],flags=0)
+ if argMatch:
+ argsKey = argMatch.group(1)
+ argsValue = argMatch.group(2)
+ paramsMatch = re.search("PARAMS\[(.*)\]|STEP\[(.*)\]|TOPO\[(.*)\]|CASE\[(.*)\]|LAST_RESPONSE|LAST_RESULT",argsValue,flags=0)
+ if not paramsMatch :
+ subString = subString + argsKey + "=" + argsValue
+ else :
+ argString = self.translate_parameters(parameters=argsValue)
+ subString = subString + argsKey + "=" + argString
+ else :
+ paramsMatch = re.match("PARAMS\[(.*)\]|STEP\[(.*)\]|TOPO\[(.*)\]|CASE\[(.*)\]|LAST_RESPONSE|LAST_RESULT",line,flags=0)
+ if paramsMatch :
+ subString = subString + self.translate_parameters(parameters=line)
+ else :
+ subString = subString + line
+ resultString = "(" + subString + ")"+ subSentence
+ return resultString
+
+
+ def translate_connect(self,**connectStatement):
+ '''
+ This will translate the CONNECT <component_name> USING1 <arg1> AS <value1>, <arg2> AS <value2>
+ into python equivalent to resultString and returns resultString
+ '''
+ args = self.parse_args(["COMPONENT","ARGUMENTS"],**connectStatement)
+ resultString = ''
+ subString = self.translate_usingas(arguments=args["ARGUMENTS"])
+ # convert the statement here
+ resultString = "main." + args["COMPONENT"] + ".connect(" + subString + ")"
+ return resultString
+
+
+ def translate_parameters(self,**parameterStatement):
+ '''
+ This will translate the OpenSpeak Case and Params parameters into python equivalent
+ to resultString and returns resultString
+ '''
+ args = self.parse_args(["PARAMETERS"],**parameterStatement)
+ argument = args["PARAMETERS"]
+ resultString = ''
+ ### match arguments
+ paramsMatch = re.search("PARAMS((\[(.*)\])*)",argument,flags=0)
+ stepsMatch = re.search("STEP((\[(.*)\])*)",argument,flags=0)
+ casesMatch = re.search("CASE((\[(.*)\])*)",argument,flags=0)
+ topoMatch = re.search("TOPO((\[(.*)\])*)",argument,flags=0)
+ lastResultMatch = re.match("LAST_RESULT",argument,flags=0)
+ lastResponseMatch = re.match("LAST_RESPONSE",argument,flags=0)
+ # convert the statement here
+ if paramsMatch :
+ params = paramsMatch.group(1)
+ resultString = resultString + "main.params" + self._argsCheck(checkvar=params)
+ elif stepsMatch :
+ resultString = resultString +"main.params[\'" + self.CurrentCase +\
+ "\'][\'STEP" + str(self.CurrentStep) + "\']" +\
+ self._argsCheck(checkvar=stepsMatch.group(1))
+ elif casesMatch :
+ resultString = resultString + "main.params[\'" + self.CurrentCase + "\']" +\
+ self._argsCheck(checkvar=casesMatch.group(1))
+ elif topoMatch :
+ resultString = resultString + "main.componentDictionary" +\
+ self._argsCheck(checkvar=topoMatch.group(1))
+ elif lastResultMatch :
+ resultString = resultString + "main.last_result"
+ elif lastResponseMatch :
+ resultString = resultString + "main.last_response"
+ return resultString
+
+ def _argsCheck(self,**args):
+ ''' This API will check if given argument is varibale reference or String and will translate accordingly.
+ It will return the tanslate form in resultString.
+ '''
+ args = self.parse_args(["CHECKVAR"],**args)
+ params = args["CHECKVAR"]
+ argsList = params.split("]")
+ resultString = ''
+ del argsList[len(argsList) - 1]
+ for index,paramArgs in enumerate(argsList) :
+ argsWidVariable = re.search("(\"|\')\s*(\w+)\s*(\'|\")",paramArgs,flags=0)
+ if argsWidVariable :
+ resultString = resultString + "[\'" + argsWidVariable.group(2) + "\']"
+ else :
+ resultString = resultString + paramArgs + "]"
+ return resultString
+
+ def translate_step(self,**stepStatement):
+ '''
+ This will translate the STEP "DO SOMETHING HERE" into python equivalent
+ to resultString and returns resultString
+ '''
+ args = self.parse_args(["STEP"],**stepStatement)
+ resultString = ''
+ resultString = "main.step(\"" + args["STEP"] + "\")"
+ # convert the statement here
+ return resultString
+
+
+ def translate_comment(self,**commentStatement):
+ '''
+ This will translate the COMMENT "DO SOMETHING HERE" into python equivalent
+ to resultString and returns resultString
+ '''
+ args = self.parse_args(["COMMENT"],**commentStatement)
+ resultString = ''
+ resultString = "#" + args["COMMENT"]
+ # convert the statement here
+ return resultString
+
+ def translate_testcase_name(self,**nameStatement):
+ '''
+ This method will convert NAME "<Testcase_name>" into python equivalent statement
+ to resultString and returns resultString
+ '''
+ args = self.parse_args(["TESTNAME"],**nameStatement)
+
+ resultString = ''
+ resultString = "main.case(\"" + args["TESTNAME"] + "\")"
+ # convert the statement here
+ return resultString
+
+
+ def translate_case_block(self,**caseBlock):
+ '''
+ This method will translate the case block in test script .
+ It returns the translated equivalent python code for test script
+ '''
+ args = self.parse_args(["CASENUMBER"],**caseBlock)
+ resultString = ""
+ resultString = "def CASE" + str(args["CASENUMBER"]) + "(self,main) :\n"
+ # process the caseBlock List translate all statements underlying the given case
+ return resultString
+
+
+
+ def translate_loop_block(self,*loopBlock):
+ '''
+ This method will translate for loop block into its equivalent python code.
+ Whole loop block will be passed into loopBlock List.
+ It returns the transalted reuslt as a string.
+ '''
+ resultString = ''
+ # process the loopBlock List translate all statements underlying the given loop block
+ return resultString
+
+
+ def translate_conjuction(self,conjuctionStatement):
+ '''
+ This will translate the AND conjuction statements into python equivalent
+ to resultString and returns resultString
+ '''
+ resultString = ''
+ # convert the statement here
+ return resultString
+
+
+ def parse_args(self,args, **kwargs):
+ '''
+ It will accept the (key,value) pair and will return the (key,value) pairs with keys in uppercase.
+ '''
+ newArgs = {}
+ for key,value in kwargs.iteritems():
+ #currentKey = str.upper(key)
+ if isinstance(args,list) and str.upper(key) in args:
+ for each in args:
+ if each==str.upper(key):
+ newArgs [str(each)] = value
+ elif each != str.upper(key) and (newArgs.has_key(str(each)) == False ):
+ newArgs[str(each)] = None
+
+
+
+ return newArgs
diff --git a/TestON/core/teston.py b/TestON/core/teston.py
new file mode 100644
index 0000000..73997f4
--- /dev/null
+++ b/TestON/core/teston.py
@@ -0,0 +1,758 @@
+#!/usr/bin/env python
+'''
+Created on 22-Oct-2012
+
+@author: Anil Kumar (anilkumar.s@paxterrasolutions.com)
+
+
+ TestON is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ TestON is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TestON. If not, see <http://www.gnu.org/licenses/>.
+
+
+
+teston is the main module.
+
+'''
+
+import sys
+import getpass
+import os
+import re
+import __builtin__
+import new
+import xmldict
+module = new.module("test")
+import openspeak
+global path, drivers_path, core_path, tests_path,logs_path
+path = re.sub("(core|bin)$", "", os.getcwd())
+drivers_path = path+"drivers/"
+core_path = path+"core"
+tests_path = path+"tests"
+logs_path = path+"logs/"
+config_path = path + "config/"
+sys.path.append(path)
+sys.path.append( drivers_path)
+sys.path.append(core_path )
+sys.path.append(tests_path)
+
+from core.utilities import Utilities
+
+import logging
+import datetime
+from optparse import OptionParser
+
+class TestON:
+ '''
+
+ TestON will initiate the specified test.
+ The main tasks are :
+ * Initiate the required Component handles for the test.
+ * Create Log file Handles.
+
+ '''
+ def __init__(self,options):
+ '''
+ Initialise the component handles specified in the topology file of the specified test.
+
+ '''
+ # Initialization of the variables.
+ __builtin__.main = self
+
+ __builtin__.path = path
+ __builtin__.utilities = Utilities()
+ self.TRUE = 1
+ self.FALSE = 0
+ self.ERROR = -1
+ self.FAIL = False
+ self.PASS = True
+ self.CASERESULT = self.TRUE
+ self.init_result = self.TRUE
+ self.testResult = "Summary"
+ self.stepName =""
+ self.EXPERIMENTAL_MODE = False
+ self.test_target = None
+ self.lastcommand = None
+ self.testDir = tests_path
+ self.configFile = config_path + "teston.cfg"
+ self.parsingClass = "xmlparser"
+ self.parserPath = core_path + "/xmlparser"
+ self.loggerPath = core_path + "/logger"
+ self.loggerClass = "Logger"
+ self.logs_path = logs_path
+ self.driver = ''
+
+ self.configparser()
+ verifyOptions(options)
+ load_logger()
+ self.componentDictionary = {}
+ self.componentDictionary = self.topology ['COMPONENT']
+ self.driversList=[]
+ if type(self.componentDictionary) == str :
+ self.componentDictionary = dict(self.componentDictionary)
+
+ for component in self.componentDictionary :
+ self.driversList.append(self.componentDictionary[component]['type'])
+
+ self.driversList = list(set(self.driversList)) # Removing duplicates.
+ # Checking the test_target option set for the component or not
+ if type(self.componentDictionary) == dict:
+ for component in self.componentDictionary.keys():
+ if 'test_target' in self.componentDictionary[component].keys():
+ self.test_target = component
+
+ # Checking for the openspeak file and test script
+ self.logger.initlog(self)
+
+ # Creating Drivers Handles
+ initString = "\n"+"*" * 30+"\n CASE INIT \n"+"*" * 30+"\n"
+ self.log.exact(initString)
+ self.driverObject = {}
+ self.random_order = 111 # Random order id to connect the components
+ components_connect_order = {}
+ #component_list.append()
+ if type(self.componentDictionary) == dict:
+ for component in self.componentDictionary.keys():
+ self.componentDictionary[component]['connect_order'] = self.componentDictionary[component]['connect_order'] if ('connect_order' in self.componentDictionary[component].keys()) else str(self.get_random())
+ components_connect_order[component] = eval(self.componentDictionary[component]['connect_order'])
+ #Ordering components based on the connect order.
+ ordered_component_list =sorted(components_connect_order, key=lambda key: components_connect_order[key])
+ print ordered_component_list
+
+ for component in ordered_component_list:
+ self.componentInit(component)
+
+ def configparser(self):
+ '''
+ It will parse the config file (teston.cfg) and return as dictionary
+ '''
+ matchFileName = re.match(r'(.*)\.cfg', self.configFile, re.M | re.I)
+ if matchFileName:
+ xml = open(self.configFile).read()
+ try :
+ self.configDict = xmldict.xml_to_dict(xml)
+ return self.configDict
+ except :
+ print "There is no such file to parse " + self.configFile
+
+ def componentInit(self,component):
+ '''
+ This method will initialize specified component
+ '''
+ global driver_options
+ self.log.info("Creating component Handle: "+component)
+ driver_options = {}
+ if 'COMPONENTS' in self.componentDictionary[component].keys():
+ driver_options =dict(self.componentDictionary[component]['COMPONENTS'])
+
+ driver_options['name']=component
+ driverName = self.componentDictionary[component]['type']
+ driver_options ['type'] = driverName
+
+ classPath = self.getDriverPath(driverName.lower())
+ driverModule = __import__(classPath, globals(), locals(), [driverName.lower()], -1)
+ driverClass = getattr(driverModule, driverName)
+ driverObject = driverClass()
+
+ connect_result = driverObject.connect(user_name = self.componentDictionary[component]['user'] if ('user' in self.componentDictionary[component].keys()) else getpass.getuser(),
+ ip_address= self.componentDictionary[component]['host'] if ('host' in self.componentDictionary[component].keys()) else 'localhost',
+ pwd = self.componentDictionary[component]['password'] if ('password' in self.componentDictionary[component].keys()) else 'changeme',
+ port = self.componentDictionary[component]['port'] if ('port' in self.componentDictionary[component].keys()) else None,
+ options = driver_options)
+ if not connect_result:
+ self.log.error("Exiting form the test execution because the connecting to the "+component+" component failed.")
+ self.exit()
+
+ vars(self)[component] = driverObject
+
+ def run(self):
+ '''
+ The Execution of the test script's cases listed in the Test params file will be done here.
+ And Update each test case result.
+ This method will return TRUE if it executed all the test cases successfully,
+ else will retun FALSE
+ '''
+
+ self.testCaseResult = {}
+ self.TOTAL_TC_RUN = 0
+ self.TOTAL_TC_NORESULT = 0
+ self.TOTAL_TC_FAIL = 0
+ self.TOTAL_TC_PASS = 0
+ self.stepCount = 0
+ self.CASERESULT = self.TRUE
+
+ import testparser
+ testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
+ test = testparser.TestParser(testFile)
+ self.testscript = test.testscript
+ self.code = test.getStepCode()
+
+ result = self.TRUE
+ for self.CurrentTestCaseNumber in self.testcases_list:
+ result = self.runCase(self.CurrentTestCaseNumber)
+ return result
+
+ def runCase(self,testCaseNumber):
+ self.CurrentTestCaseNumber = testCaseNumber
+ result = self.TRUE
+ self.stepCount = 0
+ self.EXPERIMENTAL_MODE = self.FALSE
+ self.addCaseHeader()
+ self.testCaseNumber = str(testCaseNumber)
+ stopped = False
+ try :
+ self.stepList = self.code[self.testCaseNumber].keys()
+ except KeyError,e:
+ main.log.error("There is no Test-Case "+ self.testCaseNumber)
+ return main.FALSE
+
+ self.stepCount = 0
+ while self.stepCount < len(self.code[self.testCaseNumber].keys()):
+ result = self.runStep(self.stepList,self.code,self.testCaseNumber)
+ if result == main.FALSE:
+ break
+ elif result == main.TRUE :
+ continue
+
+ if not stopped :
+ self.testCaseResult[str(self.CurrentTestCaseNumber)] = self.CASERESULT
+ self.logger.updateCaseResults(self)
+ return result
+
+ def runStep(self,stepList,code,testCaseNumber):
+ if not cli.pause:
+ try :
+ step = stepList[self.stepCount]
+ exec code[testCaseNumber][step] in module.__dict__
+ self.stepCount = self.stepCount + 1
+ except TypeError,e:
+ self.stepCount = self.stepCount + 1
+ self.log.error(e)
+ return main.TRUE
+
+ if cli.stop:
+ cli.stop = False
+ stopped = True
+ self.TOTAL_TC_NORESULT = self.TOTAL_TC_NORESULT + 1
+ self.testCaseResult[str(self.CurrentTestCaseNumber)] = "Stopped"
+ self.logger.updateCaseResults(self)
+ result = self.cleanup()
+ return main.FALSE
+
+ def addCaseHeader(self):
+ caseHeader = "\n"+"*" * 30+"\n Result summary for Testcase"+str(self.CurrentTestCaseNumber)+"\n"+"*" * 30+"\n"
+ self.log.exact(caseHeader)
+ caseHeader = "\n"+"*" * 40 +"\nStart of Test Case"+str(self.CurrentTestCaseNumber)+" : "
+ for driver in self.componentDictionary.keys():
+ vars(self)[driver+'log'].info(caseHeader)
+
+ def addCaseFooter(self):
+ if self.stepCount-1 > 0 :
+ previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
+ stepHeader = "\n"+"*" * 40+"\nEnd of Step "+previousStep+"\n"+"*" * 40+"\n"
+
+ caseFooter = "\n"+"*" * 40+"\nEnd of Test case "+str(self.CurrentTestCaseNumber)+"\n"+"*" * 40+"\n"
+
+ for driver in self.driversList:
+ vars(self)[driver].write(stepHeader+"\n"+caseFooter)
+
+ def cleanup(self):
+ '''
+ Release all the component handles and the close opened file handles.
+ This will return TRUE if all the component handles and log handles closed properly,
+ else return FALSE
+
+ '''
+ result = self.TRUE
+ self.logger.testSummary(self)
+
+ #self.reportFile.close()
+
+
+ utilities.send_mail()
+ try :
+ for component in self.componentDictionary.keys():
+ tempObject = vars(self)[component]
+ print "Disconnecting "+str(tempObject)
+
+ tempObject.disconnect()
+ #tempObject.execute(cmd="exit",prompt="(.*)",timeout=120)
+
+ except(Exception):
+ #print " There is an error with closing hanldes"
+ result = self.FALSE
+ # Closing all the driver's session files
+ for driver in self.componentDictionary.keys():
+ vars(self)[driver].close_log_handles()
+
+ print( "CLEAN!" )
+ return result
+
+ def pause(self):
+ '''
+ This function will pause the test's execution, and will continue after user provide 'resume' command.
+ '''
+ __builtin__.testthread.pause()
+
+ def onfail(self,*components):
+ '''
+ When test step failed, calling all the components onfail.
+ '''
+
+ if not components:
+ try :
+ for component in self.componentDictionary.keys():
+ tempObject = vars(self)[component]
+ result = tempObject.onfail()
+ except(Exception),e:
+ print str(e)
+ result = self.FALSE
+
+ else:
+ try :
+ for component in components:
+ tempObject = vars(self)[component]
+ result = tempObject.onfail()
+ except(Exception),e:
+ print str(e)
+ result = self.FALSE
+
+
+ def getDriverPath(self,driverName):
+ '''
+ Based on the component 'type' specified in the params , this method will find the absolute path ,
+ by recursively searching the name of the component.
+ '''
+ import commands
+
+ cmd = "find "+drivers_path+" -name "+driverName+".py"
+ result = commands.getoutput(cmd)
+
+ result_array = str(result).split('\n')
+ result_count = 0
+
+ for drivers_list in result_array:
+ result_count = result_count+1
+ if result_count > 1 :
+ print "found "+driverName+" "+ str(result_count) + " times"+str(result_array)
+ self.exit()
+
+ result = re.sub("(.*)drivers","",result)
+ result = re.sub("\.py","",result)
+ result = re.sub("\.pyc","",result)
+ result = re.sub("\/",".",result)
+ result = "drivers"+result
+ return result
+
+
+ def step(self,stepDesc):
+ '''
+ The step information of the test-case will append to the logs.
+ '''
+ previousStep = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount-1)+": "+ str(self.stepName) + ""
+ self.stepName = stepDesc
+
+ stepName = " "+str(self.CurrentTestCaseNumber)+"."+str(self.stepCount)+": "+ str(stepDesc) + ""
+ try :
+ if self.stepCount == 0:
+ stepName = " INIT : Initializing the test case :"+self.CurrentTestCase
+ except AttributeError:
+ stepName = " INIT : Initializing the test case :"+str(self.CurrentTestCaseNumber)
+
+ self.log.step(stepName)
+ stepHeader = ""
+ if self.stepCount > 1 :
+ stepHeader = "\n"+"-"*45+"\nEnd of Step "+previousStep+"\n"+"-"*45+"\n"
+
+ stepHeader += "\n"+"-"*45+"\nStart of Step"+stepName+"\n"+"-"*45+"\n"
+ for driver in self.componentDictionary.keys():
+ vars(self)[driver+'log'].info(stepHeader)
+
+ def case(self,testCaseName):
+ '''
+ Test's each test-case information will append to the logs.
+ '''
+ self.CurrentTestCase = testCaseName
+ testCaseName = " " + str(testCaseName) + ""
+ self.log.case(testCaseName)
+ caseHeader = testCaseName+"\n"+"*" * 40+"\n"
+ for driver in self.componentDictionary.keys():
+ vars(self)[driver+'log'].info(caseHeader)
+
+ def testDesc(self,description):
+ '''
+ Test description will append to the logs.
+ '''
+ description = "Test Description : " + str (description) + ""
+ self.log.info(description)
+
+ def _getTest(self):
+ '''
+ This method will parse the test script to find required test information.
+ '''
+ testFile = self.tests_path + "/"+self.TEST + "/"+self.TEST + ".py"
+ testFileHandler = open(testFile, 'r')
+ testFileList = testFileHandler.readlines()
+ testFileHandler.close()
+ #self.TOTAL_TC_PLANNED = 0
+ counter = 0
+ for index in range(len(testFileList)):
+ lineMatch = re.match('\s+def CASE(\d+)(.*):',testFileList[index],0)
+ if lineMatch:
+ counter = counter + 1
+ self.TOTAL_TC_PLANNED = counter
+
+ def response_parser(self,response, return_format):
+ ''' It will load the default response parser '''
+ response_dict = {}
+ response_dict = self.response_to_dict(response, return_format)
+ return_format_string = self.dict_to_return_format(response,return_format,response_dict)
+ return return_format_string
+
+ def response_to_dict(self,response,return_format):
+
+ response_dict = {}
+ json_match = re.search('^\s*{', response)
+ xml_match = re.search('^\s*\<', response)
+ ini_match = re.search('^\s*\[', response)
+ if json_match :
+ main.log.info(" Response is in 'JSON' format and Converting to '"+return_format+"' format")
+ # Formatting the json string
+
+ response = re.sub(r"{\s*'?(\w)", r'{"\1', response)
+ response = re.sub(r",\s*'?(\w)", r',"\1', response)
+ response = re.sub(r"(\w)'?\s*:", r'\1":', response)
+ response = re.sub(r":\s*'(\w)'\s*([,}])", r':"\1"\2', response)
+
+ try :
+ import json
+ response_dict = json.loads(response)
+ except Exception , e :
+ print e
+ main.log.error("Json Parser is unable to parse the string")
+ return response_dict
+
+ elif ini_match :
+ main.log.info(" Response is in 'INI' format and Converting to '"+return_format+"' format")
+ from configobj import ConfigObj
+ response_file = open("respnse_file.temp",'w')
+ response_file.write(response)
+ response_file.close()
+ response_dict = ConfigObj("respnse_file.temp")
+ return response_dict
+
+ elif xml_match :
+ main.log.info(" Response is in 'XML' format and Converting to '"+return_format+"' format")
+ try :
+ from core import dicttoobject
+ response_dict = xmldict.xml_to_dict("<response> "+str(response)+" </response>")
+ except Exception, e:
+ main.log.error(e)
+ return response_dict
+
+ def dict_to_return_format(self,response,return_format,response_dict):
+
+ if return_format =='table' :
+ ''' Will return in table format'''
+ to_do = "Call the table output formatter"
+ global response_table
+ response_table = '\n'
+ response_table = response_table +'\t'.join(response_dict)+"\n"
+
+ def get_table(value_to_convert):
+ ''' This will parse the dictionary recusrsively and print as table format'''
+ table_data = ""
+ if type(value_to_convert) == dict :
+ table_data = table_data +'\t'.join(value_to_convert)+"\n"
+ for temp_val in value_to_convert.values() :
+ table_data = table_data + get_table(temp_val)
+ else :
+ table_data = table_data + str(value_to_convert) +"\t"
+ return table_data
+
+ for value in response_dict.values() :
+ response_table = response_table + get_table(value)
+
+
+
+ #response_table = response_table + '\t'.join(response_dict.values())
+
+ return response_table
+
+ elif return_format =='config':
+ ''' Will return in config format'''
+ to_do = 'Call dict to config coverter'
+ response_string = str(response_dict)
+ print response_string
+ response_config = re.sub(",", "\n\t", response_string)
+ response_config = re.sub("u\'", "\'", response_config)
+ response_config = re.sub("{", "", response_config)
+ response_config = re.sub("}", "\n", response_config)
+ response_config = re.sub(":", " =", response_config)
+ return "[response]\n\t "+response_config
+
+ elif return_format == 'xml':
+ ''' Will return in xml format'''
+ from core import dicttoobject
+ response_xml = xmldict.dict_to_xml(response_dict)
+ response_xml = re.sub(">\s*<", ">\n<", response_xml)
+ return "\n"+response_xml
+
+ elif return_format == 'json':
+ ''' Will return in json format'''
+ to_do = 'Call dict to xml coverter'
+ import json
+ response_json = json.dumps(response_dict)
+ return response_json
+
+ def get_random(self):
+ self.random_order = self.random_order + 1
+ return self.random_order
+
+ def exit(self):
+ __builtin__.testthread = None
+ sys.exit()
+
+def verifyOptions(options):
+ '''
+ This will verify the command line options and set to default values, if any option not given in command line.
+ '''
+ import pprint
+ pp = pprint.PrettyPrinter(indent=4)
+
+ #pp.pprint(options)
+ verifyTest(options)
+ verifyExample(options)
+ verifyTestScript(options)
+ verifyParams()
+ verifyLogdir(options)
+ verifyMail(options)
+ verifyTestCases(options)
+
+def verifyTest(options):
+ if options.testname:
+ main.TEST = options.testname
+ main.classPath = "tests."+main.TEST+"."+main.TEST
+ main.tests_path = tests_path
+ elif options.example :
+ main.TEST = options.example
+ main.tests_path = path+"/examples/"
+ main.classPath = "examples."+main.TEST+"."+main.TEST
+ else :
+ print "Test or Example not specified please specify the --test <test name > or --example <example name>"
+ self.exit()
+
+def verifyExample(options):
+ if options.example:
+ main.testDir = path+'/examples/'
+ main.tests_path = path+"/examples/"
+ main.classPath = "examples."+main.TEST+"."+main.TEST
+
+def verifyLogdir(options):
+ #Verifying Log directory option
+ if options.logdir:
+ main.logdir = options.logdir
+ else :
+ main.logdir = main.FALSE
+
+def verifyMail(options):
+ # Checking the mailing list
+ if options.mail:
+ main.mail = options.mail
+ elif main.params.has_key('mail'):
+ main.mail = main.params['mail']
+ else :
+ main.mail = 'paxweb@paxterrasolutions.com'
+
+def verifyTestCases(options):
+ #Getting Test cases list
+ if options.testcases:
+ testcases_list = re.sub("(\[|\])", "", options.testcases)
+ main.testcases_list = eval(testcases_list+",")
+ else :
+ if 'testcases' in main.params.keys():
+ main.params['testcases'] = re.sub("(\[|\])", "", main.params['testcases'])
+ if re.search('\d+', main.params['testcases'], 0):
+ main.testcases_list = eval(main.params['testcases']+",")
+ else :
+ print "Please provide the testcases list in Params file"
+ sys.exit()
+ else :
+ print "testcases not specifed in params, please provide in params file or 'testcases' commandline argument"
+ sys.exit()
+
+def verifyTestScript(options):
+ '''
+ Verifyies test script.
+ '''
+ main.openspeak = openspeak.OpenSpeak()
+ openspeakfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".ospk"
+ testfile = main.testDir+"/" + main.TEST + "/" + main.TEST + ".py"
+ if os.path.exists(openspeakfile) :
+ main.openspeak.compiler(openspeakfile=openspeakfile,writetofile=1)
+ elif os.path.exists(testfile):
+ print ''
+ else:
+ print "\nThere is no :\""+main.TEST+"\" test, Please Provide OpenSpeak Script/ test script"
+ __builtin__.testthread = None
+ main.exit()
+
+ try :
+ testModule = __import__(main.classPath, globals(), locals(), [main.TEST], -1)
+ except(ImportError):
+ print "There is no test like "+main.TEST
+ main.exit()
+
+ testClass = getattr(testModule, main.TEST)
+ main.testObject = testClass()
+ load_parser()
+ main.params = main.parser.parseParams(main.classPath)
+ main.topology = main.parser.parseTopology(main.classPath)
+
+def verifyParams():
+ try :
+ main.params = main.params['PARAMS']
+ except(KeyError):
+ print "Error with the params file: Either the file not specified or the format is not correct"
+ main.exit()
+
+ try :
+ main.topology = main.topology['TOPOLOGY']
+ except(KeyError):
+ print "Error with the Topology file: Either the file not specified or the format is not correct"
+ main.exit()
+
+def load_parser() :
+ '''
+ It facilitates the loading customised parser for topology and params file.
+ It loads parser mentioned in tab named parser of teston.cfg file.
+ It also loads default xmlparser if no parser have specified in teston.cfg file.
+
+ '''
+ confighash = main.configDict
+ if 'file' in confighash['config']['parser'] and 'class' in confighash['config']['parser']:
+ if confighash['config']['parser']['file'] != None or confighash['config']['parser']['class']!= None :
+ if os.path.exists(confighash['config']['parser']['file']) :
+ module = re.sub(r".py\s*$","",confighash['config']['parser']['file'])
+ moduleList = module.split("/")
+ newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
+ try :
+ parsingClass = confighash['config']['parser']['class']
+ parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
+ parsingClass = getattr(parsingModule, parsingClass)
+ main.parser = parsingClass()
+ #hashobj = main.parser.parseParams(main.classPath)
+ if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
+
+ pass
+ else:
+ main.exit()
+
+ except ImportError:
+ print sys.exc_info()[1]
+ main.exit()
+ else :
+ print "No Such File Exists !!"+ confighash['config']['parser']['file'] +"using default parser"
+ load_defaultParser()
+ elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
+ load_defaultParser()
+ else:
+ load_defaultParser()
+
+def load_defaultParser():
+ '''
+ It will load the default parser which is xml parser to parse the params and topology file.
+ '''
+ moduleList = main.parserPath.split("/")
+ newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
+ try :
+ parsingClass = main.parsingClass
+ parsingModule = __import__(newModule, globals(), locals(), [parsingClass], -1)
+ parsingClass = getattr(parsingModule, parsingClass)
+ main.parser = parsingClass()
+ if hasattr(main.parser,"parseParams") and hasattr(main.parser,"parseTopology") and hasattr(main.parser,"parse") :
+ pass
+ else:
+ main.exit()
+
+ except ImportError:
+ print sys.exc_info()[1]
+
+
+def load_logger() :
+ '''
+ It facilitates the loading customised parser for topology and params file.
+ It loads parser mentioned in tab named parser of teston.cfg file.
+ It also loads default xmlparser if no parser have specified in teston.cfg file.
+
+ '''
+ confighash = main.configDict
+ if 'file' in confighash['config']['logger'] and 'class' in confighash['config']['logger']:
+ if confighash['config']['logger']['file'] != None or confighash['config']['logger']['class']!= None :
+ if os.path.exists(confighash['config']['logger']['file']) :
+ module = re.sub(r".py\s*$","",confighash['config']['logger']['file'])
+ moduleList = module.split("/")
+ newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
+ try :
+ loggerClass = confighash['config']['logger']['class']
+ loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
+ loggerClass = getattr(loggerModule, loggerClass)
+ main.logger = loggerClass()
+ #hashobj = main.parser.parseParams(main.classPath)
+
+ except ImportError:
+ print sys.exc_info()[1]
+ else :
+ print "No Such File Exists !!"+confighash['config']['logger']['file']+ "Using default logger"
+ load_defaultlogger()
+ elif confighash['config']['parser']['file'] == None or confighash['config']['parser']['class'] == None :
+ load_defaultlogger()
+ else:
+ load_defaultlogger()
+
+def load_defaultlogger():
+ '''
+ It will load the default parser which is xml parser to parse the params and topology file.
+ '''
+ moduleList = main.loggerPath.split("/")
+ newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
+ try :
+ loggerClass = main.loggerClass
+ loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
+ loggerClass = getattr(loggerModule, loggerClass)
+ main.logger = loggerClass()
+
+ except ImportError:
+ print sys.exc_info()[1]
+ main.exit()
+
+def load_defaultlogger():
+ '''
+ It will load the default parser which is xml parser to parse the params and topology file.
+ '''
+ moduleList = main.loggerPath.split("/")
+ newModule = ".".join([moduleList[len(moduleList) - 2],moduleList[len(moduleList) - 1]])
+ try :
+ loggerClass = main.loggerClass
+ loggerModule = __import__(newModule, globals(), locals(), [loggerClass], -1)
+ loggerClass = getattr(loggerModule, loggerClass)
+ main.logger = loggerClass()
+
+ except ImportError:
+ print sys.exc_info()[1]
+ main.exit()
+
+
+
+
+def _echo(self):
+ print "THIS IS ECHO"
diff --git a/TestON/core/testparser.py b/TestON/core/testparser.py
new file mode 100644
index 0000000..f158259
--- /dev/null
+++ b/TestON/core/testparser.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+'''
+Created on 26-Dec-2012
+
+@author: Anil Kumar (anilkumar.s@paxterrasolutions.com)
+
+
+ TestON is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ TestON is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TestON. If not, see <http://www.gnu.org/licenses/>.
+
+
+'''
+import re
+import sys
+class TestParser:
+ def __init__(self,testFile):
+ try :
+ testFileHandler = open(testFile, 'r')
+ except IOError:
+ print "No such file "+testFile
+ sys.exit(0)
+
+ testFileList = testFileHandler.readlines()
+ self.testscript = testFileList
+ self.caseCode = {}
+ self.caseBlock = ''
+ self.statementsList = []
+ index = 0
+ self.statementsList = []
+ #initialSpaces = len(line) -len(line.lstrip())
+ while index < len(testFileList):
+ testFileList[index] = re.sub("^\s{8}|^\s{4}", "", testFileList[index])
+ # Skip multiline comments
+ if re.match('^(\'\'\')|^(\"\"\")',testFileList[index],0) :
+ index = index + 1
+ try :
+ while not re.match('^\s*(\'\'\')|^\s*(\"\"\")',testFileList[index],0) :
+ index = index + 1
+ except IndexError,e:
+ print ''
+
+
+ # skip empty lines and single line comments
+ elif not re.match('#|^\s*$',testFileList[index],0):
+ self.statementsList.append(testFileList[index])
+ index = index + 1
+
+ def case_code(self):
+ index = 0
+ statementsList = self.statementsList
+ while index < len(statementsList):
+ #print statementsList[index]
+ m= re.match('def\s+CASE(\d+)',statementsList[index],0)
+ self.caseBlock = []
+ if m:
+ #print m.group(1)
+ index = index + 1
+ try :
+ while not re.match('\s*def\s+CASE(\d+)',statementsList[index],0) :
+ self.caseBlock.append(statementsList[index])
+ if index < len(statementsList)-1:
+ index = index + 1
+ else :
+ break
+ index = index - 1
+ except IndexError,e:
+ #print 'IndexError'
+ print ''
+
+ self.caseCode [str(m.group(1))] = self.caseBlock
+ #print "Case CODE "+self.caseCode [str(m.group(1))]
+ index = index + 1
+
+ return self.caseCode
+
+ def step_code(self,caseStatements):
+ index = 0
+ step = 0
+ stepCode = {}
+ step_flag = False
+ while index < len(caseStatements):
+ m= re.match('main\.step',caseStatements[index],0)
+ stepBlock = ''
+ if m:
+ step_flag = True
+ if step == 0 :
+ i = 0
+ block = ''
+ while i <= index :
+ block += caseStatements[i]
+ i = i + 1
+ stepCode[step] = block
+ step = step + 1
+ stepBlock= stepBlock + caseStatements[index]
+ index = index + 1
+ try :
+ while not re.match('main\.step',caseStatements[index],0) :
+ stepBlock= stepBlock + caseStatements[index]
+ if index < len(caseStatements)-1:
+ index = index + 1
+ else :
+ break
+ index = index - 1
+ except IndexError,e:
+ #print 'IndexError'
+ print ''
+ stepCode[step] = stepBlock
+ step = step + 1
+ index = index + 1
+ # If there is no step defined !!
+ if not step_flag :
+ stepCode[step] = "".join(caseStatements)
+ return stepCode
+
+ def getStepCode(self):
+ case_step_code = {}
+ case_block = self.case_code()
+
+ for case in case_block :
+ case_step_code[case] = {}
+ step_block = self.step_code(case_block[case])
+ for step in step_block :
+ case_step_code[case][step] = step_block[step]
+ return case_step_code
diff --git a/TestON/core/utilities.py b/TestON/core/utilities.py
new file mode 100644
index 0000000..b6bed3e
--- /dev/null
+++ b/TestON/core/utilities.py
@@ -0,0 +1,277 @@
+#!/usr/bin/env python
+'''
+Created on 23-Oct-2012
+
+@authors: Anil Kumar (anilkumar.s@paxterrasolutions.com),
+ Raghav Kashyap(raghavkashyap@paxterrasolutions.com)
+
+
+
+ TestON is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ TestON is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TestON. If not, see <http://www.gnu.org/licenses/>.
+
+
+Utilities will take care about the basic functions like :
+ * Extended assertion,
+ * parse_args for key-value pair handling
+ * Parsing the params or topology file.
+
+'''
+import re
+from configobj import ConfigObj
+import pydoc
+from core import ast as ast
+import smtplib
+
+import mimetypes
+import email
+import os
+import email.mime.application
+
+class Utilities:
+ '''
+ Utilities will take care about the basic functions like :
+ * Extended assertion,
+ * parse_args for key-value pair handling
+ * Parsing the params or topology file.
+ '''
+
+ def __init__(self):
+ self.wrapped = sys.modules[__name__]
+
+ def __getattr__(self, name):
+ '''
+ This will invoke, if the attribute wasn't found the usual ways.
+ Here it will look for assert_attribute and will execute when AttributeError occurs.
+ It will return the result of the assert_attribute.
+ '''
+ try:
+ return getattr(self.wrapped, name)
+ except AttributeError:
+ def assertHandling(**kwargs):
+ nameVar = re.match("^assert",name,flags=0)
+ matchVar = re.match("assert(_not_|_)(equals|matches|greater|lesser)",name,flags=0)
+ notVar = 0
+ operators = ""
+
+ try :
+ if matchVar.group(1) == "_not_" and matchVar.group(2) :
+ notVar = 1
+ operators = matchVar.group(2)
+ elif matchVar.group(1) == "_" and matchVar.group(2):
+ operators = matchVar.group(2)
+
+ except AttributeError:
+ if matchVar==None and nameVar:
+ operators ='equals'
+
+ result = self._assert(NOT=notVar,operator=operators,**kwargs)
+ if result == main.TRUE:
+ main.log.info("Assertion Passed")
+ main.CASERESULT = main.TRUE
+ elif result == main.FALSE:
+ main.log.warn("Assertion Failed")
+ main.CASERESULT = main.FALSE
+
+ else :
+ main.log.error("There is an Error in Assertion")
+ main.CASERESULT = main.ERROR
+
+ return result
+
+ return assertHandling
+
+
+ def _assert (self,**assertParam):
+ '''
+ It will take the arguments :
+ expect:'Expected output'
+ actual:'Actual output'
+ onpass:'Action or string to be triggered or displayed respectively when the assert passed'
+ onfail:'Action or string to be triggered or displayed respectively when the assert failed'
+ not:'optional argument to specify the negation of the each assertion type'
+ operator:'assertion type will be defined by using operator. Like equal , greater, lesser, matches.'
+
+ It will return the assertion result.
+
+ '''
+
+ arguments = self.parse_args(["EXPECT","ACTUAL","ONPASS","ONFAIL","NOT","OPERATOR"],**assertParam)
+
+ result = 0
+ valuetype = ''
+ operation = "not "+ str(arguments["OPERATOR"]) if arguments['NOT'] and arguments['NOT'] == 1 else arguments["OPERATOR"]
+ operators = {'equals':{'STR':'==','NUM':'=='}, 'matches' : '=~', 'greater':'>' ,'lesser':'<'}
+
+ expectMatch = re.match('^\s*[+-]?0(e0)?\s*$', str(arguments["EXPECT"]), re.I+re.M)
+ if not ((not expectMatch) and (arguments["EXPECT"]==0)):
+ valuetype = 'NUM'
+ else :
+ if arguments["OPERATOR"] == 'greater' or arguments["OPERATOR"] == 'lesser':
+ main.log.error("Numeric comparison on strings is not possibele")
+ return main.ERROR
+
+ valuetype = 'STR'
+ arguments["ACTUAL"] = str(arguments["ACTUAL"])
+ if arguments["OPERATOR"] != 'matches':
+ arguments["EXPECT"] = str(arguments["EXPECT"])
+
+ try :
+ opcode = operators[str(arguments["OPERATOR"])][valuetype] if arguments["OPERATOR"] == 'equals' else operators[str(arguments["OPERATOR"])]
+
+ except KeyError:
+ print "Key Error in assertion"
+ return main.FALSE
+
+ if opcode == '=~':
+ try:
+ assert re.search(str(arguments["EXPECT"]),str(arguments["ACTUAL"]))
+ result = main.TRUE
+ except AssertionError:
+ try :
+ assert re.match(str(arguments["EXPECT"]),str(arguments["ACTUAL"]))
+ result = main.TRUE
+ except AssertionError:
+ main.log.error("Assertion Failed")
+ result = main.FALSE
+
+ else :
+ try:
+ if str(opcode)=="==":
+ main.log.info("Verifying the Expected is equal to the actual or not using assert_equal")
+ if (arguments["EXPECT"] == arguments["ACTUAL"]):
+ result = main.TRUE
+ else :
+ result = main.FALSE
+
+ elif str(opcode) == ">":
+ main.log.info("Verifying the Expected is Greater than the actual or not using assert_greater")
+ if (ast.literal_eval(arguments["EXPECT"]) > ast.literal_eval(arguments["ACTUAL"])) :
+ result = main.TRUE
+ else :
+ result = main.FALSE
+
+ elif str(opcode) == "<":
+ main.log.info("Verifying the Expected is Lesser than the actual or not using assert_lesser")
+ if (ast.literal_eval(arguments["EXPECT"]) < ast.literal_eval(arguments["ACTUAL"])):
+ result = main.TRUE
+ else :
+ result = main.FALSE
+
+
+ except AssertionError:
+ main.log.error("Assertion Failed")
+ result = main.FALSE
+
+
+ result = result if result else 0
+ result = not result if arguments["NOT"] and arguments["NOT"] == 1 else result
+ resultString = ""
+ if result :
+ resultString = str(resultString) + "PASS"
+ main.log.info(arguments["ONPASS"])
+ else :
+ resultString = str(resultString) + "FAIL"
+ if not isinstance(arguments["ONFAIL"],str):
+ eval(str(arguments["ONFAIL"]))
+ else :
+ main.log.error(arguments["ONFAIL"])
+ main.log.report(arguments["ONFAIL"])
+
+ msg = arguments["ON" + str(resultString)]
+
+ if not isinstance(msg,str):
+ try:
+ eval(str(msg))
+ except SyntaxError:
+ print "functin definition is not write"
+
+ main.last_result = result
+ return result
+
+
+ def parse_args(self,args, **kwargs):
+ '''
+ It will accept the (key,value) pair and will return the (key,value) pairs with keys in uppercase.
+ '''
+ newArgs = {}
+ for key,value in kwargs.iteritems():
+ #currentKey = str.upper(key)
+ if isinstance(args,list) and str.upper(key) in args:
+ for each in args:
+ if each==str.upper(key):
+ newArgs [str(each)] = value
+ elif each != str.upper(key) and (newArgs.has_key(str(each)) == False ):
+ newArgs[str(each)] = None
+
+
+
+ return newArgs
+
+ def send_mail(self):
+ # Create a text/plain message
+ msg = email.mime.Multipart.MIMEMultipart()
+ try :
+ if main.test_target:
+ sub = "Result summary of \""+main.TEST+"\" run on component \""+main.test_target+"\" Version \""+vars(main)[main.test_target].get_version()+"\": "+str(main.TOTAL_TC_SUCCESS)+"% Passed"
+ else :
+ sub = "Result summary of \""+main.TEST+"\": "+str(main.TOTAL_TC_SUCCESS)+"% Passed"
+ except KeyError,AttributeError:
+ sub = "Result summary of \""+main.TEST+"\": "+str(main.TOTAL_TC_SUCCESS)+"% Passed"
+
+ msg['Subject'] = sub
+ msg['From'] = 'paxweb@paxterrasolutions.com'
+ msg['To'] = main.mail
+ #msg['Cc'] = 'paxweb@paxterrasolutions.com'
+
+ # The main body is just another attachment
+ body = email.mime.Text.MIMEText(main.logHeader+"\n"+main.testResult)
+ msg.attach(body)
+
+ # Attachment
+ for filename in os.listdir(main.logdir):
+ filepath = main.logdir+"/"+filename
+ fp=open(filepath,'rb')
+ att = email.mime.application.MIMEApplication(fp.read(),_subtype="")
+ fp.close()
+ att.add_header('Content-Disposition','attachment',filename=filename)
+ msg.attach(att)
+
+ smtp = smtplib.SMTP('198.57.211.46')
+ smtp.starttls()
+ smtp.login('paxweb@paxterrasolutions.com','pax@peace')
+ smtp.sendmail(msg['From'],[msg['To']], msg.as_string())
+ smtp.quit()
+ return main.TRUE
+
+
+ def parse(self,fileName):
+ '''
+ This will parse the params or topo or cfg file and return content in the file as Dictionary
+ '''
+ self.fileName = fileName
+ matchFileName = re.match(r'(.*)\.(cfg|params|topo)',self.fileName,re.M|re.I)
+ if matchFileName:
+ try :
+ parsedInfo = ConfigObj(self.fileName)
+ return parsedInfo
+ except :
+ print "There is no such file to parse "+fileName
+ else:
+ return 0
+
+
+if __name__ != "__main__":
+ import sys
+
+ sys.modules[__name__] = Utilities()
diff --git a/TestON/core/xmldict.py b/TestON/core/xmldict.py
new file mode 100644
index 0000000..34e9cfc
--- /dev/null
+++ b/TestON/core/xmldict.py
@@ -0,0 +1,191 @@
+'''
+Created on 03-Dec-2012
+
+@author: Anil Kumar (anilkumar.s@paxterrasolutions.com)
+
+ TestON is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ TestON is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TestON. If not, see <http://www.gnu.org/licenses/>.
+
+'''
+
+"""
+ xmldict
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Convert xml to python dictionaries.
+"""
+import datetime
+
+def xml_to_dict(root_or_str, strict=True):
+ """
+ Converts `root_or_str` which can be parsed xml or a xml string to dict.
+
+ """
+ root = root_or_str
+ if isinstance(root, str):
+ import xml.etree.cElementTree as ElementTree
+ root = ElementTree.XML(root_or_str)
+ try :
+ return {root.tag: _from_xml(root, strict)}
+ except :
+ return None
+
+def dict_to_xml(dict_xml):
+ """
+ Converts `dict_xml` which is a python dict to corresponding xml.
+ """
+ return _to_xml(dict_xml)
+
+def _to_xml(el):
+ """
+ Converts `el` to its xml representation.
+ """
+ val = None
+ if isinstance(el, dict):
+ val = _dict_to_xml(el)
+ elif isinstance(el, bool):
+ val = str(el).lower()
+ else:
+ val = el
+ if val is None: val = 'null'
+ return val
+
+def _extract_attrs(els):
+ """
+ Extracts attributes from dictionary `els`. Attributes are keys which start
+ with '@'
+ """
+ if not isinstance(els, dict):
+ return ''
+ return ''.join(' %s="%s"' % (key[1:], value) for key, value in els.iteritems()
+ if key.startswith('@'))
+
+def _dict_to_xml(els):
+ """
+ Converts `els` which is a python dict to corresponding xml.
+ """
+ def process_content(tag, content):
+ attrs = _extract_attrs(content)
+ text = isinstance(content, dict) and content.get('#text', '') or ''
+ return '<%s%s>%s%s</%s>' % (tag, attrs, _to_xml(content), text, tag)
+
+ tags = []
+ for tag, content in els.iteritems():
+ # Text and attributes
+ if tag.startswith('@') or tag == '#text':
+ continue
+ elif isinstance(content, list):
+ for el in content:
+ tags.append(process_content(tag, el))
+ elif isinstance(content, dict):
+ tags.append(process_content(tag, content))
+ else:
+ tags.append('<%s>%s</%s>' % (tag, _to_xml(content), tag))
+ return ''.join(tags)
+
+def _is_xml_el_dict(el):
+ """
+ Returns true if `el` is supposed to be a dict.
+ This function makes sense only in the context of making dicts out of xml.
+ """
+ if len(el) == 1 or el[0].tag != el[1].tag:
+ return True
+ return False
+
+def _is_xml_el_list(el):
+ """
+ Returns true if `el` is supposed to be a list.
+ This function makes sense only in the context of making lists out of xml.
+ """
+ if len(el) > 1 and el[0].tag == el[1].tag:
+ return True
+ return False
+
+def _str_to_datetime(date_str):
+ try:
+ val = datetime.datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%SZ")
+ except ValueError:
+ val = date_str
+ return val
+
+def _str_to_boolean(bool_str):
+ if bool_str.lower() != 'false' and bool(bool_str):
+ return True
+ return False
+
+def _from_xml(el, strict):
+ """
+ Extracts value of xml element element `el`.
+ """
+ val = None
+ # Parent node.
+ if el:
+ if _is_xml_el_dict(el):
+ val = _dict_from_xml(el, strict)
+ elif _is_xml_el_list(el):
+ val = _list_from_xml(el, strict)
+ # Simple node.
+ else:
+ attribs = el.items()
+ # An element with attributes.
+ if attribs and strict:
+ val = dict(('@%s' % k, v) for k, v in dict(attribs).iteritems())
+ if el.text:
+ converted = _val_and_maybe_convert(el)
+ val['#text'] = el.text
+ if converted != el.text:
+ val['#value'] = converted
+ elif el.text:
+ # An element with no subelements but text.
+ val = _val_and_maybe_convert(el)
+ elif attribs:
+ val = dict(attribs)
+ return val
+
+def _val_and_maybe_convert(el):
+ """
+ Converts `el.text` if `el` has attribute `type` with valid value.
+ """
+ text = el.text.strip()
+ data_type = el.get('type')
+ convertor = _val_and_maybe_convert.convertors.get(data_type)
+ if convertor:
+ return convertor(text)
+ else:
+ return text
+_val_and_maybe_convert.convertors = {
+ 'boolean': _str_to_boolean,
+ 'datetime': _str_to_datetime,
+ 'integer': int
+}
+
+def _list_from_xml(els, strict):
+ """
+ Converts xml elements list `el_list` to a python list.
+ """
+
+ temp = {}
+ for el in els:
+ tag = el.attrib["name"]
+ temp[tag] = (_from_xml(el, strict))
+ return temp
+
+def _dict_from_xml(els, strict):
+ """
+ Converts xml doc with root `root` to a python dict.
+ """
+ # An element with subelements.
+ res = {}
+ for el in els:
+ res[el.tag] = _from_xml(el, strict)
+ return res
diff --git a/TestON/core/xmlparser.py b/TestON/core/xmlparser.py
new file mode 100644
index 0000000..9a2321c
--- /dev/null
+++ b/TestON/core/xmlparser.py
@@ -0,0 +1,66 @@
+#/usr/bin/env python
+'''
+Created on 07-Jan-2013
+
+@author: Raghav Kashyap(raghavkashyap@paxterrasolutions.com)
+
+ TestON is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ TestON is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with TestON. If not, see <http://www.gnu.org/licenses/>.
+
+
+'''
+
+import xmldict
+import re
+
+class xmlparser :
+
+ def __init__(self) :
+ self.default = ''
+
+ def parse(self,fileName) :
+ '''
+ This will parse the params or topo or cfg file and return content in the file as Dictionary
+ '''
+ self.fileName = fileName
+ matchFileName = re.match(r'(.*)\.(params|topo|cfg)', self.fileName, re.M | re.I)
+ if matchFileName:
+ xml = open(fileName).read()
+ try :
+ parsedInfo = xmldict.xml_to_dict(xml)
+ return parsedInfo
+ except :
+ print "There is no such file to parse " + fileName
+ else :
+ print "file name is not correct"
+
+ def parseParams(self,paramsPath):
+ '''
+ It will take the params file path and will return the params dictionary
+ '''
+ paramsPath = re.sub("\.","/",paramsPath)
+ paramsPath = re.sub("tests|examples","",paramsPath)
+ params = self.parse(main.tests_path+paramsPath+".params")
+ paramsAsString = str(params)
+ return eval(paramsAsString)
+
+ def parseTopology(self,topologyPath):
+ '''
+ It will take topology file path and will return topology dictionary
+ '''
+ topologyPath = re.sub("\.","/",topologyPath)
+ topologyPath = re.sub("tests|examples","",topologyPath)
+ topology = self.parse(main.tests_path+"/"+topologyPath+".topo")
+ topoAsString = str(topology)
+ return eval(topoAsString)
+