diff options
Diffstat (limited to 'model-data/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz')
2 files changed, 195 insertions, 0 deletions
diff --git a/model-data/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadFuzzTest.java b/model-data/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadFuzzTest.java new file mode 100644 index 00000000..1a213de3 --- /dev/null +++ b/model-data/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadFuzzTest.java | |||
@@ -0,0 +1,96 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz; | ||
2 | |||
3 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
4 | import static org.junit.jupiter.api.Assertions.fail; | ||
5 | |||
6 | import java.util.Collections; | ||
7 | import java.util.LinkedList; | ||
8 | import java.util.List; | ||
9 | import java.util.stream.Stream; | ||
10 | |||
11 | import org.eclipse.viatra.solver.data.map.ContinousHashProvider; | ||
12 | import org.eclipse.viatra.solver.data.map.VersionedMapStore; | ||
13 | import org.eclipse.viatra.solver.data.map.VersionedMapStoreImpl; | ||
14 | import org.eclipse.viatra.solver.data.map.tests.fuzz.utils.FuzzTestUtils; | ||
15 | import org.eclipse.viatra.solver.data.map.tests.utils.MapTestEnvironment; | ||
16 | import org.junit.jupiter.api.Tag; | ||
17 | import org.junit.jupiter.api.Timeout; | ||
18 | import org.junit.jupiter.params.ParameterizedTest; | ||
19 | import org.junit.jupiter.params.provider.Arguments; | ||
20 | import org.junit.jupiter.params.provider.MethodSource; | ||
21 | |||
22 | class MultiThreadFuzzTest { | ||
23 | public static final int noThreads = 32; | ||
24 | |||
25 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | ||
26 | boolean evilHash) { | ||
27 | String[] values = MapTestEnvironment.prepareValues(maxValue); | ||
28 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | ||
29 | |||
30 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | ||
31 | |||
32 | // initialize runnables | ||
33 | MultiThreadTestRunnable[] runnables = new MultiThreadTestRunnable[noThreads]; | ||
34 | for(int i = 0; i<noThreads; i++) { | ||
35 | runnables[i] = new MultiThreadTestRunnable(scenario+"-T"+(i+1), store, steps, maxKey, values, seed, commitFrequency); | ||
36 | } | ||
37 | |||
38 | // initialize threads | ||
39 | Thread[] threads = new Thread[noThreads]; | ||
40 | for(int i = 0; i<noThreads; i++) { | ||
41 | threads[i] = new Thread(runnables[i]); | ||
42 | } | ||
43 | |||
44 | // start threads; | ||
45 | for(int i = 0; i<noThreads; i++) { | ||
46 | threads[i].start(); | ||
47 | } | ||
48 | |||
49 | // wait all the threads; | ||
50 | for(int i = 0; i<noThreads; i++) { | ||
51 | try { | ||
52 | threads[i].join(); | ||
53 | } catch (InterruptedException e) { | ||
54 | fail("Thread "+i+" interrupted."); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | // collect errors | ||
59 | List<Throwable> errors = new LinkedList<>(); | ||
60 | for(int i = 0; i<noThreads; i++) { | ||
61 | errors.addAll(runnables[i].getErrors()); | ||
62 | } | ||
63 | |||
64 | assertEquals(Collections.EMPTY_LIST, errors); | ||
65 | } | ||
66 | |||
67 | @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
68 | @MethodSource | ||
69 | @Timeout(value = 10) | ||
70 | @Tag("fuzz") | ||
71 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
72 | boolean evilHash) { | ||
73 | runFuzzTest("MultithreadS" + steps + "K" + noKeys + "V" + noValues + "CF" + commitFrequency + "s" + seed, seed, steps, noKeys, noValues, | ||
74 | commitFrequency, evilHash); | ||
75 | } | ||
76 | |||
77 | static Stream<Arguments> parametrizedFastFuzz() { | ||
78 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | ||
79 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | ||
80 | new Object[] { false, true }); | ||
81 | } | ||
82 | |||
83 | @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | ||
84 | @MethodSource | ||
85 | @Tag("fuzz") | ||
86 | @Tag("slow") | ||
87 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | ||
88 | boolean evilHash) { | ||
89 | runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
90 | commitFrequency, evilHash); | ||
91 | } | ||
92 | |||
93 | static Stream<Arguments> parametrizedSlowFuzz() { | ||
94 | return FuzzTestUtils.changeStepCount(RestoreFuzzTest.parametrizedFastFuzz(), 1); | ||
95 | } | ||
96 | } | ||
diff --git a/model-data/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadTestRunnable.java b/model-data/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadTestRunnable.java new file mode 100644 index 00000000..c247a9e1 --- /dev/null +++ b/model-data/src/test/java/org/eclipse/viatra/solver/data/map/tests/fuzz/MultiThreadTestRunnable.java | |||
@@ -0,0 +1,99 @@ | |||
1 | package org.eclipse.viatra.solver.data.map.tests.fuzz; | ||
2 | |||
3 | import java.util.ArrayList; | ||
4 | import java.util.HashMap; | ||
5 | import java.util.LinkedList; | ||
6 | import java.util.List; | ||
7 | import java.util.Map; | ||
8 | import java.util.Random; | ||
9 | |||
10 | import org.eclipse.viatra.solver.data.map.VersionedMapStore; | ||
11 | import org.eclipse.viatra.solver.data.map.internal.VersionedMapImpl; | ||
12 | import org.eclipse.viatra.solver.data.map.tests.utils.MapTestEnvironment; | ||
13 | |||
14 | public class MultiThreadTestRunnable implements Runnable { | ||
15 | String scenario; | ||
16 | VersionedMapStore<Integer, String> store; | ||
17 | int steps; | ||
18 | int maxKey; | ||
19 | String[] values; | ||
20 | int seed; | ||
21 | int commitFrequency; | ||
22 | List<Throwable> errors = new LinkedList<>(); | ||
23 | |||
24 | public MultiThreadTestRunnable(String scenario, VersionedMapStore<Integer, String> store, int steps, | ||
25 | int maxKey, String[] values, int seed, int commitFrequency) { | ||
26 | super(); | ||
27 | this.scenario = scenario; | ||
28 | this.store = store; | ||
29 | this.steps = steps; | ||
30 | this.maxKey = maxKey; | ||
31 | this.values = values; | ||
32 | this.seed = seed; | ||
33 | this.commitFrequency = commitFrequency; | ||
34 | } | ||
35 | |||
36 | private void logAndThrowError(String message) { | ||
37 | AssertionError error = new AssertionError(message); | ||
38 | errors.add(error); | ||
39 | } | ||
40 | |||
41 | public List<Throwable> getErrors() { | ||
42 | return errors; | ||
43 | } | ||
44 | |||
45 | @Override | ||
46 | public void run() { | ||
47 | // 1. build a map with versions | ||
48 | Random r = new Random(seed); | ||
49 | VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
50 | Map<Integer, Long> index2Version = new HashMap<>(); | ||
51 | |||
52 | for (int i = 0; i < steps; i++) { | ||
53 | int index = i + 1; | ||
54 | int nextKey = r.nextInt(maxKey); | ||
55 | String nextValue = values[r.nextInt(values.length)]; | ||
56 | try { | ||
57 | versioned.put(nextKey, nextValue); | ||
58 | } catch (Exception exception) { | ||
59 | exception.printStackTrace(); | ||
60 | logAndThrowError(scenario + ":" + index + ": exception happened: " + exception); | ||
61 | } | ||
62 | if (index % commitFrequency == 0) { | ||
63 | long version = versioned.commit(); | ||
64 | index2Version.put(i, version); | ||
65 | } | ||
66 | MapTestEnvironment.printStatus(scenario, index, steps, "building"); | ||
67 | } | ||
68 | // 2. create a non-versioned | ||
69 | VersionedMapImpl<Integer, String> reference = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
70 | r = new Random(seed); | ||
71 | |||
72 | for (int i = 0; i < steps; i++) { | ||
73 | int index = i + 1; | ||
74 | int nextKey = r.nextInt(maxKey); | ||
75 | String nextValue = values[r.nextInt(values.length)]; | ||
76 | try { | ||
77 | reference.put(nextKey, nextValue); | ||
78 | } catch (Exception exception) { | ||
79 | exception.printStackTrace(); | ||
80 | logAndThrowError(scenario + ":" + index + ": exception happened: " + exception); | ||
81 | } | ||
82 | // go back to an existing state and compare to the reference | ||
83 | if (index % (commitFrequency*2) == 0) { | ||
84 | versioned.restore(index2Version.get(i)); | ||
85 | MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned,errors); | ||
86 | |||
87 | // go back to a random state (probably created by another thread) | ||
88 | } | ||
89 | |||
90 | else if(index % (commitFrequency*2) == commitFrequency) { | ||
91 | ArrayList<Long> states = new ArrayList<Long>(store.getStates()); | ||
92 | long selectedState = states.get(r.nextInt(states.size())); | ||
93 | versioned.restore(selectedState); | ||
94 | } | ||
95 | |||
96 | MapTestEnvironment.printStatus(scenario, index, steps, "comparison"); | ||
97 | } | ||
98 | } | ||
99 | } | ||