1
2
3
4
5
6 import sys, os, string, logging, socket, copy
7
8 from pysys import log
9 from pysys.constants import *
10 from pysys.exceptions import *
11 from pysys.utils.filereplace import replace as rep
12
13 from apama.common import ApamaServerProcess, _allocateUniqueProcessStdOutErr
14 from apama.common import XArgsHolder
15 from apama.common import stringToUnicode
16 from xml.dom.minidom import getDOMImplementation
17
18
20 """Helper class for the Software AG Apama Integration Adapter Framework (IAF).
21
22 The IAF Helper class has been designed for use as an extension module to the PySys System Test
23 Framework, offering the ability to configure, start and interact with an instance of the IAF. The usage
24 pattern of the class is to create an instance per IAF, and to then make method calls onto the instance
25 to perform operations such as to start the component, request reload of the configuration file, perform
26 management operationes etc. For example::
27
28 iaf = IAFHelper(self, config="iaf-config.xml")
29 iaf.start(logfile="iaf.log")
30 iaf.client(reload=True)
31
32 Process related methods of the class declare a method signature which includes named parameters for the
33 most frequently used options to the method. They also declare the **xargs parameter to allow passing in of
34 additional supported arguments to the process. The additional arguments that are currently supported via
35 **xargs are::
36
37 workingDir: The default value for the working directory of a process
38 state: The default state of the process (pysys.constants.BACKGROUND | pysys.constants.FOREGROUND)
39 timeout: The default value of the process timeout
40 stdout: The default value of the process stdout
41 stderr: The default value of the process stderr
42 arguments: List of extra arguments to be passed to the process
43
44 This means that legitimate calls to the start method include::
45
46 iaf.start(logfile="iaf.log")
47 iaf.start(logfile="iaf.log", stdout="correlator1.out")
48 iaf.start(state=FOREGROUND, timeout=5)
49
50
51 @ivar parent: Reference to the PySys testcase instantiating this class instance
52 @type parent: pysys.basetest
53 @ivar port: Port used for starting and interaction with the Event Correlator
54 @type port: integer
55 @ivar host: Hostname for interaction with a remote Event Correlator
56 @type host: string
57 @ivar environ: The environment for running the IAF
58 @type environ: dictionary
59
60 """
61
62 - def __init__(self, parent, port=None, host=None, name='iaf'):
63 """Create an instance of the IAFHelper class.
64
65 If no port parameter is used in the argument list an available port will be dynamically found
66 from the OS and used for starting the IAF, and performing all operations against it. The host
67 parameter is only used to perform operations against a remote IAF started external to the PySys
68 framework - the class does not support the starting of an IAF remote to the localhost.
69
70 @param parent: Reference to the parent PySys testcase
71 @param port: The port used for starting and interacting with the IAF
72 @param host: The hostname used for interaction with a remote IAF
73 @param name: A display name for this process (default is "iaf"), also used for the default
74 stdout/err filenames.
75
76 """
77 ApamaServerProcess.__init__(self, parent, name=name, port=port, host=host)
78
80 """Add the supplied path to the APAMA_IAF_CLASSPATH environment variable for starting this IAF instance.
81
82 """
83 if self.environ.has_key("APAMA_IAF_CLASSPATH"):
84 self.environ["APAMA_IAF_CLASSPATH"] = r"%s%s%s" % (self.environ["APAMA_IAF_CLASSPATH"], ENVSEPERATOR, os.path.normpath(path))
85 else:
86 self.environ["APAMA_IAF_CLASSPATH"] = os.path.normpath(path)
87
88
90 """Add the supplied path to the PATH (win32) or LD_LIBRARY_PATH (unix) environment variable for starting this IAF instance.
91
92 """
93 if PLATFORM in [ "sunos", "linux" ]: key = "LD_LIBRARY_PATH"
94 else: key = "PATH"
95
96 if self.environ.has_key(key):
97 self.environ[key] = r"%s%s%s" % (self.environ[key], ENVSEPERATOR, os.path.normpath(path))
98 else:
99 self.environ[key] = os.path.normpath(path)
100
101
102 - def start(self, configname, configdir=None, replace={}, logfile=None, verbosity=None, waitForServerUp=True, **xargs):
103 """Start the IAF.
104
105 Start an IAF using the supplied configuration file. If the C{configdir} argument is not
106 supplied, the location of the configuration file defaults to the testcase input
107 directory. The configuration file can first be tailored to replaced token values within
108 the file with values required at run time using the C{replace} argument. For replace of the
109 form ::
110
111 replace = {"@logs_dir@":"/var/tmp/logs"}
112
113 any tokens in the coniguration file directly matching @logs_dir@ will be replaced with the
114 value "/var/tmp/logs". Note that multiple token value pairs can be supplied in the replace
115 dictionary.
116
117 @param configname: The IAF configuration file or template name
118 @param configdir: The directory containing the IAF configuration file or template
119 @param logfile: Name of the IAF log file
120 @param verbosity: The verbosity level of the IAF logging
121 @param replace: A dictionary of tokens / values to be replaced in the configuration file
122 @param waitForServerUp: Set to False to disable automatically waiting until the component is ready
123 @param xargs: Optional startProcess keyword arguments, e.g. timeout, ignoreExitStatus, arguments, workingDir
124
125 """
126
127 command = os.path.join(self.parent.project.APAMA_HOME, 'bin', 'iaf')
128
129 dstdout,dstderr = _allocateUniqueProcessStdOutErr(self.parent, self.name)
130
131 if not configdir: configdir = self.parent.input
132
133
134 xargs=XArgsHolder(xargs, state=BACKGROUND, stdout=dstdout, stderr=dstderr, timeout=TIMEOUTS['WaitForSocket'], project=self.parent.project)
135
136
137 output = os.path.join(self.parent.output, configname)
138 rep(os.path.join(configdir, configname), output, replace, marker='')
139
140
141 arguments = []
142 arguments.extend(["--name", self.name, "-p", "%d" % self.port])
143 if logfile: arguments.extend(["-f", logfile])
144 if verbosity: arguments.extend(["-l", verbosity])
145 if xargs.arguments: arguments.extend(xargs.arguments)
146 arguments.append(os.path.join(self.parent.output, configname))
147
148
149 env = {}
150 for key in self.environ: env[stringToUnicode(key)] = stringToUnicode(self.environ[key])
151 self.process = None
152 try:
153 hprocess = self.parent.startProcess(command, arguments, env, displayName=str(self), **xargs.kwargs)
154 self.process = hprocess
155 if waitForServerUp:
156 self.waitForComponentUp(timeout=xargs.timeout)
157 except Exception:
158 for f in [logfile, xargs.stdout, xargs.stderr]:
159 if self.parent.logFileContents(f, includes=[' ERROR .*', ' FATAL .*'], tail=True): break
160 raise
161
162 return hprocess
163
164
165 - def client(self, reload=False, suspend=False, resume=False, **xargs):
166 """Perform client operations against the IAF (reload, suspend, resume).
167
168 Runs as a foreground process by default.
169
170 @param reload: Request reload of the IAF configuration file
171 @param suspend: Request the IAF to suspend event sending
172 @param resume: Request the IAF to resume event sending
173 @param xargs: Optional startProcess keyword arguments, e.g. timeout, ignoreExitStatus, arguments, workingDir
174
175 """
176
177 command = os.path.join(self.parent.project.APAMA_HOME, 'bin', 'iaf_client')
178 displayName = "iaf_client <%s>"%self.name
179
180
181 dstdout,dstderr = _allocateUniqueProcessStdOutErr(self.parent, 'iafclient')
182
183
184 xargs=XArgsHolder(xargs, stdout=dstdout, stderr=dstderr, project=self.parent.project)
185
186
187 arguments = []
188 arguments.extend(["-p", "%d" % self.port])
189 if self.host: arguments.extend(["-n", self.host])
190 if reload: arguments.append("--reload")
191 elif suspend: arguments.append("--suspend")
192 elif resume: arguments.append("--resume")
193 if xargs.arguments: arguments.extend(xargs.arguments)
194
195
196 return self.parent.startProcess(command, arguments, self.environ, displayName=displayName, **xargs.kwargs)
197
198
200 """Block until the IAF declares itself to be ready for processing.
201
202 @deprecated: Use waitForComponentUp instead.
203 """
204 self.waitForComponentUp(*args, **kwargs)
205