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}