View Javadoc
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 = // YamlUtils.loadYaml(yamlLogFile);
58  				GuixerYamlUtils.bindSnakeYaml(SnakeYAMLUtils.loadYAML(yamlLogFile));
59  
60  		final String guixerVersion = yaml.get("guixerVersion").asString();
61  		final String dateAsString = yaml.get("date").toString();
62  		// final DateTime dateTime=DateTime.parse(dateAsString);
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 				// ? Integer.parseInt(yaml.get("successCount").asString()) //
173 				? yaml.get("successCount").asInt() //
174 				: null;
175 
176 		@Nullable
177 		final Integer refFailureCount = yaml.has("failureCount") //
178 				// ? Integer.parseInt(yaml.get("failureCount").asString()) //
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 }