1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.unitedinternet.portal.selenium.utils.logging;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.List;
22
23 import org.apache.commons.lang.ArrayUtils;
24
25 import com.thoughtworks.selenium.CommandProcessor;
26 import com.thoughtworks.selenium.HttpCommandProcessor;
27
28
29
30
31
32
33
34
35
36
37
38
39 public class LoggingCommandProcessor implements CommandProcessor {
40 static final String AUTO_SCREENSHOT_WAIT_TIMEOUT_FILENAME_PART = "WaitTimeout";
41
42 private CommandProcessor realCommandProcessor;
43
44 private LoggingResultsFormatter formatter;
45
46 final TestMetricsBean seleniumTestMetrics = new TestMetricsBean();
47
48 static final String SELENIUM_RC_OK_RESULT = "OK";
49
50 static final String SELENIUM_RC_OK_RESULT_PREFIX_WITH_COMMA = SELENIUM_RC_OK_RESULT + ",";
51
52 static final String SELENIUM_CORE_BOOLEAN_RESULT_TRUE = "true";
53
54 static final String SELENIUM_CORE_BOOLEAN_RESULT_FALSE = "false";
55
56 static final String WAIT_CLASS_NAME = "Wait";
57
58 boolean logMethodsAsComments = true;
59
60 String[] excludeCommandsFromLogging = {"getHtmlSource",};
61
62 List<LoggingBean> loggingEventsQueue = new ArrayList<LoggingBean>();
63
64 private LoggingNotifier callbackNotifier = null;
65 private Object callbackInstance = null;
66
67
68
69
70
71
72
73
74
75 public LoggingCommandProcessor(CommandProcessor commandProcessor, LoggingResultsFormatter myFormatter) {
76 this.formatter = myFormatter;
77 this.realCommandProcessor = commandProcessor;
78 }
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97 public LoggingCommandProcessor(String serverHost, int serverPort, String browserStartCommand, String browserUrl,
98 LoggingResultsFormatter myFormatter) {
99 this.formatter = myFormatter;
100 this.realCommandProcessor = new HttpCommandProcessor(serverHost, serverPort, browserStartCommand, browserUrl);
101 }
102
103
104
105
106
107 public String doCommand(String commandName, String[] args) {
108 String result = "";
109 long cmdStartMillis = System.currentTimeMillis();
110 if (SeleniumCommandExtensions.COMMAND_EXTENSION_LOG_COMMENT.getName().equals(commandName)) {
111 String comment = args[0] != null ? args[0] : "";
112 String extraInfo = "";
113 if (args.length > 1) {
114 extraInfo = args[1] != null ? args[1] : "";
115 }
116 logComment(comment, extraInfo, cmdStartMillis);
117 } else if (SeleniumCommandExtensions.COMMAND_EXTENSION_LOG_AUTO_SCREENSHOT.getName().equals(commandName)) {
118 String baseName = args[0] != null ? args[0] : "";
119 doAutomaticScreenshot(baseName);
120 } else if (SeleniumCommandExtensions.COMMAND_EXTENSION_LOG_ASSERTION.getName().equals(commandName)) {
121
122 String[] loggingArgs = new String[] {args[1], args[2]};
123 doExceptionLogging(args[0], loggingArgs, "", null, cmdStartMillis);
124 } else if (SeleniumCommandExtensions.COMMAND_EXTENSION_LOG_RESOURCE.getName().equals(commandName)) {
125 result = LoggingCommandProcessor.SELENIUM_RC_OK_RESULT;
126 long now = System.currentTimeMillis();
127 LoggingBean b = new LoggingBean();
128 b.setCallingClass(getRealCallingClassWithLineNumberAsString(getCurrentCallingClassAsStackTraceElement()));
129 b.setWaitInvolved(isWaitInvolved());
130 b.setSourceMethod("RESOURCE");
131 b.setCommandName("captureScreenshot");
132 b.setResult(result);
133 b.setArgs(args);
134 b.setCommandSuccessful(true);
135 b.setCmdStartMillis(now);
136 b.setCmdEndMillis(now);
137 loggingEventsQueue.add(b);
138 } else {
139 this.seleniumTestMetrics.incCommandsProcessed();
140 try {
141 result = this.realCommandProcessor.doCommand(commandName, args);
142 } catch (RuntimeException e) {
143 doExceptionLogging(commandName, args, "", e, cmdStartMillis);
144 throw e;
145 }
146 doLogging(commandName, args, result, cmdStartMillis);
147 }
148 return result;
149 }
150
151
152
153
154
155
156
157
158
159
160
161 public boolean getBoolean(String commandName, String[] args) {
162
163 long cmdStartMillis = System.currentTimeMillis();
164 this.seleniumTestMetrics.incCommandsProcessed();
165 this.seleniumTestMetrics.incVerificationsProcessed();
166 boolean result = false;
167 try {
168 result = this.realCommandProcessor.getBoolean(commandName, args);
169 } catch (RuntimeException e) {
170 doExceptionLogging(commandName, args, "", e, cmdStartMillis);
171 throw (e);
172 }
173 doLogging(commandName, args, LoggingCommandProcessor.SELENIUM_RC_OK_RESULT_PREFIX_WITH_COMMA + result, cmdStartMillis);
174 return result;
175 }
176
177
178
179
180 public boolean[] getBooleanArray(String commandName, String[] args) {
181 long cmdStartMillis = System.currentTimeMillis();
182 this.seleniumTestMetrics.incCommandsProcessed();
183 boolean[] results;
184 try {
185 results = this.realCommandProcessor.getBooleanArray(commandName, args);
186 } catch (RuntimeException e) {
187 doExceptionLogging(commandName, args, "", e, cmdStartMillis);
188 throw e;
189 }
190 doLogging(commandName, args, LoggingCommandProcessor.SELENIUM_RC_OK_RESULT_PREFIX_WITH_COMMA
191 + ArrayUtils.toString(results), cmdStartMillis);
192 return results;
193 }
194
195
196
197
198 public Number getNumber(String commandName, String[] args) {
199 long cmdStartMillis = System.currentTimeMillis();
200 this.seleniumTestMetrics.incCommandsProcessed();
201 Number result;
202 try {
203 result = this.realCommandProcessor.getNumber(commandName, args);
204 } catch (RuntimeException e) {
205 doExceptionLogging(commandName, args, "", e, cmdStartMillis);
206 throw e;
207 }
208 doLogging(commandName, args, LoggingCommandProcessor.SELENIUM_RC_OK_RESULT_PREFIX_WITH_COMMA + result, cmdStartMillis);
209 return result;
210 }
211
212
213
214
215 public Number[] getNumberArray(String commandName, String[] args) {
216 long cmdStartMillis = System.currentTimeMillis();
217 this.seleniumTestMetrics.incCommandsProcessed();
218 Number[] results;
219 try {
220 results = this.realCommandProcessor.getNumberArray(commandName, args);
221 } catch (RuntimeException e) {
222 doExceptionLogging(commandName, args, "", e, cmdStartMillis);
223 throw e;
224 }
225 doLogging(commandName, args, LoggingCommandProcessor.SELENIUM_RC_OK_RESULT_PREFIX_WITH_COMMA
226 + ArrayUtils.toString(results), cmdStartMillis);
227 return results;
228 }
229
230
231
232
233 public String getString(String commandName, String[] args) {
234 long cmdStartMillis = System.currentTimeMillis();
235 this.seleniumTestMetrics.incCommandsProcessed();
236 String result;
237 try {
238 result = this.realCommandProcessor.getString(commandName, args);
239 } catch (RuntimeException e) {
240 doExceptionLogging(commandName, args, "", e, cmdStartMillis);
241 throw e;
242 }
243 doLogging(commandName, args, LoggingCommandProcessor.SELENIUM_RC_OK_RESULT_PREFIX_WITH_COMMA
244 + ArrayUtils.toString(result), cmdStartMillis);
245 return result;
246 }
247
248
249
250
251 public String[] getStringArray(String commandName, String[] args) {
252 long cmdStartMillis = System.currentTimeMillis();
253 String[] results;
254 try {
255 results = this.realCommandProcessor.getStringArray(commandName, args);
256 } catch (RuntimeException e) {
257 doExceptionLogging(commandName, args, "", e, cmdStartMillis);
258 throw e;
259 }
260 doLogging(commandName, args, LoggingCommandProcessor.SELENIUM_RC_OK_RESULT_PREFIX_WITH_COMMA
261 + ArrayUtils.toString(results), cmdStartMillis);
262 return results;
263 }
264
265
266
267
268 public void start() {
269 this.realCommandProcessor.start();
270 this.seleniumTestMetrics.setStartTimeStamp(System.currentTimeMillis());
271 logExecutionEnvironment();
272 }
273
274
275
276
277 public void stop() {
278 seleniumTestFinished();
279 this.realCommandProcessor.stop();
280 seleniumTestMetrics.setCommandsExcludedFromLogging(excludeCommandsFromLogging);
281
282 new EventQueuePostProcessor(formatter, loggingEventsQueue, seleniumTestMetrics, logMethodsAsComments);
283 }
284
285
286
287
288
289
290 public String[] getExcludedCommands() {
291 return excludeCommandsFromLogging.clone();
292 }
293
294
295
296
297
298
299
300
301 public void setExcludedCommands(String[] excludedCommands) {
302 this.excludeCommandsFromLogging = excludedCommands.clone();
303 }
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321 public static LoggingBean presetLoggingBean(String commandName, String[] args, String result, long cmdStartMillis,
322 long cmdEndMillis) {
323 LoggingBean loggingBean = new LoggingBean();
324 loggingBean.setCommandName(commandName);
325 loggingBean.setArgs(args);
326 loggingBean.setResult(result);
327 loggingBean.setCmdStartMillis(cmdStartMillis);
328 loggingBean.setCmdEndMillis(cmdEndMillis);
329 return loggingBean;
330 }
331
332
333
334
335
336 void logExecutionEnvironment() {
337 final String userAgent = getEvalNoException("navigator.userAgent");
338 this.seleniumTestMetrics.setUserAgent(userAgent);
339
340
341 final String seleniumCoreVersion = getEvalNoException("window.top.Selenium.coreVersion");
342 this.seleniumTestMetrics.setSeleniumCoreVersion(seleniumCoreVersion);
343 final String seleniumCoreRevision = getEvalNoException("window.top.Selenium.coreRevision");
344 this.seleniumTestMetrics.setSeleniumCoreRevision(seleniumCoreRevision);
345
346 final String seleniumRcVersion = getEvalNoException("window.top.Selenium.rcVersion");
347 this.seleniumTestMetrics.setSeleniumRcVersion(seleniumRcVersion);
348 final String seleniumRcRevision = getEvalNoException("window.top.Selenium.rcRevision");
349 this.seleniumTestMetrics.setSeleniumRcRevision(seleniumRcRevision);
350 }
351
352
353
354
355
356
357 String getEvalNoException(String jsExpr) {
358 String propertyValue;
359 try {
360 propertyValue = this.realCommandProcessor.getString("getEval",
361 new String[] {jsExpr,});
362 } catch (Exception exc) {
363 propertyValue = "UNKNOWN";
364 }
365 return propertyValue;
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380 void doExceptionLogging(String commandName, String[] args, String result, Throwable exception, long cmdStartMillis) {
381 Boolean screenshot = true;
382 if (null!=callbackNotifier) {
383 screenshot = callbackNotifier.errorLogging(callbackInstance, commandName, args, result, exception, cmdStartMillis);
384 }
385 if (screenshot) {
386 doAutomaticScreenshot("Error");
387 }
388 String resultContent;
389 String errorMessage;
390 if (null != exception) {
391 resultContent = "ERROR," + result + " " + exception.getClass().getName() + " - " + exception.getMessage();
392 errorMessage = exception.getMessage();
393 } else {
394 resultContent = "ERROR," + result;
395 if (args.length > 0) {
396 errorMessage = "ERROR: " + args[0];
397 } else {
398 errorMessage = "INTERNAL ERROR: real error-msg could not be determined";
399 }
400 }
401 doLogging(commandName, args, resultContent, cmdStartMillis);
402 this.seleniumTestMetrics.incFailedCommands();
403 this.seleniumTestMetrics.setLastFailedCommandMessage(errorMessage);
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418 void doLogging(String commandName, String[] args, String result, long cmdStartMillis) {
419 LoggingBean currentCommand = LoggingCommandProcessor.presetLoggingBean(commandName, args, result, cmdStartMillis, System
420 .currentTimeMillis());
421 currentCommand.setExcludeFromLogging(isCommandExcludedFromLogging(commandName));
422 currentCommand.setCallingClass(getRealCallingClassWithLineNumberAsString(getCurrentCallingClassAsStackTraceElement()));
423 currentCommand.setWaitInvolved(isWaitInvolved());
424 String sourceMethodName = "unknown";
425 StackTraceElement classOrNull = getCurrentCallingClassAsStackTraceElement();
426 if (null != classOrNull) {
427 sourceMethodName = classOrNull.getMethodName();
428 }
429 currentCommand.setSourceMethod(sourceMethodName);
430 loggingEventsQueue.add(currentCommand);
431 }
432
433
434
435
436
437
438
439
440
441 void logComment(String comment, String extraInfo, long cmdStartMillis) {
442 doLogging(SeleniumCommandExtensions.COMMAND_EXTENSION_LOG_COMMENT.getName(), new String[] {comment, extraInfo}, "",
443 cmdStartMillis);
444 }
445
446
447
448
449
450
451
452
453 boolean isCommandExcludedFromLogging(final String commandName) {
454 return Arrays.asList(excludeCommandsFromLogging).contains(commandName);
455 }
456
457 StackTraceElement getCurrentCallingClassAsStackTraceElement() {
458 return StackTraceUtils.getCurrentCallingClassAsStackTraceElement(Thread.currentThread().getStackTrace(),
459 "DefaultSelenium");
460 }
461
462 String getRealCallingClassWithLineNumberAsString(StackTraceElement currentCallingClassAsStackTraceElement) {
463 return StackTraceUtils.stackTraceElementWithLinenumberAsString(currentCallingClassAsStackTraceElement);
464 }
465
466 boolean isWaitInvolved() {
467 return StackTraceUtils.isClassInStackTrace(Thread.currentThread().getStackTrace(), "."
468 + LoggingCommandProcessor.WAIT_CLASS_NAME);
469 }
470
471 void seleniumTestFinished() {
472 this.seleniumTestMetrics.setEndTimeStamp(System.currentTimeMillis());
473
474 if (loggingEventsQueue.size() > 0) {
475 LoggingBean lastBeanInQueue = loggingEventsQueue.get(loggingEventsQueue.size() - 1);
476 if (lastBeanInQueue.isWaitInvolved()) {
477 lastBeanInQueue.setResult("ERROR,wait timed out");
478 doAutomaticScreenshot(LoggingCommandProcessor.AUTO_SCREENSHOT_WAIT_TIMEOUT_FILENAME_PART);
479 this.seleniumTestMetrics.setLastFailedCommandMessage(lastBeanInQueue.getResult());
480 this.seleniumTestMetrics.incFailedCommands();
481 }
482 }
483 }
484
485 void doAutomaticScreenshot(String baseFileName) {
486 final String autoScreenshotFullPath = formatter.generateFilenameForAutomaticScreenshot(baseFileName);
487 Boolean internal = true;
488 if (null!=callbackNotifier) {
489 final String pathFile = formatter.generateFilenameForAutomaticScreenshot(
490 LoggingCommandProcessor.AUTO_SCREENSHOT_WAIT_TIMEOUT_FILENAME_PART);
491 internal = callbackNotifier.makeScreenshot(callbackInstance, pathFile);
492 }
493 if (internal) {
494 doCommand("captureScreenshot", new String[] {autoScreenshotFullPath});
495 }
496 }
497
498
499
500
501
502
503
504
505
506 public boolean isTestFailed() {
507 return seleniumTestMetrics.getFailedCommands() > 0;
508 }
509
510
511
512
513
514
515
516
517 public void setCallbackNotifier(LoggingNotifier callbackLoggingNotifier, Object callbackLoggingInstance) {
518 this.callbackNotifier = callbackLoggingNotifier;
519 this.callbackInstance = callbackLoggingInstance;
520 }
521
522 public boolean isLogMethodsAsComments() {
523 return logMethodsAsComments;
524 }
525
526 public void setLogMethodsAsComments(boolean logMethodsAsComments) {
527 this.logMethodsAsComments = logMethodsAsComments;
528 }
529 }
530