/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.everrest.assured;
import com.jayway.restassured.RestAssured;
import org.everrest.core.Filter;
import org.everrest.core.FilterDescriptor;
import org.everrest.core.ObjectFactory;
import org.everrest.core.ObjectModel;
import org.everrest.core.RequestFilter;
import org.everrest.core.ResponseFilter;
import org.everrest.core.impl.EverrestApplication;
import org.everrest.core.impl.FilterDescriptorImpl;
import org.everrest.core.impl.provider.ProviderDescriptorImpl;
import org.everrest.core.impl.resource.AbstractResourceDescriptor;
import org.everrest.core.method.MethodInvokerFilter;
import org.everrest.core.provider.ProviderDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.IInvokedMethod;
import org.testng.IInvokedMethodListener;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestNGListener;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.annotations.Listeners;
import javax.ws.rs.Path;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import java.lang.reflect.Field;
public class EverrestJetty implements ITestListener, IInvokedMethodListener {
public final static String JETTY_PORT = "jetty-port";
public final static String JETTY_SERVER = "jetty-server";
private static final Logger LOG = LoggerFactory.getLogger(EverrestJetty.class);
private JettyHttpServer httpServer;
/**
* @see org.testng.IInvokedMethodListener#afterInvocation(org.testng.IInvokedMethod,
* org.testng.ITestResult)
*/
@Override
public void afterInvocation(IInvokedMethod method, ITestResult testResult) {
if (httpServer != null && hasEverrestJettyListener(method.getTestMethod().getInstance().getClass())) {
httpServer.resetFactories();
httpServer.resetFilter();
}
}
/**
* @see org.testng.IInvokedMethodListener#beforeInvocation(org.testng.IInvokedMethod,
* org.testng.ITestResult)
*/
@Override
public void beforeInvocation(IInvokedMethod method, ITestResult testResult) {
if (httpServer != null && hasEverrestJettyListener(method.getTestMethod().getInstance().getClass())) {
httpServer.resetFactories();
httpServer.resetFilter();
initRestResource(method.getTestMethod());
}
}
public void onFinish(ITestContext context) {
JettyHttpServer httpServer = (JettyHttpServer)context.getAttribute(JETTY_SERVER);
if (httpServer != null) {
try {
httpServer.stop();
httpServer = null;
} catch (Exception e) {
LOG.error(e.getLocalizedMessage(), e);
throw new RuntimeException(e.getLocalizedMessage(), e);
}
}
}
@Override
public void onTestStart(ITestResult result) {
}
@Override
public void onTestSuccess(ITestResult result) {
}
@Override
public void onTestFailure(ITestResult result) {
}
@Override
public void onTestSkipped(ITestResult result) {
}
@Override
public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
}
public void onStart(ITestContext context) {
ITestNGMethod[] allTestMethods = context.getAllTestMethods();
if (allTestMethods == null) {
return;
}
if (httpServer == null && hasEverrestJettyListenerTestHierarchy(allTestMethods)) {
httpServer = new JettyHttpServer();
context.setAttribute(JETTY_PORT, httpServer.getPort());
context.setAttribute(JETTY_SERVER, httpServer);
try {
httpServer.start();
httpServer.resetFactories();
httpServer.resetFilter();
RestAssured.port = httpServer.getPort();
RestAssured.basePath = JettyHttpServer.UNSECURE_REST;
} catch (Exception e) {
LOG.error(e.getLocalizedMessage(), e);
throw new RuntimeException(e.getLocalizedMessage(), e);
}
}
}
private void initRestResource(ITestNGMethod... testMethods) {
for (ITestNGMethod testMethod : testMethods) {
Object instance = testMethod.getInstance();
if (hasEverrestJettyListenerTestHierarchy(instance.getClass())) {
EverrestApplication everrest = new EverrestApplication();
Field[] fields = instance.getClass().getDeclaredFields();
for (Field field : fields) {
try {
if (isRestResource(field.getType())) {
ObjectFactory<? extends ObjectModel> factory = createFactory(instance, field);
if (factory != null) {
everrest.addFactory(factory);
}
} else if (javax.servlet.Filter.class.isAssignableFrom(field.getType())) {
field.setAccessible(true);
Object fieldInstance = field.get(instance);
if (fieldInstance != null) {
httpServer.addFilter(((javax.servlet.Filter)fieldInstance), "/*");
} else {
httpServer.addFilter((Class<? extends javax.servlet.Filter>)field.getType(), "/*");
}
}
} catch (IllegalAccessException e) {
LOG.error(e.getLocalizedMessage(), e);
}
}
if (everrest.getFactories().size() > 0) {
httpServer.publish(everrest);
}
}
}
}
private boolean hasEverrestJettyListener(Class<?> clazz) {
Listeners listeners = clazz.getAnnotation(Listeners.class);
if (listeners == null) {
return false;
}
for (Class<? extends ITestNGListener> listenerClass : listeners.value()) {
if (EverrestJetty.class.isAssignableFrom(listenerClass)) {
return true;
}
}
return false;
}
private boolean hasEverrestJettyListenerTestHierarchy(Class<?> testClass) {
for (Class<?> clazz = testClass; clazz != Object.class; clazz = clazz.getSuperclass()) {
if (hasEverrestJettyListener(clazz)) {
return true;
}
}
return false;
}
private boolean hasEverrestJettyListenerTestHierarchy(ITestNGMethod... testMethods) {
for (ITestNGMethod testMethod : testMethods) {
Object instance = testMethod.getInstance();
if (hasEverrestJettyListenerTestHierarchy(instance.getClass())) {
return true;
}
}
return false;
}
private boolean isRestResource(Class<?> resourceClass) {
return resourceClass.isAnnotationPresent(Path.class) ||
resourceClass.isAnnotationPresent(Provider.class) ||
resourceClass.isAnnotationPresent(Filter.class) ||
resourceClass.isAssignableFrom(ExceptionMapper.class) ||
resourceClass.isAssignableFrom(ContextResolver.class) ||
resourceClass.isAssignableFrom(MessageBodyReader.class) ||
resourceClass.isAssignableFrom(MessageBodyWriter.class) ||
resourceClass.isAssignableFrom(MethodInvokerFilter.class) ||
resourceClass.isAssignableFrom(RequestFilter.class) ||
resourceClass.isAssignableFrom(ResponseFilter.class);
}
public ObjectFactory<? extends ObjectModel> createFactory(Object testObject, Field field) {
Class clazz = (Class)field.getType();
if (clazz.getAnnotation(Provider.class) != null) {
ProviderDescriptor providerDescriptor = new ProviderDescriptorImpl(clazz);
return new TestResourceFactory<>(providerDescriptor, testObject, field);
} else if (clazz.getAnnotation(Filter.class) != null) {
FilterDescriptor filterDescriptor = new FilterDescriptorImpl(clazz);
return new TestResourceFactory<>(filterDescriptor, testObject, field);
} else if (clazz.getAnnotation(Path.class) != null) {
AbstractResourceDescriptor resourceDescriptor = new AbstractResourceDescriptor(clazz);
return new TestResourceFactory<>(resourceDescriptor, testObject, field);
}
return null;
}
}