|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
AbstractRunnerAncestor.java | 66.7% | 86.3% | 78.8% | 83% |
|
1 | /** | |
2 | * JTRunner is free software; you can redistribute it and/or modify it under the | |
3 | * terms of the GNU General Public License as published by the Free Software | |
4 | * Foundation; either version 2, or (at your option) any later version. | |
5 | */ | |
6 | ||
7 | package jtr.runners; | |
8 | ||
9 | import java.io.ByteArrayOutputStream; | |
10 | import java.io.IOException; | |
11 | import java.io.ObjectOutputStream; | |
12 | import java.util.Date; | |
13 | import jtr.config.ParametersMap; | |
14 | import jtr.config.enterprise.EnterpriseConfig; | |
15 | import jtr.pool.RunnerPool; | |
16 | import jtr.assigner.IParamsAssigner; | |
17 | import jtr.test.ITestCompletionListener; | |
18 | import jtr.test.TestOutcomeTable; | |
19 | import jtr.test.IOutcomeFactory; | |
20 | import jtr.test.IOutcome; | |
21 | import jtr.test.IOutcome.OutcomeType; | |
22 | import static jtr.test.IOutcome.OutcomeType.*; | |
23 | ||
24 | import org.apache.log4j.Logger; | |
25 | ||
26 | /** | |
27 | * This base abstract class is the ancestor common to every JTR abstract runner. | |
28 | * It is not meant to be available to test-suite developers. | |
29 | * | |
30 | * @author Francesco Russo (frusso@dev.java.net) | |
31 | * @version 4.0 | |
32 | * @since 1.1 | |
33 | */ | |
34 | public abstract class AbstractRunnerAncestor implements IRunner { | |
35 | /** | |
36 | * This method cleans all the configurations/parameters assigned to the | |
37 | * current <code>IRunner</code>. It should be overridden by an | |
38 | * application-level runner using the delegation pattern for adding the | |
39 | * clean up of resources. This method is invoked every time an | |
40 | * <code>IRunner</code> implementation completes one of its runs. It is | |
41 | * used for reinitializing a runner between two consecutive runs if this is | |
42 | * required by the associated assignment policy (i.e. cyclic).<br> | |
43 | * This method is not intended for finalizing "expensive resources": you | |
44 | * might want to avoid the reinitialization of a JDBC or JMS connection | |
45 | * every time a run completes, maybe because you think it would be too much | |
46 | * expensive obtaining it every time.<br> | |
47 | * In such a case you should avoid putting such clean up activity in this | |
48 | * method: you should think about using the | |
49 | * <code>IRunnerPooled.cleanupResources()</code> method instead. | |
50 | * | |
51 | * | |
52 | * | |
53 | * @return IRunnerClean The same runner in the <code>CLEAN</code> state. | |
54 | * @see IRunnerPooled#cleanupResources | |
55 | */ | |
56 | 15965 | public IRunnerClean clean() { |
57 | 15966 | logger.debug("Cleaning state..."); |
58 | 15968 | setEnterprise(null); |
59 | 15970 | setParameters(null); |
60 | 15970 | setSleepTime(0L); |
61 | 15969 | logger.debug("... done"); |
62 | 15969 | return (IRunnerClean) this; |
63 | } | |
64 | ||
65 | /** | |
66 | * Assign the current epoch to the <code>IRunner</code> | |
67 | * | |
68 | * @param epoch | |
69 | * The current epoch | |
70 | */ | |
71 | 4900 | public void setEpoch(int epoch) { |
72 | 4900 | this.epoch = epoch; |
73 | } | |
74 | ||
75 | /** | |
76 | * Return the current epoch assigned to the <code>IRunner</code> | |
77 | * | |
78 | * @return int The current epoch | |
79 | */ | |
80 | 10000 | public int getEpoch() { |
81 | 10000 | return epoch; |
82 | } | |
83 | ||
84 | /** | |
85 | * Set the name of the <code>IRunner</code>. This is by default its FQN | |
86 | * followed by an increasing integer stating that this is the i-th | |
87 | * <code>IRunner</code> of that class. | |
88 | * | |
89 | * @param name | |
90 | * The name | |
91 | */ | |
92 | 98 | public void setName(String name) { |
93 | 98 | this.name = name; |
94 | } | |
95 | ||
96 | /** | |
97 | * Return the name of the <code>IRunner</code> | |
98 | * | |
99 | * @return String | |
100 | */ | |
101 | 116900 | public String getName() { |
102 | 116899 | return name; |
103 | } | |
104 | ||
105 | /** | |
106 | * Get the default name provided by <code>this.getClass().getName()</code> | |
107 | * | |
108 | * @return String The default name. | |
109 | */ | |
110 | 98 | public String getDefaultName() { |
111 | 98 | return this.getClass().getName(); |
112 | } | |
113 | ||
114 | /** | |
115 | * Return the enterprise configuration assigned to the current | |
116 | * <code>IRunner</code> | |
117 | * | |
118 | * @return EnterpriseConfig The enterprise configuration | |
119 | */ | |
120 | 34939 | public EnterpriseConfig getEnterprise() { |
121 | 34937 | return this.enterpriseConfig; |
122 | } | |
123 | ||
124 | /** | |
125 | * Assign the given enterprise configuration to the current | |
126 | * <code>IRunner</code> | |
127 | * | |
128 | * @param enterprise | |
129 | * The enterprise configuration | |
130 | */ | |
131 | 32034 | public void setEnterprise(EnterpriseConfig enterprise) { |
132 | 32038 | this.enterpriseConfig = enterprise; |
133 | } | |
134 | ||
135 | /** | |
136 | * Set the number of instances that must be active, according to the | |
137 | * jtr.xml, during the test-suite. | |
138 | * | |
139 | * @param i The number of instances | |
140 | */ | |
141 | 16068 | public void setInstanceCount(int i) { |
142 | 16068 | instanceCount = i; |
143 | } | |
144 | ||
145 | /** | |
146 | * Get the number of instances that must be active, according to the | |
147 | * jtr.xml, during the test-suite. | |
148 | * | |
149 | * @return int The number of instances | |
150 | */ | |
151 | 9999 | public int getInstanceCount() { |
152 | 9999 | return instanceCount; |
153 | } | |
154 | ||
155 | /** | |
156 | * Return the number of runs assigned to the <code>IRunner</code> | |
157 | * | |
158 | * @return int The number of runs | |
159 | */ | |
160 | 98579 | public int getRuns() { |
161 | 98592 | return runs; |
162 | } | |
163 | ||
164 | /** | |
165 | * Set the number of runs assigned to the <code>IRunner</code> | |
166 | * | |
167 | * @param runs | |
168 | * The number of runs | |
169 | */ | |
170 | 16068 | public void setRuns(int runs) { |
171 | 16068 | this.runs = runs; |
172 | } | |
173 | ||
174 | /** | |
175 | * Get the sleep runDuration assigned to this <code>IRunner</code> | |
176 | * | |
177 | * | |
178 | * | |
179 | * @return long The sleep runDuration | |
180 | */ | |
181 | 79000 | public long getSleepTime() { |
182 | 79000 | return sleepTime; |
183 | } | |
184 | ||
185 | /** | |
186 | * Get the sleep runDuration assigned to this <code>IRunner</code> | |
187 | * | |
188 | * | |
189 | * | |
190 | * @param sleepTime | |
191 | * The sleep runDuration | |
192 | */ | |
193 | 32037 | public void setSleepTime(long sleepTime) { |
194 | 32037 | this.sleepTime = sleepTime; |
195 | } | |
196 | ||
197 | /** | |
198 | * Provides the <code>IRunner</code> with its runtime parameters. | |
199 | * | |
200 | * @param params | |
201 | * The parameters | |
202 | */ | |
203 | 32037 | public void setParameters(ParametersMap params) { |
204 | 32037 | this.params = params; |
205 | } | |
206 | ||
207 | /** | |
208 | * Return the set of runtime parameters configured for the | |
209 | * <code>IRunner</code> | |
210 | * | |
211 | * @return ParametersMap | |
212 | */ | |
213 | 0 | public ParametersMap getParameters() { |
214 | 0 | return params; |
215 | } | |
216 | ||
217 | /** | |
218 | * Set the pool this <code>IRunner</code> will belong to | |
219 | * | |
220 | * @param pool | |
221 | * The pool | |
222 | * @return IRunnerPooled The same runner in its <code>POOLED</code> state | |
223 | */ | |
224 | 4998 | public IRunnerPooled setPool(RunnerPool pool) { |
225 | 4998 | this.pool = pool; |
226 | 4998 | return (IRunnerPooled) this; |
227 | } | |
228 | ||
229 | /** | |
230 | * Get the pool this <code>IRunner</code> belongs to | |
231 | * | |
232 | * @return RunnerPool The pool | |
233 | */ | |
234 | 0 | public RunnerPool getPool() { |
235 | 0 | return pool; |
236 | } | |
237 | ||
238 | /** | |
239 | * Get the <code>IParamsAssigner</code> in charge of assigning parameters | |
240 | * to the current <code>IRunner</code> | |
241 | * | |
242 | * @return IParamsAssigner The assigner | |
243 | */ | |
244 | 6272 | public IParamsAssigner getParamsAssigner() { |
245 | 6272 | return paramsAssigner; |
246 | } | |
247 | ||
248 | /** | |
249 | * Set the <code>IParamsAssigner</code> in charge of assigning parameters | |
250 | * to the current <code>IRunner</code> | |
251 | * | |
252 | * @param paramsAssigner | |
253 | * IParamsAssigner | |
254 | */ | |
255 | 16068 | public void setParamsAssigner(IParamsAssigner paramsAssigner) { |
256 | 16068 | this.paramsAssigner = paramsAssigner; |
257 | } | |
258 | ||
259 | /** | |
260 | * Get the number of failures | |
261 | * | |
262 | * @return int The failures | |
263 | */ | |
264 | 0 | public int getFailures() { |
265 | 0 | return failedRuns; |
266 | } | |
267 | ||
268 | /** | |
269 | * Get the number of successes. | |
270 | * | |
271 | * @return int The successes | |
272 | */ | |
273 | 0 | public int getSuccesses() { |
274 | 0 | return getCurrentRun() - getFailures(); |
275 | } | |
276 | ||
277 | /** | |
278 | * Return the current <code>TestOutcomeTable</code> | |
279 | * | |
280 | * @return TestOutcomeTable | |
281 | */ | |
282 | 0 | public TestOutcomeTable getTestOutcomeTable() { |
283 | 0 | return testOutcomeTable; |
284 | } | |
285 | ||
286 | /** | |
287 | * Set the current <code>TestOutcomeTable</code> | |
288 | * | |
289 | * @param testOutcomeTable | |
290 | * TestOutcomeTable | |
291 | */ | |
292 | 98 | public void setTestOutcomeTable(TestOutcomeTable testOutcomeTable) { |
293 | 98 | this.testOutcomeTable = testOutcomeTable; |
294 | } | |
295 | ||
296 | /** | |
297 | * Get the current <code>IOutcomeTable</code> | |
298 | * | |
299 | * @return IOutcomeFactory | |
300 | */ | |
301 | 0 | public IOutcomeFactory getOutcomeFactory() { |
302 | 0 | return outcomeFactory; |
303 | } | |
304 | ||
305 | /** | |
306 | * Set the current <code>IOutcomeTable</code> | |
307 | * | |
308 | * @param outcomeFactory | |
309 | * IOutcomeFactory | |
310 | */ | |
311 | 98 | public void setOutcomeFactory(IOutcomeFactory outcomeFactory) { |
312 | 98 | this.outcomeFactory = outcomeFactory; |
313 | } | |
314 | ||
315 | /** | |
316 | * This method assigns an <code>ITestCompletionListener</code> instance | |
317 | * to a runner in <code>CLEAN</code> state. This assignment can be performed | |
318 | * for just one time in a JTR test-session for each runner instance.<br> | |
319 | * <b>Note:</b> it is legal for this instance to be always <code>null</code> | |
320 | * for runner instances started on JTR passive-nodes. | |
321 | * | |
322 | * @param testComplLsnr The listener instance | |
323 | */ | |
324 | 98 | public void setTestCompletionListener(ITestCompletionListener testComplLsnr) { |
325 | 98 | if(testCompletionLsnr==null) |
326 | 98 | testCompletionLsnr = testComplLsnr; |
327 | } | |
328 | ||
329 | /** | |
330 | * This method is in charge of actually starting the test by calling | |
331 | * the user defined <code>test()</code> method over the user-defined | |
332 | * runner instances. Doing this, runDuration information is collected and | |
333 | * at the end of the run, a new <code>IOutcome</code> instance is obtained | |
334 | * from the configured <code>IOutcomeFactory</code>. Thus the outcome | |
335 | * is passed to the <code>enrichOutcome()</code> method.<br> | |
336 | * Should a user-defined outcome be in use, the developer is required | |
337 | * to override the <code>enrichOutcome()</code> method.<br> | |
338 | * <br> | |
339 | * <b>Nota:</b> the <code>enrichOutcome()</code> method can alse be used to | |
340 | * set a user-message into each run's outcome. | |
341 | * @throws java.lang.Throwable | |
342 | */ | |
343 | 44380 | protected final void doRunTest() throws Throwable { |
344 | 44389 | initializeTimers(); |
345 | 44391 | try { |
346 | 44396 | test(); |
347 | } | |
348 | finally { | |
349 | 44380 | runDuration = System.currentTimeMillis() - runDuration; |
350 | 44369 | if(testCompletionLsnr!=null) |
351 | 22182 | testCompletionLsnr.updateLocalRuns(); |
352 | } | |
353 | 32396 | IOutcome res = prepareOutcome(SUCCESS); |
354 | 32396 | testOutcomeTable.put(getName(),res); |
355 | } | |
356 | ||
357 | /** | |
358 | * Thie method is required to prevent that errors happening before the | |
359 | * doRunTest() method is invoked have negative impacts on the computation | |
360 | * of the time spent during tests. | |
361 | */ | |
362 | 44406 | protected final void initializeTimers() { |
363 | 44407 | runDuration = System.currentTimeMillis(); |
364 | 44407 | timestamp = new Date(runDuration); |
365 | } | |
366 | ||
367 | /** | |
368 | * Whenever an exception is caught during the execution of the | |
369 | * <code>test()</code> method of the <code>IRunner</code> interface, the | |
370 | * <code>AbstractRunner</code> takes care of instantiating a new | |
371 | * <code>IOutcome</code> and of adding it to the current | |
372 | * <code>TestOutcomeTable</code>.<br> | |
373 | * Once this steps have been performed, the | |
374 | * <code>receiveFailureNotification(Throwable,String)"</code> of the | |
375 | * <code>IRunner</code> interface is called. At this point your custom | |
376 | * <code>IRunner</code> gets notified of the exception and can decide what | |
377 | * to do with it. | |
378 | * | |
379 | * @param run | |
380 | * The run of the exception | |
381 | * @param t | |
382 | * The exceptioin | |
383 | */ | |
384 | 12003 | protected final void handleFailure(int run, Throwable t) { |
385 | 12003 | failedRuns++; |
386 | 12004 | String msg = "Exception occourred in IRunner " + getName() + " at thread run # " + run + " Actual parameters are: " + enterpriseConfig + " " + params + " " |
387 | + ". Exception caught: proceeding with the next run..."; | |
388 | 12004 | IOutcome outcome = prepareOutcome(FAILURE); |
389 | 12002 | if(isSerializable(t)) { |
390 | 11995 | outcome.setException(t); |
391 | } else { | |
392 | 0 | NotSerializableErrorException e = new NotSerializableErrorException("Original exception was not Serializable, reporting only the original top-level message:\n"+t.getMessage(),null); |
393 | 0 | e.setStackTrace(t.getStackTrace()); |
394 | 0 | outcome.setException(e); |
395 | } | |
396 | 11997 | testOutcomeTable.put(getName(), outcome); |
397 | 12004 | logger.error(msg, t); |
398 | 12004 | receiveFailureNotification(t, "Exception occourred"); |
399 | } | |
400 | ||
401 | /** | |
402 | * This method verifies whether the given exception could be sent over | |
403 | * the network or not. | |
404 | */ | |
405 | 12003 | private boolean isSerializable(Throwable t) { |
406 | 12002 | boolean res = true; |
407 | 12004 | try { |
408 | 12004 | ObjectOutputStream os = new ObjectOutputStream(new ByteArrayOutputStream()); |
409 | 11997 | os.writeObject(t); |
410 | } catch (IOException ex) { | |
411 | 0 | res = false; |
412 | } | |
413 | 12000 | return res; |
414 | } | |
415 | ||
416 | /** | |
417 | * Prepares an outcome, filling it in with all the required information. | |
418 | * This method takes care of calling the <code>enrichOutcome()</code> method too. | |
419 | */ | |
420 | 44398 | private IOutcome prepareOutcome(OutcomeType type) { |
421 | 44398 | IOutcome outcome = outcomeFactory.getInstance(); |
422 | 44396 | outcome.setEnterpriseConfig(enterpriseConfig); |
423 | 44398 | outcome.setEpoch(epoch); |
424 | //outcome.setNode(???); | |
425 | 44400 | outcome.setParametersMap(params); |
426 | 44399 | outcome.setRun(getCurrentRun()); |
427 | 44400 | outcome.setRunDuration(runDuration); |
428 | 44400 | outcome.setRunnerCategory(this.getClass()); |
429 | 44398 | outcome.setRunnerId(this.getName()); |
430 | 44400 | outcome.setTimeStamp(timestamp); |
431 | 44400 | outcome.setType(type); |
432 | 44399 | enrichOutcome(outcome); |
433 | 44396 | return outcome; |
434 | } | |
435 | ||
436 | /** | |
437 | * This abstract method must be used either when the user needs to enrich the given | |
438 | * outcome with a <i>JTR UserObject</i> or in case the default <code>IOutcomeFactory</code> | |
439 | * has been replaced with a custom one. Responsability of this method is filling in the | |
440 | * provided <code>IOutcome</code> instance. That instance will then be put into the | |
441 | * <code>TestOutcomeTable</code> by the JTR runtime. | |
442 | * | |
443 | * @param outcome The empty outcome of a single run | |
444 | */ | |
445 | 0 | public void enrichOutcome(IOutcome outcome) { |
446 | // nop by default | |
447 | } | |
448 | ||
449 | private long runDuration; | |
450 | private Date timestamp; | |
451 | protected int epoch; | |
452 | private int failedRuns; | |
453 | private String name; | |
454 | private EnterpriseConfig enterpriseConfig; | |
455 | private int runs; | |
456 | private int instanceCount; | |
457 | private long sleepTime; | |
458 | private ParametersMap params; | |
459 | protected IParamsAssigner paramsAssigner; | |
460 | protected RunnerPool pool; | |
461 | protected Logger logger; | |
462 | private TestOutcomeTable testOutcomeTable; | |
463 | private IOutcomeFactory<? extends IOutcome> outcomeFactory; | |
464 | // NOTE: this instance can be always null for remotely started runners | |
465 | private ITestCompletionListener testCompletionLsnr; | |
466 | } |
|