View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.surefire.junitplatform;
20  
21  import java.lang.reflect.Method;
22  
23  import org.apache.maven.surefire.api.util.ReflectionUtils;
24  import org.junit.platform.launcher.Launcher;
25  import org.junit.platform.launcher.LauncherDiscoveryRequest;
26  import org.junit.platform.launcher.TestExecutionListener;
27  import org.junit.platform.launcher.TestPlan;
28  
29  import static java.util.Objects.requireNonNull;
30  import static org.apache.maven.surefire.junitplatform.CancellationTokenAdapter.CANCELLATION_TOKEN_CLASS;
31  
32  final class LauncherAdapter {
33  
34      static final Class<?> LAUNCHER_EXECUTION_REQUEST_CLASS = loadLauncherExecutionRequestClass();
35      static final Method EXECUTE_METHOD_WITH_LAUNCHER_EXECUTION_REQUEST_PARAMETER =
36              findExecuteMethodWithLauncherExecutionRequestParameter();
37  
38      private final Launcher delegate;
39      private final CancellationTokenAdapter cancellationToken;
40  
41      LauncherAdapter(Launcher delegate, CancellationTokenAdapter cancellationToken) {
42          this.delegate = delegate;
43          this.cancellationToken = cancellationToken;
44      }
45  
46      TestPlan discover(LauncherDiscoveryRequest discoveryRequest) {
47          return delegate.discover(discoveryRequest);
48      }
49  
50      void execute(LauncherDiscoveryRequest discoveryRequest, TestExecutionListener... listeners) {
51          if (cancellationToken == null) {
52              executeWithoutCancellationToken(discoveryRequest, listeners);
53          } else {
54              executeWithCancellationToken(discoveryRequest, listeners);
55          }
56      }
57  
58      void executeWithoutCancellationToken(
59              LauncherDiscoveryRequest discoveryRequest, TestExecutionListener... listeners) {
60          delegate.execute(discoveryRequest, listeners);
61      }
62  
63      private void executeWithCancellationToken(
64              LauncherDiscoveryRequest discoveryRequest, TestExecutionListener... listeners) {
65  
66          Method executeMethod = requireNonNull(EXECUTE_METHOD_WITH_LAUNCHER_EXECUTION_REQUEST_PARAMETER);
67          Object executionRequest = createExecutionRequest(discoveryRequest, listeners);
68          ReflectionUtils.invokeMethodWithArray(delegate, executeMethod, executionRequest);
69      }
70  
71      private static Method findExecuteMethodWithLauncherExecutionRequestParameter() {
72          if (LAUNCHER_EXECUTION_REQUEST_CLASS == null) {
73              return null;
74          }
75          return ReflectionUtils.getMethod(Launcher.class, "execute", LAUNCHER_EXECUTION_REQUEST_CLASS);
76      }
77  
78      private static Class<?> loadLauncherExecutionRequestClass() {
79          return ReflectionUtils.tryLoadClass(
80                  Launcher.class.getClassLoader(), "org.junit.platform.launcher.LauncherExecutionRequest");
81      }
82  
83      private Object createExecutionRequest(
84              LauncherDiscoveryRequest discoveryRequest, TestExecutionListener[] listeners) {
85  
86          Object builder = createLauncherExecutionRequestBuilder(discoveryRequest);
87          ReflectionUtils.invokeSetter(builder, "listeners", TestExecutionListener[].class, listeners);
88          ReflectionUtils.invokeSetter(
89                  builder, "cancellationToken", CANCELLATION_TOKEN_CLASS, cancellationToken.getDelegate());
90          return ReflectionUtils.invokeGetter(builder, "build");
91      }
92  
93      private static Object createLauncherExecutionRequestBuilder(LauncherDiscoveryRequest discoveryRequest) {
94          ClassLoader classLoader = discoveryRequest.getClass().getClassLoader();
95          Class<?> builderClass = ReflectionUtils.loadClass(
96                  classLoader, "org.junit.platform.launcher.core.LauncherExecutionRequestBuilder");
97          Class<?>[] parameterTypes = {LauncherDiscoveryRequest.class};
98          Object[] parameters = {discoveryRequest};
99          return ReflectionUtils.invokeStaticMethod(builderClass, "request", parameterTypes, parameters);
100     }
101 }