// Copyright 2015 ThoughtWorks, Inc.
// This file is part of Gauge-Java.
// This program is free software.
//
// It is dual-licensed under:
// 1) the GNU General Public License as published by the Free Software Foundation,
// either version 3 of the License, or (at your option) any later version;
// or
// 2) the Eclipse Public License v1.0.
//
// You can redistribute it and/or modify it under the terms of either license.
// We would then provide copied of each license in a separate .txt file with the name of the license as the title of the file.
package com.thoughtworks.gauge.execution;
import com.google.protobuf.ByteString;
import com.thoughtworks.gauge.ClassInstanceManager;
import com.thoughtworks.gauge.ContinueOnFailure;
import com.thoughtworks.gauge.screenshot.ScreenshotFactory;
import gauge.messages.Spec;
import java.lang.reflect.Method;
import java.util.Set;
public class MethodExecutor {
private ClassInstanceManager instanceManager;
public MethodExecutor(ClassInstanceManager instanceManager) {
this.instanceManager = instanceManager;
}
public Spec.ProtoExecutionResult execute(Method method, Object... args) {
long startTime = System.currentTimeMillis();
try {
Object instance = instanceManager.get(method.getDeclaringClass());
method.invoke(instance, args);
long endTime = System.currentTimeMillis();
return Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(endTime - startTime).build();
} catch (Throwable e) {
boolean recoverable = method.isAnnotationPresent(ContinueOnFailure.class);
Class[] continuableExceptions = new Class[]{};
if (recoverable) {
continuableExceptions = method.getAnnotation(ContinueOnFailure.class).value();
}
long endTime = System.currentTimeMillis();
return createFailureExecResult(endTime - startTime, e, recoverable, continuableExceptions);
}
}
private Spec.ProtoExecutionResult createFailureExecResult(long execTime, Throwable e, boolean recoverable, Class[] continuableExceptions) {
Spec.ProtoExecutionResult.Builder builder = Spec.ProtoExecutionResult.newBuilder().setFailed(true);
builder.setScreenShot(ByteString.copyFrom(new ScreenshotFactory(instanceManager).getScreenshotBytes()));
if (e.getCause() != null) {
builder.setRecoverableError(false);
for (Class c : continuableExceptions) {
if (c.isAssignableFrom(e.getCause().getClass()) && recoverable) {
builder.setRecoverableError(true);
break;
}
}
builder.setErrorMessage(e.getCause().toString());
builder.setStackTrace(formatStackTrace(e.getCause().getStackTrace()));
} else {
builder.setRecoverableError(recoverable);
builder.setErrorMessage(e.toString());
builder.setStackTrace(formatStackTrace(e.getStackTrace()));
}
builder.setExecutionTime(execTime);
return builder.build();
}
private String formatStackTrace(StackTraceElement[] stackTrace) {
if (stackTrace == null) {
return "";
}
StringBuilder output = new StringBuilder();
for (StackTraceElement element : stackTrace) {
output.append(element.toString());
output.append("\n");
}
return output.toString();
}
public Spec.ProtoExecutionResult executeMethods(Set<Method> methods, Object... args) {
long totalExecutionTime = 0;
for (Method method : methods) {
Spec.ProtoExecutionResult result = execute(method, args);
totalExecutionTime += result.getExecutionTime();
if (result.getFailed()) {
return result;
}
}
return Spec.ProtoExecutionResult.newBuilder().setFailed(false).setExecutionTime(totalExecutionTime).build();
}
}