1 import os
2
4 """
5 A simple exception for test problems
6 """
10 return repr(self.value)
11
13 """Represents a process"""
14
15 - def __init__(self, node=None, test_case=None):
16 """Constructs a Process associating it with a particualar TestScenario and Node"""
17 self.node_ = node
18 self.test_case_ = test_case
19 self.handle_ = -1
20 self.process_port_ = test_case.get_unique_port()
21 self.args_ = ""
22 self.process_number_ = 0
23 self.log_file_ = ""
24 self.working_dir_ = ""
25 self.command_ = ""
26 self.uses_test_sync_lib_ = 1
27
29 """Set the process executable name"""
30 self.command_ = command
31
33 """Get the process executable name"""
34 return self.command_
35
37 """Set a log file name that is to be used for standard out and error collection
38 for this process. Will be created in the working directory.
39 Take care to make this unique within this scenario if you don't want
40 it to be overwritten."""
41 self.log_file_ = file_name
42
44 """Return the standard out / error log file name for this process that has been set
45 explicitly or a suitable default otherwise."""
46 if self.log_file_ == "":
47 log_file_name = '{STAF/Config/Sep/File}%s.log' % (self.get_command())
48 else:
49 log_file_name = '{STAF/Config/Sep/File}%s' % (self.log_file_)
50 return log_file_name
51
53 """Explicitly set the process working directory path.
54 Required if you don't want to take the default (which will be
55 testsuite/tests/<scenario name>
56 or whatever else has been set explicitly on the scenario
57 """
58 self.working_dir_ = working_dir
59
61 """Get the process working directory path. Returns default for this
62 TestScenario on this Process's Node"""
63 if self.working_dir_ == "":
64 if self.test_case_ == None:
65 raise TestError ("Can't get a default working directory for Process " +
66 self.command_ + " not associated with a TestScenario")
67 if self.node_ == None:
68 raise TestError ("Can't get a default working directory for Process " +
69 self.command_ + " not associated with a Node")
70 return self.test_case_.get_working_dir(self.node_)
71
72 return self.working_dir_
73
75 """Set the process 'user' arguments"""
76 self.args_ = args
77
79 """Get the process 'user' arguments"""
80 return self.args_
81
83 """Set whether this process uses the test sync lib or not.
84 Default is true. Set to 0 to prevent STAX providing extra config args
85 when this process is started."""
86 self.uses_test_sync_lib_ = does_use_it
87
89 """
90 Get the additional process args required to initialise the
91 OSPL test lib interprocess synchronisation stuff (if required)
92 You can of course do this 'manually' but this does it for you
93 if you've stuck to the usual case.
94 """
95 if self.uses_test_sync_lib_ == 0:
96 return ""
97
98 extra_args = " -ORBListenEndpoints iiop://:" + str(self.process_port_)
99 for other_process in self.test_case_.processes_:
100 if other_process == self:
101 pass
102 else:
103 extra_args += " -ORBInitRef " + other_process.get_command () + "=corbaloc:iiop:" + \
104 other_process.node_.host_name_ + ":" + str(other_process.process_port_) + \
105 "/" + other_process.get_command ()
106 return extra_args
107
109 """
110 Return the env that this process should be spawned or run with. Adds the
111 """
112 cloned_env = (self.node_.get_ospl_env())[:]
113 i = 0
114 while i < len(cloned_env):
115 upper_case_env_line = cloned_env[i].upper()
116 if upper_case_env_line.startswith('PATH=') or upper_case_env_line.startswith('LD_LIBRARY_PATH='):
117 cloned_env[i] += '{STAF/Config/Sep/Path}%s{STAF/Config/Sep/Path}%s{STAF/Config/Sep/File}testsuite{STAF/Config/Sep/File}tests{STAF/Config/Sep/File}testlibs' % \
118 (self.get_working_dir(),
119 self.node_.get_test_root())
120 i += 1
121 return cloned_env
122
124 """
125 Return a unique number identifying this process instance within the test run.
126 Handy as a key if starting asynchronously.
127 """
128 return self.process_number_
129
131 """
132 A machine environment that a part of a TestScenario runs on.
133
134 Each requires a STAF daemon.
135 """
136 - def __init__(self, host_name, test_root, ospl_home = None, staf_port = 6500, staf_url = ""):
137 """Constructor for a TestNode. Required are the/a DNS name of the host, the root at
138 which a source checkout of OSPL exists. Optionally the value of OSPL_HOME that is to be tested
139 or None if you are taking responsibility for configuring the STAF daemon environment
140 yourself & the location of the STAF daemon if not at the default port"""
141 self.host_name_ = host_name
142 self.test_root_ = test_root
143 self.staf_port_ = staf_port
144 self.staf_url_ = staf_url
145 self.requires_static_load_ = 0
146 if self.staf_url_ == "":
147 self.staf_url_ = "tcp://" + self.host_name_ + "@" + str(self.staf_port_)
148 self.initialised_ = 0
149 self.ospl_home_ = ospl_home
150 self.ospl_env_ = []
151
153 """
154 Get the location that the built test checkout resides at on this machine
155 for this run
156 """
157 return self.test_root_
158
160 """
161 Get the value of OSPL_HOME on this TestNode within this particular TestRun
162 """
163 return self.ospl_home_
164
166 """
167 Return the list of environment variable values applicable to the
168 configured OSPL_HOME (if any) within this particular TestRun on this TestNode
169 """
170 return self.ospl_env_
171
173 """
174 Convenience accessor for OSPL_URI env prop on this box. We need this to make sure we can
175 ospl list only the default domain to find out if it is running or not
176 """
177 for env_line in self.ospl_env_:
178 if env_line.startswith("OSPL_URI="):
179 return env_line[9:]
180 return ""
181
183 """
184 Returns the url that the STAF daemon is running at on this Node
185 """
186 return self.staf_url_
187
189 """
190 Returns the Node hostname or IP or whatever
191 """
192 return self.host_name_
193
195 """
196 Returns true if this TestNode is a windows box
197 """
198 return self.config_map_["OSName"].startswith('Win')
199
201 """
202 Returns the file path separator for this TestNode. i.e. / or \
203 """
204 return self.config_map_["FileSep"]
205
207 """
208 Returns the path sepator on this TestNode. i.e. : or ;
209 """
210 return self.config_map_["PathSep"]
211
213 """
214 Returns a string describing the OS on this TestNode
215 """
216 return (self.config_map_["OSName"] + " " + self.config_map_["OSMajorVersion"]
217 + "." + self.config_map_["OSMinorVersion"] + "." + self.config_map_["OSRevision"])
218
220 """
221 Represents a collection of TestScenario objects involving a number (1 or more)
222 of TestNode's
223 """
224 - def __init__(self, nodes = [], run_id = ""):
225 self.nodes_ = nodes
226 self.test_run_id_ = run_id
227 if len (self.nodes_) == 0 :
228 self.nodes_ = [ TestScenario.LOCALHOST ]
229 self.test_cases_ = []
230 self.verbose_ = 1
231 self.process_count_ = 0
232
233 the_test_run_ = None
234
235
236
237
238
239
240
241
242
243
244
246 """
247 Factory method to create a TestScenario within this test run.
248 """
249 self.test_cases_.append(TestScenario(test_name, self))
250 return self.test_cases_[len(self.test_cases_) - 1]
251
253 """
254 Represents a single test scenario within a test. A scenario has
255 1 or more Nodes, and an arbitrary number of processes
256 """
257
259 self.name_ = name
260 self.test_run_ = test_run
261 self.required_nodes_ = 1
262 self.description_ = description
263 self.nodes_ = test_run.nodes_
264 self.node_index_ = 0
265 self.locked_and_loaded_ = 0
266 self.processes_ = []
267 self.next_port_ = 23231
268 self.work_dir_override_ = ""
269
271 """
272 Accessor for the TestScenario name
273 """
274 return self.name_
275
277 """
278 Specify that this test scenario requires a *minimum* number of nodes to
279 do its thing. The default is 1 i.e. single node. If your test cannot operate
280 at all on one node specify an appropriate higher value. Do *not* specify a
281 higher value just because the test is less meaningful on less.
282 Keep this value as low as possible.
283 """
284 self.required_nodes_ = min_number
285
287 """
288 Gets a new node definition from the scenario. Will be a new node iff the scenario has enough for it to be so.
289 """
290 next_node = self.nodes_[self.node_index_]
291 if (self.node_index_ + 1) >= len (self.nodes_) :
292 pass
293 else:
294 self.node_index_ += 1
295 return next_node
296
298 """
299 Get the default working directory for this scenario on the given Node.
300 Assumes this scenario directory is under the usual test root and is named
301 as per convention.
302 """
303 if self.name_ == "":
304 raise TestError("Attempt to get the default working directory on " +
305 node.get_host_name() + " from unnamed scenario")
306
307 return (node.get_test_root()
308 + "{STAF/Config/Sep/File}testsuite{STAF/Config/Sep/File}tests{STAF/Config/Sep/File}"
309 + self.name_)
310
312 """
313 Where the logs need to be copied to
314 """
315 if self.name_ == "":
316 raise TestError("TestScenario must have a name")
317
318 return ("{STAF/Config/Sep/File}..{STAF/Config/Sep/File}"
319 + self.name_)
320
322 """
323 Checks the requirements of the whole TestScenario are met by the TestRun it
324 is within. Will actually have build and load the test processes in some embedded
325 circumstances if there's no other alternative. Scenario should exit if this does not return True.
326 No changes should be made to the scenario after this.
327 """
328 if self.locked_and_loaded_ :
329 raise TestError("Duplicate call to lock_and_load scenario: " + self.name_)
330
331 if self.check_test_reqs_met () :
332
333 self.locked_and_loaded_ = 1
334
335 return self.locked_and_loaded_
336
338 """
339 Check the TestScenario requirements can be satisfied by the TestRun it is
340 within.
341
342 If it can't it will throw an error and the scenario should be recorded as skipped.
343 """
344 if self.required_nodes_ > len (self.nodes_):
345 raise TestError("TestRun does not comprise enough Nodes for scenario: " + self.name_)
346
347 return 1
348
350 """
351 Declare a process to run on the specified Node within this TestScenario
352 """
353 process_result = Process(node, self)
354 self.processes_.append(process_result)
355 self.test_run_.process_count_ += 1
356 process_result.process_number_ = self.test_run_.process_count_
357 return process_result
358
360 """
361 Returns a unique port. Used to make soure Process instances'
362 IPC can be initialised in a non conflicting manner.
363 """
364 self.next_port_ += 1
365 return self.next_port_
366
367 LOCALHOST = TestNode("local", os.path.join(os.getcwd(), ".."))
368