1 package io.guixer.logs;
2
3 import static io.guixer.logs.StepTypes.toStepType;
4 import static net.avcompris.commons3.databeans.DataBeans.instantiate;
5 import static org.apache.commons.lang3.StringUtils.substringAfterLast;
6
7 import java.io.File;
8 import java.io.FileNotFoundException;
9 import java.io.IOException;
10 import java.util.List;
11
12 import javax.annotation.Nullable;
13
14 import org.apache.commons.io.FileUtils;
15 import org.apache.commons.lang3.NotImplementedException;
16 import org.joda.time.DateTime;
17
18 import com.avcompris.util.SnakeYAMLUtils;
19 import com.google.common.collect.Iterables;
20 import com.google.common.collect.Lists;
21
22 import io.guixer.logs.ElaborateLog.Intent;
23 import io.guixer.logs.ElaborateLog.Locator;
24 import io.guixer.logs.ElaborateLog.LogError;
25 import io.guixer.logs.ElaborateLog.Step;
26 import io.guixer.logs.ElaborateLogUtils.MutableAttribute;
27 import io.guixer.logs.ElaborateLogUtils.MutableBefore;
28 import io.guixer.logs.ElaborateLogUtils.MutableDone;
29 import io.guixer.logs.ElaborateLogUtils.MutableGroup;
30 import io.guixer.logs.ElaborateLogUtils.MutableIntent;
31 import io.guixer.logs.ElaborateLogUtils.MutableLocator;
32 import io.guixer.logs.ElaborateLogUtils.MutableLogError;
33 import io.guixer.logs.ElaborateLogUtils.MutableScreenshot;
34 import io.guixer.logs.ElaborateLogUtils.MutableStatus;
35 import io.guixer.logs.ElaborateLogUtils.MutableStep;
36 import io.guixer.types.AttributeScope;
37 import io.guixer.types.LocatorType;
38 import io.guixer.types.ResultType;
39 import io.guixer.types.StepType;
40 import net.avcompris.commons3.yaml.Yaml;
41
42 public class YamlLogLoader {
43
44 private final ElaborateLog log;
45
46 public YamlLogLoader(
47 final File yamlLogFile
48 ) throws IOException {
49
50 if (!yamlLogFile.isFile()) {
51
52 throw new FileNotFoundException("YAML file: " + yamlLogFile.getCanonicalPath());
53 }
54
55 final byte[] bytes = FileUtils.readFileToByteArray(yamlLogFile);
56
57 final Yaml yaml =
58 GuixerYamlUtils.bindSnakeYaml(SnakeYAMLUtils.loadYAML(yamlLogFile));
59
60 final String guixerVersion = yaml.get("guixerVersion").asString();
61 final String dateAsString = yaml.get("date").toString();
62
63 final long timeMillis = yaml.get("timeMillis").asLong();
64 final String testMethodName = yaml.get("testMethodName").asString();
65 final String scenario = yaml.get("scenario").asString();
66
67 final String testClassName;
68 final String testClassSimpleName;
69
70 if (yaml.has("testClassName")) {
71
72 testClassName = yaml.get("testClassName").asString();
73
74 if (yaml.has("testClassSimpleName")) {
75
76 testClassSimpleName = yaml.get("testClassSimpleName").asString();
77
78 } else if (testClassName.contains(".")) {
79
80 testClassSimpleName = substringAfterLast(testClassName, ".");
81
82 } else {
83
84 testClassSimpleName = testClassName;
85 }
86
87 } else if (yaml.has("testClassSimpleName")) {
88
89 testClassSimpleName = yaml.get("testClassSimpleName").asString();
90 testClassName = testClassSimpleName;
91
92 } else {
93
94 throw new RuntimeException("testClassName and/or testClassSimpleName should be set.");
95 }
96
97 @Nullable
98 final LogError error;
99
100 if (yaml.has("error")) {
101
102 final Yaml errorYaml = yaml.get("error");
103
104 final Yaml screenshotYaml = errorYaml.get("screenshot");
105
106 error = instantiate(MutableLogError.class)
107 .setTimeMillis(errorYaml.get("timeMillis").asLong())
108 .setTrace(errorYaml.get("trace").asString())
109 .setScreenshot(instantiate(MutableScreenshot.class)
110 .setTimeMillis(screenshotYaml.get("timeMillis").asLong())
111 .setFileName(screenshotYaml.get("fileName").asString()));
112
113 } else {
114
115 error = null;
116 }
117
118 final MutableElaborateLog log = instantiate(MutableElaborateLog.class)
119 .setSuccessCount(0)
120 .setFailureCount(0)
121 .setInError(error != null)
122 .setError(error)
123 .setRawBytes(bytes)
124 .setGuixerVersion(guixerVersion)
125 .setDateAsString(dateAsString)
126 .setTimeMillis(timeMillis)
127 .setTestClassName(testClassName)
128 .setTestClassSimpleName(testClassSimpleName)
129 .setTestMethodName(testMethodName)
130 .setScenario(scenario);
131
132 this.log = log;
133
134 if (yaml.has("attributes")) {
135
136 for (final Yaml attributeYaml : yaml.get("attributes").items()) {
137
138 log.addToAttributes(instantiate(MutableAttribute.class)
139 .setScope(toAttributeScope(attributeYaml.get("scope").asString()))
140 .setName(attributeYaml.get("name").asString())
141 .setValue(attributeYaml.has("value")
142 ? attributeYaml.get("value").asString()
143 : null));
144 }
145 }
146
147 if (yaml.has("before")) {
148
149 final MutableBefore before = instantiate(MutableBefore.class);
150
151 log.setBefore(before);
152
153 for (final Yaml stepYaml : yaml.get("before").items()) {
154
155 before.addToSteps(loadStep(stepYaml));
156 }
157 }
158
159 if (yaml.has("done")) {
160
161 final Yaml doneYaml = yaml.get("done");
162
163 log.setDone(instantiate(MutableDone.class)
164 .setTimeMillis(doneYaml.get("timeMillis").asLong())
165 .setMessage(doneYaml.get("message").asString()));
166 }
167
168 log.setIntents(getIntents(yaml));
169
170 @Nullable
171 final Integer refSuccessCount = yaml.has("successCount")
172
173 ? yaml.get("successCount").asInt()
174 : null;
175
176 @Nullable
177 final Integer refFailureCount = yaml.has("failureCount")
178
179 ? yaml.get("failureCount").asInt()
180 : null;
181
182 computeSuccessFailures(log, log.getIntents());
183
184 if (refFailureCount != null && log.getFailureCount() != refFailureCount) {
185 throw new IllegalStateException(
186 "failureCount: Expected: " + refFailureCount + ", but was: " + log.getFailureCount());
187 }
188
189 if (refSuccessCount != null && log.getSuccessCount() != refSuccessCount) {
190 throw new IllegalStateException(
191 "successCount: Expected: " + refSuccessCount + ", but was: " + log.getSuccessCount());
192 }
193 }
194
195 private static void computeSuccessFailures(
196 final MutableElaborateLog log,
197 final Intent[] intents
198 ) {
199
200 for (final Intent intent : intents) {
201
202 if (intent.getGroup() != null) {
203
204 computeSuccessFailures(log, intent.getGroup().getIntents());
205
206 } else {
207
208 for (final Step step : intent.getSteps()) {
209
210 @Nullable
211 final ResultType resultType = step.getResultType();
212
213 if (resultType == ResultType.FAILURE) {
214
215 log.setFailureCount(log.getFailureCount() + 1);
216
217 } else if (resultType == ResultType.SUCCESS) {
218
219 log.setSuccessCount(log.getSuccessCount() + 1);
220 }
221 }
222 }
223 }
224 }
225
226 public ElaborateLog getLog() {
227
228 return log;
229 }
230
231 private static Intent[] getIntents(
232 final Yaml yaml
233 ) {
234
235 final List<Intent> intents = Lists.newArrayList();
236
237 if (yaml.has("intents")) {
238
239 for (final Yaml intentYaml : yaml.get("intents").items()) {
240
241 final MutableIntent intent;
242
243 if (intentYaml.has("group")) {
244
245 final String groupName = intentYaml.get("group").asString();
246 final long beginAtMs = intentYaml.get("beginAtMs").asLong();
247 @Nullable
248 final Long endAtMs = intentYaml.has("endAtMs")
249 ? intentYaml.get("endAtMs").asLong()
250 : null;
251
252 intent = instantiate(MutableIntent.class)
253 .setTimeMillis(beginAtMs)
254 .setTitle(groupName)
255 .setGroup(instantiate(MutableGroup.class)
256 .setName(groupName)
257 .setBeginAtMs(beginAtMs)
258 .setEndAtMs(endAtMs)
259 .setIntents(getIntents(intentYaml)));
260
261 } else if (intentYaml.has("status")) {
262
263 final String label = intentYaml.get("status").asString();
264 final long statusAtMs = intentYaml.get("statusAtMs").asLong();
265
266 intent = instantiate(MutableIntent.class)
267 .setTimeMillis(statusAtMs)
268 .setTitle(label)
269 .setStatus(instantiate(MutableStatus.class)
270 .setLabel(label)
271 .setStatusAtMs(statusAtMs));
272
273 } else {
274
275 final long timeMillis = intentYaml.get("timeMillis").asLong();
276 final String title = intentYaml.get("title").asString();
277
278 intent = instantiate(MutableIntent.class)
279 .setTimeMillis(timeMillis)
280 .setTitle(title);
281
282 if (intentYaml.has("steps")) {
283
284 for (final Yaml stepYaml : intentYaml.get("steps").items()) {
285
286 intent.addToSteps(loadStep(stepYaml));
287 }
288 }
289 }
290
291 intents.add(intent);
292 }
293 }
294
295 return Iterables.toArray(intents, Intent.class);
296 }
297
298 private static Step loadStep(
299 final Yaml yaml
300 ) {
301
302 final long timeMillis = yaml.get("timeMillis").asLong();
303 final String typeAsString = yaml.get("type").asString();
304
305 final StepType type = toStepType(typeAsString);
306
307 final MutableStep step = instantiate(MutableStep.class)
308 .setTimeMillis(timeMillis)
309 .setType(type);
310
311 switch (type) {
312
313 case ASSERT_ABSENT:
314 step.setLocator(loadLocator(yaml.get("locator")))
315 .setResultType(toResultType(yaml.get("result").asString()));
316 break;
317 case ASSERT_PRESENT:
318 step.setLocator(loadLocator(yaml.get("locator")))
319 .setResultType(toResultType(yaml.get("result").asString()));
320 break;
321 case ATTRIBUTE:
322 step.setScope(toAttributeScope(yaml.get("scope").asString()))
323 .setName(yaml.get("name").asString());
324 if (yaml.has("value")) {
325 step.setValue(yaml.get("value").asString());
326 }
327 break;
328 case CALL:
329 step.setCallable(yaml.get("callable").asString());
330 break;
331 case CLEAR:
332 step.setLocator(loadLocator(yaml.get("locator")));
333 break;
334 case CLICK:
335 step.setLocator(loadLocator(yaml.get("locator")));
336 break;
337 case EXECUTE_SCRIPT:
338 step.setScript(yaml.get("script").asString());
339 break;
340 case EXT:
341 step.setNamespace(yaml.get("namespace").asString())
342 .setValue(yaml.get("value").asString());
343 break;
344 case FAILURE:
345 step.setMessage(yaml.get("message").asString())
346 .setResultType(toResultType(yaml.get("result").asString()));
347 break;
348 case GET:
349 step.setUrl(yaml.get("url").asString());
350 break;
351 case MESSAGE:
352 step.setMessage(yaml.get("message").asString());
353 break;
354 case SEND_KEYS:
355 step.setLocator(loadLocator(yaml.get("locator")))
356 .setValue(yaml.get("value").asString());
357 break;
358 case SET_VARIABLE:
359 step.setName(yaml.get("name").asString())
360 .setValue(yaml.get("value").asString());
361 break;
362 case SET_MASKED_VARIABLE:
363 step.setName(yaml.get("name").asString())
364 .setValue(yaml.get("value").asString());
365 break;
366 case SLEEP:
367 step.setSeconds(yaml.get("seconds").asInt());
368 break;
369 case SUCCESS:
370 step.setMessage(yaml.get("message").asString())
371 .setResultType(toResultType(yaml.get("result").asString()));
372 break;
373 case STATUS:
374 step.setLabel(yaml.get("label").asString());
375 break;
376 case TAKE_SCREENSHOT:
377 step.setFileName(yaml.get("fileName").asString());
378 break;
379 case WAIT_FOR:
380 step.setLocator(loadLocator(yaml.get("locator")));
381 break;
382 case WAIT_FOR_NOT:
383 step.setLocator(loadLocator(yaml.get("locator")));
384 break;
385 default:
386 throw new NotImplementedException("type: " + type);
387 }
388
389 return step;
390
391 }
392
393 private static AttributeScope toAttributeScope(
394 final String scopeAsString
395 ) {
396
397 if ("UPLOAD".equals(scopeAsString)) {
398 return AttributeScope.UPLOAD;
399 } else if ("RUN".equals(scopeAsString)) {
400 return AttributeScope.RUN;
401 } else if ("STEP".equals(scopeAsString)) {
402 return AttributeScope.STEP;
403 } else {
404 throw new NotImplementedException("scope: " + scopeAsString);
405 }
406 }
407
408 private static ResultType toResultType(
409 final String resultTypeAsString
410 ) {
411
412 if ("FAILURE".equals(resultTypeAsString)) {
413 return ResultType.FAILURE;
414 } else if ("SUCCESS".equals(resultTypeAsString)) {
415 return ResultType.SUCCESS;
416 } else {
417 throw new NotImplementedException("resultType: " + resultTypeAsString);
418 }
419 }
420
421 private static Locator loadLocator(
422 final Yaml locatorYaml
423 ) {
424
425 return instantiate(MutableLocator.class)
426 .setType(toLocatorType(locatorYaml.get("type").asString()))
427 .setValue(locatorYaml.get("value").asString());
428 }
429
430 private static LocatorType toLocatorType(
431 final String typeAsString
432 ) {
433
434 if ("By.id".equals(typeAsString)) {
435 return LocatorType.BY_ID;
436 } else if ("By.cssSelector".equals(typeAsString)) {
437 return LocatorType.BY_CSS_SELECTOR;
438 } else if ("By.xpath".equals(typeAsString)) {
439 return LocatorType.BY_XPATH;
440 } else {
441 throw new NotImplementedException("type: " + typeAsString);
442 }
443 }
444
445 private interface MutableElaborateLog extends ElaborateLog {
446
447 MutableElaborateLog setGuixerVersion(
448 String guixerVersion
449 );
450
451 MutableElaborateLog setDateAsString(
452 String dateAsString
453 );
454
455 MutableElaborateLog setDate(
456 @Nullable DateTime date
457 );
458
459 MutableElaborateLog setTestClassName(
460 String testClassName
461 );
462
463 MutableElaborateLog setTestClassSimpleName(
464 String testClassSimpleName
465 );
466
467 MutableElaborateLog setTestMethodName(
468 String testMethodName
469 );
470
471 MutableElaborateLog setTimeMillis(
472 long timeMillis
473 );
474
475 MutableElaborateLog setScenario(
476 String scenario
477 );
478
479 MutableElaborateLog setSuccessCount(
480 int successCount
481 );
482
483 MutableElaborateLog setFailureCount(
484 int failureCount
485 );
486
487 MutableElaborateLog addToAttributes(
488 Attribute attribute
489 );
490
491 MutableElaborateLog setBefore(
492 @Nullable Before before
493 );
494
495 MutableElaborateLog addToIntents(
496 Intent intent
497 );
498
499 MutableElaborateLog setIntents(
500 Intent[] intents
501 );
502
503 MutableElaborateLog setInError(
504 boolean inError
505 );
506
507 MutableElaborateLog setError(
508 @Nullable LogError error
509 );
510
511 MutableElaborateLog setRawBytes(
512 byte[] bytes
513 );
514
515 MutableElaborateLog setDone(
516 Done done
517 );
518 }
519 }