1 package io.guixer.logs;
2
3 import static com.google.common.base.Preconditions.checkNotNull;
4 import static net.avcompris.commons3.databeans.DataBeans.instantiate;
5 import static org.apache.commons.lang3.StringUtils.split;
6
7 import java.io.File;
8 import java.io.IOException;
9 import java.util.Collection;
10 import java.util.List;
11 import java.util.Stack;
12
13 import javax.annotation.Nullable;
14
15 import org.apache.commons.io.FileUtils;
16 import org.apache.commons.lang3.NotImplementedException;
17 import org.joda.time.DateTime;
18
19 import com.google.common.collect.Iterables;
20 import com.google.common.collect.Lists;
21
22 import io.guixer.logs.ElaborateLog.Attribute;
23 import io.guixer.logs.ElaborateLog.Before;
24 import io.guixer.logs.ElaborateLog.Done;
25 import io.guixer.logs.ElaborateLog.Group;
26 import io.guixer.logs.ElaborateLog.Intent;
27 import io.guixer.logs.ElaborateLog.Locator;
28 import io.guixer.logs.ElaborateLog.LogError;
29 import io.guixer.logs.ElaborateLog.Screenshot;
30 import io.guixer.logs.ElaborateLog.Status;
31 import io.guixer.logs.ElaborateLog.Step;
32 import io.guixer.logs.LoggedBy.LoggedByCssSelector;
33 import io.guixer.logs.LoggedBy.LoggedById;
34 import io.guixer.logs.LoggedBy.LoggedByXPath;
35 import io.guixer.logs.lines.AssertAbsentLogLine;
36 import io.guixer.logs.lines.AssertPresentLogLine;
37 import io.guixer.logs.lines.AttributeLogLine;
38 import io.guixer.logs.lines.BeginGroupLogLine;
39 import io.guixer.logs.lines.CallLogLine;
40 import io.guixer.logs.lines.ClearLogLine;
41 import io.guixer.logs.lines.ClickLogLine;
42 import io.guixer.logs.lines.DoneLogLine;
43 import io.guixer.logs.lines.EndGroupLogLine;
44 import io.guixer.logs.lines.ErrorLogLine;
45 import io.guixer.logs.lines.ExecuteScriptLogLine;
46 import io.guixer.logs.lines.ExtLogLine;
47 import io.guixer.logs.lines.FailureLogLine;
48 import io.guixer.logs.lines.GetLogLine;
49 import io.guixer.logs.lines.IntentLogLine;
50 import io.guixer.logs.lines.LogLine;
51 import io.guixer.logs.lines.MessageLogLine;
52 import io.guixer.logs.lines.SendKeysLogLine;
53 import io.guixer.logs.lines.SetMaskedVariableLogLine;
54 import io.guixer.logs.lines.SetVariableLogLine;
55 import io.guixer.logs.lines.SleepLogLine;
56 import io.guixer.logs.lines.StatusLogLine;
57 import io.guixer.logs.lines.SuccessLogLine;
58 import io.guixer.logs.lines.TakeScreenshotLogLine;
59 import io.guixer.logs.lines.WaitForLogLine;
60 import io.guixer.logs.lines.WaitForNotLogLine;
61 import io.guixer.types.AttributeScope;
62 import io.guixer.types.LocatorType;
63 import io.guixer.types.ResultType;
64 import io.guixer.types.StepType;
65 import net.avcompris.binding.annotation.XPath;
66 import net.avcompris.binding.dom.helper.DomBinderUtils;
67 import net.avcompris.domdumper.Dumper;
68 import net.avcompris.domdumper.XMLDumpers;
69
70 public abstract class ElaborateLogUtils {
71
72 public static ElaborateLog toElaborateLog(
73 final Log log
74 ) {
75 checkNotNull(log, "log");
76
77 final Attribute[] attributes = new Attribute[log.getAttributes().length];
78
79 for (int i = 0; i < attributes.length; ++i) {
80
81 final AttributeLogLine logLine = (AttributeLogLine) log.getAttributes()[i];
82
83 attributes[i] = new Attribute() {
84
85 @Override
86 public AttributeScope getScope() {
87 return logLine.getScope();
88 }
89
90 @Override
91 public String getName() {
92 return logLine.getName();
93 }
94
95 @Override
96 @Nullable
97 public String getValue() {
98 return logLine.getValue();
99 }
100 };
101 }
102
103 MutableIntent currentIntent = null;
104 MutableBefore currentBefore = null;
105 Done currentDone = null;
106 MutableLogError currentError = null;
107
108 final Stack<MutableGroup> nestedGroups = new Stack<>();
109
110 final Intents rootIntents = new Intents() {
111
112 private final List<Intent> intents = Lists.newArrayList();
113
114 @Override
115 public Intents addToIntents(
116 final Intent intent
117 ) {
118 intents.add(intent);
119
120 return this;
121 }
122
123 @Override
124 public Intent[] getIntents() {
125
126 return Iterables.toArray(intents, Intent.class);
127 }
128 };
129
130
131
132 Intents currentIntents = rootIntents;
133
134 for (final LogLine logLine : log.getLogLines()) {
135
136 final LogLine.Type type = logLine.getType();
137 final long timeMillis = logLine.getTimeMillis();
138
139 if (type == LogLine.Type.INTENT) {
140
141
142
143 currentIntent = instantiate(MutableIntent.class)
144 .setTimeMillis(timeMillis)
145 .setTitle(((IntentLogLine) logLine).getIntent());
146
147 currentIntents.addToIntents(currentIntent);
148
149 } else if (type == LogLine.Type.BEGIN_GROUP) {
150
151 final String groupName = ((BeginGroupLogLine) logLine).getGroupName();
152
153 final MutableGroup group = instantiate(MutableGroup.class)
154 .setName(groupName)
155 .setBeginAtMs(timeMillis);
156
157 nestedGroups.push(group);
158
159 final MutableIntent intent = instantiate(MutableIntent.class)
160 .setTimeMillis(timeMillis)
161 .setTitle(groupName)
162 .setGroup(group);
163
164 currentIntents.addToIntents(intent);
165
166 currentIntent = null;
167
168 currentIntents = group;
169
170 } else if (type == LogLine.Type.END_GROUP) {
171
172 final String groupName = ((EndGroupLogLine) logLine).getGroupName();
173
174 final MutableGroup currentGroup = nestedGroups.peek();
175
176 if (!groupName.equals(currentGroup.getName())) {
177 throw new IllegalStateException(
178 "currentGroup.name: Expected: " + currentGroup.getName() + ", but was: " + groupName);
179 }
180
181 currentGroup.setEndAtMs(timeMillis);
182
183 nestedGroups.pop();
184
185 currentIntents = nestedGroups.isEmpty()
186 ? rootIntents
187 : nestedGroups.peek();
188
189 } else if (type == LogLine.Type.STATUS) {
190
191 final String label = ((StatusLogLine) logLine).getLabel();
192
193 final MutableIntent intent = instantiate(MutableIntent.class)
194 .setTimeMillis(timeMillis)
195 .setTitle(label)
196 .setStatus(instantiate(MutableStatus.class)
197 .setStatusAtMs(timeMillis)
198 .setLabel(label));
199
200 currentIntents.addToIntents(intent);
201
202 } else if (currentIntent == null) {
203
204 if (currentBefore == null) {
205 currentBefore = instantiate(MutableBefore.class);
206 }
207
208 if (type == LogLine.Type.CALL) {
209
210 currentBefore.addToSteps(instantiate(MutableStep.class)
211 .setType(StepType.CALL)
212 .setTimeMillis(timeMillis)
213 .setCallable(((CallLogLine) logLine).getCallable()));
214
215 } else if (type == LogLine.Type.ATTRIBUTE) {
216
217 final AttributeLogLine attributeLogLine = (AttributeLogLine) logLine;
218
219 currentBefore.addToSteps(instantiate(MutableStep.class)
220 .setType(StepType.ATTRIBUTE)
221 .setTimeMillis(timeMillis)
222 .setScope(attributeLogLine.getScope())
223 .setName(attributeLogLine.getName())
224 .setValue(attributeLogLine.getValue()));
225
226 } else {
227
228 throw new NotImplementedException("currentIntent == null, and type: " + type);
229 }
230
231 } else if (type == LogLine.Type.ASSERT_ABSENT) {
232
233 final AssertAbsentLogLine assertAbsentLogLine = (AssertAbsentLogLine) logLine;
234
235 currentIntent.addToSteps(instantiate(MutableStep.class)
236 .setType(StepType.ASSERT_ABSENT)
237 .setTimeMillis(timeMillis)
238 .setLocator(toLocator(assertAbsentLogLine.getLocator()))
239 .setResultType(assertAbsentLogLine.isSuccess()
240 ? ResultType.SUCCESS
241 : ResultType.FAILURE));
242
243 } else if (type == LogLine.Type.ASSERT_PRESENT) {
244
245 final AssertPresentLogLine assertPresentLogLine = (AssertPresentLogLine) logLine;
246
247 currentIntent.addToSteps(instantiate(MutableStep.class)
248 .setType(StepType.ASSERT_PRESENT)
249 .setTimeMillis(timeMillis)
250 .setLocator(toLocator(assertPresentLogLine.getLocator()))
251 .setResultType(assertPresentLogLine.isSuccess()
252 ? ResultType.SUCCESS
253 : ResultType.FAILURE));
254
255 } else if (type == LogLine.Type.ATTRIBUTE) {
256
257 final AttributeLogLine attributeLogLine = (AttributeLogLine) logLine;
258
259 currentIntent.addToSteps(instantiate(MutableStep.class)
260 .setType(StepType.ATTRIBUTE)
261 .setTimeMillis(timeMillis)
262 .setScope(attributeLogLine.getScope())
263 .setName(attributeLogLine.getName())
264 .setValue(attributeLogLine.getValue()));
265
266 } else if (type == LogLine.Type.CALL) {
267
268 currentIntent.addToSteps(instantiate(MutableStep.class)
269 .setType(StepType.CALL)
270 .setTimeMillis(timeMillis)
271 .setCallable(((CallLogLine) logLine).getCallable()));
272
273 } else if (type == LogLine.Type.CLEAR) {
274
275 currentIntent.addToSteps(instantiate(MutableStep.class)
276 .setType(StepType.CLEAR)
277 .setTimeMillis(timeMillis)
278 .setLocator(toLocator(((ClearLogLine) logLine).getLocator())));
279
280 } else if (type == LogLine.Type.CLICK) {
281
282 currentIntent.addToSteps(instantiate(MutableStep.class)
283 .setType(StepType.CLICK)
284 .setTimeMillis(timeMillis)
285 .setLocator(toLocator(((ClickLogLine) logLine).getLocator())));
286
287 } else if (type == LogLine.Type.DONE) {
288
289 currentDone = instantiate(MutableDone.class)
290 .setTimeMillis(timeMillis)
291 .setMessage("Done.");
292
293 } else if (type == LogLine.Type.ERROR) {
294
295 currentError = instantiate(MutableLogError.class)
296 .setTimeMillis(timeMillis)
297 .setTrace(((ErrorLogLine) logLine).getTrace());
298
299 } else if (type == LogLine.Type.EXECUTE_SCRIPT) {
300
301 final ExecuteScriptLogLine executeScriptLogLine = (ExecuteScriptLogLine) logLine;
302
303 currentIntent.addToSteps(instantiate(MutableStep.class)
304 .setType(StepType.EXECUTE_SCRIPT)
305 .setTimeMillis(timeMillis)
306 .setScript(executeScriptLogLine.getScript()));
307
308 } else if (type == LogLine.Type.EXT) {
309
310 final ExtLogLine extLogLine = (ExtLogLine) logLine;
311
312 currentIntent.addToSteps(instantiate(MutableStep.class)
313 .setType(StepType.EXT)
314 .setTimeMillis(timeMillis)
315 .setNamespace(extLogLine.getNamespace())
316 .setValue(extLogLine.getText()));
317
318 } else if (type == LogLine.Type.FAILURE) {
319
320 currentIntent.addToSteps(instantiate(MutableStep.class)
321 .setType(StepType.FAILURE)
322 .setTimeMillis(timeMillis)
323 .setResultType(ResultType.FAILURE)
324 .setMessage((((FailureLogLine) logLine).getMessage())));
325
326 } else if (type == LogLine.Type.GET) {
327
328 currentIntent.addToSteps(instantiate(MutableStep.class)
329 .setType(StepType.GET)
330 .setTimeMillis(timeMillis)
331 .setUrl(((GetLogLine) logLine).getUrl()));
332
333 } else if (type == LogLine.Type.MESSAGE) {
334
335 currentIntent.addToSteps(instantiate(MutableStep.class)
336 .setType(StepType.MESSAGE)
337 .setTimeMillis(timeMillis)
338 .setMessage(((MessageLogLine) logLine).getText()));
339
340 } else if (type == LogLine.Type.SEND_KEYS) {
341
342 final SendKeysLogLine sendKeysLogLine = (SendKeysLogLine) logLine;
343
344 currentIntent.addToSteps(instantiate(MutableStep.class)
345 .setType(StepType.SEND_KEYS)
346 .setTimeMillis(timeMillis)
347 .setLocator(toLocator(sendKeysLogLine.getLocator()))
348 .setValue(sendKeysLogLine.getValue()));
349
350 } else if (type == LogLine.Type.SET_MASKED_VARIABLE) {
351
352 final SetMaskedVariableLogLine setVariableLogLine = (SetMaskedVariableLogLine) logLine;
353
354 currentIntent.addToSteps(instantiate(MutableStep.class)
355 .setType(StepType.SET_MASKED_VARIABLE)
356 .setTimeMillis(timeMillis)
357 .setName(setVariableLogLine.getName())
358 .setValue(setVariableLogLine.getValue()));
359
360 } else if (type == LogLine.Type.SET_VARIABLE) {
361
362 final SetVariableLogLine setVariableLogLine = (SetVariableLogLine) logLine;
363
364 currentIntent.addToSteps(instantiate(MutableStep.class)
365 .setType(StepType.SET_VARIABLE)
366 .setTimeMillis(timeMillis)
367 .setName(setVariableLogLine.getName())
368 .setValue(setVariableLogLine.getValue()));
369
370 } else if (type == LogLine.Type.SLEEP) {
371
372 currentIntent.addToSteps(instantiate(MutableStep.class)
373 .setType(StepType.SLEEP)
374 .setTimeMillis(timeMillis)
375 .setSeconds((((SleepLogLine) logLine).getSeconds())));
376
377 } else if (type == LogLine.Type.SUCCESS) {
378
379 currentIntent.addToSteps(instantiate(MutableStep.class)
380 .setType(StepType.SUCCESS)
381 .setTimeMillis(timeMillis)
382 .setResultType(ResultType.SUCCESS)
383 .setMessage(((SuccessLogLine) logLine).getMessage()));
384
385 } else if (type == LogLine.Type.TAKE_SCREENSHOT) {
386
387 final String fileName = ((TakeScreenshotLogLine) logLine).getFileName();
388
389 if (currentError == null) {
390
391 currentIntent.addToSteps(instantiate(MutableStep.class)
392 .setType(StepType.TAKE_SCREENSHOT)
393 .setTimeMillis(timeMillis)
394 .setFileName(fileName));
395
396 } else {
397
398 currentError.setScreenshot(instantiate(MutableScreenshot.class)
399 .setTimeMillis(timeMillis)
400 .setFileName(fileName));
401 }
402
403 } else if (type == LogLine.Type.WAIT_FOR) {
404
405 currentIntent.addToSteps(instantiate(MutableStep.class)
406 .setType(StepType.WAIT_FOR)
407 .setTimeMillis(timeMillis)
408 .setLocator(toLocator(((WaitForLogLine) logLine).getLocator())));
409
410 } else if (type == LogLine.Type.WAIT_FOR_NOT) {
411
412 currentIntent.addToSteps(instantiate(MutableStep.class)
413 .setType(StepType.WAIT_FOR_NOT)
414 .setTimeMillis(timeMillis)
415 .setLocator(toLocator(((WaitForNotLogLine) logLine).getLocator())));
416
417 } else {
418
419 throw new NotImplementedException("type: " + type);
420 }
421 }
422
423 @Nullable
424 final Before before = currentBefore;
425
426 @Nullable
427 final Done done = currentDone;
428
429 @Nullable
430 final LogError error = currentError;
431
432 return new ElaborateLog() {
433
434 @Override
435 public byte[] getRawBytes() {
436 return log.getRawBytes();
437 }
438
439 @Override
440 public String getGuixerVersion() {
441 return log.getGuixerVersion();
442 }
443
444 @Override
445 public String getDateAsString() {
446 return log.getDateAsString();
447 }
448
449 @Override
450 public DateTime getDate() {
451 return log.getDate();
452 }
453
454 @Override
455 public String getTestClassName() {
456 return log.getTestClassName();
457 }
458
459 @Override
460 public String getTestClassSimpleName() {
461 return log.getTestClassSimpleName();
462 }
463
464 @Override
465 public String getTestMethodName() {
466 return log.getTestMethodName();
467 }
468
469 @Override
470 public long getTimeMillis() {
471 return log.getTimeMillis();
472 }
473
474 @Override
475 public String getScenario() {
476 return log.getScenario();
477 }
478
479 @Override
480 public boolean isInError() {
481 return log.isInError();
482 }
483
484 @Override
485 @Nullable
486 public LogError getError() {
487 return error;
488 }
489
490 @Override
491 public int getSuccessCount() {
492 return log.getSuccessCount();
493 }
494
495 @Override
496 public int getFailureCount() {
497 return log.getFailureCount();
498 }
499
500 @Override
501 public Attribute[] getAttributes() {
502 return attributes;
503 }
504
505 @Override
506 @Nullable
507 public Before getBefore() {
508 return before;
509 }
510
511 @Override
512 public Intent[] getIntents() {
513
514 return rootIntents.getIntents();
515 }
516
517 @Override
518 public Done getDone() {
519 return done;
520 }
521 };
522 }
523
524 private static Locator toLocator(
525 final LoggedBy loggedBy
526 ) {
527
528 checkNotNull(loggedBy, "loggedBy");
529
530 if (loggedBy instanceof LoggedById) {
531
532 return instantiate(MutableLocator.class)
533 .setType(LocatorType.BY_ID)
534 .setValue(((LoggedById) loggedBy).id);
535
536 } else if (loggedBy instanceof LoggedByCssSelector) {
537
538 return instantiate(MutableLocator.class)
539 .setType(LocatorType.BY_CSS_SELECTOR)
540 .setValue(((LoggedByCssSelector) loggedBy).cssSelector);
541
542 } else if (loggedBy instanceof LoggedByXPath) {
543
544 return instantiate(MutableLocator.class)
545 .setType(LocatorType.BY_XPATH)
546 .setValue(((LoggedByXPath) loggedBy).xpathExpression);
547
548 } else {
549
550 throw new NotImplementedException("loggedBy: " + loggedBy);
551 }
552 }
553
554 public interface MutableIntent extends Intent {
555
556 MutableIntent setTimeMillis(
557 long timeMillis
558 );
559
560 MutableIntent setTitle(
561 String title
562 );
563
564 MutableIntent addToSteps(
565 Step steps
566 );
567
568 MutableIntent setGroup(
569 @Nullable Group group
570 );
571
572 MutableIntent setStatus(
573 @Nullable Status status
574 );
575 }
576
577 public interface MutableStep extends Step {
578
579 MutableStep setTimeMillis(
580 long timeMillis
581 );
582
583 MutableStep setType(
584 StepType type
585 );
586
587 MutableStep setUrl(
588 @Nullable String url
589 );
590
591 MutableStep setFileName(
592 @Nullable String fileName
593 );
594
595 MutableStep setNamespace(
596 @Nullable String namespace
597 );
598
599 MutableStep setScope(
600 @Nullable AttributeScope scope
601 );
602
603 MutableStep setScript(
604 @Nullable String script
605 );
606
607 MutableStep setName(
608 @Nullable String name
609 );
610
611 MutableStep setValue(
612 @Nullable String value
613 );
614
615 MutableStep setLocator(
616 @Nullable Locator locator
617 );
618
619 MutableStep setMessage(
620 @Nullable String message
621 );
622
623 MutableStep setResultType(
624 @Nullable ResultType resultType
625 );
626
627 MutableStep setCallable(
628 @Nullable String callable
629 );
630
631 MutableStep setSeconds(
632 @Nullable Integer seconds
633 );
634
635 MutableStep setLabel(
636 @Nullable String label
637 );
638 }
639
640 public interface MutableLocator extends Locator {
641
642 MutableLocator setType(
643 LocatorType type
644 );
645
646 MutableLocator setValue(
647 String value
648 );
649 }
650
651 public interface MutableAttribute extends Attribute {
652
653 MutableAttribute setScope(
654 AttributeScope scope
655 );
656
657 MutableAttribute setName(
658 String name
659 );
660
661 MutableAttribute setValue(
662 @Nullable String name
663 );
664 }
665
666 public interface MutableDone extends Done {
667
668 MutableDone setTimeMillis(
669 long timeMillis
670 );
671
672 MutableDone setMessage(
673 String message
674 );
675 }
676
677 public interface MutableBefore extends Before {
678
679 MutableBefore addToSteps(
680 Step step
681 );
682 }
683
684 public interface MutableGroup extends Group, Intents {
685
686 MutableGroup setName(
687 String name
688 );
689
690 MutableGroup setBeginAtMs(
691 long beginAtMs
692 );
693
694 MutableGroup setEndAtMs(
695 @Nullable Long endAtMs
696 );
697
698 MutableGroup setIntents(
699 Intent[] intents
700 );
701
702 @Override
703 MutableGroup addToIntents(
704 Intent intent
705 );
706 }
707
708 public interface MutableStatus extends Status {
709
710 MutableStatus setStatusAtMs(
711 long timeMillis
712 );
713
714 MutableStatus setLabel(
715 String label
716 );
717 }
718
719 public interface Intents {
720
721 Intents addToIntents(
722 Intent intent
723 );
724
725 Intent[] getIntents();
726 }
727
728 public interface MutableLogError extends LogError {
729
730 MutableLogError setTimeMillis(
731 long timeMillis
732 );
733
734 MutableLogError setTrace(
735 String trace
736 );
737
738 MutableLogError setScreenshot(
739 Screenshot screenshot
740 );
741 }
742
743 public interface MutableScreenshot extends Screenshot {
744
745 MutableScreenshot setTimeMillis(
746 long timeMillis
747 );
748
749 MutableScreenshot setFileName(
750 String fileName
751 );
752 }
753
754 public static void generateXML(
755 final ElaborateLog log,
756 final File xmlOutFile
757 ) throws IOException {
758
759 final Dumper dumper = XMLDumpers.newDumper("log", xmlOutFile, "UTF-8")
760 .addAttribute("guixerVersion", log.getGuixerVersion())
761 .addAttribute("date", log.getDateAsString())
762 .addAttribute("timeMillis", log.getTimeMillis())
763 .addAttribute("testClassName", log.getTestClassName())
764 .addAttribute("testClassSimpleName", log.getTestClassSimpleName())
765 .addAttribute("testMethodName", log.getTestMethodName())
766 .addAttribute("scenario", log.getScenario())
767 .addAttribute("failureCount", log.getFailureCount())
768 .addAttribute("successCount", log.getSuccessCount());
769
770 for (final Attribute attribute : log.getAttributes()) {
771
772 dumper.addElement("attribute")
773 .addAttribute("scope", attribute.getScope().name())
774 .addAttribute("name", attribute.getName())
775 .addAttribute("value", attribute.getValue());
776 }
777
778 if (log.getBefore() != null) {
779
780 final Dumper beforeDumper = dumper.addElement("before");
781
782 dumpSteps(beforeDumper, log.getBefore().getSteps());
783 }
784
785 dumpIntents(dumper, log.getIntents());
786
787 if (log.isInError()) {
788
789 final LogError error = log.getError();
790
791 dumper.addElement("error")
792 .addAttribute("timeMillis", error.getTimeMillis())
793 .addElement("screenshot")
794 .addAttribute("timeMillis", error.getScreenshot().getTimeMillis())
795 .addAttribute("fileName", error.getScreenshot().getFileName())
796 .close()
797 .addElement("trace")
798 .addCharacters(error.getTrace());
799 }
800
801 if (log.getDone() != null) {
802
803 final Done done = log.getDone();
804
805 dumper.addElement("done")
806 .addAttribute("timeMillis", done.getTimeMillis())
807 .addAttribute("message", done.getMessage());
808 }
809
810 dumper.close();
811 }
812
813 private static void dumpIntents(
814 final Dumper dumper,
815 final Intent[] intents
816 ) throws IOException {
817
818 for (final Intent intent : intents) {
819
820 final Dumper intentDumper = dumper.addElement("intent")
821 .addAttribute("timeMillis", intent.getTimeMillis())
822 .addAttribute("title", intent.getTitle());
823
824 if (intent.getGroup() != null) {
825
826 final Group group = intent.getGroup();
827
828 final Dumper groupDumper = intentDumper.addElement("group")
829 .addAttribute("name", group.getName())
830 .addAttribute("beginAtMs", group.getBeginAtMs())
831 .addAttribute("title", intent.getTitle());
832
833 if (group.getEndAtMs() != null) {
834 groupDumper.addAttribute("endAtMs", group.getEndAtMs());
835 }
836
837 dumpIntents(groupDumper, group.getIntents());
838
839 } else if (intent.getStatus() != null) {
840
841 final Status status = intent.getStatus();
842
843 intentDumper.addElement("status")
844 .addAttribute("statusAtMs", status.getStatusAtMs())
845 .addAttribute("label", status.getLabel());
846
847 } else {
848
849 dumpSteps(intentDumper, intent.getSteps());
850 }
851 }
852
853 }
854
855 private static void dumpSteps(
856 final Dumper dumper,
857 final Step[] steps
858 ) throws IOException {
859
860 for (final Step step : steps) {
861
862 final Dumper stepDumper = dumper.addElement("step")
863 .addAttribute("type", step.getType().name())
864 .addAttribute("callable", step.getCallable())
865 .addAttribute("fileName", step.getFileName())
866 .addAttribute("label", step.getLabel())
867 .addAttribute("message", step.getMessage())
868 .addAttribute("name", step.getName())
869 .addAttribute("namespace", step.getNamespace())
870 .addAttribute("script", step.getScript())
871 .addAttribute("timeMillis", step.getTimeMillis())
872 .addAttribute("url", step.getUrl())
873 .addAttribute("value", step.getValue())
874 .addAttribute("scope", step.getScope() == null ? null : step.getScope().name())
875 .addAttribute("resultType", step.getResultType() == null ? null : step.getResultType().name());
876
877 if (step.getSeconds() != null) {
878 stepDumper.addAttribute("seconds", step.getSeconds());
879 }
880
881 if (step.getLocator() != null) {
882
883 final Locator locator = step.getLocator();
884
885 stepDumper.addElement("locator")
886 .addAttribute("type", locator.getType().name())
887 .addAttribute("value", locator.getValue());
888 }
889 }
890 }
891
892 public static ElaborateLog loadFromXML(
893 final File xmlFile
894 ) throws IOException {
895
896 final ElaborateLogBinding binding = DomBinderUtils.xmlContentToJava(xmlFile, ElaborateLogBinding.class);
897
898 final byte[] rawBytes = FileUtils.readFileToByteArray(xmlFile);
899
900 return new ElaborateLog() {
901
902 @Override
903 public byte[] getRawBytes() {
904 return rawBytes;
905 }
906
907 @Override
908 public String getGuixerVersion() {
909 return binding.getGuixerVersion();
910 }
911
912 @Override
913 public String getDateAsString() {
914 return binding.getDateAsString();
915 }
916
917 @Override
918 @Nullable
919 public DateTime getDate() {
920 return null;
921 }
922
923 @Override
924 public String getTestClassName() {
925 return binding.getTestClassName();
926 }
927
928 @Override
929 public String getTestClassSimpleName() {
930 return binding.getTestClassSimpleName();
931 }
932
933 @Override
934 public String getTestMethodName() {
935 return binding.getTestMethodName();
936 }
937
938 @Override
939 public long getTimeMillis() {
940 return binding.getTimeMillis();
941 }
942
943 @Override
944 public String getScenario() {
945 return binding.getScenario();
946 }
947
948 @Override
949 public boolean isInError() {
950 return binding.getError() != null;
951 }
952
953 @Override
954 public int getSuccessCount() {
955 return binding.isNullSuccessCount() ? 0 : binding.getSuccessCount();
956 }
957
958 @Override
959 public int getFailureCount() {
960 return binding.isNullFailureCount() ? 0 : binding.getFailureCount();
961 }
962
963 @Override
964 public Attribute[] getAttributes() {
965 return binding.getAttributes();
966 }
967
968 @Override
969 @Nullable
970 public Before getBefore() {
971 return binding.getBefore();
972 }
973
974 @Override
975 public Intent[] getIntents() {
976 return binding.getIntents();
977 }
978
979 @Override
980 @Nullable
981 public Done getDone() {
982 return binding.getDone();
983 }
984
985 @Override
986 @Nullable
987 public LogError getError() {
988 return binding.getError();
989 }
990 };
991 }
992
993 private interface ElaborateLogBinding {
994
995 @XPath("@guixerVersion")
996 String getGuixerVersion();
997
998 @XPath("@date")
999 String getDateAsString();
1000
1001
1002
1003
1004
1005 @XPath("@testClassName")
1006 String getTestClassName();
1007
1008 @XPath("@testClassSimpleName")
1009 String getTestClassSimpleName();
1010
1011 @XPath("@testMethodName")
1012 String getTestMethodName();
1013
1014 @XPath("@timeMillis")
1015 long getTimeMillis();
1016
1017 @Nullable
1018 @XPath("@scenario")
1019 String getScenario();
1020
1021 boolean isNullSuccessCount();
1022
1023 @Nullable
1024 @XPath("@successCount")
1025 Integer getSuccessCount();
1026
1027 boolean isNullFailureCount();
1028
1029 @Nullable
1030 @XPath("@failureCount")
1031 Integer getFailureCount();
1032
1033 @XPath("attribute")
1034 Attribute[] getAttributes();
1035
1036 @Nullable
1037 @XPath("before")
1038 Before getBefore();
1039
1040 @XPath("intent")
1041 Intent[] getIntents();
1042
1043 @Nullable
1044 @XPath("done")
1045 Done getDone();
1046
1047 boolean isNullError();
1048
1049 @Nullable
1050 @XPath("error")
1051 LogError getError();
1052 }
1053
1054 private static void dumpAsGuixerOutLogLines(
1055 final Intent intent,
1056 final Collection<LogLine> logLines
1057 ) {
1058
1059 final Group group = intent.getGroup();
1060 final Status status = intent.getStatus();
1061
1062 if (group != null) {
1063
1064 logLines.add(new BeginGroupLogLine(
1065 group.getBeginAtMs(),
1066 "beginGroup: " + group.getName(),
1067 group.getName()));
1068
1069 for (final Intent subIntent : group.getIntents()) {
1070
1071 dumpAsGuixerOutLogLines(subIntent, logLines);
1072 }
1073
1074 if (group.getEndAtMs() != null) {
1075 logLines.add(new EndGroupLogLine(
1076 group.getEndAtMs(),
1077 "endGroup: " + group.getName(),
1078 group.getName()));
1079 }
1080
1081 } else if (status != null) {
1082
1083 logLines.add(new StatusLogLine(
1084 status.getStatusAtMs(),
1085 "status: " + status.getLabel(),
1086 status.getLabel()));
1087
1088 } else {
1089
1090 logLines.add(new IntentLogLine(
1091 intent.getTimeMillis(),
1092 "intent: " + intent.getTitle(),
1093 intent.getTitle()));
1094
1095 for (final Step step : intent.getSteps()) {
1096
1097 logLines.add(toGuixerOutLogLine(step));
1098 }
1099 }
1100 }
1101
1102 private static LoggedBy toLoggedBy(
1103 final Locator locator
1104 ) {
1105
1106 switch (locator.getType()) {
1107 case BY_ID:
1108 return LoggedBy.id(locator.getValue());
1109 case BY_CSS_SELECTOR:
1110 return LoggedBy.cssSelector(locator.getValue());
1111 case BY_XPATH:
1112 return LoggedBy.xpath(locator.getValue());
1113 default:
1114 throw new NotImplementedException("locator.type: " + locator.getType());
1115 }
1116 }
1117
1118 private static String serialize(
1119 final Locator locator
1120 ) {
1121
1122 switch (locator.getType()) {
1123 case BY_ID:
1124 return "By.id: " + locator.getValue();
1125 case BY_CSS_SELECTOR:
1126 return "By.cssSelector: " + locator.getValue();
1127 case BY_XPATH:
1128 return "By.xpath: " + locator.getValue();
1129 default:
1130 throw new NotImplementedException("locator.type: " + locator.getType());
1131 }
1132 }
1133
1134 private static String inQuotes(
1135 final String s
1136 ) {
1137
1138 return "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
1139 }
1140
1141 private static LogLine toGuixerOutLogLine(
1142 final Step step
1143 ) {
1144 switch (step.getType()) {
1145 case ASSERT_ABSENT:
1146 return new AssertAbsentLogLine(
1147 step.getTimeMillis(),
1148 "assertAbsent: " + serialize(step.getLocator())
1149 + " -> " + step.getResultType(),
1150 toLoggedBy(step.getLocator()),
1151 step.getResultType() == ResultType.SUCCESS);
1152 case ASSERT_PRESENT:
1153 return new AssertPresentLogLine(
1154 step.getTimeMillis(),
1155 "assertPresent: " + serialize(step.getLocator())
1156 + " -> " + step.getResultType(),
1157 toLoggedBy(step.getLocator()),
1158 step.getResultType() == ResultType.SUCCESS);
1159 case ATTRIBUTE:
1160 return new AttributeLogLine(
1161 step.getTimeMillis(),
1162 "attribute: " + step.getScope() + " " + inQuotes(step.getName()) + " " + inQuotes(step.getValue()),
1163 step.getScope(),
1164 step.getName(),
1165 step.getValue());
1166 case CALL:
1167 return new CallLogLine(
1168 step.getTimeMillis(),
1169 "call: " + step.getCallable(),
1170 step.getCallable());
1171 case CLEAR:
1172 return new ClearLogLine(
1173 step.getTimeMillis(),
1174 "clear: " + serialize(step.getLocator()),
1175 toLoggedBy(step.getLocator()));
1176 case CLICK:
1177 return new ClickLogLine(
1178 step.getTimeMillis(),
1179 "click: " + serialize(step.getLocator()),
1180 toLoggedBy(step.getLocator()));
1181 case EXECUTE_SCRIPT:
1182 return new ExecuteScriptLogLine(
1183 step.getTimeMillis(),
1184 "executeScript: " + step.getScript(),
1185 step.getScript());
1186 case EXT:
1187 return new ExtLogLine(
1188 step.getTimeMillis(),
1189 "ext: " + inQuotes(step.getNamespace())
1190 + " " + inQuotes(step.getValue()),
1191 step.getNamespace(),
1192 step.getValue());
1193 case FAILURE:
1194 return new FailureLogLine(
1195 step.getTimeMillis(),
1196 "failure: " + step.getMessage()
1197 + " -> " + step.getResultType(),
1198 step.getMessage());
1199 case GET:
1200 return new GetLogLine(
1201 step.getTimeMillis(),
1202 "get: " + step.getUrl(),
1203 step.getUrl());
1204 case MESSAGE:
1205 return new MessageLogLine(
1206 step.getTimeMillis(),
1207 "message: " + step.getMessage(),
1208 step.getMessage());
1209 case SEND_KEYS:
1210 return new SendKeysLogLine(
1211 step.getTimeMillis(),
1212 "sendKeys: " + serialize(step.getLocator()) + " " + inQuotes(step.getValue()),
1213 toLoggedBy(step.getLocator()),
1214 step.getValue());
1215 case SET_MASKED_VARIABLE:
1216 return new SetMaskedVariableLogLine(
1217 step.getTimeMillis(),
1218 "setMaskedVariable: " + step.getName() + " " + step.getValue(),
1219 step.getName(),
1220 step.getValue());
1221 case SET_VARIABLE:
1222 return new SetVariableLogLine(
1223 step.getTimeMillis(),
1224 "setVariable: " + step.getName() + " " + step.getValue(),
1225 step.getName(),
1226 step.getValue());
1227 case SLEEP:
1228 return new SleepLogLine(
1229 step.getTimeMillis(),
1230 "sleep: " + step.getSeconds(),
1231 step.getSeconds().toString());
1232 case SUCCESS:
1233 return new SuccessLogLine(
1234 step.getTimeMillis(),
1235 "success: " + step.getMessage() + " -> " + ResultType.SUCCESS,
1236 step.getMessage());
1237 case TAKE_SCREENSHOT:
1238 return new TakeScreenshotLogLine(
1239 step.getTimeMillis(),
1240 "takeScreenshot: " + step.getFileName(),
1241 step.getFileName());
1242 case WAIT_FOR:
1243 return new WaitForLogLine(
1244 step.getTimeMillis(),
1245 "waitFor: " + serialize(step.getLocator()),
1246 toLoggedBy(step.getLocator()));
1247 case WAIT_FOR_NOT:
1248 return new WaitForNotLogLine(
1249 step.getTimeMillis(),
1250 "waitForNot: " + serialize(step.getLocator()),
1251 toLoggedBy(step.getLocator()));
1252 default:
1253 throw new NotImplementedException("step.type: " + step.getType());
1254 }
1255 }
1256
1257 public static Log toGuixerOutLog(
1258 final ElaborateLog log,
1259 final byte[] rawBytes
1260 ) {
1261
1262 final long runAtMs = log.getTimeMillis();
1263
1264 final List<LogLine> attributeLogLines = Lists.newArrayList();
1265
1266 for (final Attribute attribute : log.getAttributes()) {
1267
1268 attributeLogLines.add(new AttributeLogLine(
1269 runAtMs,
1270 "attribute: " + attribute.getScope()
1271 + " " + inQuotes(attribute.getName())
1272 + " " + inQuotes(attribute.getValue()),
1273 attribute.getScope(),
1274 attribute.getName(),
1275 attribute.getValue()));
1276 }
1277
1278 final List<LogLine> logLines = Lists.newArrayList();
1279
1280 if (log.getBefore() != null) {
1281
1282 for (final Step step : log.getBefore().getSteps()) {
1283
1284 logLines.add(toGuixerOutLogLine(step));
1285 }
1286 }
1287
1288 for (final Intent intent : log.getIntents()) {
1289
1290 dumpAsGuixerOutLogLines(intent, logLines);
1291 }
1292
1293 final LogError error = log.getError();
1294
1295 if (error != null) {
1296
1297 final String trace = error.getTrace();
1298 final String firstLine = split(trace, "\n")[0];
1299 final String fileName = error.getScreenshot().getFileName();
1300
1301 logLines.add(new ErrorLogLine(
1302 error.getTimeMillis(),
1303 "error: " + firstLine,
1304 trace));
1305 logLines.add(new TakeScreenshotLogLine(
1306 error.getScreenshot().getTimeMillis(),
1307 "takeScreenshot: " + fileName,
1308 fileName));
1309 }
1310
1311 final Done done = log.getDone();
1312
1313 if (done != null) {
1314
1315 logLines.add(new DoneLogLine(
1316 done.getTimeMillis(),
1317 done.getMessage()));
1318 }
1319
1320 return new Log() {
1321
1322 @Override
1323 public byte[] getRawBytes() {
1324 return rawBytes;
1325 }
1326
1327 @Override
1328 public String getGuixerVersion() {
1329 return log.getGuixerVersion();
1330 }
1331
1332 @Override
1333 public String getDateAsString() {
1334 return log.getDateAsString();
1335 }
1336
1337 @Override
1338 public String getTestClassName() {
1339 return log.getTestClassName();
1340 }
1341
1342 @Override
1343 public String getTestClassSimpleName() {
1344 return log.getTestClassSimpleName();
1345 }
1346
1347 @Override
1348 public String getTestMethodName() {
1349 return log.getTestMethodName();
1350 }
1351
1352 @Override
1353 public long getTimeMillis() {
1354 return runAtMs;
1355 }
1356
1357 @Override
1358 @Nullable
1359 public String getScenario() {
1360 return log.getScenario();
1361 }
1362
1363 @Override
1364 public boolean isInError() {
1365 return log.isInError();
1366 }
1367
1368 @Override
1369 public int getSuccessCount() {
1370 return log.getSuccessCount();
1371 }
1372
1373 @Override
1374 public int getFailureCount() {
1375 return log.getFailureCount();
1376 }
1377
1378 @Override
1379 public DateTime getDate() {
1380 return log.getDate();
1381 }
1382
1383 @Override
1384 public LogLine[] getAttributes() {
1385 return Iterables.toArray(attributeLogLines, LogLine.class);
1386 }
1387
1388 @Override
1389 public LogLine[] getLogLines() {
1390 return Iterables.toArray(logLines, LogLine.class);
1391 }
1392 };
1393 }
1394 }