001/** 002 * Copyright (C) 2006-2018 Talend Inc. - www.talend.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.talend.sdk.component.junit.http.internal.junit5; 017 018import static java.util.Optional.ofNullable; 019 020import java.lang.annotation.Annotation; 021import java.lang.reflect.InvocationTargetException; 022import java.util.Optional; 023import java.util.concurrent.Executor; 024import java.util.function.Predicate; 025import java.util.function.Supplier; 026 027import javax.net.ssl.SSLContext; 028 029import org.junit.jupiter.api.extension.AfterAllCallback; 030import org.junit.jupiter.api.extension.AfterEachCallback; 031import org.junit.jupiter.api.extension.BeforeAllCallback; 032import org.junit.jupiter.api.extension.BeforeEachCallback; 033import org.junit.jupiter.api.extension.ExtensionContext; 034import org.talend.sdk.component.junit.base.junit5.JUnit5InjectionSupport; 035import org.talend.sdk.component.junit.http.api.HttpApiHandler; 036import org.talend.sdk.component.junit.http.api.ResponseLocator; 037import org.talend.sdk.component.junit.http.internal.impl.DefaultResponseLocator; 038import org.talend.sdk.component.junit.http.internal.impl.HandlerImpl; 039import org.talend.sdk.component.junit.http.internal.impl.Handlers; 040import org.talend.sdk.component.junit.http.junit5.HttpApi; 041import org.talend.sdk.component.junit.http.junit5.HttpApiInject; 042import org.talend.sdk.component.junit.http.junit5.HttpApiName; 043 044public class JUnit5HttpApi extends HttpApiHandler<JUnit5HttpApi> 045 implements BeforeAllCallback, AfterAllCallback, JUnit5InjectionSupport, AfterEachCallback, BeforeEachCallback { 046 047 private static final ExtensionContext.Namespace NAMESPACE = 048 ExtensionContext.Namespace.create(JUnit5HttpApi.class.getName()); 049 050 @Override 051 public void beforeAll(final ExtensionContext extensionContext) { 052 final HttpApi config = extensionContext.getElement().map(c -> c.getAnnotation(HttpApi.class)).orElse(null); 053 if (config != null) { 054 setGlobalProxyConfiguration(config.globalProxyConfiguration()); 055 setLogLevel(config.logLevel()); 056 setPort(config.port()); 057 newInstance(config.responseLocator(), ResponseLocator.class).ifPresent(this::setResponseLocator); 058 newInstance(config.headerFilter(), Predicate.class).ifPresent(this::setHeaderFilter); 059 newInstance(config.executor(), Executor.class).ifPresent(this::setExecutor); 060 newInstance(config.sslContext(), Supplier.class) 061 .map(s -> SSLContext.class.cast(s.get())) 062 .ifPresent(this::setSslContext); 063 setSkipProxyHeaders(config.skipProxyHeaders()); 064 if (config.useSsl()) { 065 activeSsl(); 066 } 067 } 068 extensionContext.getStore(NAMESPACE).put(HttpApiHandler.class.getName(), this); 069 final HandlerImpl<JUnit5HttpApi> handler = new HandlerImpl<>(this, null, null); 070 extensionContext.getStore(NAMESPACE).put(HandlerImpl.class.getName(), handler); 071 handler.start(); 072 } 073 074 @Override 075 public void afterAll(final ExtensionContext extensionContext) { 076 HandlerImpl.class.cast(extensionContext.getStore(NAMESPACE).get(HandlerImpl.class.getName())).close(); 077 } 078 079 @Override 080 public Class<? extends Annotation> injectionMarker() { 081 return HttpApiInject.class; 082 } 083 084 @Override 085 public void beforeEach(final ExtensionContext extensionContext) { 086 // test name 087 final ResponseLocator responseLocator = getResponseLocator(); 088 if (!DefaultResponseLocator.class.isInstance(responseLocator)) { 089 return; 090 } 091 final String test = extensionContext.getTestMethod().map(m -> { 092 final String displayName = sanitizeDisplayName(extensionContext.getDisplayName()); 093 return ofNullable(m.getAnnotation(HttpApiName.class)) 094 .map(HttpApiName::value) 095 .map(it -> it.replace("${class}", m.getDeclaringClass().getName())) 096 .map(it -> it.replace("${method}", m.getName())) 097 .map(it -> it.replace("${displayName}", displayName)) 098 .orElseGet(() -> m.getDeclaringClass().getName() + "_" + m.getName() 099 + (displayName.equals(m.getName()) ? "" : ("_" + displayName))); 100 }).orElse(null); 101 DefaultResponseLocator.class.cast(responseLocator).setTest(test); 102 } 103 104 @Override 105 public void afterEach(final ExtensionContext extensionContext) { 106 if (Handlers.isActive("capture")) { 107 Optional 108 .of(getResponseLocator()) 109 .filter(DefaultResponseLocator.class::isInstance) 110 .map(DefaultResponseLocator.class::cast) 111 .ifPresent(r -> r.flush(Handlers.getBaseCapture())); 112 } 113 } 114 115 private String sanitizeDisplayName(final String displayName) { 116 final String base = displayName.replace(" ", "_"); 117 final int parenthesis = base.indexOf('('); 118 if (parenthesis > 0) { 119 return base.substring(0, parenthesis); 120 } 121 return base; 122 } 123 124 private static <T> Optional<T> newInstance(final Class<?> type, final Class<T> api) { 125 if (api == type) { 126 return Optional.empty(); 127 } 128 try { 129 return Optional.of(api.cast(type.getConstructor().newInstance())); 130 } catch (final NoSuchMethodException | InstantiationException | IllegalAccessException e) { 131 throw new IllegalArgumentException(e); 132 } catch (final InvocationTargetException e) { 133 throw new IllegalStateException(e.getTargetException()); 134 } 135 } 136}