001/**
002 * Copyright (C) 2006-2022 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.junit5.environment;
017
018import static java.util.Collections.singletonList;
019import static java.util.Optional.of;
020import static java.util.Optional.ofNullable;
021
022import java.lang.annotation.Annotation;
023import java.util.List;
024import java.util.stream.Stream;
025
026import org.junit.jupiter.api.extension.AfterEachCallback;
027import org.junit.jupiter.api.extension.BeforeEachCallback;
028import org.junit.jupiter.api.extension.ConditionEvaluationResult;
029import org.junit.jupiter.api.extension.ExecutionCondition;
030import org.junit.jupiter.api.extension.Extension;
031import org.junit.jupiter.api.extension.ExtensionContext;
032import org.junit.jupiter.api.extension.ParameterContext;
033import org.junit.jupiter.api.extension.ParameterResolutionException;
034import org.junit.jupiter.api.extension.ParameterResolver;
035import org.junit.jupiter.api.extension.TestInstancePostProcessor;
036import org.junit.jupiter.api.extension.TestTemplateInvocationContext;
037import org.junit.platform.commons.util.AnnotationUtils;
038import org.talend.sdk.component.junit.environment.DecoratingEnvironmentProvider;
039import org.talend.sdk.component.junit.environment.EnvironmentConfiguration;
040import org.talend.sdk.component.junit.environment.EnvironmentConfigurations;
041import org.talend.sdk.component.junit.environment.EnvironmentProvider;
042import org.talend.sdk.component.junit5.ComponentExtension;
043
044import lombok.AllArgsConstructor;
045
046@AllArgsConstructor
047public class EnvironmentalContext implements TestTemplateInvocationContext {
048
049    private final EnvironmentProvider provider;
050
051    private final String displayName;
052
053    private final ComponentExtension componentExtension;
054
055    @Override
056    public String getDisplayName(final int invocationIndex) {
057        return displayName;
058    }
059
060    @Override
061    public List<Extension> getAdditionalExtensions() {
062        return singletonList(new EnvironmentalLifecycle(provider, componentExtension, null));
063    }
064
065    @AllArgsConstructor
066    public static class EnvironmentalLifecycle implements BeforeEachCallback, AfterEachCallback, ExecutionCondition,
067            ParameterResolver, TestInstancePostProcessor {
068
069        private final EnvironmentProvider provider;
070
071        private final ComponentExtension componentExtension;
072
073        private AutoCloseable closeable;
074
075        @Override
076        public void beforeEach(final ExtensionContext context) {
077            closeable = provider
078                    .start(context.getRequiredTestClass(),
079                            Stream
080                                    .concat(Stream.of(context.getRequiredTestClass().getAnnotations()),
081                                            Stream
082                                                    .of(of(AnnotationUtils
083                                                            .findRepeatableAnnotations(context.getRequiredTestClass(),
084                                                                    EnvironmentConfiguration.class))
085                                                                            .filter(it -> !it.isEmpty())
086                                                                            .map(l -> new Annotation[] {
087                                                                                    new EnvironmentConfigurations() {
088
089                                                                                        @Override
090                                                                                        public Class<? extends Annotation>
091                                                                                                annotationType() {
092                                                                                            return EnvironmentConfigurations.class;
093                                                                                        }
094
095                                                                                        @Override
096                                                                                        public EnvironmentConfiguration[]
097                                                                                                value() {
098                                                                                            return l
099                                                                                                    .toArray(
100                                                                                                            new EnvironmentConfiguration[0]);
101                                                                                        }
102                                                                                    } })
103                                                                            .orElseGet(() -> new Annotation[0])))
104                                    .toArray(Annotation[]::new));
105            ofNullable(componentExtension).ifPresent(c -> {
106                c.doStart(context);
107                c.doInject(context);
108            });
109        }
110
111        @Override
112        public void afterEach(final ExtensionContext context) {
113            ofNullable(componentExtension).ifPresent(c -> {
114                c.resetState();
115                c.doStop(context);
116            });
117            ofNullable(closeable).ifPresent(c -> {
118                try {
119                    c.close();
120                } catch (final Exception e) {
121                    throw new IllegalStateException(e);
122                }
123            });
124        }
125
126        @Override
127        public ConditionEvaluationResult evaluateExecutionCondition(final ExtensionContext context) {
128            return isActive() ? ConditionEvaluationResult.enabled("provider is active")
129                    : ConditionEvaluationResult.disabled("provider is disabled");
130        }
131
132        private boolean isActive() {
133            return DecoratingEnvironmentProvider.class.isInstance(provider)
134                    && DecoratingEnvironmentProvider.class.cast(provider).isActive();
135        }
136
137        @Override
138        public boolean supportsParameter(final ParameterContext parameterContext,
139                final ExtensionContext extensionContext) throws ParameterResolutionException {
140            return componentExtension != null
141                    && componentExtension.supportsParameter(parameterContext, extensionContext);
142        }
143
144        @Override
145        public Object resolveParameter(final ParameterContext parameterContext, final ExtensionContext extensionContext)
146                throws ParameterResolutionException {
147            return componentExtension == null ? null
148                    : componentExtension.resolveParameter(parameterContext, extensionContext);
149        }
150
151        @Override
152        public void postProcessTestInstance(final Object o, final ExtensionContext extensionContext) {
153            if (componentExtension != null) {
154                componentExtension.postProcessTestInstance(o, extensionContext);
155            }
156        }
157    }
158}