Last Updated: September 28, 2015
2.0 Supported Platforms and Python Versions
5.0 Module PySTAFMon
STAF Python support must be installed in order to submit requests to STAF via a Python program.
The version of Python used to build the STAF Python libraries is usually the only Python version that will work with those STAF Python libraries.
STAF currently provides STAF Python support on the following platforms:
Section 2.0 provides details about the STAF Python support by platform.
If you want to use a different version of Python or if you want STAF Python support for a different operating system, you can either:
If you build STAF Python support for a different operating system and/or different Python version, please contribute it to the STAF project. To contribute it, browse the STAF Support Requests to see if someone else has already provided STAF Python support for this operating system and Python version combination. If not, open a STAF Support Request with the "Summary" containing "STAF V3 Support for Python x.x.x (Platform)", replacing x.x.x with the Python version and replacing Platform with the operating system on which you built the support. Attach the necessary files (e.g. PYSTAF.pyd for Windows or PYSTAF.so for Unix) to the Support Request.
Note: In STAF V3.2.1+, the extension of the PYSTAF extension module for Windows is now .pyd (instead of .dll) because starting in Python 2.5, the .dll extension is no longer supported as a filename extension for Python extension modules on Windows. If you have both PYSTAF.pyd and PYSTAF.dll on your system (e.g. because you had an earlier version of STAF installed or because you downloaded it from a support request), Python finds PYSTAF.pyd before PYSTAF.dll so make sure that the STAF Python extension module you want to use is PYSTAF.pyd.
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.2.x (default) | 2.2.1 | bin/python22/PYSTAF.pyd |
2.3.x | 2.3.5 | bin/python23/PYSTAF.pyd |
2.4.x | 2.4.4 | bin/python24/PYSTAF.pyd |
2.5.x | 2.5.4 | bin/python25/PYSTAF.pyd |
2.6.x | 2.6.2 | bin/python26/PYSTAF.pyd |
2.7.x | 2.7.0 | bin/python27/PYSTAF.pyd |
3.0.x | 3.0.1 | bin/python30/PYSTAF.pyd |
3.1.x | 3.1.2 | bin/python31/PYSTAF.pyd |
3.2.x | 3.2.5 | bin/python32/PYSTAF.pyd |
3.3.x | 3.3.5 | bin/python33/PYSTAF.pyd |
3.4.x | 3.4.3 | bin/python34/PYSTAF.pyd |
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.5.x (default) | 2.5.4 | bin/python25/PYSTAF.pyd |
2.6.x | 2.6.2 | bin/python26/PYSTAF.pyd |
2.7.x | 2.7.0 | bin/python27/PYSTAF.pyd |
3.0.x | 3.0.1 | bin/python30/PYSTAF.pyd |
3.1.x | 3.1.2 | bin/python31/PYSTAF.pyd |
3.2.x | 3.2.5 | bin/python32/PYSTAF.pyd |
3.3.x | 3.3.5 | bin/python33/PYSTAF.pyd |
3.4.x | 3.4.3 | bin/python34/PYSTAF.pyd |
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.2.x (default) | 2.2.2 | lib/python22/PYSTAF.so |
2.3.x | 2.3.5 | lib/python23/PYSTAF.so |
2.4.x | 2.4.4 | lib/python24/PYSTAF.so |
2.5.x | 2.5.4 | lib/python25/PYSTAF.so |
2.6.x | 2.6.2 | lib/python26/PYSTAF.so |
2.7.x | 2.7.0 | lib/python27/PYSTAF.so |
3.0.x | 3.0.1 | lib/python30/PYSTAF.so |
3.1.x | 3.1.2 | lib/python31/PYSTAF.so |
3.2.x | 3.2.6 | lib/python32/PYSTAF.so |
3.3.x | 3.3.6 | lib/python33/PYSTAF.so |
3.4.x | 3.4.3 | lib/python34/PYSTAF.so |
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.2.x (default) | 2.2.3 | lib/python22/PYSTAF.so |
2.3.x | 2.3.5 | lib/python23/PYSTAF.so |
2.4.x | 2.4.4 | lib/python24/PYSTAF.so |
2.5.x | 2.5.4 | lib/python25/PYSTAF.so |
2.6.x | 2.6.2 | lib/python26/PYSTAF.so |
2.7.x | 2.7.0 | lib/python27/PYSTAF.so |
3.0.x | 3.0.1 | lib/python30/PYSTAF.so |
3.1.x | 3.1.2 | lib/python31/PYSTAF.so |
3.2.x | 3.2.6 | lib/python32/PYSTAF.so |
3.3.x | 3.3.6 | lib/python33/PYSTAF.so |
3.4.x | 3.4.3 | lib/python34/PYSTAF.so |
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.2.x (default) | 2.2.3 | lib/python22/PYSTAF.so |
2.3.x | 2.3.5 | lib/python23/PYSTAF.so |
2.4.x | 2.4.4 | lib/python24/PYSTAF.so |
2.5.x | 2.5.4 | lib/python25/PYSTAF.so |
2.6.x | 2.6.2 | lib/python26/PYSTAF.so |
2.7.x | 2.7.0 | lib/python27/PYSTAF.so |
3.0.x | 3.0.1 | lib/python30/PYSTAF.so |
3.1.x | 3.1.2 | lib/python31/PYSTAF.so |
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.2.x (default) | 2.2.3 | lib/python22/PYSTAF.so |
2.3.x | 2.3.5 | lib/python23/PYSTAF.so |
2.4.x | 2.4.4 | lib/python24/PYSTAF.so |
2.5.x | 2.5.4 | lib/python25/PYSTAF.so |
2.6.x | 2.6.2 | lib/python26/PYSTAF.so |
2.7.x | 2.7.0 | lib/python27/PYSTAF.so |
3.0.x | 3.0.1 | lib/python30/PYSTAF.so |
3.1.x | 3.1.2 | lib/python31/PYSTAF.so |
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.2.x (default) | 2.2.3 | lib/python22/PYSTAF.so |
2.3.x | 2.3.5 | lib/python23/PYSTAF.so |
2.4.x | 2.4.4 | lib/python24/PYSTAF.so |
2.5.x | 2.5.4 | lib/python25/PYSTAF.so |
2.6.x | 2.6.2 | lib/python26/PYSTAF.so |
2.7.x | 2.7.0 | lib/python27/PYSTAF.so |
3.0.x | 3.0.1 | lib/python30/PYSTAF.so |
3.1.x | 3.1.2 | lib/python31/PYSTAF.so |
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.2.x (default) | 2.2.3 | lib/python22/PYSTAF.so |
2.3.x | 2.3.5 | lib/python23/PYSTAF.so |
2.4.x | 2.4.4 | lib/python24/PYSTAF.so |
2.5.x | 2.5.4 | lib/python25/PYSTAF.so |
2.6.x | 2.6.2 | lib/python26/PYSTAF.so |
2.7.x | 2.7.0 | lib/python27/PYSTAF.so |
3.0.x | 3.0.1 | lib/python30/PYSTAF.so |
3.1.x | 3.1.2 | lib/python31/PYSTAF.so |
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.2.x (default) | 2.2.3 | lib/python22/PYSTAF.so |
2.3.x | 2.3.5 | lib/python23/PYSTAF.so |
2.4.x | 2.4.4 | lib/python24/PYSTAF.so |
2.5.x | 2.5.4 | lib/python25/PYSTAF.so |
2.6.x | 2.6.2 | lib/python26/PYSTAF.so |
2.7.x | 2.7.0 | lib/python27/PYSTAF.so |
3.0.x | 3.0.1 | lib/python30/PYSTAF.so |
3.1.x | 3.1.2 | lib/python31/PYSTAF.so |
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.2.x (default) | 2.2.3 | lib/python22/PYSTAF.so |
2.3.x | 2.3.5 | lib/python23/PYSTAF.so |
2.4.x | 2.4.4 | lib/python24/PYSTAF.so |
2.5.x | 2.5.4 | lib/python25/PYSTAF.so |
2.6.x | 2.6.2 | lib/python26/PYSTAF.so |
2.7.x | 2.7.0 | lib/python27/PYSTAF.so |
3.0.x | 3.0.1 | lib/python30/PYSTAF.so |
3.1.x | 3.1.2 | lib/python31/PYSTAF.so |
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.2.x (default) | 2.2.3 | lib/python22/PYSTAF.so |
2.3.x | 2.3.5 | lib/python23/PYSTAF.so |
2.4.x | 2.4.4 | lib/python24/PYSTAF.so |
2.5.x | 2.5.4 | lib/python25/PYSTAF.so |
2.6.x | 2.6.2 | lib/python26/PYSTAF.so |
2.7.x | 2.7.0 | lib/python27/PYSTAF.so |
3.0.x | 3.0.1 | lib/python30/PYSTAF.so |
3.1.x | 3.1.2 | lib/python31/PYSTAF.so |
Supported Python Version | Built with | PYSTAF library | 2.2.x | 2.2.3 | lib/python22/PYSTAF.so |
---|---|---|
2.3.x | 2.3.5 | lib/python23/PYSTAF.so |
2.4.x (default) | 2.4.4 | lib/python24/PYSTAF.so |
2.5.x | 2.5.4 | lib/python25/PYSTAF.so |
2.6.x | 2.6.2 | lib/python26/PYSTAF.so |
2.7.x | 2.7.0 | lib/python27/PYSTAF.so |
3.0.x | 3.0.1 | lib/python30/PYSTAF.so |
3.1.x | 3.1.2 | lib/python31/PYSTAF.so |
3.2.x | 3.2.6 | lib/python32/PYSTAF.so |
3.3.x | 3.3.6 | lib/python33/PYSTAF.so |
3.4.x | 3.4.3 | lib/python34/PYSTAF.so |
Supported Python Version | Built with | PYSTAF library |
---|---|---|
2.6.x (default) | 2.6.1 | lib/python26/PYSTAF.so |
2.7.x | 2.7.0 | lib/python27/PYSTAF.so |
3.1.x | 3.1.2 | lib/python31/PYSTAF.so |
If when using STAF Python support for Python 3.1 (or later) provided for Mac OS X (Universal), and /usr/local/Python-3.1/lib/libpython3.1.dylib does not exist (e.g. this Python library it is dependent on was not installed at this location on your Mac OS X system), you may get an error similar to the following when you try to import PySTAF:
Python 3.1.2 (default, Apr 19 2012, 00:55:09) [GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import PySTAF Fatal Python error: Interpreter not initialized (version mismatch?) Abort trap: 6Run dyldinfo -dylibs on the lib/python27/PYSTAF.so file to see its dylibs dependencies. For example:
# dyldinfo -dylibs /Library/staf/lib/python27/PYSTAF.so for arch i386: attributes dependent dylibs /opt/dev/autobuild/build/rel/macosx/staf/retail/lib/libSTAF.dylib /usr/local/Python-3.1/lib/libpython3.1.dylib /usr/lib/libSystem.B.dylib /usr/lib/libc++.1.dylib for arch x86_64: attributes dependent dylibs /opt/dev/autobuild/build/rel/macosx/staf/retail/lib/libSTAF.dylib /usr/local/Python-3.1/lib/libpython3.1.dylib /usr/lib/libSystem.B.dylib /usr/lib/libc++.1.dylibSo, PYSTAF.so requires that /usr/local/Python-3.1/lib/libpython3.1.dylib exists. If it does not (e.g. because the Python 3.1 libraries were installed in a different location on your Mac OS X system), you can resolve this problem by creating a symbolic link in this spot pointing to the actual location of libpython3.1.dylib on your system.
Note that STAF Mac OS X (Universal) binaries provided on SourceForge were built on a Mac OS X 10.10 system where Python 3.1 was built from Python source into /usr/local/Python-3.1 and this resulted in libpython3.1.dylib being created in /usr/local/Python-3.1/lib.
Another workaround would be to build STAF support for Python on your Mac OS X
system yourself so that you don't have this issue. See the
STAF Developer's Guide for more information on building STAF core and STAF
support for Python.
Once STAF Python support is installed, verify that the STAF Python library file exists:
The library file for the version of Python that was selected as the default Python version during the STAF installation will either have a link in {STAF/Config/STAFRoot}/lib (on Unix) or a copy in {STAF/Config/STAFRoot}/bin on Windows.
export PYTHONPATH=/usr/local/staf/lib:$PYTHONPATH
export PYTHONPATH=/Library/staf/lib:$PYTHONPATH
set PYTHONPATH=C:\STAF\bin;%PYTHONPATH%
from PySTAF import *
The PySTAFv3 module provides the base level of support for Python 3.x scripts to call into STAF.
These packages externalize some classes, utility functions, and constants. Whether you are using Python 2.x or Python 3.x, usage of these classes, utility functions, and constants is exactly the same. In your Python script, just make sure to import the version that corresponds to the version of Python you are using (i.e use PySTAF with Python 2.x, and use PySTAFv3 with Python 3.x).
The STAF Python classes that it externalizes are:
The STAF Python functions that it externalizes are:
from PySTAF import *
To use this module with Python 3.x you simply import it like so:
from PySTAFv3 import *
Since the STAF Python libraries include several files with "PYSTAF" as their file name (with varying cases, i.e. PySTAF, PYSTAF), make sure that you are not using the "PYTHONCASEOK" environment variable. For example, if you have it set as "PYTHONCASEOK=1" and then try to use the STAF Python libraries, you will get the following error:
Traceback (most recent call last): File "TestPython.py", line 9, in ? from PySTAF import * ImportError: dynamic module does not define init function (initPySTAF)
To correct this error, set "PYTHONCASEOK=".
There are two ways to create a STAFHandle instance object:
If a STAFHandle instance object could not be created, an instance of STAFException is generated.
The required argument handleNameOrHandle specifies a handle name or number. If you specify a standard handle type (the default), this argument must be a string containing a name for the STAF handle to be created. If you specify a static handle type, this argument must be an integer containing the handle number for an existing static STAF handle.
The optional argument handleType specifies the type of handle. The valid handle types are:
Once you have a valid STAFHandle instance object, you can begin submitting requests to STAF services. To do this, you use the submit() method, to which you specify the machine and service which should handle the request, as well as the request string itself.
Before the Python script exits, it should unregister with STAF by calling the unregister() method.
STAFHandle defines the following member variables. They are initialized by the constructor, and should not be modified directly.
Since: STAF V3.3.1
STAFHandle defines the following methods:
The required argument location specifies the endpoint of the machine where the service is registered.
The required argument service specifies the name of the service to submit the request to.
The required argument request specifies the request to submit to the service.
The optional argument mode specifies the mode to use when submitting the request. The default is STAFHandle.Synchronous. Other possible values are:
The required argument flag should be 0 to disable auto-unmarshalling or 1 to enable auto-unmarshalling.
Since: STAF V3.3.1.
Returns 0 if auto-unmarshalling is disabled or 1 if auto-unmarshalling is enabled.
Since: STAF V3.3.1.
STAFHandle defines the following constants:
# STAFHandle types Standard = 0 Static = 1 # Modes for submit call Synchronous = 0 FireAndForget = 1 Queue = 2 Retain = 3 QueueRetain = 4Note, you can obtain more information on standard vs. static handles and the various submission modes in the C API reference in the STAF User's Guide.
from PySTAF import * import sys try: handle = STAFHandle("MyTest") except STAFException, e: print "Error registering with STAF, RC: %d" % e.rc sys.exit(e.rc) result = handle.submit("local", "ping", "ping") if (result.rc != 0): print "Error submitting request, RC: %d, Result: %s" % (result.rc, result.result) result = handle.submit("local", "var", "resolve string {STAF/Config/OS/Name}") if (result.rc != 0): print "Error submitting request, RC: %d, Result: %s" % (result.rc, result.result) else: print "OS Name: %s" % result.result rc = handle.unregister() sys.exit(rc)The following is the same Python script, written to support Python 3.x.
from PySTAFv3 import * import sys try: handle = STAFHandle("MyTest") except STAFException as e: print("Error registering with STAF, RC: %d" % e.rc) sys.exit(e.rc) result = handle.submit("local", "ping", "ping") if (result.rc != 0): print("Error submitting request, RC: %d, Result: %s" % (result.rc, result.result)) result = handle.submit("local", "var", "resolve string {STAF/Config/OS/Name}") if (result.rc != 0): print("Error submitting request, RC: %d, Result: %s" % (result.rc, result.result)) else: print("OS Name: %s" % result.result) rc = handle.unregister() sys.exit(rc)Note that the remaining examples in this document will show scripts that support Python 2.x.
The following is an example of a program which registers with STAF using
a static STAF handle. Note that a static handle is a handle which can be
shared by several processes on the same system. See the STAF User's Guide
for more information on static handles. Generally, you don't need to use
a static STAF handle.
from PySTAF import *
# First, need to obtain an existing static handle number from somewhere.
# This example assumes that this Python program will be run by submitting
# a START request to the STAF PROCESS service using the STATICHANDLENAME
# option. This allows it to obtain the STAF static handle number from
# environment variable STAF_STATIC_HANDLE.
#
# Note: Another way a static handle could have been obtained is if it
# is passed to the Python program as an argument. The static handle
# could have been created by another program (which submitted a CREATE
# HANDLE request to the HANDLE service).
import os
staticHandleNumber = os.environ.get('STAF_STATIC_HANDLE')
if staticHandleNumber == None:
print "Error: STAF_STATIC_HANDLE environment variable does not exist"
sys.exit(1)
staticHandleNumber = int(staticHandleNumber)
print "Using STAF static handle %s" % (staticHandleNumber)
# Register with STAF using a static STAF handle that already exists
try:
handle = STAFHandle(staticHandleNumber, STAFHandle.Static)
except STAFException, e:
print "Error registering with STAF, RC: %d" % e.rc
sys.exit(e.rc)
result = handle.submit("local", "ping", "ping")
if (result.rc != 0):
print "Error submitting request, RC: %d, Result: %s" % (result.rc, result.result)
This class encapsulates the result of a STAF service request (made via the STAFHandle.submit() method). This class also contains a set of constants representing the various common STAF return codes. It has two constructors:
STAFResult defines the following member variables. They are initialized by the constructor, and should not be modified directly.
Note: This variable was added in STAF V3.3.1.
Note: This variable was added in STAF V3.3.1.
STAFResult defines the following constants representing the various common STAF return codes.
Ok = 0 InvalidAPI = 1 UnknownService = 2 InvalidHandle = 3 HandleAlreadyExists = 4 HandleDoesNotExist = 5 UnknownError = 6 InvalidRequestString = 7 InvalidServiceResult = 8 REXXError = 9 BaseOSError = 10 ProcessAlreadyComplete = 11 ProcessNotComplete = 12 VariableDoesNotExist = 13 UnResolvableString = 14 InvalidResolveString = 15 NoPathToMachine = 16 FileOpenError = 17 FileReadError = 18 FileWriteError = 19 FileDeleteError = 20 STAFNotRunning = 21 CommunicationError = 22 TrusteeDoesNotExist = 23 InvalidTrustLevel = 24 AccessDenied = 25 STAFRegistrationError = 26 ServiceConfigurationError = 27 QueueFull = 28 NoQueueElement = 29 NotifieeDoesNotExist = 30 InvalidAPILevel = 31 ServiceNotUnregisterable = 32 ServiceNotAvailable = 33 SemaphoreDoesNotExist = 34 NotSemaphoreOwner = 35 SemaphoreHasPendingRequests = 36 Timeout = 37 JavaError = 38 ConverterError = 39 InvalidObject = 41 InvalidParm = 42 RequestNumberNotFound = 43 InvalidAsynchOption = 44 RequestNotComplete = 45 ProcessAuthenticationDenied = 46 InvalidValue = 47 DoesNotExist = 48 AlreadyExists = 49 DirectoryNotEmpty = 50 DirectoryCopyError = 51 DiagnosticsNotEnabled = 52 HandleAuthenticationDenied = 53 HandleAlreadyAuthenticated = 54 InvalidSTAFVersion = 55 RequestCancelled = 56 CreateThreadError = 57 MaximumSizeExceeded = 58 MaximumHandlesExceeded = 59
# The variable "handle" is an instance of the STAFHandle class that was # previously instantiated result = handle.submit("local", "ping", "ping") print "Ping request RC: %d" % result.rc print "Ping request result buffer: %s" % result.result
# The variable "handle" is an instance of the STAFHandle class that was # previously instantiated dirName = "{STAF/Config/STAFRoot}/bin"; request = "LIST DIRECTORY " + wrapData(dirName) + " TYPE F LONG"; result = handle.submit("local", "FS", request); print "LIST DIRECTORY request RC: %d" % result.rc print "LIST DIRECTORY result context: %s" % result.resultContext list = result.resultObj print "LIST DIRECTORY result contains %s entries" % len(list)
The optional argument rc specifies the numeric return code which
is the basis of the exception. The default is 0.
The optional argument result specifies a string which further
describes the exception. The default is "".
STAFException defines the following member variables. They are initialized by the constructor, and should not be modified directly.
from PySTAF import * import sys try: handle = STAFHandle("MyTest") except STAFException, e: print "Error registering with STAF, RC: %d" % e.rc
Note that STAFWrapData is an alias for the wrapData function and can be used instead to call this function.
outputString = wrapData("Hello world")
semName = "My Synch Sem" result = handle.submit("local", "sem", "event %s post" % wrapData(semName))
These APIs allow you to define, manipulate, and (un)marshall data structures, and print marshalled data in human-readable ("pretty" print) format.
STAF supports the automatic marshalling and unmarshalling of structured data. The act of marshalling takes a data structure and converts it into a string-based representation. The act of unmarshalling reverses this and converts the string-based representation back into a data structure. See Section 6.1, "Marshalling Structured Data" in the STAF User's Guide for more information.
The optional keyword argument name specifies the name of the STAF map class definition. The default is None.
STAFMapClassDefinition defines the following methods:
The required keyword argument keyName specifies the name of a key.
The optional keyword argument displayName specifies a string to use when displaying the key. The default is None which indicates to use the actual key name when displaying the key.
The required keyword argument keyName specifies the name of a key for which this property is being set.
The required keyword argument property specifies the name of the property being set. The only property name currently recognized is 'display-short-name' which is used by the STAF executable when displaying a result in a tabular format when the length of the values for the fields is less than the length of the 'display-name'.
The required keyword argument value specifies the value for the property being set.
myMapClassDef = STAFMapClassDefinition('Test/MyMap') myMapClassDef.addKey('name', 'Name') myMapClassDef.addKey('exec', 'Executable') myMapClassDef.addKey('testType', 'Test Type') myMapClassDef.setKeyProperty('testType', 'display-short-name', 'Test') myMapClassDef.addKey('outputList', 'Outputs') print "The keys for map class definition '%s' are:" % (myMapClassDef.name()) print formatObject(myMapClassDef.keys())
The keys for map class definition 'Test/MyMap' are: [ { display-name: Name key : name } { display-name: Executable key : exec } { display-name : Test Type key : testType display-short-name: Test } { display-name: Outputs key : outputList } ]
In order to use a map class when marshalling data, you must add the map class definition to the marshalling context, set the root object of the marshalling context to the object you want to marshall, and then marshall the marshalling context itself. When you unmarshall a data structure, you will always receive a marshalling context. Any map class definitions referenced by map classes within the data structure will be present in the marshalling context.
The primary use of this class is to represent multi-valued results that consist of a data structure (e.g. results from a QUERY/LIST service request, etc.) as a string that can also be converted back into the data structure. This string can be assigned to the string result buffer returned from the service request.
The optional keyword argument obj specifies the root object to be marshalled. The default is None.
STAFMarshallingContext defines the following methods:
The required argument mapClassDef specifies a STAFMapClassDefinition object that can be used when marshalling the object. You may call this method any number of times to set multiple STAFMapClassDefinition objects for the marshalling context.
The required argument mapClassName specifies a string containing the name of the STAFMapClassDefinition object that you want to return.
The required argument mapClassName specifies a string containing the name of the STAFMapClassDefinition object that you want to check if the marshalling context's contains in its list of map class defintions.
The required argument rootObject can specify any object.
# Create a map class definition myMapClassDef = STAFMapClassDefinition('Test/MyMap') myMapClassDef.addKey('name', 'Name') myMapClassDef.addKey('exec', 'Executable') testList = [ {'name': 'TestA', 'exec': '/tests/TestA.py'}, {'name': 'TestB', 'exec': '/tests/TestB.sh'}, {'name': 'TestC', 'exec': '/tests/TestC.cmd'} ] # Create a marshalling context with testList mc = STAFMarshallingContext() mc.setMapClassDefinition(myMapClassDef) myTestList = [] for test in testList: testMap = myMapClassDef.createInstance() testMap['name'] = test['name'] testMap['exec'] = test['exec'] myTestList.append(testMap) mc.setRootObject(myTestList) print 'Test List:\n%s' % (mc) # Create a string from the marshalling context # This string could be a message that you log or send to a queue, etc. stringResult = mc.marshall() # Convert the marshalled string representation back into a list mc2 = unmarshall(stringResult) theTestList = mc2.getRootObject()
Test List: [ { Name : TestA Executable: /tests/TestA.py } { Name : TestB Executable: /tests/TestB.sh } { Name : TestC Executable: /tests/TestC.cmd } ]
if isMarshalledData(result.result): mc = unmarshall(result.result)
The default for optional keyword argument context is None.
Note, normally you would use a STAFMarshallingContext object's marshall() method instead of this function.
myTestMap = {'name': 'TestA', 'exec': '/tests/TestA.py', 'testType': 'FVT', 'outputs': ['TestA.out', 'TestA.err']} message = marshall(myTestMap) result = handle.submit('local', 'QUEUE', 'QUEUE MESSAGE %s' % message) if result.rc != STAFResult.Ok: print 'QUEUE MESSAGE failed with RC=%s Result=%s' % (result.rc, result.result) sys.exit(result.rc) # Another process could obtain the message from the queue and unmarshall # it to get the original dictionary (map) object result = handle.submit('local', 'QUEUE', 'GET') # Note that if auto-unmarshalling is enabled for a handle, which it is # by default, you don't have to unmarshall the STAFResult's result string # returned by the submit() method. Instead, you can directly access the # the result's marshalling context, result.resultContext, and/or the root # object of the result's marshalling context, result.resultObj. if result.rc == STAFResult.Ok: mc = unmarshall(result.result) yourTestMap = mc.getRootObject() print 'Received following message:\n%s\n' % (mc) else: print 'QUEUE GET failed with RC=%s Result=%s\n' % (result.rc, result.result) sys.exit(result.rc);
This example creates a marshalling context with one map class definition and a Python list where each entry is a map. It then creates a string-based marshalled representation of it.
myMapClassDef = STAFMapClassDefinition('Test/MyMap') myMapClassDef.addKey('name', 'Name') myMapClassDef.addKey('exec', 'Executable') testList = [ {'name': 'TestA', 'exec': '/tests/TestA.py'}, {'name': 'TestB', 'exec': '/tests/TestB.sh'}, {'name': 'TestC', 'exec': '/tests/TestC.cmd'} ] mc = STAFMarshallingContext() mc.setMapClassDefinition(myMapClassDef) myTestList = [] for test in testList: testMap = myMapClassDef.createInstance() testMap['name'] = test['name'] testMap['exec'] = test['exec'] myTestList.append(testMap) print 'Test List:\n%s' % (STAFFormatObject(myTestList, mc)) message = marshall(myTestList, mc)
The required keyword argument data is a string to be unmarshalled.
The optional keyword argument context specifies the STAFMarshallingContext object that should be used when generating when unmarshalling the string. The default is None.
The optional keyword argument flags can be used to control how to unmarshall the string. When a string is unmarshalled into a data structure, it is possible that one of the string objects that is unmarshalled is itself the string form of another marshalled data structure. The default is UNMARSHALLING_DEFAULTS which will recursively unmarshall these nested objects. Use IGNORE_INDIRECT_OBJECTS to disable this additional processing.
fileName = 'C:/tests/testA' result = handle.submit('local', 'FS', 'QUERY ENTRY %s' % fileName) if result.rc != STAFResult.Ok: print 'FS QUERY ENTRY %s failed' % fileName print 'RC=%s Result=%s' % (result.rc, result,result) sys.exit(1) # Note that if auto-unmarshalling is enabled for a handle, which it is # by default, you don't have to unmarshall the STAFResult's result string # returned by the submit() method. Instead, you can directly access the # the result's marshalling context, result.resultContext, and/or the root # object of the result's marshalling context, result.resultObj. mc = unmarshall(result.result) entryMap = mc.getRootObject() if entryMap['type'] == 'F': print 'File %s has size %s and was last modified on %s' % \ (fileName, entryMap['lowerSize'], entryMap['lastModifiedTimestamp']) else: print '%s is not a file. Type=%s' % entryMap['type']
The required keyword argument obj specifies the object to be formatted in a verbose, more readable format.
The optional keyword argument context specifies the STAFMarshallingContext object that should be used when generating the "pretty print" output. The default is None.
myTestMap = {'name': 'TestA', 'exec': '/tests/TestA.py', 'testType': 'FVT', 'outputs': ['TestA.out', 'TestA.err']} print formatObject(myTestMap)
{ outputs : [ TestA.out TestA.err ] testType: FVT name : TestA exec : /tests/TestA.py }
This example prints the result from a FS QUERY ENTRY request in a "pretty" verbose format:
fileName = '{STAF/Config/ConfigFile}' request = 'QUERY ENTRY %s' % (fileName) result = handle.submit('local', 'FS', request) if result.rc != STAFResult.Ok: print 'Request failed: STAF local FS %s' % (request) print 'RC=%s Result=%s' % (result.rc, result.result) sys.exit(1) print 'Formatted output:\n%s' % formatObject(result.resultObj, result.resultContext)
Formatted output: { Name : c:\staf\bin\STAF.cfg Type : F Upper 32-bit Size : 0 Lower 32-bit Size : 5902 Modified Date-Time: 20050322-11:07:02 }
print 'Formatted output:\n%s' % (result.resultContext)
These APIs allow you to handle private data. See Section 7.3, "Private Data" in the STAF User's Guide for more information about handling private data.
This method should be used by anyone who wants to protect private data specified in a STAF command option that supports handling private data.
Required argument data is a String that contains data you want to protect.
Returns a String object containing the string with opening and closing privacy delimiters added and escapes any privacy delimiters already contained in the string with a caret (^). If the string has length 0 or already has an unescaped opening privacy delimiter at the beginning and an unescaped closing privacy delimiter at the end, privacy delimiters are not added.
Examples:
Since: STAF V3.1.0
Note that STAFAddPrivacyDelimiters is an alias for the addPrivacyDelimiters function and can be used instead to call this function.
password = addPrivacyDelimiters('passw0rd') request = 'START SHELL COMMAND C:/tests/TestA USERNAME Test1 PASSWORD %s' % (password) result = handle.submit('local', 'PROCESS', request);
command = 'C:/tests/admin -password %s' % (addPrivacyDelimiters('secret')) request = 'START SHELL COMMAND %s" % (wrapData(command)) result = handle.submit('local', "PROCESS", request)
This method should be used before calling the addPrivacyDelimiters method for data that needs to be protected but may contain substrings !!@ and/or @!! that should not be mistaken for privacy delimiters .
Required argument data is a String.
Returns a String object containing the updated data.
For example, if the data is 'passw@!!d', this method would return 'passw^@!!d'.
Since: STAF V3.1.0
Note that STAFEscapePrivacyDelimiters is an alias for the escapePrivacyDelimiters function and can be used instead to call this function.
password = addPrivacyDelimiters(escapePrivacyDelimiters('passw@!!d')) request = 'START SHELL COMMAND C:/tests/TestA USERNAME Test1 PASSWORD %s' % (password) result = handle.submit('local', 'PROCESS', request);
Required argument data is a String that may contain privacy delimiters (e.g. !!@, @!!).
Optional argument numLevels in an int that specifies the number of levels of privacy data to remove. The default is 0 which indicates to remove all levels of privacy data. Note that, generally, you'll want to remove all levels of privacy delimiters.
Returns a String object containing the updated data with privacy delimiters removed.
Examples:
Since: STAF V3.1.0
Note that STAFRemovePrivacyDelimiters is an alias for the removePrivacyDelimiters function and can be used instead to call this function.
protectedPassword = '!!@secret@!!' password = removePrivacyDelimiters(protectedPassword)
Required argument data is a String that may contain privacy delimiters (e.g. !!@, @!!).
Returns a String object containing the string with any private data masked.
Examples:
Since: STAF V3.1.0
Note that STAFMaskPrivateData is an alias for the maskPrivateData function and can be used instead to call this function.
request = 'START COMMAND C:/tests/TestA.exe USERNAME Test1 PASSWORD %s' % \ (addPrivacyDelimiters('passw0rd')) print maskPrivateData(request)
from PySTAFMon import *
The required keyword argument stafHandle specifies the STAF handle to use to submit the request to the Monitor service.
The optional keyword argument system specifies the endpoint of the machine to submit the request to. The default is "local".
The optional keyword argument service specifies the registered name of the STAF Monitor service. The default is "Monitor".
Note: By default, the STAFMonitor class will use the service named "Monitor" on the local system. This can be changed by explicitly specifying the system and/or service when you construct the STAFMonitor object.
STAFMonitor defines the following methods:
The required keyword argument message specifies the message to log.
from PySTAFMon import * # The variable "handle" is an instance of the STAFHandle class that was # previously instantiated monitor = STAFMonitor(handle) result = monitor.log("Beginning section ABC of test")
from PySTAFLog import *
The required keyword argument handle specifies the STAF handle to use to submit the request to the Log service.
The required keyword argument logType specifies the log type (e.g. STAFLog.Global, STAFLog.Machine, or STAFLog.Handle)
The required keyword argument name specifies the name of the log.
The optional keyword argument monitorMask specifies a mask that consists of a list of logging levels. This list controls which messages are also sent to the Monitor service. The default is to enable "Fatal", "Error", "Warning", "Start", "Stop", "Pass", and "Fail". If there is an error logging, STAFLog will also try to send an error to the Monitor service.
The optional keyword argument system specifies the endpoint of the machine to submit the log request to. The default is "local".
The optional keyword argument service specifies the registered name of the STAF Log service. The default is "Log".
Note: By default, the STAFLog class will use the service named "Log" on the local system. This can be changed by explicitly specifying the system and/or service when you construct the STAFLog object.
STAFLog defines the following methods:
The required keyword argument level specifies the logging level (e.g. STAFLog.Info, STAFLog.Error, etc.
The required keyword argument message specifies the message to log.
STAFLog defines the following constants:
# Log type constants Global = "GLOBAL" Machine = "MACHINE" Handle = "HANDLE" # Log level constants Fatal = "Fatal" Error = "Error" Warning = "Warning" Info = "Info" Trace = "Trace" Trace2 = "Trace2" Trace3 = "Trace3" Debug = "Debug" Debug2 = "Debug2" Debug3 = "Debug3" Start = "Start" Stop = "Stop" Pass = "Pass" Fail = "Fail" Status = "Status" User1 = "User1" User2 = "User2" User3 = "User3" User4 = "User4" User5 = "User5" User6 = "User6" User7 = "User7" User8 = "User8" # Log service return codes InvalidLevel = 4004 InvalidLogFileFormat = 4007 PurgeFailure = 4008
from PySTAFLog import * # The variable "handle" is an instance of the STAFHandle class that was # previously instantiated # Let's create a machine based log file that also sends fatal, error, and # warning messages to the Monitor service log = STAFLog(handle, STAFLog.Machine, "MyLog", [STAFLog.Fatal, STAFLog.Error, STAFLog.Warning]) # This message will only go to the log service, since we didn't specify # that start message get sent to the Monitor service result = log.log(STAFLog.Start, "Beginning ABC test") # This message will be sent to the Log and Monitor services result = log.log(STAFLog.Warning, "Got some ambiguous result")
This example shows a Python program that tests most of the STAF Python APIs.
The source code for this program is provided in the STAF source code directory tree at src/staf/lang/python/TestPython.py. See section "Obtaining the STAF Source Code" in the STAF Developer's Guide for instructions on how to download STAF source code.
Note that a version of this script for Python 3.x is provided in the STAF source code directory tree at src/staf/lang/python/TestPythonV3.py.
############################################################################# # Software Testing Automation Framework (STAF) # # (C) Copyright IBM Corp. 2001, 2005 # # # # This software is licensed under the Eclipse Public License (EPL) V1.0. # ############################################################################# # This file contains tests for the STAF Python support from PySTAF import * from PySTAFMon import * from PySTAFLog import * import string import sys ############################################## # Test the STAFHandle and STAFResult classes # ############################################## print "Testing the STAFHandle constructor" # Verify get error if specify an integer for handle name when # registering using a static STAF Handle typeError = 0 try: handle = STAFHandle(1) except STAFException, e: print "Error registering with STAF, RC: %d, Result: %s" % (e.rc, e.result) sys.exit(e.rc) except TypeError, e: typeError = 1 #print "Got expected TypeError: %s" % (e) if typeError != 1: print "Did not get expected TypeError when specifying an invalid handle name" sys.exit(1) # Verify get error if specify a non-integer for handle number when # registering using a static STAF Handle typeError = 0 try: handle = STAFHandle("MyHandle", STAFHandle.Static) except STAFException, e: print "Error registering with STAF, RC: %d, Result: %s" % (e.rc, e.result) sys.exit(e.rc) except TypeError, e: typeError = 1 #print "Got expected Type Error: %s" % (e) if typeError != 1: print "Did not get expected TypeError when specifying an invalid handle number" sys.exit(1) # Verify creating a standard handle works and then use it to submit requests print "Testing creating a standard handle and using it to submit requests" try: handle = STAFHandle("Lang/Python/Test/Basic") except STAFException, e: print "Error registering with STAF, RC: %d" % e.rc sys.exit(e.rc) print "Using standard handle %d" % handle.handle print "Testing submitting requests using a standard handle" result = handle.submit("local", "ping", "ping") if ((result.rc != STAFResult.Ok) or (result.result != "PONG")): print "Error on ping request." print "Expected RC: 0, Result: PONG" print "Received RC: %d, Result: %s" % (result.rc, result.result) sys.exit(1) result = handle.submit("local", "var", "resolve string {STAF/Config/MachineNickname}") if (result.rc != STAFResult.Ok): print "Error resolving machine nickname, RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) self = result.result # Verify creating a static handle works print "Testing creating a reference to a static handle that exists" result = handle.submit("local", "HANDLE", "CREATE HANDLE NAME TestPython"); if (result.rc != STAFResult.Ok): print "Error on create handle request." print "Expected RC: 0, Result: <A Number>" print "Received RC: %d, Result: %s" % (result.rc, result.result) sys.exit(1) staticHandleNumber = int(result.result) print "Using static handle %s" % (staticHandleNumber) try: staticHandle = STAFHandle(staticHandleNumber, STAFHandle.Static) except STAFException, e: print "Error registering a static handle with STAF, RC: %d" % e.rc sys.exit(e.rc) if staticHandle.handle != staticHandleNumber: print "Invalid static handle number %s. Expected %s." % \ (staticHandle.handle, staticHandleNumber) if staticHandle.handleType != STAFHandle.Static: print "Invalid handle type %s. Expected %s." % \ (staticHandle.handleType, STAFHandle.Static) print "Testing submitting requests using a static handle" result = staticHandle.submit("local", "PING", "PING") if (result.rc != 0) or (result.result != "PONG"): print "Error submitting request, RC: %d, Result: %s" % (result.rc, result.result) sys.exit(result.rc) # Verify doUnmarshallingResult defaults to 1 when creating a static handle if staticHandle.getDoUnmarshallResult() != 1: print "ERROR: staticHandle.getDoUnmarshallResult() != 1" print 'Found: %s' % (staticHandle.getDoUnmarshallResult()) sys.exit(1) print "Unregister and delete static handle %s" % (staticHandleNumber) try: staticHandle.unregister() except STAFException, e: print "Error unregistering static handle with STAF, RC: %d" % e.rc sys.exit(e.rc) result = handle.submit("local", "HANDLE", "DELETE HANDLE %s" % (staticHandleNumber)) if (result.rc != STAFResult.Ok): print "Error deleting static handle." print "Expected RC: 0" print "Received RC: %d, Result: %s" % (result.rc, result.result) sys.exit(1) result = handle.submit("local", "HANDLE", "QUERY HANDLE %s" % (staticHandleNumber)) if (result.rc != STAFResult.HandleDoesNotExist): print "ERROR: Static handle %s still exists after being deleted." print "Expected RC: %s, Result: %s" % (STAFResult.HandleDoesNotExist, staticHandleNumber) print "Received RC: %d, Result: %s" % (result.rc, result.result) sys.exit(1) print "\nVerify that auto-unmarshalling result is turned on by default" # Test the STAFHandle.getDoUnmarshallResult API if handle.getDoUnmarshallResult() != 1: print "ERROR: handle.getDoUnmarshallResult() != 1" print 'Found: %s' % (handle.getDoUnmarshallResult()) sys.exit(1) request = "WHOAMI" result = handle.submit("local", "MISC", request) if (result.rc != STAFResult.Ok): print "Error on MISC WHOAMI requst, RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) # Make sure that the resultContext and resultObj variables in the # STAFResult class were set correctly since auto-unmarshalling result is on if result.resultContext.getRootObject() != unmarshall(result.result).getRootObject(): print 'STAFResult resultContext variable is not set correctly.' print 'Expected:\n%s' % (unmarshall(result.result)) print 'Found:\n%s' % (result.resultContext) sys.exit(1) if result.resultObj != unmarshall(result.result).getRootObject(): print 'STAFResult resultObj variable is not set correctly.' print 'Expected:\n%s' % (unmarshall(result.result).getRootObject()) print 'Found:\n%s' % (result.resultObj) sys.exit(1) # Make sure that if turn off auto-unmarshalling result that the # resultContext and resultObj variables are set to None since # auto-unmarshalling result is off # Test the STAFHandle.setDoUnmarshallResult API print "Turn off auto-unmarshalling result" handle.setDoUnmarshallResult(0) if handle.getDoUnmarshallResult() != 0: print "ERROR: handle.getDoUnmarshallResult() != 0" print 'Found: %s' % (handle.getDoUnmarshallResult()) sys.exit(1) result = handle.submit("local", "MISC", request) if (result.rc != STAFResult.Ok): print "Error on MISC WHOAMI requst, RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) if result.resultContext != None: print 'STAFResult resultContext variable != None' print 'Found:\n%s' % (result.resultContext) sys.exit(1) if result.resultObj != None: print 'STAFResult resultObj variable != None' print 'Found:\n%s' % (result.resultObj) sys.exit(1) # Test if pass in any true value to setDoUnmarshallResult() that # getDoUnmarshallResult returns 1 handle.setDoUnmarshallResult("true"); if handle.getDoUnmarshallResult() != 1: print "ERROR: handle.getDoUnmarshallResult() != 1" print 'Found: %s' % (handle.getDoUnmarshallResult()) sys.exit(1) # Test if pass in any false value to setDoUnmarshallResult() that # getDoUnmarshallResult returns 0 handle.setDoUnmarshallResult(""); if handle.getDoUnmarshallResult() != 0: print "ERROR: handle.getDoUnmarshallResult() != 0" print 'Found: %s' % (handle.getDoUnmarshallResult()) sys.exit(1) # Make sure that if turn on auto-unmarshalling result that the # resultContext and resultObj variables are set correctly since # auto-unmarshalling result is on print "Turn on auto-unmarshalling result" handle.setDoUnmarshallResult(1) if handle.getDoUnmarshallResult() != 1: print "ERROR: handle.getDoUnmarshallResult() != 1" print 'Found: %s' % (handle.getDoUnmarshallResult()) sys.exit(1) result = handle.submit("local", "MISC", request) if (result.rc != STAFResult.Ok): print "Error on MISC WHOAMI requst, RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) # Make sure that the resultContext and resultObj variables in the # STAFResult class were set correctly if result.resultContext.getRootObject() != unmarshall(result.result).getRootObject(): print 'STAFResult resultContext variable is not set correctly.' print 'Expected:\n%s' % (unmarshall(result.result)) print 'Found:\n%s' % (result.resultContext) sys.exit(1) if result.resultObj != unmarshall(result.result).getRootObject(): print 'STAFResult resultObj variable is not set correctly.' print 'Expected:\n%s' % (unmarshall(result.result).getRootObject()) print 'Found:\n%s' % (result.resultObj) sys.exit(1) ############################################### # Next, lets test the monitor service wrapper # ############################################### print "\nTesting Monitor service functions" # Log the message monitor = STAFMonitor(handle) monitorMessage = "Hello World" result = monitor.log(monitorMessage) if (result.rc != STAFResult.Ok): print "Error on STAFMonitorDoLog, RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) # Try to retrieve it request = "query machine %s handle %d" % (self, handle.handle) result = handle.submit("local", "monitor", request) if (result.rc != STAFResult.Ok): print "Error querying monitor info, RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) # Make sure we got back the correct message monitorMap = result.resultObj if monitorMap['message'] != monitorMessage: print "Wrong output for MONITOR QUERY request" print "Expected to find:" print "{" print " Date-Time: <Timestamp>" print " Message : %s" % (monitorMessage) print "}" print "Found:\n%s" % context sys.exit(1) ############################################## # Finally, lets test the log service wrapper # ############################################## print "Testing Log service functions" logName = "PythonTest" # Setup logging log = STAFLog(handle, STAFLog.Handle, logName, [ STAFLog.Fatal, STAFLog.Error, STAFLog.Warning, STAFLog.Info ]) # Log the message logMessage = "A log message" result = log.log(STAFLog.Info, logMessage) if (result.rc != STAFResult.Ok): print "Error on STAFLog.log(), RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) # Try to retrieve it request = "query machine %s handle %d logname %s" % \ (self, handle.handle, logName) result = handle.submit("local", "log", request) if (result.rc != STAFResult.Ok): print "Error on STAF LOG Service QUERY, RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) # Make sure we got back the correct message logRecordList = result.resultObj if (len(logRecordList) > 0 and logRecordList[len(logRecordList) - 1]['level'] == STAFLog.Info and logRecordList[len(logRecordList) - 1]['message'] == logMessage): logRecord = logRecordList[len(logRecordList) - 1] else: print "Wrong output for log query request" print "Expected to find one record with level: '%s' and message: '%s'" % \ (STAFLog.Info, logMessage) print "Found:\n'%s'" % context sys.exit(1) # Try to retrieve it from monitor request = "query machine %s handle %d" % (self, handle.handle) result = handle.submit("local", "monitor", request) if (result.rc != STAFResult.Ok): print "Error on querying monitor info, RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) # Make sure we got back the correct message from monitor monitorMap = result.resultObj if monitorMap['message'] != '%s:%s' % (STAFLog.Info, logMessage): print "Wrong output for MONITOR QUERY request" print "Expected to find:" print "{" print " Date-Time: <Timestamp>" print " Message : %s:%s" % (STAFLog.Info, logMessage) print "}" print "Found:\n%s" % context sys.exit(1) # Delete the log file request = "delete machine %s handle %d logname %s confirm" % \ (self, handle.handle, logName) result = handle.submit("local", "log", request) if (result.rc != STAFResult.Ok): print "Error deleting log file, RC: %s, Result: %s" % \ (result.rc, result.result) sys.exit(1) # Log the message so that Monitor shouldn't get it result = log.log(STAFLog.Status, logMessage) if (result.rc != STAFResult.Ok): print "Error on STAFLog.log(), RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) # Try to retrieve it request = "query machine %s handle %d logname %s" % \ (self, handle.handle, logName) result = handle.submit("local", "log", request) if (result.rc != STAFResult.Ok): print "Error on STAF LOG Service QUERY, RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) # Make sure we got back the correct message logRecordList = result.resultObj if (len(logRecordList) == 1 and logRecordList[0]['level'] == STAFLog.Status and logRecordList[0]['message'] == logMessage): logRecord = logRecordList[0] else: print "Wrong output for log query request" print "Expected to find one record with level: '%s' and message: '%s'" % \ (STAFLog.Status, logMessage) print "Found '%s'" % context sys.exit(1) # Try to retrieve it from monitor request = "query machine %s handle %d" % (self, handle.handle) result = handle.submit("local", "monitor", request) if (result.rc != STAFResult.Ok): print "Error on querying monitor info, RC: %d, Result: %s" % \ (result.rc, result.result) sys.exit(result.rc) # Make sure we got back the correct (old) message from monitor monitorMap = result.resultObj if monitorMap['message'] != '%s:%s' % (STAFLog.Info, logMessage): print "Wrong output for MONITOR QUERY request" print "Expected to find:" print "{" print " Date-Time: <Timestamp>" print " Message : %s:%s" % (STAFLog.Info, logMessage) print "}" print "Found:\n%s" % context sys.exit(1) # Delete the log file request = "delete machine %s handle %d logname %s confirm" % \ (self, handle.handle, logName) result = handle.submit("local", "log", request) if (result.rc != STAFResult.Ok): print "Error deleting log file, RC: %s, Result: %s" % \ (result.rc, result.result) sys.exit(1) ######################################## # Next, test the marshall function # ######################################## print "Testing marshall function" myTestMap = {'name': 'TestA', 'exec': '/tests/TestA.py', 'testType': 'FVT', 'outputs': ['TestA.out', 'TestA.err']} marshalledResult = marshall(myTestMap) expectedResult = ( "@SDT/{:138::7:outputs@SDT/[2:38:@SDT/$S:9:TestA.out" + "@SDT/$S:9:TestA.err:8:testType@SDT/$S:3:FVT:4:name" + "@SDT/$S:5:TestA:4:exec@SDT/$S:15:/tests/TestA.py") if marshalledResult != expectedResult: print "Wrong output for marshall function" print "Expected to find:\n%s" % (expectedResult) print "Found:\n%s" % (marshalledResult) sys.exit(1) ######################################### # Next, test the STAFMapClassDefinition # ######################################### print "Testing STAFMapClassDefinition class" mapClassDefName = 'Test/MyMap' myMapClassDef = STAFMapClassDefinition(mapClassDefName) myMapClassDef.addKey('name', 'Name') myMapClassDef.addKey('exec', 'Executable') myMapClassDef.addKey('testType', 'Test Type') myMapClassDef.setKeyProperty('testType', 'display-short-name', 'test') myMapClassDef.addKey('outputs', 'Outputs') expectedKeyMap = [ {'display-name': 'Name', 'key': 'name'}, {'display-name': 'Executable', 'key': 'exec'}, {'display-name': 'Test Type', 'key': 'testType', 'display-short-name': 'test'}, {'display-name': 'Outputs', 'key': 'outputs'} ] if myMapClassDef.keys() != expectedKeyMap: print "Wrong keys for myMapClassDef" print "Expected:\n%s" % (expectedKeyMap) print "Found:\n%s" % (myMapClassDef.keys()) sys.exit(1) if myMapClassDef.name() != mapClassDefName: print "Wrong name for myMapClassDef" print "Expected: %s" % (myClassDefName) print "Found : %s" % (myMapClassDef.name()) sys.exit(1) expectedMapClass = { 'keys': [ {'display-name': 'Name', 'key': 'name'}, {'display-name': 'Executable', 'key': 'exec'}, {'display-name': 'Test Type', 'key': 'testType', 'display-short-name': 'test'}, {'display-name': 'Outputs', 'key': 'outputs'} ], 'name': 'Test/MyMap' } if myMapClassDef.getMapClassDefinitionObject() != expectedMapClass: print "getMapClassDefinitionObject() returned wrong object" print "Expected:\n%s" % (expectedMapClass) print "Found:\n%s" % (myMapClassDef.getMapClassDefinitionObject()) sys.exit(1) myMapClass = myMapClassDef.createInstance() ######################################### # Next, test the STAFMarshallingContext # ######################################### print "Testing STAFMarshallingContext class" mc = STAFMarshallingContext() mc.setMapClassDefinition(myMapClassDef) theMapClassDef = mc.getMapClassDefinition('Test/MyMap') if theMapClassDef.keys() != expectedKeyMap: print "Wrong keys for theMapClassDef" print "Expected:\n%s" % (expectedKeyMap) print "Found:\n%s" % (theMapClassDef.keys()) sys.exit(1) if theMapClassDef.getMapClassDefinitionObject() != expectedMapClass: print "Error: getMapClassDefinitionObject() returned wrong object" print "Expected:\n%s" % (expectedMapClass) print "Found:\n%s" % (theMapClassDef.getMapClassDefinitionObject()) sys.exit(1) if mc.hasMapClassDefinition('Test/MyMap') != 1: print "Error: The marshalling context does not have map class definition 'Test/MyMap'" sys.exit(1) mc.setRootObject(myTestMap) rootObj = mc.getRootObject() if rootObj != myTestMap: print "Error: mc.getRootObject() returned wrong object" print "Expected:\n%s" % (myTestMap) print "Found:\n%s" % (rootObj) sys.exit(1) if isMarshalledData('xyz'): print "Error: 'xyz' is not marshalled data" sys.exit(1) if not mc.isMarshalledData(marshalledResult): print "Not marshalled data. marshalledResult=%s" % (marshalledResult) sys.exit(1) keyMap = mc.mapClassDefinitionIterator() if len(keyMap) == 1 and keyMap[0] == 'Test/MyMap': print '' else: print "Error: mc.mapClassDefinitionIterator() != ['Test/MapMap']" print "mc.mapClassDefinitionIterator()=%s" % mc.mapClassDefinitionIterator() sys.exit() priObj = mc.getPrimaryObject() if priObj != mc: print "Error: mc.getPrimaryObject() != mc" print "mc.getPrimaryObject()=%s" % (mc.getPrimaryObject()) print "mc=%s" % (mc) sys.exit() formattedOutput = '%s' % (mc) formattedOutput1 = mc.__str__() formattedOutput2 = mc.__repr__() formattedOutput3 = formatObject(myTestMap, mc) if (formattedOutput != formattedOutput1 or formattedOutput != formattedOutput2 or formattedOutput != formattedOutput3): print "Error in str(), repr(), or formatObject function" print "formattedOutput=%s" % (formattedOutput) print "formattedOutput1=%s" % (formattedOutput) print "formattedOutput2=%s" % (formattedOutput) print "formattedOutput3=%s" % (formattedOutput) sys.exit(1) # Test the marshall function using a MapClassDefinition expectedResult2 = ( "@SDT/*:558:@SDT/{:398::13:map-class-map@SDT/{:370::10:Test/MyMap" + "@SDT/{:345::4:keys@SDT/[4:298:@SDT/{:50::12:display-name" + "@SDT/$S:4:Name:3:key@SDT/$S:4:name@SDT/{:57::12:display-name" + "@SDT/$S:10:Executable:3:key@SDT/$S:4:exec@SDT/{:95::12:display-name" + "@SDT/$S:9:Test Type:3:key@SDT/$S:8:testType:18:display-short-name" + "@SDT/$S:4:test@SDT/{:56::12:display-name@SDT/$S:7:Outputs:3:key" + "@SDT/$S:7:outputs:4:name@SDT/$S:10:Test/MyMap@SDT/{:138::7:outputs" + "@SDT/[2:38:@SDT/$S:9:TestA.out@SDT/$S:9:TestA.err:8:testType" + "@SDT/$S:3:FVT:4:name@SDT/$S:5:TestA:4:exec@SDT/$S:15:/tests/TestA.py") marshalledResult2 = marshall(mc, mc) if marshalledResult2 != expectedResult2: print "Error: Wrong output for marshall function" print "Expected to find:\n%s" % (expectedResult2) print "Found:\n%s" % (marshalledResult2) sys.exit(1) marshalledResult3 = mc.marshall() if marshalledResult3 != expectedResult2: print "Error: Wrong output for marshall function" print "Expected to find:\n%s" % (expectedResult2) print "Found:\n%s" % (marshalledResult3) sys.exit(1) # Create a STAFMarshallingContext instance specifying the object # and mapClassMap mc2 = STAFMarshallingContext(myTestMap, mc.getMapClassMap()) if mc2.hasMapClassDefinition('Test/MyMap') != 1: print "Error: mc2 does not have map class definition 'Test/MyMap'" print "mc2=%s" % mc2 sys.exit(1) rootObj = mc2.getRootObject() if rootObj != myTestMap: print "Error: mc2.getRootObject() returned wrong object" print "Expected:\n%s" % (myTestMap) print "Found:\n%s" % (rootObj) sys.exit(1) ######################################## # Next, test the unmarshall function # ######################################## print "Testing unmarshall function" # Unmarshall the marshalledResult mc = unmarshall(marshalledResult) if mc.getRootObject() != myTestMap: print 'Unmarshalled object not same as original object that was marshalled' print 'Expected:\n%s' % (myTestMap) print 'Found:\n%s' % (marshalledResult.getRootObject()) sys.exit(1) # Unmarshall the result from a FS QUERY ENTRY request fileName = '{STAF/Config/ConfigFile}' result = handle.submit('local', 'FS', 'QUERY ENTRY %s' % fileName) if result.rc != STAFResult.Ok: print 'FS QUERY ENTRY %s failed' % fileName print 'RC=%s Result=%s' % (result.rc, result,result) sys.exit(1) mc = unmarshall(result.result) entryMap = mc.getRootObject() if entryMap['type'] == 'F' and int(entryMap['lowerSize']) > 0 and entryMap['lastModifiedTimestamp']: print '' else: print 'Unmarshall/getRootObject() failed' print "entryMap['type']=%s entryMap['lowerSize']=%s entryMap['lastModifiedTimestamp']=%s" % \ (entryMap['type'], entryMap['lowerSize'], entryMap['lastModoifiedTimestamp']) # Marshall a map and queue it; Get it off the queue, and unmarshall it # and verify results in original map object that was marshalled message = marshall(myTestMap) result = handle.submit('local', 'QUEUE', 'QUEUE MESSAGE %s' % message) if result.rc != STAFResult.Ok: print 'QUEUE MESSAGE failed with RC=%s Result=%s' % (result.rc, result.result) sys.exit(1) # Another process could obtain the message from the queue and unmarshall # it to get the original dictionary (map) object result = handle.submit('local', 'QUEUE', 'GET MESSAGE') if result.rc == STAFResult.Ok: mc = unmarshall(result.result) yourTestMap = mc.getRootObject() ############################################ # Next, test the formatObject function # ############################################ print "Testing formatObject function\n" print "Printing formatted output for %s" % (myTestMap) print formatObject(myTestMap) fileName = '{STAF/Config/ConfigFile}' result = handle.submit('local', 'FS', 'QUERY ENTRY %s' % wrapData(fileName)) if result.rc != STAFResult.Ok: print 'FS QUERY ENTRY %s failed' % fileName print 'RC=%s Result=%s' % (result.rc, result,result) sys.exit(1) print "Printing formatted output for FS QUERY ENTRY %s" % (fileName) print formatObject(result.resultObj, result.resultContext) # Create a marshalling context and marshall it, and unmarshall it myMapClassDef = STAFMapClassDefinition('Test/MyMap') myMapClassDef.addKey('name', 'Name') myMapClassDef.addKey('exec', 'Executable') testList = [ {'name': 'TestA', 'exec': '/tests/TestA.py'}, {'name': 'TestB', 'exec': '/tests/TestB.sh'}, {'name': 'TestC', 'exec': '/tests/TestC.cmd'} ] mc = STAFMarshallingContext() mc.setMapClassDefinition(myMapClassDef) myTestList = [] for test in testList: testMap = myMapClassDef.createInstance() testMap['name'] = test['name'] testMap['exec'] = test['exec'] myTestList.append(testMap) mc.setRootObject(myTestList) message = marshall(mc) mc2 = unmarshall(message) mc2.getRootObject() if str(mc) != str(mc2): print "Error: str(mc) != str(mc2)" print "mc=%s" % mc print "mc2=%s" % mc2 sys.exit(1) mc3 = STAFMarshallingContext(mapClassMap=mc.getMapClassMap()) mc4 = STAFMarshallingContext(obj=myTestList, mapClassMap=mc.getMapClassMap()) # Test privacy methods password = 'secret'; pwWithPD = STAFAddPrivacyDelimiters(password) print 'STAFAddPrivacyDelimiters(%s)=%s' % (password, pwWithPD) print 'STAFEscapePrivacyDelimiters(%s)=%s' % (pwWithPD, STAFEscapePrivacyDelimiters(pwWithPD)) print 'STAFMaskPrivateData(%s)=%s' % (pwWithPD, STAFMaskPrivateData(pwWithPD)) print 'STAFRemovePrivacyDelimiters(%s)=%s' % (pwWithPD, STAFRemovePrivacyDelimiters(pwWithPD)) password = 'secret'; pwWithPD = addPrivacyDelimiters(password) print 'addPrivacyDelimiters(%s)=%s' % (password, pwWithPD) print 'escapePrivacyDelimiters(%s)=%s' % (pwWithPD, escapePrivacyDelimiters(pwWithPD)) print 'maskPrivateData(%s)=%s' % (pwWithPD, maskPrivateData(pwWithPD)) print 'removePrivacyDelimiters(%s)=%s' % (pwWithPD, removePrivacyDelimiters(pwWithPD)) # Test private data methods testData = ['secret', 'secret', '!!@secret@!!', 'Pw: !!@pw@!!', '^!!@secret@!!', '^!!@secret^@!!', '!!@secret', '!!@secret^@!!', 'Pw1=%s, Pw2=%s.' % (addPrivacyDelimiters('a'), addPrivacyDelimiters('pw')), '^%s^%s' % (addPrivacyDelimiters('a'), addPrivacyDelimiters('b')), 'Pw1=!!@secret, !!@pw@!!.', 'Pw1=!!@secret@!!, !!@pw.', 'Msg: !!@Pw: ^!!@pw^@!!@!!', '@!!a!!@b@!!', '' ] print ("KEY:\n apd() = STAFUtil.addPrivacyDelimiters()\n" + " mpd() = STAFUtil.maskPrivateData()\n" + " rpd() = STAFUtil.removePrivacyDelimiters()\n" + " epd() = STAFUtil.escapePrivacyDelimiters()\n") numErrors = 0; for i in range(0, len(testData)): data = testData[i] print '\n%s) data: %s\n' % ((i+1), data) maskedData2 = maskPrivateData(data) print "mpd(" + data + "): " + maskedData2 + "\n" dataWithPrivacy = addPrivacyDelimiters(data) print "apd(" + data + "): " + dataWithPrivacy dataWithPrivacyRemoved = removePrivacyDelimiters(dataWithPrivacy, 1) print "rpd(" + dataWithPrivacy + ", 1): " + dataWithPrivacyRemoved dataWithPrivacyRemoved2 = removePrivacyDelimiters(dataWithPrivacy, 2) print "rpd(" + dataWithPrivacy + ", 2): " + dataWithPrivacyRemoved2 dataWithAllPrivacyRemoved = removePrivacyDelimiters(dataWithPrivacy, 0) print "rpd(" + dataWithPrivacy + ", 0): " + dataWithAllPrivacyRemoved escapedData = escapePrivacyDelimiters(data) print "\nepd(" + data + "): " + escapedData dataWithPrivacy = addPrivacyDelimiters(escapedData) print "apd(" + escapedData + "): " + dataWithPrivacy dataWithPrivacyRemoved = removePrivacyDelimiters(dataWithPrivacy, 1) print "rpd(" + dataWithPrivacy + ", 1): " + dataWithPrivacyRemoved if (dataWithPrivacyRemoved != data): print "ERROR: removePrivacyDelimiters(" + dataWithPrivacyRemoved + ", 1) != " + data numErrors = numErrors + 1 dataWithAllPrivacyRemoved = removePrivacyDelimiters(dataWithPrivacy) print "rpd(" + dataWithPrivacy + ", 0): " + dataWithAllPrivacyRemoved if (dataWithAllPrivacyRemoved != data): print "ERROR: removePrivacyDelimiters(" + dataWithAllPrivacyRemoved + ", 0) != " + data numErrors = numErrors + 1 if (numErrors == 0): print "\n*** All tests successful ***" else: print "\n*** ERROR: %s tests failed ***" % (numErrors) ############# # Finish up # ############# result = handle.unregister() if (result != STAFResult.Ok): print "Error unregistering with STAF, RC: %d" % result sys.exit(result) sys.exit(0)
This example could print the following when run:
Testing the STAFHandle constructor Testing creating a standard handle and using it to submit requests Using standard handle 35 Testing submitting requests using a standard handle Testing creating a reference to a static handle that exists Using static handle 36 Testing submitting requests using a static handle Unregister and delete static handle 36 Verify that auto-unmarshalling result is turned on by default Turn off auto-unmarshalling result Turn on auto-unmarshalling result Testing Monitor service functions Testing Log service functions Testing marshall function Testing STAFMapClassDefinition class Testing STAFMarshallingContext class Testing unmarshall function Testing formatObject function Printing formatted output for {'outputs': ['TestA.out', 'TestA.err'], 'testType': 'FVT', 'name': 'TestA', 'exec': '/tests/TestA.py'} { outputs : [ TestA.out TestA.err ] testType: FVT name : TestA exec : /tests/TestA.py } Printing formatted output for FS QUERY ENTRY {STAF/Config/ConfigFile} { Name : c:\staf\bin\staf3x.cfg Type : F Upper 32-bit Size : 0 Lower 32-bit Size : 8845 Modified Date-Time: 20080721-17:33:22 } STAFAddPrivacyDelimiters(secret)=!!@secret@!! STAFEscapePrivacyDelimiters(!!@secret@!!)=^!!@secret^@!! STAFMaskPrivateData(!!@secret@!!)=************ STAFRemovePrivacyDelimiters(!!@secret@!!)=secret addPrivacyDelimiters(secret)=!!@secret@!! escapePrivacyDelimiters(!!@secret@!!)=^!!@secret^@!! maskPrivateData(!!@secret@!!)=************ removePrivacyDelimiters(!!@secret@!!)=secret KEY: apd() = STAFUtil.addPrivacyDelimiters() mpd() = STAFUtil.maskPrivateData() rpd() = STAFUtil.removePrivacyDelimiters() epd() = STAFUtil.escapePrivacyDelimiters() 1) data: secret mpd(secret): secret apd(secret): !!@secret@!! rpd(!!@secret@!!, 1): secret rpd(!!@secret@!!, 2): secret rpd(!!@secret@!!, 0): secret epd(secret): secret apd(secret): !!@secret@!! rpd(!!@secret@!!, 1): secret rpd(!!@secret@!!, 0): secret 2) data: secret mpd(secret): secret apd(secret): !!@secret@!! rpd(!!@secret@!!, 1): secret rpd(!!@secret@!!, 2): secret rpd(!!@secret@!!, 0): secret epd(secret): secret apd(secret): !!@secret@!! rpd(!!@secret@!!, 1): secret rpd(!!@secret@!!, 0): secret 3) data: !!@secret@!! mpd(!!@secret@!!): ************ apd(!!@secret@!!): !!@secret@!! rpd(!!@secret@!!, 1): secret rpd(!!@secret@!!, 2): secret rpd(!!@secret@!!, 0): secret epd(!!@secret@!!): ^!!@secret^@!! apd(^!!@secret^@!!): !!@^^!!@secret^^@!!@!! rpd(!!@^^!!@secret^^@!!@!!, 1): !!@secret@!! rpd(!!@^^!!@secret^^@!!@!!, 0): !!@secret@!! 4) data: Pw: !!@pw@!! mpd(Pw: !!@pw@!!): Pw: ******** apd(Pw: !!@pw@!!): !!@Pw: ^!!@pw^@!!@!! rpd(!!@Pw: ^!!@pw^@!!@!!, 1): Pw: !!@pw@!! rpd(!!@Pw: ^!!@pw^@!!@!!, 2): Pw: pw rpd(!!@Pw: ^!!@pw^@!!@!!, 0): Pw: pw epd(Pw: !!@pw@!!): Pw: ^!!@pw^@!! apd(Pw: ^!!@pw^@!!): !!@Pw: ^^!!@pw^^@!!@!! rpd(!!@Pw: ^^!!@pw^^@!!@!!, 1): Pw: !!@pw@!! rpd(!!@Pw: ^^!!@pw^^@!!@!!, 0): Pw: !!@pw@!! 5) data: ^!!@secret@!! mpd(^!!@secret@!!): ^!!@secret@!! apd(^!!@secret@!!): !!@^^!!@secret^@!!@!! rpd(!!@^^!!@secret^@!!@!!, 1): !!@secret@!! rpd(!!@^^!!@secret^@!!@!!, 2): !!@secret@!! rpd(!!@^^!!@secret^@!!@!!, 0): !!@secret@!! epd(^!!@secret@!!): ^^!!@secret^@!! apd(^^!!@secret^@!!): !!@^^^!!@secret^^@!!@!! rpd(!!@^^^!!@secret^^@!!@!!, 1): ^!!@secret@!! rpd(!!@^^^!!@secret^^@!!@!!, 0): ^!!@secret@!! 6) data: ^!!@secret^@!! mpd(^!!@secret^@!!): ^!!@secret^@!! apd(^!!@secret^@!!): !!@^^!!@secret^^@!!@!! rpd(!!@^^!!@secret^^@!!@!!, 1): !!@secret@!! rpd(!!@^^!!@secret^^@!!@!!, 2): !!@secret@!! rpd(!!@^^!!@secret^^@!!@!!, 0): !!@secret@!! epd(^!!@secret^@!!): ^^!!@secret^^@!! apd(^^!!@secret^^@!!): !!@^^^!!@secret^^^@!!@!! rpd(!!@^^^!!@secret^^^@!!@!!, 1): ^!!@secret^@!! rpd(!!@^^^!!@secret^^^@!!@!!, 0): ^!!@secret^@!! 7) data: !!@secret mpd(!!@secret): !!@secret apd(!!@secret): !!@^!!@secret@!! rpd(!!@^!!@secret@!!, 1): !!@secret rpd(!!@^!!@secret@!!, 2): !!@secret rpd(!!@^!!@secret@!!, 0): !!@secret epd(!!@secret): ^!!@secret apd(^!!@secret): !!@^^!!@secret@!! rpd(!!@^^!!@secret@!!, 1): !!@secret rpd(!!@^^!!@secret@!!, 0): !!@secret 8) data: !!@secret^@!! mpd(!!@secret^@!!): !!@secret^@!! apd(!!@secret^@!!): !!@^!!@secret^^@!!@!! rpd(!!@^!!@secret^^@!!@!!, 1): !!@secret@!! rpd(!!@^!!@secret^^@!!@!!, 2): !!@secret@!! rpd(!!@^!!@secret^^@!!@!!, 0): !!@secret@!! epd(!!@secret^@!!): ^!!@secret^^@!! apd(^!!@secret^^@!!): !!@^^!!@secret^^^@!!@!! rpd(!!@^^!!@secret^^^@!!@!!, 1): !!@secret^@!! rpd(!!@^^!!@secret^^^@!!@!!, 0): !!@secret^@!! 9) data: Pw1=!!@a@!!, Pw2=!!@pw@!!. mpd(Pw1=!!@a@!!, Pw2=!!@pw@!!.): Pw1=*******, Pw2=********. apd(Pw1=!!@a@!!, Pw2=!!@pw@!!.): !!@Pw1=^!!@a^@!!, Pw2=^!!@pw^@!!.@!! rpd(!!@Pw1=^!!@a^@!!, Pw2=^!!@pw^@!!.@!!, 1): Pw1=!!@a@!!, Pw2=!!@pw@!!. rpd(!!@Pw1=^!!@a^@!!, Pw2=^!!@pw^@!!.@!!, 2): Pw1=a, Pw2=pw. rpd(!!@Pw1=^!!@a^@!!, Pw2=^!!@pw^@!!.@!!, 0): Pw1=a, Pw2=pw. epd(Pw1=!!@a@!!, Pw2=!!@pw@!!.): Pw1=^!!@a^@!!, Pw2=^!!@pw^@!!. apd(Pw1=^!!@a^@!!, Pw2=^!!@pw^@!!.): !!@Pw1=^^!!@a^^@!!, Pw2=^^!!@pw^^@!!.@!! rpd(!!@Pw1=^^!!@a^^@!!, Pw2=^^!!@pw^^@!!.@!!, 1): Pw1=!!@a@!!, Pw2=!!@pw@!!. rpd(!!@Pw1=^^!!@a^^@!!, Pw2=^^!!@pw^^@!!.@!!, 0): Pw1=!!@a@!!, Pw2=!!@pw@!!. 10) data: ^!!@a@!!^!!@b@!! mpd(^!!@a@!!^!!@b@!!): ^!!@a@!!^!!@b@!! apd(^!!@a@!!^!!@b@!!): !!@^^!!@a^@!!^^!!@b^@!!@!! rpd(!!@^^!!@a^@!!^^!!@b^@!!@!!, 1): !!@a@!!!!@b@!! rpd(!!@^^!!@a^@!!^^!!@b^@!!@!!, 2): !!@a@!!!!@b@!! rpd(!!@^^!!@a^@!!^^!!@b^@!!@!!, 0): !!@a@!!!!@b@!! epd(^!!@a@!!^!!@b@!!): ^^!!@a^@!!^^!!@b^@!! apd(^^!!@a^@!!^^!!@b^@!!): !!@^^^!!@a^^@!!^^^!!@b^^@!!@!! rpd(!!@^^^!!@a^^@!!^^^!!@b^^@!!@!!, 1): ^!!@a@!!^!!@b@!! rpd(!!@^^^!!@a^^@!!^^^!!@b^^@!!@!!, 0): ^!!@a@!!^!!@b@!! 11) data: Pw1=!!@secret, !!@pw@!!. mpd(Pw1=!!@secret, !!@pw@!!.): Pw1=*******************. apd(Pw1=!!@secret, !!@pw@!!.): !!@Pw1=^!!@secret, ^!!@pw^@!!.@!! rpd(!!@Pw1=^!!@secret, ^!!@pw^@!!.@!!, 1): Pw1=!!@secret, !!@pw@!!. rpd(!!@Pw1=^!!@secret, ^!!@pw^@!!.@!!, 2): Pw1=secret, !!@pw. rpd(!!@Pw1=^!!@secret, ^!!@pw^@!!.@!!, 0): Pw1=secret, !!@pw. epd(Pw1=!!@secret, !!@pw@!!.): Pw1=^!!@secret, ^!!@pw^@!!. apd(Pw1=^!!@secret, ^!!@pw^@!!.): !!@Pw1=^^!!@secret, ^^!!@pw^^@!!.@!! rpd(!!@Pw1=^^!!@secret, ^^!!@pw^^@!!.@!!, 1): Pw1=!!@secret, !!@pw@!!. rpd(!!@Pw1=^^!!@secret, ^^!!@pw^^@!!.@!!, 0): Pw1=!!@secret, !!@pw@!!. 12) data: Pw1=!!@secret@!!, !!@pw. mpd(Pw1=!!@secret@!!, !!@pw.): Pw1=************, !!@pw. apd(Pw1=!!@secret@!!, !!@pw.): !!@Pw1=^!!@secret^@!!, ^!!@pw.@!! rpd(!!@Pw1=^!!@secret^@!!, ^!!@pw.@!!, 1): Pw1=!!@secret@!!, !!@pw. rpd(!!@Pw1=^!!@secret^@!!, ^!!@pw.@!!, 2): Pw1=secret, !!@pw. rpd(!!@Pw1=^!!@secret^@!!, ^!!@pw.@!!, 0): Pw1=secret, !!@pw. epd(Pw1=!!@secret@!!, !!@pw.): Pw1=^!!@secret^@!!, ^!!@pw. apd(Pw1=^!!@secret^@!!, ^!!@pw.): !!@Pw1=^^!!@secret^^@!!, ^^!!@pw.@!! rpd(!!@Pw1=^^!!@secret^^@!!, ^^!!@pw.@!!, 1): Pw1=!!@secret@!!, !!@pw. rpd(!!@Pw1=^^!!@secret^^@!!, ^^!!@pw.@!!, 0): Pw1=!!@secret@!!, !!@pw. 13) data: Msg: !!@Pw: ^!!@pw^@!!@!! mpd(Msg: !!@Pw: ^!!@pw^@!!@!!): Msg: ******************** apd(Msg: !!@Pw: ^!!@pw^@!!@!!): !!@Msg: ^!!@Pw: ^^!!@pw^^@!!^@!!@!! rpd(!!@Msg: ^!!@Pw: ^^!!@pw^^@!!^@!!@!!, 1): Msg: !!@Pw: ^!!@pw^@!!@!! rpd(!!@Msg: ^!!@Pw: ^^!!@pw^^@!!^@!!@!!, 2): Msg: Pw: !!@pw@!! rpd(!!@Msg: ^!!@Pw: ^^!!@pw^^@!!^@!!@!!, 0): Msg: Pw: pw epd(Msg: !!@Pw: ^!!@pw^@!!@!!): Msg: ^!!@Pw: ^^!!@pw^^@!!^@!! apd(Msg: ^!!@Pw: ^^!!@pw^^@!!^@!!): !!@Msg: ^^!!@Pw: ^^^!!@pw^^^@!!^^@!!@!! rpd(!!@Msg: ^^!!@Pw: ^^^!!@pw^^^@!!^^@!!@!!, 1): Msg: !!@Pw: ^!!@pw^@!!@!! rpd(!!@Msg: ^^!!@Pw: ^^^!!@pw^^^@!!^^@!!@!!, 0): Msg: !!@Pw: ^!!@pw^@!!@!! 14) data: @!!a!!@b@!! mpd(@!!a!!@b@!!): @!!a******* apd(@!!a!!@b@!!): !!@^@!!a^!!@b^@!!@!! rpd(!!@^@!!a^!!@b^@!!@!!, 1): @!!a!!@b@!! rpd(!!@^@!!a^!!@b^@!!@!!, 2): @!!ab rpd(!!@^@!!a^!!@b^@!!@!!, 0): @!!ab epd(@!!a!!@b@!!): ^@!!a^!!@b^@!! apd(^@!!a^!!@b^@!!): !!@^^@!!a^^!!@b^^@!!@!! rpd(!!@^^@!!a^^!!@b^^@!!@!!, 1): @!!a!!@b@!! rpd(!!@^^@!!a^^!!@b^^@!!@!!, 0): @!!a!!@b@!! 15) data: mpd(): apd(): rpd(, 1): rpd(, 2): rpd(, 0): epd(): apd(): rpd(, 1): rpd(, 0): *** All tests successful ***