Skip to content

Commit d45886c

Browse files
authored
Fixed flaky test WorkerFactoryRegistryTest.testRandomOrder (#2886)
1 parent 7a8e684 commit d45886c

1 file changed

Lines changed: 47 additions & 40 deletions

File tree

temporal-sdk/src/test/java/io/temporal/internal/client/WorkerFactoryRegistryTest.java

Lines changed: 47 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,67 @@
33
import static org.junit.Assert.*;
44
import static org.mockito.Mockito.mock;
55

6+
import com.google.common.collect.Lists;
67
import io.temporal.client.WorkflowClient;
78
import io.temporal.worker.WorkerFactory;
8-
import java.util.Iterator;
9+
import java.util.ArrayList;
10+
import java.util.HashSet;
11+
import java.util.List;
12+
import java.util.stream.Collectors;
13+
import java.util.stream.LongStream;
14+
import java.util.stream.Stream;
915
import org.junit.Test;
1016

1117
public class WorkerFactoryRegistryTest {
1218
/**
1319
* Covers a situation when one {@link WorkflowClient} used to create several WorkerFactories.
1420
* {@link WorkerFactoryRegistry#workerFactoriesRandomOrder()} will be used to get an iterator over
15-
* registered WorkerFactories and such an iterator should lead to an even distribution of
16-
* requests.
21+
* registered WorkerFactories. The iteration order should be random to allow a roughly even
22+
* distribution of requests. This test verifies every possible permutation of workers can happen,
23+
* which we use as a proxy to determine the ordering is sufficiently random.
1724
*/
1825
@Test
1926
public void testRandomOrder() {
20-
final int TOTAL_COUNT = 3000;
27+
// Creating 5 separate factories. Indices in this list will be used to identify ordering of
28+
// returned random iterables.
29+
List<WorkerFactory> orderedFactories =
30+
Stream.of(
31+
mock(WorkerFactory.class),
32+
mock(WorkerFactory.class),
33+
mock(WorkerFactory.class),
34+
mock(WorkerFactory.class),
35+
mock(WorkerFactory.class))
36+
.collect(Collectors.toList());
2137

2238
WorkerFactoryRegistry workerFactoryRegistry = new WorkerFactoryRegistry();
23-
WorkerFactory workerFactory1 = mock(WorkerFactory.class);
24-
WorkerFactory workerFactory2 = mock(WorkerFactory.class);
25-
WorkerFactory workerFactory3 = mock(WorkerFactory.class);
26-
27-
workerFactoryRegistry.register(workerFactory1);
28-
workerFactoryRegistry.register(workerFactory2);
29-
workerFactoryRegistry.register(workerFactory3);
30-
31-
int firstFactoryFirst = 0;
32-
int secondFactoryFirst = 0;
33-
int thirdFactoryFirst = 0;
34-
35-
for (int i = 0; i < TOTAL_COUNT; i++) {
36-
Iterable<WorkerFactory> workerFactories = workerFactoryRegistry.workerFactoriesRandomOrder();
37-
Iterator<WorkerFactory> iterator = workerFactories.iterator();
38-
WorkerFactory first = iterator.next();
39-
WorkerFactory second = iterator.next();
40-
WorkerFactory third = iterator.next();
41-
42-
assertFalse(iterator.hasNext());
43-
assertNotEquals(first, second);
44-
assertNotEquals(first, third);
45-
assertNotEquals(second, third);
46-
47-
if (first == workerFactory1) {
48-
firstFactoryFirst++;
49-
} else if (first == workerFactory2) {
50-
secondFactoryFirst++;
51-
} else if (first == workerFactory3) {
52-
thirdFactoryFirst++;
53-
} else {
54-
fail("Unexpected WorkerFactory");
39+
orderedFactories.forEach(workerFactoryRegistry::register);
40+
41+
HashSet<Long> permutationsFound = new HashSet<>();
42+
// The number of all possible permutations is the factorial of number of elements.
43+
long expectedPermutationsCount =
44+
LongStream.rangeClosed(1, orderedFactories.size()).reduce(1, (a, b) -> a * b);
45+
46+
while (permutationsFound.size() < expectedPermutationsCount) {
47+
List<WorkerFactory> randomFactories =
48+
Lists.newArrayList(workerFactoryRegistry.workerFactoriesRandomOrder());
49+
assertEquals(orderedFactories.size(), randomFactories.size());
50+
51+
List<Integer> indices = new ArrayList<>(orderedFactories.size());
52+
for (WorkerFactory factory : randomFactories) {
53+
int index = orderedFactories.indexOf(factory);
54+
assertFalse("Factory " + index + " appears twice", indices.contains(index));
55+
indices.add(index);
5556
}
56-
}
5757

58-
assertTrue(Math.abs(secondFactoryFirst - firstFactoryFirst) < TOTAL_COUNT * 0.05);
59-
assertTrue(Math.abs(thirdFactoryFirst - firstFactoryFirst) < TOTAL_COUNT * 0.05);
60-
assertTrue(Math.abs(thirdFactoryFirst - secondFactoryFirst) < TOTAL_COUNT * 0.05);
58+
// This number uniquely identifies the current permutation, so that we can ensure all
59+
// permutations were seen. Written in base-(orderedFactories.size()), the digits are
60+
// the respective indices of randomFactories in orderedFactories.
61+
long permutationId = 0;
62+
for (int index : indices) {
63+
permutationId *= orderedFactories.size();
64+
permutationId += index;
65+
}
66+
permutationsFound.add(permutationId);
67+
}
6168
}
6269
}

0 commit comments

Comments
 (0)