Skip to content

Commit 4e06253

Browse files
committed
copy some code from jupiter5.4.0.M1 for some issues
1 parent 9491d2c commit 4e06253

File tree

15 files changed

+1619
-42
lines changed

15 files changed

+1619
-42
lines changed

dubbo-cluster/src/test/java/org/apache/dubbo/rpc/cluster/support/FailbackClusterInvokerTest.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
/*
23
* Licensed to the Apache Software Foundation (ASF) under one or more
34
* contributor license agreements. See the NOTICE file distributed with
@@ -25,16 +26,16 @@
2526
import org.apache.dubbo.rpc.RpcInvocation;
2627
import org.apache.dubbo.rpc.RpcResult;
2728
import org.apache.dubbo.rpc.cluster.Directory;
29+
import org.apache.dubbo.rpc.cluster.support.api.MethodOrderer;
30+
import org.apache.dubbo.rpc.cluster.support.api.Order;
31+
import org.apache.dubbo.rpc.cluster.support.api.TestMethodOrder;
2832

2933
import org.apache.log4j.Level;
3034
import org.junit.jupiter.api.AfterEach;
3135
import org.junit.jupiter.api.Assertions;
3236
import org.junit.jupiter.api.BeforeEach;
3337
import org.junit.jupiter.api.Disabled;
34-
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
35-
import org.junit.jupiter.api.Order;
3638
import org.junit.jupiter.api.Test;
37-
import org.junit.jupiter.api.TestMethodOrder;
3839

3940
import java.util.ArrayList;
4041
import java.util.List;
@@ -50,7 +51,7 @@
5051
* <p>
5152
* add annotation @TestMethodOrder, the testARetryFailed Method must to first execution
5253
*/
53-
@TestMethodOrder(OrderAnnotation.class)
54+
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
5455
public class FailbackClusterInvokerTest {
5556

5657
List<Invoker<FailbackClusterInvokerTest>> invokers = new ArrayList<Invoker<FailbackClusterInvokerTest>>();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2015-2018 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* http://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package org.apache.dubbo.rpc.cluster.support.api;
12+
13+
import org.apiguardian.api.API;
14+
15+
import java.lang.annotation.Annotation;
16+
import java.lang.reflect.Method;
17+
import java.util.List;
18+
import java.util.Optional;
19+
20+
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
21+
22+
/**
23+
* {@link MethodDescriptor} encapsulates functionality for a given {@link Method}.
24+
*
25+
* @since 5.4
26+
* @see MethodOrdererContext
27+
*/
28+
@API(status = EXPERIMENTAL, since = "5.4")
29+
public interface MethodDescriptor {
30+
31+
/**
32+
* Get the method for this descriptor.
33+
*
34+
* @return the method; never {@code null}
35+
*/
36+
Method getMethod();
37+
38+
/**
39+
* Determine if an annotation of {@code annotationType} is either
40+
* <em>present</em> or <em>meta-present</em> on the {@link Method} for
41+
* this descriptor.
42+
*
43+
* @param annotationType the annotation type to search for; never {@code null}
44+
* @return {@code true} if the annotation is present or meta-present
45+
* @see #findAnnotation(Class)
46+
* @see #findRepeatableAnnotations(Class)
47+
*/
48+
boolean isAnnotated(Class<? extends Annotation> annotationType);
49+
50+
/**
51+
* Find the first annotation of {@code annotationType} that is either
52+
* <em>present</em> or <em>meta-present</em> on the {@link Method} for
53+
* this descriptor.
54+
*
55+
* @param <A> the annotation type
56+
* @param annotationType the annotation type to search for; never {@code null}
57+
* @return an {@code Optional} containing the annotation; never {@code null} but
58+
* potentially empty
59+
* @see #isAnnotated(Class)
60+
* @see #findRepeatableAnnotations(Class)
61+
*/
62+
<A extends Annotation> Optional<A> findAnnotation(Class<A> annotationType);
63+
64+
/**
65+
* Find all <em>repeatable</em> {@linkplain Annotation annotations} of
66+
* {@code annotationType} that are either <em>present</em> or
67+
* <em>meta-present</em> on the {@link Method} for this descriptor.
68+
*
69+
* @param <A> the annotation type
70+
* @param annotationType the repeatable annotation type to search for; never
71+
* {@code null}
72+
* @return the list of all such annotations found; neither {@code null} nor
73+
* mutable, but potentially empty
74+
* @see #isAnnotated(Class)
75+
* @see #findAnnotation(Class)
76+
* @see java.lang.annotation.Repeatable
77+
*/
78+
<A extends Annotation> List<A> findRepeatableAnnotations(Class<A> annotationType);
79+
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
/*
2+
* Copyright 2015-2018 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* http://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package org.apache.dubbo.rpc.cluster.support.api;
12+
13+
import org.apiguardian.api.API;
14+
import org.junit.jupiter.api.parallel.ExecutionMode;
15+
import org.junit.platform.commons.logging.Logger;
16+
import org.junit.platform.commons.logging.LoggerFactory;
17+
import org.junit.platform.commons.util.ClassUtils;
18+
19+
import java.lang.reflect.Method;
20+
import java.util.Collections;
21+
import java.util.Comparator;
22+
import java.util.Optional;
23+
24+
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
25+
26+
/**
27+
* {@code MethodOrderer} defines the API for ordering the <em>test methods</em>
28+
* in a given test class.
29+
*
30+
* <p>In this context, the term "test method" refers to any method annotated with
31+
* {@code @Test}, {@code @RepeatedTest}, {@code @ParameterizedTest},
32+
* {@code @TestFactory}, or {@code @TestTemplate}.
33+
*
34+
* <h4>Built-in Implementations</h4>
35+
*
36+
* <p>JUnit Jupiter provides the following built-in {@code MethodOrderer}
37+
* implementations.
38+
*
39+
* <ul>
40+
* <li>{@link Alphanumeric}</li>
41+
* <li>{@link OrderAnnotation}</li>
42+
* <li>{@link Random}</li>
43+
* </ul>
44+
*
45+
* @since 5.4
46+
* @see TestMethodOrder
47+
* @see MethodOrdererContext
48+
* @see #orderMethods(MethodOrdererContext)
49+
*/
50+
@API(status = EXPERIMENTAL, since = "5.4")
51+
public interface MethodOrderer {
52+
53+
/**
54+
* Order the methods encapsulated in the supplied {@link MethodOrdererContext}.
55+
*
56+
* <p>The methods to order or sort are made indirectly available via
57+
* {@link MethodOrdererContext#getMethodDescriptors()}. Since this method
58+
* has a {@code void} return type, the list of method descriptors must be
59+
* modified directly.
60+
*
61+
* <p>For example, a simplified implementation of the {@link Random}
62+
* {@code MethodOrderer} might look like the following.
63+
*
64+
* <pre class="code">
65+
* public void orderMethods(MethodOrdererContext context) {
66+
* Collections.shuffle(context.getMethodDescriptors());
67+
* }
68+
* </pre>
69+
*
70+
* @param context the {@code MethodOrdererContext} containing the
71+
* {@link MethodDescriptor method descriptors} to order; never {@code null}
72+
* @see #getDefaultExecutionMode()
73+
*/
74+
void orderMethods(MethodOrdererContext context);
75+
76+
/**
77+
* Get the <em>default</em> {@link ExecutionMode} for the test class
78+
* configured with this {@link MethodOrderer}.
79+
*
80+
* <p>This method is guaranteed to be invoked after
81+
* {@link #orderMethods(MethodOrdererContext)} which allows implementations
82+
* of this method to determine the appropriate return value programmatically,
83+
* potentially based on actions that were taken in {@code orderMethods()}.
84+
*
85+
* <p>Defaults to {@link ExecutionMode#SAME_THREAD SAME_THREAD}, since
86+
* ordered methods are typically sorted in a fashion that would conflict
87+
* with concurrent execution.
88+
*
89+
* <p>In case the ordering does not conflict with concurrent execution,
90+
* implementations should return an empty {@link Optional} to signal that
91+
* the engine should decide which execution mode to use.
92+
*
93+
* <p>Can be overridden via an explicit
94+
* {@link org.junit.jupiter.api.parallel.Execution @Execution} declaration
95+
* on the test class or in concrete implementations of the
96+
* {@code MethodOrderer} API.
97+
*
98+
* @return the default {@code ExecutionMode}; never {@code null} but
99+
* potentially empty
100+
* @see #orderMethods(MethodOrdererContext)
101+
*/
102+
default Optional<ExecutionMode> getDefaultExecutionMode() {
103+
return Optional.of(ExecutionMode.SAME_THREAD);
104+
}
105+
106+
/**
107+
* {@code MethodOrderer} that sorts methods alphanumerically based on their
108+
* names using {@link String#compareTo(String)}.
109+
*
110+
* <p>If two methods have the same name, {@code String} representations of
111+
* their formal parameter lists will be used as a fallback for comparing the
112+
* methods.
113+
*/
114+
class Alphanumeric implements MethodOrderer {
115+
116+
/**
117+
* Sort the methods encapsulated in the supplied
118+
* {@link MethodOrdererContext} alphanumerically based on their names
119+
* and formal parameter lists.
120+
*/
121+
@Override
122+
public void orderMethods(MethodOrdererContext context) {
123+
context.getMethodDescriptors().sort(comparator);
124+
}
125+
126+
private static final Comparator<MethodDescriptor> comparator = (descriptor1, descriptor2) -> {
127+
Method method1 = descriptor1.getMethod();
128+
Method method2 = descriptor2.getMethod();
129+
130+
int result = method1.getName().compareTo(method2.getName());
131+
if (result != 0) {
132+
return result;
133+
}
134+
135+
// else
136+
return parameterList(method1).compareTo(parameterList(method2));
137+
};
138+
139+
private static String parameterList(Method method) {
140+
return ClassUtils.nullSafeToString(method.getParameterTypes());
141+
}
142+
}
143+
144+
/**
145+
* {@code MethodOrderer} that sorts methods based on the {@link Order @Order}
146+
* annotation.
147+
*
148+
* <p>Any methods that are assigned the same order value will be sorted
149+
* arbitrarily adjacent to each other.
150+
*
151+
* <p>Any methods not annotated with {@code @Order} will be assigned a default
152+
* order value of {@link Integer#MAX_VALUE} which will effectively cause them to
153+
* appear at the end of the sorted list.
154+
*/
155+
class OrderAnnotation implements MethodOrderer {
156+
157+
/**
158+
* Sort the methods encapsulated in the supplied
159+
* {@link MethodOrdererContext} based on the {@link Order @Order}
160+
* annotation.
161+
*/
162+
@Override
163+
public void orderMethods(MethodOrdererContext context) {
164+
context.getMethodDescriptors().sort(comparator);
165+
}
166+
167+
private static final Comparator<MethodDescriptor> comparator = //
168+
(descriptor1, descriptor2) -> Integer.compare(getOrder(descriptor1), getOrder(descriptor2));
169+
170+
private static int getOrder(MethodDescriptor descriptor) {
171+
return descriptor.findAnnotation(Order.class).map(Order::value).orElse(Integer.MAX_VALUE);
172+
}
173+
}
174+
175+
/**
176+
* {@code MethodOrderer} that orders methods pseudo-randomly and allows for
177+
* concurrent execution by default.
178+
*
179+
* <h4>Custom Seed</h4>
180+
*
181+
* <p>By default, the random <em>seed</em> used for ordering methods is the
182+
* value returned by {@link System#nanoTime()}. In order to produce repeatable
183+
* builds, a custom seed may be specified via the
184+
* {@link Random#RANDOM_SEED_PROPERTY_NAME junit.jupiter.execution.order.random.seed}
185+
* <em>configuration parameter</em> which can be supplied via the
186+
* {@code Launcher} API, build tools (e.g., Gradle and Maven), a JVM system
187+
* property, or the JUnit Platform configuration file (i.e., a file named
188+
* {@code junit-platform.properties} in the root of the class path). Consult
189+
* the User Guide for further information.
190+
*
191+
* @see #getDefaultExecutionMode()
192+
* @see Random#RANDOM_SEED_PROPERTY_NAME
193+
* @see java.util.Random
194+
*/
195+
class Random implements MethodOrderer {
196+
197+
private static final Logger logger = LoggerFactory.getLogger(Random.class);
198+
199+
/**
200+
* Property name used to set the random seed used by this
201+
* {@code MethodOrderer}: {@value}
202+
*
203+
* <h3>Supported Values</h3>
204+
*
205+
* <p>Supported values include any string that can be converted to a
206+
* {@link Long} via {@link Long#valueOf(String)}.
207+
*
208+
* <p>If not specified or if the specified value cannot be converted to
209+
* a {@code Long}, {@link System#nanoTime()} will be used as the random
210+
* seed.
211+
*/
212+
public static final String RANDOM_SEED_PROPERTY_NAME = "junit.jupiter.execution.order.random.seed";
213+
214+
private boolean usingCustomSeed = false;
215+
216+
/**
217+
* Order the methods encapsulated in the supplied
218+
* {@link MethodOrdererContext} pseudo-randomly.
219+
*/
220+
@Override
221+
public void orderMethods(MethodOrdererContext context) {
222+
Long seed = null;
223+
224+
Optional<String> configurationParameter = context.getConfigurationParameter(RANDOM_SEED_PROPERTY_NAME);
225+
if (configurationParameter.isPresent()) {
226+
String value = configurationParameter.get();
227+
try {
228+
seed = Long.valueOf(value);
229+
this.usingCustomSeed = true;
230+
logger.config(
231+
() -> String.format("Using custom seed for configuration parameter [%s] with value [%s].",
232+
RANDOM_SEED_PROPERTY_NAME, value));
233+
}
234+
catch (NumberFormatException ex) {
235+
logger.warn(ex,
236+
() -> String.format("Failed to convert configuration parameter [%s] with value [%s] to a long. "
237+
+ "Using System.nanoTime() as fallback.",
238+
RANDOM_SEED_PROPERTY_NAME, value));
239+
}
240+
}
241+
242+
if (seed == null) {
243+
seed = System.nanoTime();
244+
}
245+
246+
Collections.shuffle(context.getMethodDescriptors(), new java.util.Random(seed));
247+
}
248+
249+
/**
250+
* Get the <em>default</em> {@link ExecutionMode} for the test class.
251+
*
252+
* <p>If a custom seed has been specified, this method returns
253+
* {@link ExecutionMode#SAME_THREAD SAME_THREAD} in order to ensure that
254+
* the results are repeatable across executions of the test plan.
255+
* Otherwise, this method returns {@link ExecutionMode#CONCURRENT
256+
* CONCURRENT} to allow concurrent execution of randomly ordered methods
257+
* by default.
258+
*
259+
* @return {@code SAME_THREAD} if a custom seed has been configured;
260+
* otherwise, {@code CONCURRENT}
261+
*/
262+
@Override
263+
public Optional<ExecutionMode> getDefaultExecutionMode() {
264+
return this.usingCustomSeed ? Optional.of(ExecutionMode.SAME_THREAD) : Optional.empty();
265+
}
266+
}
267+
268+
}

0 commit comments

Comments
 (0)