1 package io.guixer.logs;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4 import static com.google.common.base.Preconditions.checkState;
5 import static io.guixer.logs.Utils.tokenize;
6 import static io.guixer.logs.lines.LogLine.Type.ERROR;
7 import static java.nio.charset.StandardCharsets.UTF_8;
8 import static net.avcompris.commons3.databeans.DataBeans.instantiate;
9 import static org.apache.commons.lang3.StringUtils.isBlank;
10 import static org.apache.commons.lang3.StringUtils.substringAfter;
11 import static org.apache.commons.lang3.StringUtils.substringBefore;
12
13 import java.io.File;
14 import java.io.FileNotFoundException;
15 import java.io.IOException;
16
17 import org.apache.commons.io.FileUtils;
18 import org.apache.commons.lang3.NotImplementedException;
19 import org.joda.time.DateTime;
20
21 import io.guixer.logs.lines.AssertAbsentLogLine;
22 import io.guixer.logs.lines.AssertFalseLogLine;
23 import io.guixer.logs.lines.AssertPresentLogLine;
24 import io.guixer.logs.lines.AssertTrueLogLine;
25 import io.guixer.logs.lines.AttributeLogLine;
26 import io.guixer.logs.lines.BeginGroupLogLine;
27 import io.guixer.logs.lines.CallLogLine;
28 import io.guixer.logs.lines.ClearLogLine;
29 import io.guixer.logs.lines.ClickLogLine;
30 import io.guixer.logs.lines.DoneLogLine;
31 import io.guixer.logs.lines.EndGroupLogLine;
32 import io.guixer.logs.lines.ErrorLogLine;
33 import io.guixer.logs.lines.ExecuteScriptLogLine;
34 import io.guixer.logs.lines.ExtLogLine;
35 import io.guixer.logs.lines.FailureLogLine;
36 import io.guixer.logs.lines.GetLogLine;
37 import io.guixer.logs.lines.IntentLogLine;
38 import io.guixer.logs.lines.LogLine;
39 import io.guixer.logs.lines.MessageLogLine;
40 import io.guixer.logs.lines.SendKeysLogLine;
41 import io.guixer.logs.lines.SetLaneLogLine;
42 import io.guixer.logs.lines.SetMaskedVariableLogLine;
43 import io.guixer.logs.lines.SetVariableLogLine;
44 import io.guixer.logs.lines.SleepLogLine;
45 import io.guixer.logs.lines.StatusLogLine;
46 import io.guixer.logs.lines.SuccessLogLine;
47 import io.guixer.logs.lines.TagLogLine;
48 import io.guixer.logs.lines.TakeScreenshotLogLine;
49 import io.guixer.logs.lines.WaitForLogLine;
50 import io.guixer.logs.lines.WaitForNotLogLine;
51 import io.guixer.types.AttributeScope;
52
53 public class LogLoader {
54
55 private final Log log;
56
57 public LogLoader(
58 final File logDirOrFile
59 ) throws IOException {
60
61 checkNotNull(logDirOrFile, "logDirOrFile");
62
63 final File testLogFile;
64
65 if (logDirOrFile.isDirectory()) {
66
67 testLogFile = new File(logDirOrFile, "test.log");
68
69 } else {
70
71 testLogFile = logDirOrFile;
72 }
73
74 this.log = loadLog(testLogFile);
75 }
76
77 private static Log loadLog(
78 final File testLogFile
79 ) throws IOException {
80
81 if (!testLogFile.isFile()) {
82
83 throw new FileNotFoundException("test.log should exist and be a file: " + testLogFile.getCanonicalPath());
84 }
85
86 final byte[] bytes = FileUtils.readFileToByteArray(testLogFile);
87
88 final MutableLog log = instantiate(MutableLog.class)
89 .setSuccessCount(0)
90 .setFailureCount(0)
91 .setInError(false)
92 .setRawBytes(bytes);
93
94 ErrorLogLine currentError = null;
95
96 for (final String line : FileUtils.readLines(testLogFile, UTF_8)) {
97
98 if (isBlank(line)) {
99
100 currentError = null;
101
102 continue;
103 }
104
105 if (currentError != null) {
106
107 currentError.addLine(line);
108
109 continue;
110 }
111
112 if (line.startsWith("guixerVersion: ")
113 || line.startsWith("gxVersion: ")) {
114
115 log.setGuixerVersion(substringAfter(line, ": "));
116
117 } else if (line.startsWith("date: ")) {
118
119 final String dateAsString = substringAfter(line, ": ");
120
121 log.setDateAsString(dateAsString);
122
123 final DateTime date = DateTime.parse(dateAsString);
124
125 log.setDate(date);
126
127 } else if (line.startsWith("testClassName: ")) {
128
129 log.setTestClassName(substringAfter(line, ": "));
130
131 } else if (line.startsWith("testClassSimpleName: ")) {
132
133 final String testClassSimpleName = substringAfter(line, ": ");
134
135 final String testClassName = log.getTestClassName();
136
137 checkState(testClassName.endsWith("." + testClassSimpleName),
138 "testClassName should end with: ." + testClassSimpleName + ", but was: " + testClassName);
139
140 log.setTestClassSimpleName(testClassSimpleName);
141
142 } else if (line.startsWith("testMethodName: ")) {
143
144 log.setTestMethodName(substringAfter(line, ": "));
145
146 } else if (line.startsWith("timeMillis: ")) {
147
148 final String timeMillisAsString = substringAfter(line, ": ");
149
150 final long timeMillis;
151
152 try {
153
154 timeMillis = Long.parseLong(timeMillisAsString);
155
156 } catch (final NumberFormatException e) {
157
158 throw new RuntimeException("Unable to parse timeMillis: " + timeMillisAsString);
159 }
160
161 log.setTimeMillis(timeMillis);
162
163 } else if (line.startsWith("suite: ")) {
164
165
166
167 } else if (line.startsWith("scenario: ")
168 || line.startsWith("test: ")) {
169
170 log.setScenario(substringAfter(line, ": "));
171
172 } else if (line.startsWith("successCount: ")) {
173
174 final String successCountAsString = substringAfter(line, ": ");
175
176 final int successCount;
177
178 try {
179
180 successCount = Integer.parseInt(successCountAsString);
181
182 } catch (final NumberFormatException e) {
183
184 throw new RuntimeException("Unable to parse successCount: " + successCountAsString, e);
185 }
186
187 log.setSuccessCount(successCount);
188
189 } else if (line.startsWith("failureCount: ")) {
190
191 final String failureCountAsString = substringAfter(line, ": ");
192
193 final int failureCount;
194
195 try {
196
197 failureCount = Integer.parseInt(failureCountAsString);
198
199 } catch (final NumberFormatException e) {
200
201 throw new RuntimeException("Unable to parse failureCount: " + failureCountAsString, e);
202 }
203
204 log.setFailureCount(failureCount);
205
206 } else if (line.startsWith("attribute: ")) {
207
208
209
210 final String[] tokens = tokenize(substringAfter(line, ": "));
211
212 log.addToAttributes(new AttributeLogLine(
213 log.getDate().getMillis(),
214 line,
215 AttributeScope.valueOf(tokens[0]), tokens[1], tokens[2]));
216
217 } else if (line.startsWith("tag: ")) {
218
219
220
221 final String[] tokens = tokenize(substringAfter(line, ": "));
222
223 log.addToAttributes(new TagLogLine(
224 log.getDate().getMillis(),
225 line,
226 AttributeScope.valueOf(tokens[0]), tokens[1]));
227
228 } else {
229
230 final LogLine logLine = parseLogLine(line);
231
232 log.addToLogLines(logLine);
233
234 if (logLine.getType() == ERROR) {
235
236 log.setInError(true);
237
238 currentError = (ErrorLogLine) logLine;
239 }
240 }
241 }
242
243 return log;
244 }
245
246 private static LogLine parseLogLine(
247 final String line
248 ) {
249
250 checkNotNull(line, "line");
251
252 final String timeMillisAsString = substringBefore(line, " ");
253
254 final long timeMillis;
255
256 try {
257
258 timeMillis = Long.parseLong(timeMillisAsString);
259
260 } catch (final NumberFormatException e) {
261
262 throw new RuntimeException("Unable to parse timeMillis: " + timeMillisAsString);
263 }
264
265 final String rawText = substringAfter(line, " ");
266
267 if ("Done.".equals(rawText)) {
268 return new DoneLogLine(timeMillis, rawText);
269 }
270
271 final String command = substringBefore(rawText, ": ");
272 final String args = substringAfter(rawText, ": ");
273
274 if ("beginGroup".equals(command)) {
275
276 return new BeginGroupLogLine(timeMillis, rawText, args);
277
278 } else if ("endGroup".equals(command)) {
279
280 return new EndGroupLogLine(timeMillis, rawText, args);
281
282 } else if ("status".equals(command)) {
283
284 return new StatusLogLine(timeMillis, rawText, args);
285
286 } else if ("intent".equals(command)) {
287
288 return new IntentLogLine(timeMillis, rawText, args);
289
290 } else if ("setLane".equals(command)) {
291
292 return new SetLaneLogLine(timeMillis, rawText, args);
293
294 } else if ("get".equals(command)
295 || "goTo".equals(command)) {
296
297 return new GetLogLine(timeMillis, rawText, args);
298
299 } else if ("sendKeys".equals(command)
300 || "type".equals(command)) {
301
302 final String locator;
303 final String value;
304
305 if (line.endsWith("'")) {
306
307 final int index = args.lastIndexOf("'", args.length() - 2);
308
309 locator = args.substring(0, index - 1);
310 value = args.substring(index + 1, args.length() - 1);
311
312 } else if (line.endsWith(" ***")) {
313
314 final int index = args.lastIndexOf(" ", args.length());
315
316 locator = args.substring(0, index);
317 value = args.substring(index + 1);
318
319 } else {
320
321 throw new NotImplementedException("line: " + line);
322 }
323
324 return new SendKeysLogLine(timeMillis, rawText, LoggedBy.parse(locator), value);
325
326 } else if ("clear".equals(command)) {
327
328 return new ClearLogLine(timeMillis, rawText, LoggedBy.parse(args));
329
330 } else if ("click".equals(command)) {
331
332 return new ClickLogLine(timeMillis, rawText, LoggedBy.parse(args));
333
334 } else if ("executeScript".equals(command)) {
335
336 return new ExecuteScriptLogLine(timeMillis, rawText, args);
337
338 } else if ("call".equals(command)) {
339
340 return new CallLogLine(timeMillis, rawText, args);
341
342 } else if ("setVariable".equals(command)) {
343
344 final String name;
345 final String value;
346
347 if (line.endsWith("'")) {
348
349 final int index = args.lastIndexOf("'", args.length() - 2);
350
351 name = args.substring(0, index - 1);
352 value = args.substring(index + 1, args.length() - 1);
353
354 } else {
355
356 name = substringBefore(args, " ");
357 value = substringAfter(args, " ");
358 }
359
360 return new SetVariableLogLine(timeMillis, rawText, name, value);
361
362 } else if ("setMaskedVariable".equals(command)) {
363
364 final String name;
365 final String value;
366
367 if (line.endsWith("'")) {
368
369 final int index = args.lastIndexOf("'", args.length() - 2);
370
371 name = args.substring(0, index - 1);
372 value = args.substring(index + 1, args.length() - 1);
373
374 } else {
375
376 name = substringBefore(args, " ");
377 value = substringAfter(args, " ");
378 }
379
380 return new SetMaskedVariableLogLine(timeMillis, rawText, name, value);
381
382 } else if ("sleep".equals(command)) {
383
384 return new SleepLogLine(timeMillis, rawText, args);
385
386 } else if ("waitFor".equals(command)) {
387
388 return new WaitForLogLine(timeMillis, rawText, LoggedBy.parse(args));
389
390 } else if ("waitForNot".equals(command)) {
391
392 return new WaitForNotLogLine(timeMillis, rawText, LoggedBy.parse(args));
393
394 } else if ("takeScreenshot".equals(command)) {
395
396 return new TakeScreenshotLogLine(timeMillis, rawText, args);
397
398 } else if ("failure".equals(command)) {
399
400 if (!args.endsWith(" -> FAILURE")) {
401
402 throw new NotImplementedException("args: " + args);
403 }
404
405 final int end = args.lastIndexOf(" -> ");
406
407 final String message = args.substring(0, end);
408
409 return new FailureLogLine(timeMillis, rawText, message);
410
411 } else if ("success".equals(command)) {
412
413 if (!args.endsWith(" -> SUCCESS")) {
414
415 throw new NotImplementedException("args: " + args);
416 }
417
418 final int end = args.lastIndexOf(" -> ");
419
420 final String message = args.substring(0, end);
421
422 return new SuccessLogLine(timeMillis, rawText, message);
423
424 } else if ("message".equals(command)) {
425
426 return new MessageLogLine(timeMillis, rawText, args);
427
428 } else if ("assertTrue".equals(command)) {
429
430 final boolean success;
431
432 if (args.endsWith(" -> SUCCESS")) {
433
434 success = true;
435
436 } else if (args.endsWith(" -> FAILURE")) {
437
438 success = false;
439
440 } else {
441
442 throw new NotImplementedException("args: " + args);
443 }
444
445 final int end = args.lastIndexOf(" -> ");
446 final int index = args.lastIndexOf(" ", end - 1);
447
448 final String locator = args.substring(0, index);
449
450 final String attribute = args.substring(index + 1, end);
451
452 return new AssertTrueLogLine(timeMillis, rawText, LoggedBy.parse(locator), attribute, success);
453
454 } else if ("assertFalse".equals(command)) {
455
456 final boolean success;
457
458 if (args.endsWith(" -> SUCCESS")) {
459
460 success = true;
461
462 } else if (args.endsWith(" -> FAILURE")) {
463
464 success = false;
465
466 } else {
467
468 throw new NotImplementedException("args: " + args);
469 }
470
471 final int end = args.lastIndexOf(" -> ");
472 final int index = args.lastIndexOf(" ", end - 1);
473
474 final String locator = args.substring(0, index);
475
476 final String attribute = args.substring(index + 1, end);
477
478 return new AssertFalseLogLine(timeMillis, rawText, LoggedBy.parse(locator), attribute, success);
479
480 } else if ("assertPresent".equals(command)) {
481
482 final boolean success;
483
484 if (args.endsWith(" -> SUCCESS")) {
485
486 success = true;
487
488 } else if (args.endsWith(" -> FAILURE")) {
489
490 success = false;
491
492 } else {
493
494 throw new NotImplementedException("args: " + args);
495 }
496
497 final int end = args.lastIndexOf(" -> ");
498
499 final String locator = args.substring(0, end);
500
501 return new AssertPresentLogLine(timeMillis, rawText, LoggedBy.parse(locator), success);
502
503 } else if ("assertAbsent".equals(command)) {
504
505 final boolean success;
506
507 if (args.endsWith(" -> SUCCESS")) {
508
509 success = true;
510
511 } else if (args.endsWith(" -> FAILURE")) {
512
513 success = false;
514
515 } else {
516
517 throw new NotImplementedException("args: " + args);
518 }
519
520 final int end = args.lastIndexOf(" -> ");
521
522 final String locator = args.substring(0, end);
523
524 return new AssertAbsentLogLine(timeMillis, rawText, LoggedBy.parse(locator), success);
525
526 } else if ("attribute".equals(command)) {
527
528
529
530 final String[] tokens = tokenize(args);
531
532 return new AttributeLogLine(timeMillis, rawText, AttributeScope.valueOf(tokens[0]), tokens[1], tokens[2]);
533
534 } else if ("tag".equals(command)) {
535
536
537
538 final String[] tokens = tokenize(args);
539
540 return new TagLogLine(timeMillis, rawText, AttributeScope.valueOf(tokens[0]), tokens[1]);
541
542 } else if ("ext".equals(command)) {
543
544 final String[] tokens = tokenize(args);
545
546 return new ExtLogLine(timeMillis, rawText, tokens[0], tokens[1]);
547
548 } else if ("error".equals(command)) {
549
550 return new ErrorLogLine(timeMillis, rawText, args);
551 }
552
553 throw new NotImplementedException("line: " + line);
554 }
555
556 public Log getLog() {
557
558 return log;
559 }
560
561 private interface MutableLog extends Log {
562
563 MutableLog setGuixerVersion(
564 String guixerVersion
565 );
566
567 MutableLog setDateAsString(
568 String dateAsString
569 );
570
571 MutableLog setDate(
572 DateTime date
573 );
574
575 MutableLog setTestClassName(
576 String testClassName
577 );
578
579 MutableLog setTestClassSimpleName(
580 String testClassSimpleName
581 );
582
583 MutableLog setTestMethodName(
584 String testMethodName
585 );
586
587 MutableLog setTimeMillis(
588 long timeMillis
589 );
590
591 MutableLog setScenario(
592 String scenario
593 );
594
595 MutableLog setSuccessCount(
596 int successCount
597 );
598
599 MutableLog setFailureCount(
600 int failureCount
601 );
602
603 MutableLog addToAttributes(
604 LogLine logLine
605 );
606
607 MutableLog addToLogLines(
608 LogLine logLine
609 );
610
611 MutableLog setInError(
612 boolean inError
613 );
614
615 MutableLog setRawBytes(
616 byte[] bytes
617 );
618 }
619 }