diff options
Diffstat (limited to 'subprojects/store/src/test/java')
22 files changed, 1449 insertions, 401 deletions
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java new file mode 100644 index 00000000..98756460 --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/InOrderCursorTest.java | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.map.tests; | ||
7 | |||
8 | import org.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.map.VersionedMapStore; | ||
10 | import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; | ||
11 | import tools.refinery.store.map.internal.state.InOrderMapCursor; | ||
12 | import tools.refinery.store.map.internal.state.VersionedMapStateImpl; | ||
13 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | ||
14 | |||
15 | import static org.junit.jupiter.api.Assertions.*; | ||
16 | |||
17 | class InOrderCursorTest { | ||
18 | @Test | ||
19 | void testCursor() { | ||
20 | var store = VersionedMapStore.<Integer,String>builder() | ||
21 | .strategy(VersionedMapStoreFactoryBuilder.StoreStrategy.STATE) | ||
22 | .stateBasedImmutableWhenCommitting(true) | ||
23 | .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) | ||
24 | .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE) | ||
25 | .defaultValue("x") | ||
26 | .build() | ||
27 | .createOne(); | ||
28 | |||
29 | VersionedMapStateImpl<Integer,String> map = (VersionedMapStateImpl<Integer,String>) store.createMap(); | ||
30 | checkMove(map,0); | ||
31 | |||
32 | map.put(1,"A"); | ||
33 | map.commit(); | ||
34 | checkMove(map,1); | ||
35 | |||
36 | |||
37 | map.put(2,"B"); | ||
38 | map.commit(); | ||
39 | checkMove(map,2); | ||
40 | |||
41 | map.put(3,"C"); | ||
42 | map.commit(); | ||
43 | checkMove(map,3); | ||
44 | |||
45 | } | ||
46 | |||
47 | private void checkMove(VersionedMapStateImpl<Integer,String> map, int num) { | ||
48 | InOrderMapCursor<Integer,String> cursor = new InOrderMapCursor<>(map); | ||
49 | for(int i=0; i<num; i++) { | ||
50 | assertTrue(cursor.move()); | ||
51 | assertFalse(cursor.isTerminated()); | ||
52 | } | ||
53 | assertFalse(cursor.move()); | ||
54 | assertTrue(cursor.isTerminated()); | ||
55 | } | ||
56 | } | ||
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java index 153f2e78..cc2e425c 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java | |||
@@ -7,7 +7,7 @@ package tools.refinery.store.map.tests; | |||
7 | 7 | ||
8 | import org.junit.jupiter.api.Test; | 8 | import org.junit.jupiter.api.Test; |
9 | import tools.refinery.store.map.VersionedMapStore; | 9 | import tools.refinery.store.map.VersionedMapStore; |
10 | import tools.refinery.store.map.VersionedMapStoreImpl; | 10 | import tools.refinery.store.map.internal.state.VersionedMapStoreStateImpl; |
11 | import tools.refinery.store.model.TupleHashProvider; | 11 | import tools.refinery.store.model.TupleHashProvider; |
12 | import tools.refinery.store.tuple.Tuple; | 12 | import tools.refinery.store.tuple.Tuple; |
13 | 13 | ||
@@ -16,11 +16,82 @@ import static org.junit.jupiter.api.Assertions.assertEquals; | |||
16 | class MapUnitTests { | 16 | class MapUnitTests { |
17 | @Test | 17 | @Test |
18 | void defaultTest() { | 18 | void defaultTest() { |
19 | VersionedMapStore<Tuple, Boolean> store = new VersionedMapStoreImpl<>(TupleHashProvider.INSTANCE, false); | 19 | VersionedMapStore<Tuple, Boolean> store = new VersionedMapStoreStateImpl<>(TupleHashProvider.INSTANCE, false); |
20 | var map = store.createMap(); | 20 | var map = store.createMap(); |
21 | var out1 = map.put(Tuple.of(0), true); | 21 | var out1 = map.put(Tuple.of(0), true); |
22 | assertEquals(false, out1); | 22 | assertEquals(false, out1); |
23 | var out2 = map.put(Tuple.of(1), true); | 23 | var out2 = map.put(Tuple.of(1), true); |
24 | assertEquals(false, out2); | 24 | assertEquals(false, out2); |
25 | } | 25 | } |
26 | |||
27 | @Test | ||
28 | void deltaRestoreTest() { | ||
29 | VersionedMapStore<Integer,String> store = | ||
30 | VersionedMapStore.<Integer,String>builder().defaultValue("x").build().createOne(); | ||
31 | var map = store.createMap(); | ||
32 | map.put(1,"val"); | ||
33 | var version1 = map.commit(); | ||
34 | map.put(1,"x"); | ||
35 | map.restore(version1); | ||
36 | System.out.println(map.getSize()); | ||
37 | assertEquals(1,map.getSize()); | ||
38 | } | ||
39 | |||
40 | @Test | ||
41 | void deltaRestoreTest2() { | ||
42 | VersionedMapStore<Integer,String> store = | ||
43 | VersionedMapStore.<Integer,String>builder().defaultValue("x").build().createOne(); | ||
44 | var map = store.createMap(); | ||
45 | map.put(1,"x"); | ||
46 | var version1 = map.commit(); | ||
47 | map.put(1,"1"); | ||
48 | map.restore(version1); | ||
49 | System.out.println(map.getSize()); | ||
50 | assertEquals(0,map.getSize()); | ||
51 | } | ||
52 | @Test | ||
53 | void deltaRestoreTest3() { | ||
54 | VersionedMapStore<Integer,String> store = | ||
55 | VersionedMapStore.<Integer,String>builder().defaultValue("x").build().createOne(); | ||
56 | var map = store.createMap(); | ||
57 | map.commit(); | ||
58 | map.put(1,"1"); | ||
59 | map.put(2,"x"); | ||
60 | assertEquals(1,map.getSize()); | ||
61 | var version1 = map.commit(); | ||
62 | map.put(1,"x"); | ||
63 | assertEquals(0,map.getSize()); | ||
64 | map.put(2,"2"); | ||
65 | assertEquals(1,map.getSize()); | ||
66 | map.put(2,"x"); | ||
67 | assertEquals(0,map.getSize()); | ||
68 | var version2 = map.commit(); | ||
69 | map.restore(version1); | ||
70 | assertEquals(1,map.getSize()); | ||
71 | map.restore(version2); | ||
72 | assertEquals(0,map.getSize()); | ||
73 | } | ||
74 | |||
75 | @Test | ||
76 | void deltaRestoreTest4() { | ||
77 | VersionedMapStore<Integer,String> store = | ||
78 | VersionedMapStore.<Integer,String>builder().defaultValue("x").build().createOne(); | ||
79 | var map = store.createMap(); | ||
80 | map.commit(); | ||
81 | map.put(1,"1"); | ||
82 | map.put(2,"x"); | ||
83 | assertEquals(1,map.getSize()); | ||
84 | var version1 = map.commit(); | ||
85 | map.put(1,"x"); | ||
86 | assertEquals(0,map.getSize()); | ||
87 | map.put(2,"2"); | ||
88 | assertEquals(1,map.getSize()); | ||
89 | map.put(2,"x"); | ||
90 | assertEquals(0,map.getSize()); | ||
91 | var version2 = map.commit(); | ||
92 | map.restore(version1); | ||
93 | assertEquals(1,map.getSize()); | ||
94 | map.restore(version2); | ||
95 | assertEquals(0,map.getSize()); | ||
96 | } | ||
26 | } | 97 | } |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java index eabe5bd1..58206eda 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java | |||
@@ -5,33 +5,32 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.map.tests.fuzz; | 6 | package tools.refinery.store.map.tests.fuzz; |
7 | 7 | ||
8 | import static org.junit.jupiter.api.Assertions.fail; | ||
9 | |||
10 | import java.util.Random; | ||
11 | import java.util.stream.Stream; | ||
12 | |||
13 | import org.junit.jupiter.api.Tag; | 8 | import org.junit.jupiter.api.Tag; |
14 | import org.junit.jupiter.api.Timeout; | 9 | import org.junit.jupiter.api.Timeout; |
15 | import org.junit.jupiter.params.ParameterizedTest; | 10 | import org.junit.jupiter.params.ParameterizedTest; |
16 | import org.junit.jupiter.params.provider.Arguments; | 11 | import org.junit.jupiter.params.provider.Arguments; |
17 | import org.junit.jupiter.params.provider.MethodSource; | 12 | import org.junit.jupiter.params.provider.MethodSource; |
18 | |||
19 | import tools.refinery.store.map.ContinousHashProvider; | ||
20 | import tools.refinery.store.map.VersionedMapStore; | 13 | import tools.refinery.store.map.VersionedMapStore; |
21 | import tools.refinery.store.map.VersionedMapStoreImpl; | 14 | import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; |
22 | import tools.refinery.store.map.internal.VersionedMapImpl; | ||
23 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; | 15 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; |
24 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | 16 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; |
25 | 17 | ||
18 | import java.util.Random; | ||
19 | import java.util.stream.Stream; | ||
20 | |||
21 | import static org.junit.jupiter.api.Assertions.fail; | ||
22 | import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; | ||
23 | |||
26 | class CommitFuzzTest { | 24 | class CommitFuzzTest { |
27 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | ||
28 | boolean evilHash) { | ||
29 | String[] values = MapTestEnvironment.prepareValues(maxValue); | ||
30 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | ||
31 | 25 | ||
32 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | 26 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, |
33 | VersionedMapImpl<Integer, String> sut = (VersionedMapImpl<Integer, String>) store.createMap(); | 27 | boolean nullDefault, int commitFrequency, |
34 | MapTestEnvironment<Integer, String> e = new MapTestEnvironment<Integer, String>(sut); | 28 | VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
29 | String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); | ||
30 | |||
31 | VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne(); | ||
32 | var sut = store.createMap(); | ||
33 | MapTestEnvironment<Integer, String> e = new MapTestEnvironment<>(sut); | ||
35 | 34 | ||
36 | Random r = new Random(seed); | 35 | Random r = new Random(seed); |
37 | 36 | ||
@@ -39,24 +38,13 @@ class CommitFuzzTest { | |||
39 | } | 38 | } |
40 | 39 | ||
41 | private void iterativeRandomPutsAndCommits(String scenario, int steps, int maxKey, String[] values, | 40 | private void iterativeRandomPutsAndCommits(String scenario, int steps, int maxKey, String[] values, |
42 | MapTestEnvironment<Integer, String> e, Random r, int commitFrequency) { | 41 | MapTestEnvironment<Integer, String> e, Random r, int commitFrequency) { |
43 | int stopAt = -1; | ||
44 | for (int i = 0; i < steps; i++) { | 42 | for (int i = 0; i < steps; i++) { |
45 | int index = i + 1; | 43 | int index = i + 1; |
46 | int nextKey = r.nextInt(maxKey); | 44 | int nextKey = r.nextInt(maxKey); |
47 | String nextValue = values[r.nextInt(values.length)]; | 45 | String nextValue = values[r.nextInt(values.length)]; |
48 | if (index == stopAt) { | ||
49 | System.out.println("issue!"); | ||
50 | System.out.println("State before:"); | ||
51 | e.printComparison(); | ||
52 | e.sut.prettyPrint(); | ||
53 | System.out.println("Next: put(" + nextKey + "," + nextValue + ")"); | ||
54 | } | ||
55 | try { | 46 | try { |
56 | e.put(nextKey, nextValue); | 47 | e.put(nextKey, nextValue); |
57 | if (index == stopAt) { | ||
58 | e.sut.prettyPrint(); | ||
59 | } | ||
60 | e.checkEquivalence(scenario + ":" + index); | 48 | e.checkEquivalence(scenario + ":" + index); |
61 | } catch (Exception exception) { | 49 | } catch (Exception exception) { |
62 | exception.printStackTrace(); | 50 | exception.printStackTrace(); |
@@ -64,35 +52,37 @@ class CommitFuzzTest { | |||
64 | } | 52 | } |
65 | MapTestEnvironment.printStatus(scenario, index, steps, null); | 53 | MapTestEnvironment.printStatus(scenario, index, steps, null); |
66 | if (index % commitFrequency == 0) { | 54 | if (index % commitFrequency == 0) { |
67 | e.sut.commit(); | 55 | e.commit(); |
68 | } | 56 | } |
69 | } | 57 | } |
70 | } | 58 | } |
71 | 59 | ||
72 | @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 60 | public static final String title = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " + |
61 | "seed={6} config={7}"; | ||
62 | |||
63 | @ParameterizedTest(name = title) | ||
73 | @MethodSource | 64 | @MethodSource |
74 | @Timeout(value = 10) | 65 | @Timeout(value = 10) |
75 | @Tag("fuzz") | 66 | @Tag("fuzz") |
76 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 67 | void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, |
77 | boolean evilHash) { | 68 | int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
78 | runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 69 | runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
79 | commitFrequency, evilHash); | 70 | nullDefault, commitFrequency, builder); |
80 | } | 71 | } |
81 | 72 | ||
82 | static Stream<Arguments> parametrizedFastFuzz() { | 73 | static Stream<Arguments> parametrizedFastFuzz() { |
83 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | 74 | return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, |
84 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | 75 | commitFrequencyOptions, randomSeedOptions, storeConfigs); |
85 | new Object[] { false, true }); | ||
86 | } | 76 | } |
87 | 77 | ||
88 | @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 78 | @ParameterizedTest(name = title) |
89 | @MethodSource | 79 | @MethodSource |
90 | @Tag("fuzz") | 80 | @Tag("fuzz") |
91 | @Tag("slow") | 81 | @Tag("slow") |
92 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 82 | void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, |
93 | boolean evilHash) { | 83 | int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
94 | runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 84 | runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
95 | commitFrequency, evilHash); | 85 | nullDefault, commitFrequency, builder); |
96 | } | 86 | } |
97 | 87 | ||
98 | static Stream<Arguments> parametrizedSlowFuzz() { | 88 | static Stream<Arguments> parametrizedSlowFuzz() { |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java index b0502a2b..c49911b8 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java | |||
@@ -10,8 +10,10 @@ import org.junit.jupiter.api.Timeout; | |||
10 | import org.junit.jupiter.params.ParameterizedTest; | 10 | import org.junit.jupiter.params.ParameterizedTest; |
11 | import org.junit.jupiter.params.provider.Arguments; | 11 | import org.junit.jupiter.params.provider.Arguments; |
12 | import org.junit.jupiter.params.provider.MethodSource; | 12 | import org.junit.jupiter.params.provider.MethodSource; |
13 | import tools.refinery.store.map.*; | 13 | import tools.refinery.store.map.Cursor; |
14 | import tools.refinery.store.map.internal.VersionedMapImpl; | 14 | import tools.refinery.store.map.VersionedMap; |
15 | import tools.refinery.store.map.VersionedMapStore; | ||
16 | import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; | ||
15 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; | 17 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; |
16 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | 18 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; |
17 | 19 | ||
@@ -22,23 +24,25 @@ import java.util.List; | |||
22 | import java.util.Random; | 24 | import java.util.Random; |
23 | import java.util.stream.Stream; | 25 | import java.util.stream.Stream; |
24 | 26 | ||
25 | import static org.junit.jupiter.api.Assertions.*; | 27 | import static org.junit.jupiter.api.Assertions.fail; |
28 | import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; | ||
26 | 29 | ||
27 | class ContentEqualsFuzzTest { | 30 | class ContentEqualsFuzzTest { |
28 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | 31 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, |
29 | boolean evilHash) { | 32 | boolean nullDefault, int commitFrequency, |
30 | String[] values = MapTestEnvironment.prepareValues(maxValue); | 33 | VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
31 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | 34 | String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); |
35 | |||
32 | 36 | ||
33 | Random r = new Random(seed); | 37 | Random r = new Random(seed); |
34 | 38 | ||
35 | iterativeRandomPutsAndCommitsThenCompare(scenario, chp, steps, maxKey, values, r, commitFrequency); | 39 | iterativeRandomPutsAndCommitsThenCompare(scenario, builder, steps, maxKey, values, r, commitFrequency); |
36 | } | 40 | } |
37 | 41 | ||
38 | private void iterativeRandomPutsAndCommitsThenCompare(String scenario, ContinousHashProvider<Integer> chp, | 42 | private void iterativeRandomPutsAndCommitsThenCompare(String scenario, VersionedMapStoreFactoryBuilder<Integer, String> builder, |
39 | int steps, int maxKey, String[] values, Random r, | 43 | int steps, int maxKey, String[] values, Random r, |
40 | int commitFrequency) { | 44 | int commitFrequency) { |
41 | VersionedMapStore<Integer, String> store1 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | 45 | VersionedMapStore<Integer, String> store1 = builder.defaultValue(values[0]).build().createOne(); |
42 | VersionedMap<Integer, String> sut1 = store1.createMap(); | 46 | VersionedMap<Integer, String> sut1 = store1.createMap(); |
43 | 47 | ||
44 | // Fill one map | 48 | // Fill one map |
@@ -68,7 +72,7 @@ class ContentEqualsFuzzTest { | |||
68 | // Randomize the order of the content | 72 | // Randomize the order of the content |
69 | Collections.shuffle(content, r); | 73 | Collections.shuffle(content, r); |
70 | 74 | ||
71 | VersionedMapStore<Integer, String> store2 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | 75 | VersionedMapStore<Integer, String> store2 = builder.defaultValue(values[0]).build().createOne(); |
72 | VersionedMap<Integer, String> sut2 = store2.createMap(); | 76 | VersionedMap<Integer, String> sut2 = store2.createMap(); |
73 | int index2 = 1; | 77 | int index2 = 1; |
74 | for (SimpleEntry<Integer, String> entry : content) { | 78 | for (SimpleEntry<Integer, String> entry : content) { |
@@ -78,40 +82,39 @@ class ContentEqualsFuzzTest { | |||
78 | } | 82 | } |
79 | 83 | ||
80 | // Check the integrity of the maps | 84 | // Check the integrity of the maps |
81 | ((VersionedMapImpl<Integer, String>) sut1).checkIntegrity(); | 85 | sut1.checkIntegrity(); |
82 | ((VersionedMapImpl<Integer, String>) sut2).checkIntegrity(); | 86 | sut2.checkIntegrity(); |
83 | 87 | ||
84 | // Compare the two maps | 88 | // Compare the two maps |
85 | MapTestEnvironment.compareTwoMaps(scenario, sut1, sut2); | 89 | MapTestEnvironment.compareTwoMaps(scenario, sut1, sut2); |
86 | } | 90 | } |
87 | 91 | ||
88 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} " + | 92 | public static final String title = "Compare {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit frequency={5}" + |
89 | "evil-hash={6}") | 93 | "seed={6} config={7}"; |
94 | |||
95 | @ParameterizedTest(name = title) | ||
90 | @MethodSource | 96 | @MethodSource |
91 | @Timeout(value = 10) | 97 | @Timeout(value = 10) |
92 | @Tag("fuzz") | 98 | @Tag("fuzz") |
93 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 99 | void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, |
94 | boolean evilHash) { | 100 | int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
95 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 101 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
96 | commitFrequency, evilHash); | 102 | nullDefault, commitFrequency, builder); |
97 | } | 103 | } |
98 | 104 | ||
99 | static Stream<Arguments> parametrizedFastFuzz() { | 105 | static Stream<Arguments> parametrizedFastFuzz() { |
100 | return FuzzTestUtils.permutationWithSize(new Object[]{FuzzTestUtils.FAST_STEP_COUNT}, new Object[]{3, 32, | 106 | return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, |
101 | 32 * 32}, | 107 | commitFrequencyOptions, randomSeedOptions, storeConfigs); |
102 | new Object[]{2, 3}, new Object[]{1, 10, 100}, new Object[]{1, 2, 3}, | ||
103 | new Object[]{false, true}); | ||
104 | } | 108 | } |
105 | 109 | ||
106 | @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} " + | 110 | @ParameterizedTest(name = title) |
107 | "evil-hash={6}") | ||
108 | @MethodSource | 111 | @MethodSource |
109 | @Tag("fuzz") | 112 | @Tag("fuzz") |
110 | @Tag("slow") | 113 | @Tag("slow") |
111 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 114 | void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int commitFrequency, |
112 | boolean evilHash) { | 115 | int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
113 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 116 | runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
114 | commitFrequency, evilHash); | 117 | defaultNull, commitFrequency, builder); |
115 | } | 118 | } |
116 | 119 | ||
117 | static Stream<Arguments> parametrizedSlowFuzz() { | 120 | static Stream<Arguments> parametrizedSlowFuzz() { |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java index 8274336e..94259edc 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java | |||
@@ -5,115 +5,134 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.map.tests.fuzz; | 6 | package tools.refinery.store.map.tests.fuzz; |
7 | 7 | ||
8 | import static org.junit.jupiter.api.Assertions.fail; | ||
9 | |||
10 | import java.util.Random; | ||
11 | import java.util.stream.Stream; | ||
12 | |||
13 | import org.junit.jupiter.api.Tag; | 8 | import org.junit.jupiter.api.Tag; |
14 | import org.junit.jupiter.api.Timeout; | 9 | import org.junit.jupiter.api.Timeout; |
15 | import org.junit.jupiter.params.ParameterizedTest; | 10 | import org.junit.jupiter.params.ParameterizedTest; |
16 | import org.junit.jupiter.params.provider.Arguments; | 11 | import org.junit.jupiter.params.provider.Arguments; |
17 | import org.junit.jupiter.params.provider.MethodSource; | 12 | import org.junit.jupiter.params.provider.MethodSource; |
18 | 13 | import tools.refinery.store.map.*; | |
19 | import tools.refinery.store.map.ContinousHashProvider; | ||
20 | import tools.refinery.store.map.DiffCursor; | ||
21 | import tools.refinery.store.map.VersionedMapStore; | ||
22 | import tools.refinery.store.map.VersionedMapStoreImpl; | ||
23 | import tools.refinery.store.map.internal.VersionedMapImpl; | ||
24 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; | 14 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; |
25 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | 15 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; |
26 | 16 | ||
17 | import java.util.HashMap; | ||
18 | import java.util.Map; | ||
19 | import java.util.Random; | ||
20 | import java.util.stream.Stream; | ||
21 | |||
22 | import static org.junit.jupiter.api.Assertions.fail; | ||
23 | import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; | ||
24 | |||
27 | class DiffCursorFuzzTest { | 25 | class DiffCursorFuzzTest { |
28 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | 26 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, |
29 | boolean evilHash) { | 27 | int commitFrequency, boolean commitBeforeDiffCursor, |
30 | String[] values = MapTestEnvironment.prepareValues(maxValue); | 28 | VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
31 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | 29 | String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); |
32 | 30 | ||
33 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | 31 | VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne(); |
34 | iterativeRandomPutsAndCommitsThenDiffcursor(scenario, store, steps, maxKey, values, seed, commitFrequency); | 32 | iterativeRandomPutsAndCommitsThenDiffCursor(scenario, store, steps, maxKey, values, seed, commitFrequency, |
33 | commitBeforeDiffCursor); | ||
35 | } | 34 | } |
36 | 35 | ||
37 | private void iterativeRandomPutsAndCommitsThenDiffcursor(String scenario, VersionedMapStore<Integer, String> store, | 36 | private void iterativeRandomPutsAndCommitsThenDiffCursor(String scenario, VersionedMapStore<Integer, String> store, |
38 | int steps, int maxKey, String[] values, int seed, int commitFrequency) { | 37 | int steps, int maxKey, String[] values, int seed, |
39 | // 1. build a map with versions | 38 | int commitFrequency, boolean commitBeforeDiffCursor) { |
40 | Random r = new Random(seed); | 39 | |
41 | VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
42 | int largestCommit = -1; | 40 | int largestCommit = -1; |
41 | Map<Integer,Version> index2Version = new HashMap<>(); | ||
43 | 42 | ||
44 | for (int i = 0; i < steps; i++) { | 43 | { |
45 | int index = i + 1; | 44 | // 1. build a map with versions |
46 | int nextKey = r.nextInt(maxKey); | 45 | Random r = new Random(seed); |
47 | String nextValue = values[r.nextInt(values.length)]; | 46 | VersionedMap<Integer, String> versioned = store.createMap(); |
48 | try { | 47 | for (int i = 0; i < steps; i++) { |
49 | versioned.put(nextKey, nextValue); | 48 | int index = i + 1; |
50 | } catch (Exception exception) { | 49 | int nextKey = r.nextInt(maxKey); |
51 | exception.printStackTrace(); | 50 | String nextValue = values[r.nextInt(values.length)]; |
52 | fail(scenario + ":" + index + ": exception happened: " + exception); | ||
53 | } | ||
54 | if (index % commitFrequency == 0) { | ||
55 | long version = versioned.commit(); | ||
56 | largestCommit = (int) version; | ||
57 | } | ||
58 | if (index % 10000 == 0) | ||
59 | System.out.println(scenario + ":" + index + "/" + steps + " building finished"); | ||
60 | } | ||
61 | // 2. create a non-versioned map, | ||
62 | VersionedMapImpl<Integer, String> moving = (VersionedMapImpl<Integer, String>) store.createMap(); | ||
63 | Random r2 = new Random(seed + 1); | ||
64 | |||
65 | final int diffTravelFrequency = commitFrequency * 2; | ||
66 | for (int i = 0; i < steps; i++) { | ||
67 | int index = i + 1; | ||
68 | if (index % diffTravelFrequency == 0) { | ||
69 | // difftravel | ||
70 | long travelToVersion = r2.nextInt(largestCommit + 1); | ||
71 | DiffCursor<Integer, String> diffCursor = moving.getDiffCursor(travelToVersion); | ||
72 | moving.putAll(diffCursor); | ||
73 | |||
74 | } else { | ||
75 | // random puts | ||
76 | int nextKey = r2.nextInt(maxKey); | ||
77 | String nextValue = values[r2.nextInt(values.length)]; | ||
78 | try { | 51 | try { |
79 | moving.put(nextKey, nextValue); | 52 | versioned.put(nextKey, nextValue); |
80 | } catch (Exception exception) { | 53 | } catch (Exception exception) { |
81 | exception.printStackTrace(); | 54 | exception.printStackTrace(); |
82 | fail(scenario + ":" + index + ": exception happened: " + exception); | 55 | fail(scenario + ":" + index + ": exception happened: " + exception); |
83 | } | 56 | } |
84 | if (index % commitFrequency == 0) { | 57 | if (index % commitFrequency == 0) { |
85 | versioned.commit(); | 58 | Version version = versioned.commit(); |
59 | index2Version.put(index,version); | ||
60 | largestCommit = index; | ||
86 | } | 61 | } |
87 | if (index % 10000 == 0) | 62 | if (index % 10000 == 0) |
88 | System.out.println(scenario + ":" + index + "/" + steps + " building finished"); | 63 | System.out.println(scenario + ":" + index + "/" + steps + " building finished"); |
89 | } | 64 | } |
90 | } | 65 | } |
91 | 66 | ||
67 | { | ||
68 | // 2. create a non-versioned map, | ||
69 | VersionedMap<Integer, String> moving = store.createMap(); | ||
70 | Random r2 = new Random(seed + 1); | ||
71 | |||
72 | final int diffTravelFrequency = commitFrequency * 2; | ||
73 | for (int i = 0; i < steps; i++) { | ||
74 | int index = i + 1; | ||
75 | if (index % diffTravelFrequency == 0) { | ||
76 | // diff-travel | ||
77 | int travelToVersion = r2.nextInt(largestCommit + 1); | ||
78 | |||
79 | VersionedMap<Integer, String> oracle = store.createMap(index2Version.get(travelToVersion)); | ||
80 | |||
81 | if(commitBeforeDiffCursor) { | ||
82 | moving.commit(); | ||
83 | } | ||
84 | DiffCursor<Integer, String> diffCursor = moving.getDiffCursor(index2Version.get(travelToVersion)); | ||
85 | moving.putAll(diffCursor); | ||
86 | moving.commit(); | ||
87 | |||
88 | MapTestEnvironment.compareTwoMaps(scenario + ":c" + index, oracle, moving); | ||
89 | |||
90 | moving.restore(index2Version.get(travelToVersion)); | ||
91 | |||
92 | } else { | ||
93 | // random puts | ||
94 | int nextKey = r2.nextInt(maxKey); | ||
95 | String nextValue = values[r2.nextInt(values.length)]; | ||
96 | try { | ||
97 | moving.put(nextKey, nextValue); | ||
98 | } catch (Exception exception) { | ||
99 | exception.printStackTrace(); | ||
100 | fail(scenario + ":" + index + ": exception happened: " + exception); | ||
101 | } | ||
102 | if (index % 10000 == 0) | ||
103 | System.out.println(scenario + ":" + index + "/" + steps + " building finished"); | ||
104 | } | ||
105 | } | ||
106 | } | ||
92 | } | 107 | } |
93 | 108 | ||
94 | @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 109 | public static final String title = "DiffCursor {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + |
110 | "commit frequency={5} seed={6} commit before diff={7} config={8}"; | ||
111 | |||
112 | @ParameterizedTest(name = title) | ||
95 | @MethodSource | 113 | @MethodSource |
96 | @Timeout(value = 10) | 114 | @Timeout(value = 10) |
97 | @Tag("fuzz") | 115 | @Tag("fuzz") |
98 | void parametrizedFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 116 | void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, |
99 | boolean evilHash) { | 117 | int commitFrequency, int seed, boolean commitBeforeDiffCursor, |
100 | runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, | 118 | VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
101 | noKeys, noValues, commitFrequency, evilHash); | 119 | runFuzzTest("DiffCursorS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, |
120 | noKeys, noValues, nullDefault, commitFrequency, commitBeforeDiffCursor, builder); | ||
102 | } | 121 | } |
103 | 122 | ||
104 | static Stream<Arguments> parametrizedFuzz() { | 123 | static Stream<Arguments> parametrizedFuzz() { |
105 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | 124 | return FuzzTestUtils.permutationWithSize(new Object[]{100}, keyCounts, valueCounts, nullDefaultOptions, |
106 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | 125 | commitFrequencyOptions, randomSeedOptions, new Object[]{false,true}, storeConfigs); |
107 | new Object[] { false, true }); | ||
108 | } | 126 | } |
109 | @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 127 | |
128 | @ParameterizedTest(name = title) | ||
110 | @MethodSource | 129 | @MethodSource |
111 | @Tag("fuzz") | 130 | @Tag("fuzz") |
112 | @Tag("slow") | 131 | @Tag("slow") |
113 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 132 | void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, |
114 | boolean evilHash) { | 133 | int seed, boolean commitBeforeDiffCursor, VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
115 | runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 134 | runFuzzTest("DiffCursorS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
116 | commitFrequency, evilHash); | 135 | nullDefault, commitFrequency, commitBeforeDiffCursor, builder); |
117 | } | 136 | } |
118 | 137 | ||
119 | static Stream<Arguments> parametrizedSlowFuzz() { | 138 | static Stream<Arguments> parametrizedSlowFuzz() { |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java index ab2b9435..3b55434c 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java | |||
@@ -5,95 +5,96 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.map.tests.fuzz; | 6 | package tools.refinery.store.map.tests.fuzz; |
7 | 7 | ||
8 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
9 | import static org.junit.jupiter.api.Assertions.fail; | ||
10 | |||
11 | import java.util.Collections; | ||
12 | import java.util.LinkedList; | ||
13 | import java.util.List; | ||
14 | import java.util.stream.Stream; | ||
15 | |||
16 | import org.junit.jupiter.api.Tag; | 8 | import org.junit.jupiter.api.Tag; |
17 | import org.junit.jupiter.api.Timeout; | 9 | import org.junit.jupiter.api.Timeout; |
18 | import org.junit.jupiter.params.ParameterizedTest; | 10 | import org.junit.jupiter.params.ParameterizedTest; |
19 | import org.junit.jupiter.params.provider.Arguments; | 11 | import org.junit.jupiter.params.provider.Arguments; |
20 | import org.junit.jupiter.params.provider.MethodSource; | 12 | import org.junit.jupiter.params.provider.MethodSource; |
21 | |||
22 | import tools.refinery.store.map.ContinousHashProvider; | ||
23 | import tools.refinery.store.map.VersionedMapStore; | 13 | import tools.refinery.store.map.VersionedMapStore; |
24 | import tools.refinery.store.map.VersionedMapStoreImpl; | 14 | import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; |
25 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; | 15 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; |
26 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | 16 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; |
27 | 17 | ||
18 | import java.util.Collections; | ||
19 | import java.util.LinkedList; | ||
20 | import java.util.List; | ||
21 | import java.util.stream.Stream; | ||
22 | |||
23 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
24 | import static org.junit.jupiter.api.Assertions.fail; | ||
25 | import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; | ||
26 | |||
28 | class MultiThreadFuzzTest { | 27 | class MultiThreadFuzzTest { |
29 | public static final int noThreads = 32; | 28 | public static final int noThreads = 10; |
30 | 29 | ||
31 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | 30 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
32 | boolean evilHash) { | 31 | String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); |
33 | String[] values = MapTestEnvironment.prepareValues(maxValue); | 32 | |
34 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | 33 | VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne(); |
35 | 34 | ||
36 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | ||
37 | |||
38 | // initialize runnables | 35 | // initialize runnables |
39 | MultiThreadTestRunnable[] runnables = new MultiThreadTestRunnable[noThreads]; | 36 | MultiThreadTestRunnable[] runnables = new MultiThreadTestRunnable[noThreads]; |
40 | for(int i = 0; i<noThreads; i++) { | 37 | for (int i = 0; i < noThreads; i++) { |
41 | runnables[i] = new MultiThreadTestRunnable(scenario+"-T"+(i+1), store, steps, maxKey, values, seed, commitFrequency); | 38 | runnables[i] = new MultiThreadTestRunnable(scenario + "-T" + (i + 1), store, steps, maxKey, values, seed |
39 | , commitFrequency); | ||
42 | } | 40 | } |
43 | 41 | ||
44 | // initialize threads | 42 | // initialize threads |
45 | Thread[] threads = new Thread[noThreads]; | 43 | Thread[] threads = new Thread[noThreads]; |
46 | for(int i = 0; i<noThreads; i++) { | 44 | for (int i = 0; i < noThreads; i++) { |
47 | threads[i] = new Thread(runnables[i]); | 45 | threads[i] = new Thread(runnables[i]); |
48 | } | 46 | } |
49 | 47 | ||
50 | // start threads; | 48 | // start threads; |
51 | for(int i = 0; i<noThreads; i++) { | 49 | for (int i = 0; i < noThreads; i++) { |
52 | threads[i].start(); | 50 | runnables[i].run(); |
51 | //threads[i].start(); | ||
53 | } | 52 | } |
54 | 53 | ||
55 | // wait all the threads; | 54 | // wait all the threads; |
56 | for(int i = 0; i<noThreads; i++) { | 55 | for (int i = 0; i < noThreads; i++) { |
57 | try { | 56 | try { |
58 | threads[i].join(); | 57 | threads[i].join(); |
59 | } catch (InterruptedException e) { | 58 | } catch (InterruptedException e) { |
60 | fail("Thread "+i+" interrupted."); | 59 | fail("Thread " + i + " interrupted."); |
61 | } | 60 | } |
62 | } | 61 | } |
63 | 62 | ||
64 | // collect errors | 63 | // collect errors |
65 | List<Throwable> errors = new LinkedList<>(); | 64 | List<Throwable> errors = new LinkedList<>(); |
66 | for(int i = 0; i<noThreads; i++) { | 65 | for (int i = 0; i < noThreads; i++) { |
67 | errors.addAll(runnables[i].getErrors()); | 66 | errors.addAll(runnables[i].getErrors()); |
68 | } | 67 | } |
69 | 68 | ||
70 | assertEquals(Collections.EMPTY_LIST, errors); | 69 | assertEquals(Collections.EMPTY_LIST, errors); |
71 | } | 70 | } |
72 | 71 | ||
73 | @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 72 | static final String title = "MultiThread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " + |
73 | "frequency={5} seed={6} config={7}"; | ||
74 | |||
75 | @ParameterizedTest(name = title) | ||
74 | @MethodSource | 76 | @MethodSource |
75 | @Timeout(value = 10) | 77 | @Timeout(value = 10) |
76 | @Tag("fuzz") | 78 | @Tag("fuzz") |
77 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 79 | void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, |
78 | boolean evilHash) { | 80 | int commitFrequency, int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
79 | runFuzzTest("MultithreadS" + steps + "K" + noKeys + "V" + noValues + "CF" + commitFrequency + "s" + seed, seed, steps, noKeys, noValues, | 81 | runFuzzTest("MultiThreadS" + steps + "K" + noKeys + "V" + noValues + defaultNull + "CF" + commitFrequency + |
80 | commitFrequency, evilHash); | 82 | "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, builder); |
81 | } | 83 | } |
82 | 84 | ||
83 | static Stream<Arguments> parametrizedFastFuzz() { | 85 | static Stream<Arguments> parametrizedFastFuzz() { |
84 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | 86 | return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, |
85 | new Object[] { 2, 3 }, new Object[] { 10, 100 }, new Object[] { 1, 2, 3 }, | 87 | new Object[]{10, 100}, randomSeedOptions, storeConfigs); |
86 | new Object[] { false, true }); | ||
87 | } | 88 | } |
88 | 89 | ||
89 | @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 90 | @ParameterizedTest(name = title) |
90 | @MethodSource | 91 | @MethodSource |
91 | @Tag("fuzz") | 92 | @Tag("fuzz") |
92 | @Tag("slow") | 93 | @Tag("slow") |
93 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 94 | void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, |
94 | boolean evilHash) { | 95 | int commitFrequency, int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
95 | runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 96 | runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
96 | commitFrequency, evilHash); | 97 | nullDefault, commitFrequency, builder); |
97 | } | 98 | } |
98 | 99 | ||
99 | static Stream<Arguments> parametrizedSlowFuzz() { | 100 | static Stream<Arguments> parametrizedSlowFuzz() { |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java index 502c8362..dfe46bae 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java | |||
@@ -13,22 +13,23 @@ import java.util.List; | |||
13 | import java.util.Map; | 13 | import java.util.Map; |
14 | import java.util.Random; | 14 | import java.util.Random; |
15 | 15 | ||
16 | import tools.refinery.store.map.Version; | ||
17 | import tools.refinery.store.map.VersionedMap; | ||
16 | import tools.refinery.store.map.VersionedMapStore; | 18 | import tools.refinery.store.map.VersionedMapStore; |
17 | import tools.refinery.store.map.internal.VersionedMapImpl; | ||
18 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | 19 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; |
19 | 20 | ||
20 | public class MultiThreadTestRunnable implements Runnable { | 21 | public class MultiThreadTestRunnable implements Runnable { |
21 | String scenario; | 22 | final String scenario; |
22 | VersionedMapStore<Integer, String> store; | 23 | final VersionedMapStore<Integer, String> store; |
23 | int steps; | 24 | final int steps; |
24 | int maxKey; | 25 | final int maxKey; |
25 | String[] values; | 26 | final String[] values; |
26 | int seed; | 27 | final int seed; |
27 | int commitFrequency; | 28 | final int commitFrequency; |
28 | List<Throwable> errors = new LinkedList<>(); | 29 | final List<Throwable> errors = new LinkedList<>(); |
29 | 30 | ||
30 | public MultiThreadTestRunnable(String scenario, VersionedMapStore<Integer, String> store, int steps, | 31 | public MultiThreadTestRunnable(String scenario, VersionedMapStore<Integer, String> store, int steps, |
31 | int maxKey, String[] values, int seed, int commitFrequency) { | 32 | int maxKey, String[] values, int seed, int commitFrequency) { |
32 | super(); | 33 | super(); |
33 | this.scenario = scenario; | 34 | this.scenario = scenario; |
34 | this.store = store; | 35 | this.store = store; |
@@ -43,17 +44,25 @@ public class MultiThreadTestRunnable implements Runnable { | |||
43 | AssertionError error = new AssertionError(message); | 44 | AssertionError error = new AssertionError(message); |
44 | errors.add(error); | 45 | errors.add(error); |
45 | } | 46 | } |
46 | 47 | ||
47 | public List<Throwable> getErrors() { | 48 | public List<Throwable> getErrors() { |
48 | return errors; | 49 | return errors; |
49 | } | 50 | } |
50 | 51 | ||
51 | @Override | 52 | @Override |
52 | public void run() { | 53 | public void run() { |
54 | try{ | ||
55 | task(); | ||
56 | } catch(Exception e) { | ||
57 | e.printStackTrace(); | ||
58 | } | ||
59 | } | ||
60 | |||
61 | private void task() { | ||
53 | // 1. build a map with versions | 62 | // 1. build a map with versions |
54 | Random r = new Random(seed); | 63 | Random r = new Random(seed); |
55 | VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap(); | 64 | VersionedMap<Integer, String> versioned = store.createMap(); |
56 | Map<Integer, Long> index2Version = new HashMap<>(); | 65 | Map<Integer, Version> index2Version = new HashMap<>(); |
57 | 66 | ||
58 | for (int i = 0; i < steps; i++) { | 67 | for (int i = 0; i < steps; i++) { |
59 | int index = i + 1; | 68 | int index = i + 1; |
@@ -66,15 +75,15 @@ public class MultiThreadTestRunnable implements Runnable { | |||
66 | logAndThrowError(scenario + ":" + index + ": exception happened: " + exception); | 75 | logAndThrowError(scenario + ":" + index + ": exception happened: " + exception); |
67 | } | 76 | } |
68 | if (index % commitFrequency == 0) { | 77 | if (index % commitFrequency == 0) { |
69 | long version = versioned.commit(); | 78 | Version version = versioned.commit(); |
70 | index2Version.put(i, version); | 79 | index2Version.put(i, version); |
71 | } | 80 | } |
72 | MapTestEnvironment.printStatus(scenario, index, steps, "building"); | 81 | MapTestEnvironment.printStatus(scenario, index, steps, "building"); |
73 | } | 82 | } |
74 | // 2. create a non-versioned | 83 | // 2. create a non-versioned |
75 | VersionedMapImpl<Integer, String> reference = (VersionedMapImpl<Integer, String>) store.createMap(); | 84 | VersionedMap<Integer, String> reference = store.createMap(); |
76 | r = new Random(seed); | 85 | r = new Random(seed); |
77 | Random r2 = new Random(seed+1); | 86 | Random r2 = new Random(seed + 1); |
78 | 87 | ||
79 | for (int i = 0; i < steps; i++) { | 88 | for (int i = 0; i < steps; i++) { |
80 | int index = i + 1; | 89 | int index = i + 1; |
@@ -89,13 +98,16 @@ public class MultiThreadTestRunnable implements Runnable { | |||
89 | // go back to an existing state and compare to the reference | 98 | // go back to an existing state and compare to the reference |
90 | if (index % (commitFrequency) == 0) { | 99 | if (index % (commitFrequency) == 0) { |
91 | versioned.restore(index2Version.get(i)); | 100 | versioned.restore(index2Version.get(i)); |
92 | MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned,errors); | 101 | MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned, null); |
93 | 102 | ||
94 | // go back to a random state (probably created by another thread) | 103 | // go back to a random state (probably created by another thread) |
95 | List<Long> states = new ArrayList<>(store.getStates()); | 104 | List<Version> states = new ArrayList<>(index2Version.values()); |
105 | //states.sort(Long::compare); | ||
96 | Collections.shuffle(states, r2); | 106 | Collections.shuffle(states, r2); |
97 | for(Long state : states.subList(0, Math.min(states.size(), 100))) { | 107 | for (Version state : states.subList(0, Math.min(states.size(), 100))) { |
98 | versioned.restore(state); | 108 | versioned.restore(state); |
109 | var clean = store.createMap(state); | ||
110 | MapTestEnvironment.compareTwoMaps(scenario + ":" + index, clean, versioned, null); | ||
99 | } | 111 | } |
100 | versioned.restore(index2Version.get(i)); | 112 | versioned.restore(index2Version.get(i)); |
101 | } | 113 | } |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java index 32dde0da..fdcd7f9f 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.map.tests.fuzz; | 6 | package tools.refinery.store.map.tests.fuzz; |
7 | 7 | ||
8 | import static org.junit.jupiter.api.Assertions.fail; | 8 | import static org.junit.jupiter.api.Assertions.fail; |
9 | import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; | ||
9 | 10 | ||
10 | import java.util.Random; | 11 | import java.util.Random; |
11 | import java.util.stream.Stream; | 12 | import java.util.stream.Stream; |
@@ -16,21 +17,18 @@ import org.junit.jupiter.params.ParameterizedTest; | |||
16 | import org.junit.jupiter.params.provider.Arguments; | 17 | import org.junit.jupiter.params.provider.Arguments; |
17 | import org.junit.jupiter.params.provider.MethodSource; | 18 | import org.junit.jupiter.params.provider.MethodSource; |
18 | 19 | ||
19 | import tools.refinery.store.map.ContinousHashProvider; | 20 | import tools.refinery.store.map.*; |
20 | import tools.refinery.store.map.VersionedMapStore; | ||
21 | import tools.refinery.store.map.VersionedMapStoreImpl; | ||
22 | import tools.refinery.store.map.internal.VersionedMapImpl; | ||
23 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; | 21 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; |
24 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | 22 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; |
25 | 23 | ||
26 | class MutableFuzzTest { | 24 | class MutableFuzzTest { |
27 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean evilHash) { | 25 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, |
28 | String[] values = MapTestEnvironment.prepareValues(maxValue); | 26 | boolean nullDefault, VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
29 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | 27 | String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); |
30 | 28 | ||
31 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | 29 | VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne(); |
32 | VersionedMapImpl<Integer, String> sut = (VersionedMapImpl<Integer, String>) store.createMap(); | 30 | VersionedMap<Integer, String> sut = store.createMap(); |
33 | MapTestEnvironment<Integer, String> e = new MapTestEnvironment<Integer, String>(sut); | 31 | MapTestEnvironment<Integer, String> e = new MapTestEnvironment<>(sut); |
34 | 32 | ||
35 | Random r = new Random(seed); | 33 | Random r = new Random(seed); |
36 | 34 | ||
@@ -38,24 +36,14 @@ class MutableFuzzTest { | |||
38 | } | 36 | } |
39 | 37 | ||
40 | private void iterativeRandomPuts(String scenario, int steps, int maxKey, String[] values, | 38 | private void iterativeRandomPuts(String scenario, int steps, int maxKey, String[] values, |
41 | MapTestEnvironment<Integer, String> e, Random r) { | 39 | MapTestEnvironment<Integer, String> e, Random r) { |
42 | int stopAt = -1; | ||
43 | for (int i = 0; i < steps; i++) { | 40 | for (int i = 0; i < steps; i++) { |
44 | int index = i + 1; | 41 | int index = i + 1; |
45 | int nextKey = r.nextInt(maxKey); | 42 | int nextKey = r.nextInt(maxKey); |
46 | String nextValue = values[r.nextInt(values.length)]; | 43 | String nextValue = values[r.nextInt(values.length)]; |
47 | if (index == stopAt) { | 44 | |
48 | System.out.println("issue!"); | ||
49 | System.out.println("State before:"); | ||
50 | e.printComparison(); | ||
51 | e.sut.prettyPrint(); | ||
52 | System.out.println("Next: put(" + nextKey + "," + nextValue + ")"); | ||
53 | } | ||
54 | try { | 45 | try { |
55 | e.put(nextKey, nextValue); | 46 | e.put(nextKey, nextValue); |
56 | if (index == stopAt) { | ||
57 | e.sut.prettyPrint(); | ||
58 | } | ||
59 | e.checkEquivalence(scenario + ":" + index); | 47 | e.checkEquivalence(scenario + ":" + index); |
60 | } catch (Exception exception) { | 48 | } catch (Exception exception) { |
61 | exception.printStackTrace(); | 49 | exception.printStackTrace(); |
@@ -65,30 +53,34 @@ class MutableFuzzTest { | |||
65 | } | 53 | } |
66 | } | 54 | } |
67 | 55 | ||
68 | @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} seed={4} evil-hash={5}") | 56 | final String title = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} seed={5} " + |
57 | "config={6}"; | ||
58 | |||
59 | @ParameterizedTest(name = title) | ||
69 | @MethodSource | 60 | @MethodSource |
70 | @Timeout(value = 10) | 61 | @Timeout(value = 10) |
71 | @Tag("fuzz") | 62 | @Tag("fuzz") |
72 | void parametrizedFuzz(int test, int steps, int noKeys, int noValues, int seed, boolean evilHash) { | 63 | void parametrizedFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, int seed, |
64 | VersionedMapStoreFactoryBuilder<Integer, String> builder) { | ||
73 | runFuzzTest( | 65 | runFuzzTest( |
74 | "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), | 66 | "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, |
75 | seed, steps, noKeys, noValues, evilHash); | 67 | seed, steps, noKeys, noValues, defaultNull, builder); |
76 | } | 68 | } |
77 | 69 | ||
78 | static Stream<Arguments> parametrizedFuzz() { | 70 | static Stream<Arguments> parametrizedFuzz() { |
79 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, | 71 | return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, |
80 | new Object[] { 3, 32, 32 * 32, 32 * 32 * 32 * 32 }, new Object[] { 2, 3 }, new Object[] { 1, 2, 3 }, | 72 | randomSeedOptions, storeConfigs); |
81 | new Object[] { false, true }); | ||
82 | } | 73 | } |
83 | 74 | ||
84 | @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} seed={4} evil-hash={5}") | 75 | @ParameterizedTest(name = title) |
85 | @MethodSource | 76 | @MethodSource |
86 | @Tag("fuzz") | 77 | @Tag("fuzz") |
87 | @Tag("slow") | 78 | @Tag("slow") |
88 | void parametrizedSlowFuzz(int test, int steps, int noKeys, int noValues, int seed, boolean evilHash) { | 79 | void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int seed, |
80 | VersionedMapStoreFactoryBuilder<Integer, String> builder) { | ||
89 | runFuzzTest( | 81 | runFuzzTest( |
90 | "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"), | 82 | "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, |
91 | seed, steps, noKeys, noValues, evilHash); | 83 | seed, steps, noKeys, noValues, nullDefault, builder); |
92 | } | 84 | } |
93 | 85 | ||
94 | static Stream<Arguments> parametrizedSlowFuzz() { | 86 | static Stream<Arguments> parametrizedSlowFuzz() { |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java index 347c49be..abfb4791 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.map.tests.fuzz; | 6 | package tools.refinery.store.map.tests.fuzz; |
7 | 7 | ||
8 | import static org.junit.jupiter.api.Assertions.fail; | 8 | import static org.junit.jupiter.api.Assertions.fail; |
9 | import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; | ||
9 | 10 | ||
10 | import java.util.Random; | 11 | import java.util.Random; |
11 | import java.util.stream.Stream; | 12 | import java.util.stream.Stream; |
@@ -16,22 +17,22 @@ import org.junit.jupiter.params.ParameterizedTest; | |||
16 | import org.junit.jupiter.params.provider.Arguments; | 17 | import org.junit.jupiter.params.provider.Arguments; |
17 | import org.junit.jupiter.params.provider.MethodSource; | 18 | import org.junit.jupiter.params.provider.MethodSource; |
18 | 19 | ||
19 | import tools.refinery.store.map.ContinousHashProvider; | 20 | import tools.refinery.store.map.ContinuousHashProvider; |
20 | import tools.refinery.store.map.VersionedMapStore; | 21 | import tools.refinery.store.map.VersionedMapStore; |
21 | import tools.refinery.store.map.VersionedMapStoreImpl; | 22 | import tools.refinery.store.map.internal.state.VersionedMapStoreStateImpl; |
22 | import tools.refinery.store.map.internal.VersionedMapImpl; | 23 | import tools.refinery.store.map.internal.state.VersionedMapStateImpl; |
23 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; | 24 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; |
24 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | 25 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; |
25 | 26 | ||
26 | class MutableImmutableCompareFuzzTest { | 27 | class MutableImmutableCompareFuzzTest { |
27 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | 28 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, |
28 | boolean evilHash) { | 29 | boolean nullDefault, int commitFrequency, boolean evilHash) { |
29 | String[] values = MapTestEnvironment.prepareValues(maxValue); | 30 | String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); |
30 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | 31 | ContinuousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); |
31 | 32 | ||
32 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | 33 | VersionedMapStore<Integer, String> store = new VersionedMapStoreStateImpl<>(chp, values[0]); |
33 | VersionedMapImpl<Integer, String> immutable = (VersionedMapImpl<Integer, String>) store.createMap(); | 34 | VersionedMapStateImpl<Integer, String> immutable = (VersionedMapStateImpl<Integer, String>) store.createMap(); |
34 | VersionedMapImpl<Integer, String> mutable = (VersionedMapImpl<Integer, String>) store.createMap(); | 35 | VersionedMapStateImpl<Integer, String> mutable = (VersionedMapStateImpl<Integer, String>) store.createMap(); |
35 | 36 | ||
36 | Random r = new Random(seed); | 37 | Random r = new Random(seed); |
37 | 38 | ||
@@ -39,9 +40,9 @@ class MutableImmutableCompareFuzzTest { | |||
39 | commitFrequency); | 40 | commitFrequency); |
40 | } | 41 | } |
41 | 42 | ||
42 | private void iterativeRandomPutsAndCommitsAndCompare(String scenario, VersionedMapImpl<Integer, String> immutable, | 43 | private void iterativeRandomPutsAndCommitsAndCompare(String scenario, VersionedMapStateImpl<Integer, String> immutable, |
43 | VersionedMapImpl<Integer, String> mutable, int steps, int maxKey, String[] values, Random r, | 44 | VersionedMapStateImpl<Integer, String> mutable, int steps, int maxKey, String[] values, Random r, |
44 | int commitFrequency) { | 45 | int commitFrequency) { |
45 | for (int i = 0; i < steps; i++) { | 46 | for (int i = 0; i < steps; i++) { |
46 | int index = i + 1; | 47 | int index = i + 1; |
47 | int nextKey = r.nextInt(maxKey); | 48 | int nextKey = r.nextInt(maxKey); |
@@ -62,30 +63,31 @@ class MutableImmutableCompareFuzzTest { | |||
62 | } | 63 | } |
63 | } | 64 | } |
64 | 65 | ||
65 | @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 66 | @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + |
67 | "commit frequency={5} seed={6} evil-hash={7}") | ||
66 | @MethodSource | 68 | @MethodSource |
67 | @Timeout(value = 10) | 69 | @Timeout(value = 10) |
68 | @Tag("fuzz") | 70 | @Tag("fuzz") |
69 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 71 | void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, |
70 | boolean evilHash) { | 72 | int seed, boolean evilHash) { |
71 | runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, | 73 | runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, |
72 | noKeys, noValues, commitFrequency, evilHash); | 74 | noKeys, noValues, nullDefault, commitFrequency, evilHash); |
73 | } | 75 | } |
74 | 76 | ||
75 | static Stream<Arguments> parametrizedFastFuzz() { | 77 | static Stream<Arguments> parametrizedFastFuzz() { |
76 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | 78 | return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, |
77 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | 79 | commitFrequencyOptions, randomSeedOptions, new Object[]{false, true}); |
78 | new Object[] { false, true }); | ||
79 | } | 80 | } |
80 | 81 | ||
81 | @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 82 | @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} " + |
83 | "commit frequency={5} seed={6} evil-hash={7}") | ||
82 | @MethodSource | 84 | @MethodSource |
83 | @Tag("fuzz") | 85 | @Tag("fuzz") |
84 | @Tag("slow") | 86 | @Tag("slow") |
85 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 87 | void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, |
86 | boolean evilHash) { | 88 | int seed, boolean evilHash) { |
87 | runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, | 89 | runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, |
88 | noKeys, noValues, commitFrequency, evilHash); | 90 | noKeys, noValues, nullDefault, commitFrequency, evilHash); |
89 | } | 91 | } |
90 | 92 | ||
91 | static Stream<Arguments> parametrizedSlowFuzz() { | 93 | static Stream<Arguments> parametrizedSlowFuzz() { |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java index f7b9d61e..5c768788 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java | |||
@@ -5,43 +5,43 @@ | |||
5 | */ | 5 | */ |
6 | package tools.refinery.store.map.tests.fuzz; | 6 | package tools.refinery.store.map.tests.fuzz; |
7 | 7 | ||
8 | import static org.junit.jupiter.api.Assertions.fail; | ||
9 | |||
10 | import java.util.HashMap; | ||
11 | import java.util.Map; | ||
12 | import java.util.Random; | ||
13 | import java.util.stream.Stream; | ||
14 | |||
15 | import org.junit.jupiter.api.Tag; | 8 | import org.junit.jupiter.api.Tag; |
16 | import org.junit.jupiter.api.Timeout; | 9 | import org.junit.jupiter.api.Timeout; |
17 | import org.junit.jupiter.params.ParameterizedTest; | 10 | import org.junit.jupiter.params.ParameterizedTest; |
18 | import org.junit.jupiter.params.provider.Arguments; | 11 | import org.junit.jupiter.params.provider.Arguments; |
19 | import org.junit.jupiter.params.provider.MethodSource; | 12 | import org.junit.jupiter.params.provider.MethodSource; |
20 | 13 | import tools.refinery.store.map.Version; | |
21 | import tools.refinery.store.map.ContinousHashProvider; | 14 | import tools.refinery.store.map.VersionedMap; |
22 | import tools.refinery.store.map.VersionedMapStore; | 15 | import tools.refinery.store.map.VersionedMapStore; |
23 | import tools.refinery.store.map.VersionedMapStoreImpl; | 16 | import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; |
24 | import tools.refinery.store.map.internal.VersionedMapImpl; | ||
25 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; | 17 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; |
26 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | 18 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; |
27 | 19 | ||
20 | import java.util.HashMap; | ||
21 | import java.util.Map; | ||
22 | import java.util.Random; | ||
23 | import java.util.stream.Stream; | ||
24 | |||
25 | import static org.junit.jupiter.api.Assertions.fail; | ||
26 | import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; | ||
27 | |||
28 | class RestoreFuzzTest { | 28 | class RestoreFuzzTest { |
29 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | 29 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, |
30 | boolean evilHash) { | 30 | boolean nullDefault, int commitFrequency, |
31 | String[] values = MapTestEnvironment.prepareValues(maxValue); | 31 | VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
32 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | 32 | String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); |
33 | 33 | ||
34 | VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]); | 34 | VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne(); |
35 | 35 | ||
36 | iterativeRandomPutsAndCommitsThenRestore(scenario, store, steps, maxKey, values, seed, commitFrequency); | 36 | iterativeRandomPutsAndCommitsThenRestore(scenario, store, steps, maxKey, values, seed, commitFrequency); |
37 | } | 37 | } |
38 | 38 | ||
39 | private void iterativeRandomPutsAndCommitsThenRestore(String scenario, VersionedMapStore<Integer, String> store, | 39 | private void iterativeRandomPutsAndCommitsThenRestore(String scenario, VersionedMapStore<Integer, String> store, |
40 | int steps, int maxKey, String[] values, int seed, int commitFrequency) { | 40 | int steps, int maxKey, String[] values, int seed, int commitFrequency) { |
41 | // 1. build a map with versions | 41 | // 1. build a map with versions |
42 | Random r = new Random(seed); | 42 | Random r = new Random(seed); |
43 | VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap(); | 43 | VersionedMap<Integer, String> versioned = store.createMap(); |
44 | Map<Integer, Long> index2Version = new HashMap<>(); | 44 | Map<Integer, Version> index2Version = new HashMap<>(); |
45 | 45 | ||
46 | for (int i = 0; i < steps; i++) { | 46 | for (int i = 0; i < steps; i++) { |
47 | int index = i + 1; | 47 | int index = i + 1; |
@@ -54,13 +54,13 @@ class RestoreFuzzTest { | |||
54 | fail(scenario + ":" + index + ": exception happened: " + exception); | 54 | fail(scenario + ":" + index + ": exception happened: " + exception); |
55 | } | 55 | } |
56 | if (index % commitFrequency == 0) { | 56 | if (index % commitFrequency == 0) { |
57 | long version = versioned.commit(); | 57 | Version version = versioned.commit(); |
58 | index2Version.put(i, version); | 58 | index2Version.put(i, version); |
59 | } | 59 | } |
60 | MapTestEnvironment.printStatus(scenario, index, steps, "building"); | 60 | MapTestEnvironment.printStatus(scenario, index, steps, "building"); |
61 | } | 61 | } |
62 | // 2. create a non-versioned and | 62 | // 2. create a non-versioned and |
63 | VersionedMapImpl<Integer, String> reference = (VersionedMapImpl<Integer, String>) store.createMap(); | 63 | VersionedMap<Integer, String> reference = store.createMap(); |
64 | r = new Random(seed); | 64 | r = new Random(seed); |
65 | 65 | ||
66 | for (int i = 0; i < steps; i++) { | 66 | for (int i = 0; i < steps; i++) { |
@@ -82,30 +82,32 @@ class RestoreFuzzTest { | |||
82 | 82 | ||
83 | } | 83 | } |
84 | 84 | ||
85 | @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 85 | public static final String title = "Commit {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit frequency={5} " + |
86 | "seed={6} config={7}"; | ||
87 | |||
88 | @ParameterizedTest(name = title) | ||
86 | @MethodSource | 89 | @MethodSource |
87 | @Timeout(value = 10) | 90 | @Timeout(value = 10) |
88 | @Tag("smoke") | 91 | @Tag("smoke") |
89 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 92 | void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, |
90 | boolean evilHash) { | 93 | int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
91 | runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 94 | runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
92 | commitFrequency, evilHash); | 95 | nullDefault, commitFrequency, builder); |
93 | } | 96 | } |
94 | 97 | ||
95 | static Stream<Arguments> parametrizedFastFuzz() { | 98 | static Stream<Arguments> parametrizedFastFuzz() { |
96 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | 99 | return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, |
97 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | 100 | commitFrequencyOptions, randomSeedOptions, storeConfigs); |
98 | new Object[] { false, true }); | ||
99 | } | 101 | } |
100 | 102 | ||
101 | @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 103 | @ParameterizedTest(name = title) |
102 | @MethodSource | 104 | @MethodSource |
103 | @Tag("smoke") | 105 | @Tag("smoke") |
104 | @Tag("slow") | 106 | @Tag("slow") |
105 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 107 | void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, |
106 | boolean evilHash) { | 108 | int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) { |
107 | runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 109 | runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
108 | commitFrequency, evilHash); | 110 | nullDefault, commitFrequency, builder); |
109 | } | 111 | } |
110 | 112 | ||
111 | static Stream<Arguments> parametrizedSlowFuzz() { | 113 | static Stream<Arguments> parametrizedSlowFuzz() { |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java index 4b4172d0..299c94b1 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java | |||
@@ -18,61 +18,64 @@ import org.junit.jupiter.params.ParameterizedTest; | |||
18 | import org.junit.jupiter.params.provider.Arguments; | 18 | import org.junit.jupiter.params.provider.Arguments; |
19 | import org.junit.jupiter.params.provider.MethodSource; | 19 | import org.junit.jupiter.params.provider.MethodSource; |
20 | 20 | ||
21 | import tools.refinery.store.map.ContinousHashProvider; | 21 | import tools.refinery.store.map.ContinuousHashProvider; |
22 | import tools.refinery.store.map.Version; | ||
22 | import tools.refinery.store.map.VersionedMapStore; | 23 | import tools.refinery.store.map.VersionedMapStore; |
23 | import tools.refinery.store.map.VersionedMapStoreImpl; | 24 | import tools.refinery.store.map.internal.state.VersionedMapStoreStateImpl; |
24 | import tools.refinery.store.map.internal.VersionedMapImpl; | 25 | import tools.refinery.store.map.internal.state.VersionedMapStateImpl; |
25 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; | 26 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; |
26 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | 27 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; |
27 | 28 | ||
29 | import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; | ||
30 | |||
28 | class SharedStoreFuzzTest { | 31 | class SharedStoreFuzzTest { |
29 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency, | 32 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, |
30 | boolean evilHash) { | 33 | boolean nullDefault, int commitFrequency, boolean evilHash) { |
31 | String[] values = MapTestEnvironment.prepareValues(maxValue); | 34 | String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); |
32 | ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); | 35 | ContinuousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash); |
33 | 36 | ||
34 | List<VersionedMapStore<Integer, String>> stores = VersionedMapStoreImpl.createSharedVersionedMapStores(5, chp, values[0]); | 37 | List<VersionedMapStore<Integer, String>> stores = VersionedMapStoreStateImpl.createSharedVersionedMapStores(5, chp, values[0]); |
35 | 38 | ||
36 | iterativeRandomPutsAndCommitsThenRestore(scenario, stores, steps, maxKey, values, seed, commitFrequency); | 39 | iterativeRandomPutsAndCommitsThenRestore(scenario, stores, steps, maxKey, values, seed, commitFrequency); |
37 | } | 40 | } |
38 | 41 | ||
39 | private void iterativeRandomPutsAndCommitsThenRestore(String scenario, List<VersionedMapStore<Integer, String>> stores, | 42 | private void iterativeRandomPutsAndCommitsThenRestore(String scenario, List<VersionedMapStore<Integer, String>> stores, |
40 | int steps, int maxKey, String[] values, int seed, int commitFrequency) { | 43 | int steps, int maxKey, String[] values, int seed, int commitFrequency) { |
41 | // 1. maps with versions | 44 | // 1. maps with versions |
42 | Random r = new Random(seed); | 45 | Random r = new Random(seed); |
43 | List<VersionedMapImpl<Integer, String>> versioneds = new LinkedList<>(); | 46 | List<VersionedMapStateImpl<Integer, String>> versioneds = new LinkedList<>(); |
44 | for(VersionedMapStore<Integer, String> store : stores) { | 47 | for (VersionedMapStore<Integer, String> store : stores) { |
45 | versioneds.add((VersionedMapImpl<Integer, String>) store.createMap()); | 48 | versioneds.add((VersionedMapStateImpl<Integer, String>) store.createMap()); |
46 | } | 49 | } |
47 | 50 | ||
48 | List<Map<Integer, Long>> index2Version = new LinkedList<>(); | 51 | List<Map<Integer, Version>> index2Version = new LinkedList<>(); |
49 | for(int i = 0; i<stores.size(); i++) { | 52 | for (int i = 0; i < stores.size(); i++) { |
50 | index2Version.add(new HashMap<>()); | 53 | index2Version.add(new HashMap<>()); |
51 | } | 54 | } |
52 | 55 | ||
53 | for (int i = 0; i < steps; i++) { | 56 | for (int i = 0; i < steps; i++) { |
54 | int stepIndex = i + 1; | 57 | int stepIndex = i + 1; |
55 | for (int storeIndex = 0; storeIndex<versioneds.size(); storeIndex++) { | 58 | for (int storeIndex = 0; storeIndex < versioneds.size(); storeIndex++) { |
56 | int nextKey = r.nextInt(maxKey); | 59 | int nextKey = r.nextInt(maxKey); |
57 | String nextValue = values[r.nextInt(values.length)]; | 60 | String nextValue = values[r.nextInt(values.length)]; |
58 | versioneds.get(storeIndex).put(nextKey, nextValue); | 61 | versioneds.get(storeIndex).put(nextKey, nextValue); |
59 | if (stepIndex % commitFrequency == 0) { | 62 | if (stepIndex % commitFrequency == 0) { |
60 | long version = versioneds.get(storeIndex).commit(); | 63 | Version version = versioneds.get(storeIndex).commit(); |
61 | index2Version.get(storeIndex).put(i, version); | 64 | index2Version.get(storeIndex).put(i, version); |
62 | } | 65 | } |
63 | MapTestEnvironment.printStatus(scenario, stepIndex, steps, "building"); | 66 | MapTestEnvironment.printStatus(scenario, stepIndex, steps, "building"); |
64 | } | 67 | } |
65 | } | 68 | } |
66 | // 2. create a non-versioned and | 69 | // 2. create a non-versioned and |
67 | List<VersionedMapImpl<Integer, String>> reference = new LinkedList<>(); | 70 | List<VersionedMapStateImpl<Integer, String>> reference = new LinkedList<>(); |
68 | for(VersionedMapStore<Integer, String> store : stores) { | 71 | for (VersionedMapStore<Integer, String> store : stores) { |
69 | reference.add((VersionedMapImpl<Integer, String>) store.createMap()); | 72 | reference.add((VersionedMapStateImpl<Integer, String>) store.createMap()); |
70 | } | 73 | } |
71 | r = new Random(seed); | 74 | r = new Random(seed); |
72 | 75 | ||
73 | for (int i = 0; i < steps; i++) { | 76 | for (int i = 0; i < steps; i++) { |
74 | int index = i + 1; | 77 | int index = i + 1; |
75 | for (int storeIndex = 0; storeIndex<versioneds.size(); storeIndex++) { | 78 | for (int storeIndex = 0; storeIndex < versioneds.size(); storeIndex++) { |
76 | int nextKey = r.nextInt(maxKey); | 79 | int nextKey = r.nextInt(maxKey); |
77 | String nextValue = values[r.nextInt(values.length)]; | 80 | String nextValue = values[r.nextInt(values.length)]; |
78 | reference.get(storeIndex).put(nextKey, nextValue); | 81 | reference.get(storeIndex).put(nextKey, nextValue); |
@@ -81,35 +84,36 @@ class SharedStoreFuzzTest { | |||
81 | MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference.get(storeIndex), versioneds.get(storeIndex)); | 84 | MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference.get(storeIndex), versioneds.get(storeIndex)); |
82 | } | 85 | } |
83 | } | 86 | } |
84 | MapTestEnvironment.printStatus(scenario, index, steps, "comparison"); | 87 | MapTestEnvironment.printStatus(scenario, index, steps, "comparison"); |
85 | } | 88 | } |
86 | 89 | ||
87 | } | 90 | } |
88 | 91 | ||
89 | @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 92 | @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit " + |
93 | "frequency={4} seed={5} evil-hash={6}") | ||
90 | @MethodSource | 94 | @MethodSource |
91 | @Timeout(value = 10) | 95 | @Timeout(value = 10) |
92 | @Tag("smoke") | 96 | @Tag("smoke") |
93 | void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 97 | void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, |
94 | boolean evilHash) { | 98 | int seed, boolean evilHash) { |
95 | runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 99 | runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
96 | commitFrequency, evilHash); | 100 | nullDefault, commitFrequency, evilHash); |
97 | } | 101 | } |
98 | 102 | ||
99 | static Stream<Arguments> parametrizedFastFuzz() { | 103 | static Stream<Arguments> parametrizedFastFuzz() { |
100 | return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 }, | 104 | return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, |
101 | new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 }, | 105 | commitFrequencyOptions, randomSeedOptions, new Object[]{false, true}); |
102 | new Object[] { false, true }); | ||
103 | } | 106 | } |
104 | 107 | ||
105 | @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}") | 108 | @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} nullDefault={4} commit " + |
109 | "frequency={4} seed={5} evil-hash={6}") | ||
106 | @MethodSource | 110 | @MethodSource |
107 | @Tag("smoke") | 111 | @Tag("smoke") |
108 | @Tag("slow") | 112 | @Tag("slow") |
109 | void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed, | 113 | void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, int commitFrequency, |
110 | boolean evilHash) { | 114 | int seed, boolean evilHash) { |
111 | runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | 115 | runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, |
112 | commitFrequency, evilHash); | 116 | nullDefault, commitFrequency, evilHash); |
113 | } | 117 | } |
114 | 118 | ||
115 | static Stream<Arguments> parametrizedSlowFuzz() { | 119 | static Stream<Arguments> parametrizedSlowFuzz() { |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java new file mode 100644 index 00000000..1337cf3a --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SingleThreadFuzzTest.java | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.map.tests.fuzz; | ||
7 | |||
8 | import org.junit.jupiter.api.Tag; | ||
9 | import org.junit.jupiter.api.Timeout; | ||
10 | import org.junit.jupiter.params.ParameterizedTest; | ||
11 | import org.junit.jupiter.params.provider.Arguments; | ||
12 | import org.junit.jupiter.params.provider.MethodSource; | ||
13 | import tools.refinery.store.map.VersionedMapStore; | ||
14 | import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; | ||
15 | import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils; | ||
16 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | ||
17 | |||
18 | import java.util.stream.Stream; | ||
19 | |||
20 | import static tools.refinery.store.map.tests.fuzz.utils.FuzzTestCollections.*; | ||
21 | |||
22 | class SingleThreadFuzzTest { | ||
23 | private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean nullDefault, int commitFrequency, VersionedMapStoreFactoryBuilder<Integer, String> builder) { | ||
24 | String[] values = MapTestEnvironment.prepareValues(maxValue, nullDefault); | ||
25 | |||
26 | VersionedMapStore<Integer, String> store = builder.defaultValue(values[0]).build().createOne(); | ||
27 | |||
28 | // initialize runnables | ||
29 | MultiThreadTestRunnable runnable = new MultiThreadTestRunnable(scenario, store, steps, maxKey, values, seed, commitFrequency); | ||
30 | |||
31 | // start threads; | ||
32 | runnable.run(); | ||
33 | } | ||
34 | |||
35 | static final String title = "SingleThread {index}/{0} Steps={1} Keys={2} Values={3} defaultNull={4} commit " + | ||
36 | "frequency={5} seed={6} config={7}"; | ||
37 | |||
38 | @ParameterizedTest(name = title) | ||
39 | @MethodSource | ||
40 | @Timeout(value = 10) | ||
41 | @Tag("fuzz") | ||
42 | void parametrizedFastFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean defaultNull, | ||
43 | int commitFrequency, int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) { | ||
44 | runFuzzTest("SingleThreadS" + steps + "K" + noKeys + "V" + noValues + defaultNull + "CF" + commitFrequency + | ||
45 | "s" + seed, seed, steps, noKeys, noValues, defaultNull, commitFrequency, builder); | ||
46 | } | ||
47 | |||
48 | static Stream<Arguments> parametrizedFastFuzz() { | ||
49 | return FuzzTestUtils.permutationWithSize(stepCounts, keyCounts, valueCounts, nullDefaultOptions, | ||
50 | new Object[]{10, 100}, randomSeedOptions, storeConfigs); | ||
51 | } | ||
52 | |||
53 | @ParameterizedTest(name = title) | ||
54 | @MethodSource | ||
55 | @Tag("fuzz") | ||
56 | @Tag("slow") | ||
57 | void parametrizedSlowFuzz(int ignoredTests, int steps, int noKeys, int noValues, boolean nullDefault, | ||
58 | int commitFrequency, int seed, VersionedMapStoreFactoryBuilder<Integer, String> builder) { | ||
59 | runFuzzTest("SingleThreadS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues, | ||
60 | nullDefault, commitFrequency, builder); | ||
61 | } | ||
62 | |||
63 | static Stream<Arguments> parametrizedSlowFuzz() { | ||
64 | return FuzzTestUtils.changeStepCount(RestoreFuzzTest.parametrizedFastFuzz(), 1); | ||
65 | } | ||
66 | } | ||
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java new file mode 100644 index 00000000..ec04904e --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestCollections.java | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.map.tests.fuzz.utils; | ||
7 | |||
8 | import tools.refinery.store.map.VersionedMapStore; | ||
9 | import tools.refinery.store.map.VersionedMapStoreFactoryBuilder; | ||
10 | import tools.refinery.store.map.tests.utils.MapTestEnvironment; | ||
11 | |||
12 | public final class FuzzTestCollections { | ||
13 | public static final Object[] stepCounts = {FuzzTestUtils.FAST_STEP_COUNT}; | ||
14 | public static final Object[] keyCounts = {1 , 32, 32 * 32}; | ||
15 | public static final Object[] valueCounts = {2, 3}; | ||
16 | public static final Object[] nullDefaultOptions = {false, true}; | ||
17 | public static final Object[] commitFrequencyOptions = {1, 10, 100}; | ||
18 | public static final Object[] randomSeedOptions = {1}; | ||
19 | public static final Object[] storeConfigs = { | ||
20 | // State based | ||
21 | // Default | ||
22 | VersionedMapStore.<Integer,String>builder() | ||
23 | .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) | ||
24 | .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE), | ||
25 | // Evil hash code test | ||
26 | VersionedMapStore.<Integer,String>builder() | ||
27 | .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(true)) | ||
28 | .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE), | ||
29 | // No weak hashmap test | ||
30 | VersionedMapStore.<Integer,String>builder() | ||
31 | .versionFreeing(false) | ||
32 | .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) | ||
33 | .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE), | ||
34 | // Copy when committing, do not hurt the work copy, share between saves. | ||
35 | VersionedMapStore.<Integer,String>builder() | ||
36 | .stateBasedImmutableWhenCommitting(false) | ||
37 | .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) | ||
38 | .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.SHARED_NODE_CACHE), | ||
39 | // Copy when committing, do not hurt the work copy, do not share between states. | ||
40 | VersionedMapStore.<Integer,String>builder() | ||
41 | .stateBasedImmutableWhenCommitting(false) | ||
42 | .stateBasedHashProvider(MapTestEnvironment.prepareHashProvider(false)) | ||
43 | .stateBasedSharingStrategy(VersionedMapStoreFactoryBuilder.SharingStrategy.NO_NODE_CACHE), | ||
44 | |||
45 | // Delta based | ||
46 | // Set based transactions | ||
47 | VersionedMapStore.<Integer,String>builder() | ||
48 | .deltaTransactionStrategy(VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy.SET), | ||
49 | // List based transactions | ||
50 | VersionedMapStore.<Integer,String>builder() | ||
51 | .deltaTransactionStrategy(VersionedMapStoreFactoryBuilder.DeltaTransactionStrategy.LIST) | ||
52 | }; | ||
53 | } | ||
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java index a819d348..32675635 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java | |||
@@ -13,7 +13,7 @@ import java.util.stream.Stream; | |||
13 | import org.junit.jupiter.params.provider.Arguments; | 13 | import org.junit.jupiter.params.provider.Arguments; |
14 | 14 | ||
15 | public final class FuzzTestUtils { | 15 | public final class FuzzTestUtils { |
16 | public static final int FAST_STEP_COUNT = 500; | 16 | public static final int FAST_STEP_COUNT = 250; |
17 | public static final int SLOW_STEP_COUNT = 32 * 32 * 32 * 32; | 17 | public static final int SLOW_STEP_COUNT = 32 * 32 * 32 * 32; |
18 | 18 | ||
19 | private FuzzTestUtils() { | 19 | private FuzzTestUtils() { |
@@ -56,14 +56,12 @@ public final class FuzzTestUtils { | |||
56 | 56 | ||
57 | public static Stream<Arguments> permutationWithSize(Object[]... valueOption) { | 57 | public static Stream<Arguments> permutationWithSize(Object[]... valueOption) { |
58 | int size = 1; | 58 | int size = 1; |
59 | for (int i = 0; i < valueOption.length; i++) { | 59 | for (Object[] objects : valueOption) { |
60 | size *= valueOption[i].length; | 60 | size *= objects.length; |
61 | } | 61 | } |
62 | Object[][] newValueOption = new Object[valueOption.length + 1][]; | 62 | Object[][] newValueOption = new Object[valueOption.length + 1][]; |
63 | newValueOption[0] = new Object[] { size }; | 63 | newValueOption[0] = new Object[]{size}; |
64 | for (int i = 1; i < newValueOption.length; i++) { | 64 | System.arraycopy(valueOption, 0, newValueOption, 1, newValueOption.length - 1); |
65 | newValueOption[i] = valueOption[i - 1]; | ||
66 | } | ||
67 | return permutation(newValueOption); | 65 | return permutation(newValueOption); |
68 | } | 66 | } |
69 | } | 67 | } |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java index dc621574..951d6336 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java | |||
@@ -6,31 +6,36 @@ | |||
6 | package tools.refinery.store.map.tests.fuzz.utils; | 6 | package tools.refinery.store.map.tests.fuzz.utils; |
7 | 7 | ||
8 | import static org.junit.jupiter.api.Assertions.assertEquals; | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; |
9 | import static org.junit.jupiter.api.Assertions.assertTrue; | ||
9 | 10 | ||
10 | import java.util.List; | 11 | import java.util.List; |
12 | import java.util.Optional; | ||
11 | 13 | ||
12 | import org.junit.jupiter.api.Test; | 14 | import org.junit.jupiter.api.Test; |
15 | import org.junit.jupiter.params.provider.Arguments; | ||
13 | 16 | ||
14 | class FuzzTestUtilsTest { | 17 | class FuzzTestUtilsTest { |
15 | @Test | 18 | @Test |
16 | void permutationInternalTest() { | 19 | void permutationInternalTest() { |
17 | List<List<Object>> res = FuzzTestUtils.permutationInternal(0, new Object[] { 1, 2, 3 }, | 20 | List<List<Object>> res = FuzzTestUtils.permutationInternal(0, new Object[]{1, 2, 3}, |
18 | new Object[] { 'a', 'b', 'c' }, new Object[] { "alpha", "beta", "gamma", "delta" }); | 21 | new Object[]{'a', 'b', 'c'}, new Object[]{"alpha", "beta", "gamma", "delta"}); |
19 | assertEquals(3 * 3 * 4, res.size()); | 22 | assertEquals(3 * 3 * 4, res.size()); |
20 | } | 23 | } |
21 | 24 | ||
22 | @Test | 25 | @Test |
23 | void permutationTest1() { | 26 | void permutationTest1() { |
24 | var res = FuzzTestUtils.permutation(new Object[] { 1, 2, 3 }, new Object[] { 'a', 'b', 'c' }, | 27 | var res = FuzzTestUtils.permutation(new Object[]{1, 2, 3}, new Object[]{'a', 'b', 'c'}, |
25 | new Object[] { "alpha", "beta", "gamma", "delta" }); | 28 | new Object[]{"alpha", "beta", "gamma", "delta"}); |
26 | assertEquals(3 * 3 * 4, res.count()); | 29 | assertEquals(3 * 3 * 4, res.count()); |
27 | } | 30 | } |
28 | 31 | ||
29 | @Test | 32 | @Test |
30 | void permutationTest2() { | 33 | void permutationTest2() { |
31 | var res = FuzzTestUtils.permutation(new Object[] { 1, 2, 3 }, new Object[] { 'a', 'b', 'c' }, | 34 | var res = FuzzTestUtils.permutation(new Object[]{1, 2, 3}, new Object[]{'a', 'b', 'c'}, |
32 | new Object[] { "alpha", "beta", "gamma", "delta" }); | 35 | new Object[]{"alpha", "beta", "gamma", "delta"}); |
33 | var arguments = res.findFirst().get().get(); | 36 | Optional<Arguments> first = res.findFirst(); |
37 | assertTrue(first.isPresent()); | ||
38 | var arguments = first.get().get(); | ||
34 | assertEquals(1, arguments[0]); | 39 | assertEquals(1, arguments[0]); |
35 | assertEquals('a', arguments[1]); | 40 | assertEquals('a', arguments[1]); |
36 | assertEquals("alpha", arguments[2]); | 41 | assertEquals("alpha", arguments[2]); |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java index f861f496..b84df280 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java +++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java | |||
@@ -6,7 +6,7 @@ | |||
6 | package tools.refinery.store.map.tests.utils; | 6 | package tools.refinery.store.map.tests.utils; |
7 | 7 | ||
8 | import tools.refinery.store.map.*; | 8 | import tools.refinery.store.map.*; |
9 | import tools.refinery.store.map.internal.VersionedMapImpl; | 9 | import tools.refinery.store.map.internal.state.VersionedMapStateImpl; |
10 | 10 | ||
11 | import java.util.*; | 11 | import java.util.*; |
12 | import java.util.Map.Entry; | 12 | import java.util.Map.Entry; |
@@ -14,35 +14,35 @@ import java.util.Map.Entry; | |||
14 | import static org.junit.jupiter.api.Assertions.*; | 14 | import static org.junit.jupiter.api.Assertions.*; |
15 | 15 | ||
16 | public class MapTestEnvironment<K, V> { | 16 | public class MapTestEnvironment<K, V> { |
17 | public static String[] prepareValues(int maxValue) { | 17 | public static String[] prepareValues(int maxValue, boolean nullDefault) { |
18 | String[] values = new String[maxValue]; | 18 | String[] values = new String[maxValue]; |
19 | values[0] = "DEFAULT"; | 19 | if (nullDefault) { |
20 | values[0] = null; | ||
21 | } else { | ||
22 | values[0] = "DEFAULT"; | ||
23 | } | ||
24 | |||
20 | for (int i = 1; i < values.length; i++) { | 25 | for (int i = 1; i < values.length; i++) { |
21 | values[i] = "VAL" + i; | 26 | values[i] = "VAL" + i; |
22 | } | 27 | } |
23 | return values; | 28 | return values; |
24 | } | 29 | } |
25 | 30 | ||
26 | public static ContinousHashProvider<Integer> prepareHashProvider(final boolean evil) { | 31 | public static ContinuousHashProvider<Integer> prepareHashProvider(final boolean evil) { |
27 | // Use maxPrime = 2147483629 | 32 | // Use maxPrime = 2147483629 |
28 | 33 | ||
29 | ContinousHashProvider<Integer> chp = new ContinousHashProvider<Integer>() { | 34 | return (key, index) -> { |
30 | 35 | if (evil && index < 15 && index < key / 3) { | |
31 | @Override | 36 | return 7; |
32 | public int getHash(Integer key, int index) { | 37 | } |
33 | if (evil && index < 15 && index < key / 3) { | 38 | int result = 1; |
34 | return 7; | 39 | final int prime = 31; |
35 | } | ||
36 | int result = 1; | ||
37 | final int prime = 31; | ||
38 | 40 | ||
39 | result = prime * result + key; | 41 | result = prime * result + key; |
40 | result = prime * result + index; | 42 | result = prime * result + index; |
41 | 43 | ||
42 | return result; | 44 | return result; |
43 | } | ||
44 | }; | 45 | }; |
45 | return chp; | ||
46 | } | 46 | } |
47 | 47 | ||
48 | public static void printStatus(String scenario, int actual, int max, String stepName) { | 48 | public static void printStatus(String scenario, int actual, int max, String stepName) { |
@@ -60,29 +60,17 @@ public class MapTestEnvironment<K, V> { | |||
60 | 60 | ||
61 | public static <K, V> void compareTwoMaps(String title, VersionedMap<K, V> map1, | 61 | public static <K, V> void compareTwoMaps(String title, VersionedMap<K, V> map1, |
62 | VersionedMap<K, V> map2, List<Throwable> errors) { | 62 | VersionedMap<K, V> map2, List<Throwable> errors) { |
63 | assertEqualsList(map1.getSize(), map2.getSize(), title + ": Sizes not equal", errors); | 63 | map1.checkIntegrity(); |
64 | map2.checkIntegrity(); | ||
64 | 65 | ||
65 | Cursor<K, V> cursor1 = map1.getAll(); | 66 | assertContentEqualsList(map1, map2, title + ": map1.contentEquals(map2)", errors); |
66 | Cursor<K, V> cursor2 = map2.getAll(); | 67 | assertContentEqualsList(map2, map1, title + ": map2.contentEquals(map1)", errors); |
67 | while (!cursor1.isTerminated()) { | 68 | assertEqualsList(map1.getSize(), map2.getSize(), title + ": Sizes not equal", errors); |
68 | if (cursor2.isTerminated()) { | ||
69 | fail("cursor 2 terminated before cursor1"); | ||
70 | } | ||
71 | assertEqualsList(cursor1.getKey(), cursor2.getKey(), title + ": Keys not equal", errors); | ||
72 | assertEqualsList(cursor2.getValue(), cursor2.getValue(), title + ": Values not equal", errors); | ||
73 | cursor1.move(); | ||
74 | cursor2.move(); | ||
75 | } | ||
76 | if (!cursor2.isTerminated()) { | ||
77 | fail("cursor 1 terminated before cursor 2"); | ||
78 | } | ||
79 | 69 | ||
80 | for (var mode : ContentHashCode.values()) { | 70 | for (var mode : ContentHashCode.values()) { |
81 | assertEqualsList(map1.contentHashCode(mode), map2.contentHashCode(mode), | 71 | assertEqualsList(map1.contentHashCode(mode), map2.contentHashCode(mode), |
82 | title + ": " + mode + " hashCode check", errors); | 72 | title + ": " + mode + " hashCode check", errors); |
83 | } | 73 | } |
84 | assertContentEqualsList(map1, map2, title + ": map1.contentEquals(map2)", errors); | ||
85 | assertContentEqualsList(map2, map1, title + ": map2.contentEquals(map1)", errors); | ||
86 | } | 74 | } |
87 | 75 | ||
88 | private static void assertEqualsList(Object o1, Object o2, String message, List<Throwable> errors) { | 76 | private static void assertEqualsList(Object o1, Object o2, String message, List<Throwable> errors) { |
@@ -112,29 +100,35 @@ public class MapTestEnvironment<K, V> { | |||
112 | } | 100 | } |
113 | } | 101 | } |
114 | 102 | ||
115 | public VersionedMapImpl<K, V> sut; | 103 | final private VersionedMap<K, V> sut; |
116 | Map<K, V> oracle = new HashMap<K, V>(); | 104 | final private V defaultValue; |
105 | Map<K, V> oracle = new HashMap<>(); | ||
117 | 106 | ||
118 | public MapTestEnvironment(VersionedMapImpl<K, V> sut) { | 107 | public MapTestEnvironment(VersionedMap<K, V> sut) { |
119 | this.sut = sut; | 108 | this.sut = sut; |
109 | this.defaultValue = sut.getDefaultValue(); | ||
120 | } | 110 | } |
121 | 111 | ||
122 | public void put(K key, V value) { | 112 | public void put(K key, V value) { |
123 | V oldSutValue = sut.put(key, value); | 113 | V oldSutValue = sut.put(key, value); |
124 | V oldOracleValue; | 114 | V oldOracleValue; |
125 | if (value != sut.getDefaultValue()) { | 115 | if (value != defaultValue) { |
126 | oldOracleValue = oracle.put(key, value); | 116 | oldOracleValue = oracle.put(key, value); |
127 | } else { | 117 | } else { |
128 | oldOracleValue = oracle.remove(key); | 118 | oldOracleValue = oracle.remove(key); |
129 | } | 119 | } |
130 | if (oldSutValue == sut.getDefaultValue() && oldOracleValue != null) { | 120 | if (oldSutValue == defaultValue && oldOracleValue != null) { |
131 | fail("After put, SUT old nodeId was default, but oracle old value was " + oldOracleValue); | 121 | fail("After put, SUT old nodeId was default, but oracle old value was " + oldOracleValue); |
132 | } | 122 | } |
133 | if (oldSutValue != sut.getDefaultValue()) { | 123 | if (oldSutValue != defaultValue) { |
134 | assertEquals(oldOracleValue, oldSutValue); | 124 | assertEquals(oldOracleValue, oldSutValue); |
135 | } | 125 | } |
136 | } | 126 | } |
137 | 127 | ||
128 | public Version commit(){ | ||
129 | return sut.commit(); | ||
130 | } | ||
131 | |||
138 | public void checkEquivalence(String title) { | 132 | public void checkEquivalence(String title) { |
139 | // 0. Checking integrity | 133 | // 0. Checking integrity |
140 | try { | 134 | try { |
@@ -181,7 +175,7 @@ public class MapTestEnvironment<K, V> { | |||
181 | long sutSize = sut.getSize(); | 175 | long sutSize = sut.getSize(); |
182 | if (oracleSize != sutSize || oracleSize != elementsInSutEntrySet) { | 176 | if (oracleSize != sutSize || oracleSize != elementsInSutEntrySet) { |
183 | printComparison(); | 177 | printComparison(); |
184 | fail(title + ": Non-equivalent size() result: SUT.getSize()=" + sutSize + ", SUT.entryset.size=" | 178 | fail(title + ": Non-equivalent size() result: SUT.getSize()=" + sutSize + ", SUT.entrySet.size=" |
185 | + elementsInSutEntrySet + ", Oracle=" + oracleSize + "!"); | 179 | + elementsInSutEntrySet + ", Oracle=" + oracleSize + "!"); |
186 | } | 180 | } |
187 | } | 181 | } |
@@ -190,15 +184,15 @@ public class MapTestEnvironment<K, V> { | |||
190 | K previous = null; | 184 | K previous = null; |
191 | Cursor<K, V> cursor = versionedMap.getAll(); | 185 | Cursor<K, V> cursor = versionedMap.getAll(); |
192 | while (cursor.move()) { | 186 | while (cursor.move()) { |
193 | System.out.println(cursor.getKey() + " " + ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().getHash(cursor.getKey(), 0)); | 187 | //System.out.println(cursor.getKey() + " " + ((VersionedMapImpl<K, V>) versionedMap).getHashProvider() |
188 | // .getHash(cursor.getKey(), 0)); | ||
194 | if (previous != null) { | 189 | if (previous != null) { |
195 | int comparisonResult = ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().compare(previous, | 190 | int comparisonResult = ((VersionedMapStateImpl<K, V>) versionedMap).getHashProvider().compare(previous, |
196 | cursor.getKey()); | 191 | cursor.getKey()); |
197 | assertTrue(comparisonResult < 0, scenario + " Cursor order is not incremental!"); | 192 | assertTrue(comparisonResult < 0, scenario + " Cursor order is not incremental!"); |
198 | } | 193 | } |
199 | previous = cursor.getKey(); | 194 | previous = cursor.getKey(); |
200 | } | 195 | } |
201 | System.out.println(); | ||
202 | } | 196 | } |
203 | 197 | ||
204 | public void printComparison() { | 198 | public void printComparison() { |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java index 4d4f5e26..5b595da7 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/model/hashtests/HashEfficiencyTest.java | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * SPDX-License-Identifier: EPL-2.0 | 4 | * SPDX-License-Identifier: EPL-2.0 |
5 | */ | 5 | */ |
6 | package tools.refinery.store.model.hashtests; | 6 | package tools.refinery.store.model.hashTests; |
7 | 7 | ||
8 | import static org.junit.jupiter.api.Assertions.assertEquals; | 8 | import static org.junit.jupiter.api.Assertions.assertEquals; |
9 | 9 | ||
@@ -14,10 +14,9 @@ import java.util.Random; | |||
14 | 14 | ||
15 | import org.junit.jupiter.api.Test; | 15 | import org.junit.jupiter.api.Test; |
16 | 16 | ||
17 | import tools.refinery.store.map.ContinousHashProvider; | 17 | import tools.refinery.store.map.ContinuousHashProvider; |
18 | import tools.refinery.store.tuple.Tuple; | 18 | import tools.refinery.store.tuple.Tuple; |
19 | import tools.refinery.store.model.TupleHashProvider; | 19 | import tools.refinery.store.model.TupleHashProvider; |
20 | import tools.refinery.store.model.TupleHashProviderBitMagic; | ||
21 | 20 | ||
22 | class HashEfficiencyTest { | 21 | class HashEfficiencyTest { |
23 | 22 | ||
@@ -95,7 +94,7 @@ class HashEfficiencyTest { | |||
95 | List<Tuple> p = nRandoms(2, amount, 1);; | 94 | List<Tuple> p = nRandoms(2, amount, 1);; |
96 | assertEquals(amount,p.size()); | 95 | assertEquals(amount,p.size()); |
97 | } | 96 | } |
98 | private static double calculateHashClashes(List<Tuple> tuples, ContinousHashProvider<Tuple> chp) { | 97 | private static double calculateHashClashes(List<Tuple> tuples, ContinuousHashProvider<Tuple> chp) { |
99 | int sumClashes = 0; | 98 | int sumClashes = 0; |
100 | 99 | ||
101 | for(int i = 0; i<tuples.size(); i++) { | 100 | for(int i = 0; i<tuples.size(); i++) { |
@@ -108,7 +107,7 @@ class HashEfficiencyTest { | |||
108 | } | 107 | } |
109 | return (sumClashes+0.0) / tuples.size(); | 108 | return (sumClashes+0.0) / tuples.size(); |
110 | } | 109 | } |
111 | private static int calculateHashClash(ContinousHashProvider<Tuple> chp, Tuple a, Tuple b) { | 110 | private static int calculateHashClash(ContinuousHashProvider<Tuple> chp, Tuple a, Tuple b) { |
112 | if(a.equals(b)) return 0; | 111 | if(a.equals(b)) return 0; |
113 | final int bits = 5; | 112 | final int bits = 5; |
114 | final int segments = Integer.SIZE/bits; | 113 | final int segments = Integer.SIZE/bits; |
@@ -131,11 +130,9 @@ class HashEfficiencyTest { | |||
131 | } | 130 | } |
132 | public static void main(String[] args) { | 131 | public static void main(String[] args) { |
133 | List<String> hashNames = new LinkedList<>(); | 132 | List<String> hashNames = new LinkedList<>(); |
134 | List<ContinousHashProvider<Tuple>> hashes = new LinkedList<>(); | 133 | List<ContinuousHashProvider<Tuple>> hashes = new LinkedList<>(); |
135 | hashNames.add("PrimeGroup"); | 134 | hashNames.add("PrimeGroup"); |
136 | hashes.add(new TupleHashProvider()); | 135 | hashes.add(new TupleHashProvider()); |
137 | hashNames.add("BitMagic"); | ||
138 | hashes.add(new TupleHashProviderBitMagic()); | ||
139 | 136 | ||
140 | int[] arities = new int[] {2,3,4,5}; | 137 | int[] arities = new int[] {2,3,4,5}; |
141 | int[] sizes = new int[] {32*32,32*32*8}; | 138 | int[] sizes = new int[] {32*32,32*32*8}; |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java index 56b75804..dc7b776e 100644 --- a/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java +++ b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java | |||
@@ -6,6 +6,7 @@ | |||
6 | package tools.refinery.store.model.tests; | 6 | package tools.refinery.store.model.tests; |
7 | 7 | ||
8 | import org.junit.jupiter.api.Test; | 8 | import org.junit.jupiter.api.Test; |
9 | import tools.refinery.store.map.Version; | ||
9 | import tools.refinery.store.model.Model; | 10 | import tools.refinery.store.model.Model; |
10 | import tools.refinery.store.model.ModelStore; | 11 | import tools.refinery.store.model.ModelStore; |
11 | import tools.refinery.store.representation.Symbol; | 12 | import tools.refinery.store.representation.Symbol; |
@@ -120,7 +121,7 @@ class ModelTest { | |||
120 | assertTrue(model.hasUncommittedChanges()); | 121 | assertTrue(model.hasUncommittedChanges()); |
121 | assertEquals(Model.NO_STATE_ID, model.getState()); | 122 | assertEquals(Model.NO_STATE_ID, model.getState()); |
122 | 123 | ||
123 | long state1 = model.commit(); | 124 | Version state1 = model.commit(); |
124 | 125 | ||
125 | assertFalse(model.hasUncommittedChanges()); | 126 | assertFalse(model.hasUncommittedChanges()); |
126 | assertEquals(state1, model.getState()); | 127 | assertEquals(state1, model.getState()); |
@@ -134,7 +135,7 @@ class ModelTest { | |||
134 | assertTrue(model.hasUncommittedChanges()); | 135 | assertTrue(model.hasUncommittedChanges()); |
135 | assertEquals(state1, model.getState()); | 136 | assertEquals(state1, model.getState()); |
136 | 137 | ||
137 | long state2 = model.commit(); | 138 | Version state2 = model.commit(); |
138 | 139 | ||
139 | assertFalse(model.hasUncommittedChanges()); | 140 | assertFalse(model.hasUncommittedChanges()); |
140 | assertEquals(state2, model.getState()); | 141 | assertEquals(state2, model.getState()); |
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java new file mode 100644 index 00000000..3c35849e --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/EquivalenceTest.java | |||
@@ -0,0 +1,217 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.statecoding; | ||
7 | |||
8 | import org.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.map.Version; | ||
10 | import tools.refinery.store.model.Model; | ||
11 | import tools.refinery.store.model.ModelStore; | ||
12 | import tools.refinery.store.representation.Symbol; | ||
13 | import tools.refinery.store.statecoding.neighbourhood.ObjectCodeImpl; | ||
14 | import tools.refinery.store.tuple.Tuple; | ||
15 | |||
16 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
17 | |||
18 | class EquivalenceTest { | ||
19 | Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false); | ||
20 | Symbol<Integer> age = new Symbol<>("age", 1, Integer.class, null); | ||
21 | Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
22 | Symbol<Boolean> parents = new Symbol<>("parents", 3, Boolean.class, false); | ||
23 | Symbol<Integer> population = new Symbol<>("population", 0, Integer.class, 0); | ||
24 | |||
25 | private ModelStore createStore() { | ||
26 | return ModelStore.builder() | ||
27 | .symbols(person, age, friend, parents, population) | ||
28 | .with(StateCoderAdapter.builder()) | ||
29 | .build(); | ||
30 | } | ||
31 | |||
32 | @Test | ||
33 | void emptyModelCode0() { | ||
34 | ModelStore store = createStore(); | ||
35 | var stateCoder = store.getAdapter(StateCoderStoreAdapter.class); | ||
36 | Model model = createStore().createEmptyModel(); | ||
37 | Version v1 = model.commit(); | ||
38 | Version v2 = model.commit(); | ||
39 | |||
40 | assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v1, v2)); | ||
41 | |||
42 | var personI = model.getInterpretation(person); | ||
43 | var friendI = model.getInterpretation(friend); | ||
44 | |||
45 | personI.put(Tuple.of(1), true); | ||
46 | personI.put(Tuple.of(2), true); | ||
47 | friendI.put(Tuple.of(1, 2), true); | ||
48 | |||
49 | Version v3 = model.commit(); | ||
50 | |||
51 | assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v3)); | ||
52 | } | ||
53 | |||
54 | @Test | ||
55 | void nullRelationTest() { | ||
56 | ModelStore store = createStore(); | ||
57 | var stateCoder = store.getAdapter(StateCoderStoreAdapter.class); | ||
58 | Model model = createStore().createEmptyModel(); | ||
59 | |||
60 | var populationI = model.getInterpretation(population); | ||
61 | |||
62 | Version v1 = model.commit(); | ||
63 | |||
64 | populationI.put(Tuple.of(), 1); | ||
65 | Version v2 = model.commit(); | ||
66 | |||
67 | assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2)); | ||
68 | |||
69 | populationI.put(Tuple.of(), 2); | ||
70 | Version v3 = model.commit(); | ||
71 | |||
72 | assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3)); | ||
73 | } | ||
74 | |||
75 | @Test | ||
76 | void unaryBooleanTest() { | ||
77 | ModelStore store = createStore(); | ||
78 | var stateCoder = store.getAdapter(StateCoderStoreAdapter.class); | ||
79 | Model model = createStore().createEmptyModel(); | ||
80 | |||
81 | var personI = model.getInterpretation(person); | ||
82 | |||
83 | Version v1 = model.commit(); | ||
84 | |||
85 | personI.put(Tuple.of(1), true); | ||
86 | Version v2 = model.commit(); | ||
87 | |||
88 | assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2)); | ||
89 | |||
90 | personI.put(Tuple.of(2), true); | ||
91 | Version v3 = model.commit(); | ||
92 | |||
93 | assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3)); | ||
94 | |||
95 | personI.put(Tuple.of(1), false); | ||
96 | Version v4 = model.commit(); | ||
97 | |||
98 | assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4)); | ||
99 | } | ||
100 | |||
101 | @Test | ||
102 | void unaryIntTest() { | ||
103 | ModelStore store = createStore(); | ||
104 | var stateCoder = store.getAdapter(StateCoderStoreAdapter.class); | ||
105 | Model model = createStore().createEmptyModel(); | ||
106 | |||
107 | var ageI = model.getInterpretation(age); | ||
108 | |||
109 | ageI.put(Tuple.of(1), 3); | ||
110 | Version v1 = model.commit(); | ||
111 | |||
112 | ageI.put(Tuple.of(1), 4); | ||
113 | Version v2 = model.commit(); | ||
114 | |||
115 | assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2)); | ||
116 | |||
117 | ageI.put(Tuple.of(2), 4); | ||
118 | Version v3 = model.commit(); | ||
119 | |||
120 | assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3)); | ||
121 | |||
122 | ageI.put(Tuple.of(1), null); | ||
123 | Version v4 = model.commit(); | ||
124 | |||
125 | assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4)); | ||
126 | } | ||
127 | |||
128 | @Test | ||
129 | void binaryTest() { | ||
130 | ModelStore store = createStore(); | ||
131 | var stateCoder = store.getAdapter(StateCoderStoreAdapter.class); | ||
132 | Model model = createStore().createEmptyModel(); | ||
133 | |||
134 | var friendI = model.getInterpretation(friend); | ||
135 | |||
136 | Version v1 = model.commit(); | ||
137 | |||
138 | friendI.put(Tuple.of(1, 2), true); | ||
139 | Version v2 = model.commit(); | ||
140 | |||
141 | assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2)); | ||
142 | |||
143 | friendI.put(Tuple.of(2, 1), true); | ||
144 | Version v3 = model.commit(); | ||
145 | |||
146 | assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3)); | ||
147 | |||
148 | friendI.put(Tuple.of(1, 2), false); | ||
149 | Version v4 = model.commit(); | ||
150 | |||
151 | assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4)); | ||
152 | } | ||
153 | |||
154 | @Test | ||
155 | void NaryTest() { | ||
156 | ModelStore store = createStore(); | ||
157 | var stateCoder = store.getAdapter(StateCoderStoreAdapter.class); | ||
158 | Model model = createStore().createEmptyModel(); | ||
159 | |||
160 | var parentsI = model.getInterpretation(parents); | ||
161 | |||
162 | Version v1 = model.commit(); | ||
163 | |||
164 | parentsI.put(Tuple.of(3, 1, 2), true); | ||
165 | Version v2 = model.commit(); | ||
166 | |||
167 | assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v1, v2)); | ||
168 | |||
169 | parentsI.put(Tuple.of(4, 1, 2), true); | ||
170 | Version v3 = model.commit(); | ||
171 | |||
172 | assertEquals(StateEquivalenceChecker.EquivalenceResult.DIFFERENT, stateCoder.checkEquivalence(v2, v3)); | ||
173 | |||
174 | parentsI.put(Tuple.of(3, 1, 2), false); | ||
175 | Version v4 = model.commit(); | ||
176 | |||
177 | assertEquals(StateEquivalenceChecker.EquivalenceResult.ISOMORPHIC, stateCoder.checkEquivalence(v2, v4)); | ||
178 | } | ||
179 | |||
180 | @Test | ||
181 | void largeUnknownTest() { | ||
182 | final int limit = 100; | ||
183 | |||
184 | StateCodeCalculator calculator = () -> { | ||
185 | var code = new ObjectCodeImpl(); | ||
186 | for (int i = 0; i < limit; i++) { | ||
187 | code.set(i, 1); | ||
188 | } | ||
189 | return new StateCoderResult(1, code); | ||
190 | }; | ||
191 | |||
192 | ModelStore store = ModelStore.builder() | ||
193 | .symbols(person, age, friend, parents, population) | ||
194 | .with(StateCoderAdapter.builder() | ||
195 | .stateCodeCalculatorFactory((p1, p2) -> calculator)) | ||
196 | .build(); | ||
197 | |||
198 | var stateCoder = store.getAdapter(StateCoderStoreAdapter.class); | ||
199 | Model model = createStore().createEmptyModel(); | ||
200 | |||
201 | var personI = model.getInterpretation(person); | ||
202 | var friendI = model.getInterpretation(friend); | ||
203 | |||
204 | for (int i = 0; i < limit; i++) { | ||
205 | personI.put(Tuple.of(i), true); | ||
206 | } | ||
207 | |||
208 | friendI.put(Tuple.of(11,12),true); | ||
209 | var v1 = model.commit(); | ||
210 | |||
211 | friendI.put(Tuple.of(11,12),false); | ||
212 | friendI.put(Tuple.of(21,22),false); | ||
213 | var v2 = model.commit(); | ||
214 | |||
215 | assertEquals(StateEquivalenceChecker.EquivalenceResult.UNKNOWN, stateCoder.checkEquivalence(v1,v2)); | ||
216 | } | ||
217 | } | ||
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java new file mode 100644 index 00000000..f5ffc18d --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/ExperimentalSetupTest.java | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.statecoding; | ||
7 | |||
8 | import org.eclipse.collections.api.factory.primitive.IntObjectMaps; | ||
9 | import org.eclipse.collections.api.map.primitive.MutableIntObjectMap; | ||
10 | import org.junit.jupiter.api.Tag; | ||
11 | import org.junit.jupiter.api.Test; | ||
12 | import org.junit.jupiter.params.ParameterizedTest; | ||
13 | import org.junit.jupiter.params.provider.ValueSource; | ||
14 | import tools.refinery.store.map.Version; | ||
15 | import tools.refinery.store.model.Model; | ||
16 | import tools.refinery.store.model.ModelStore; | ||
17 | import tools.refinery.store.representation.Symbol; | ||
18 | import tools.refinery.store.tuple.Tuple; | ||
19 | |||
20 | import java.util.ArrayList; | ||
21 | import java.util.HashSet; | ||
22 | import java.util.List; | ||
23 | import java.util.Set; | ||
24 | |||
25 | import static org.junit.jupiter.api.Assertions.assertEquals; | ||
26 | import static org.junit.jupiter.api.Assertions.assertTrue; | ||
27 | |||
28 | class ExperimentalSetupTest { | ||
29 | static class ExperimentalSetupResult { | ||
30 | int versions = 0; | ||
31 | int different = 0; | ||
32 | int isomorphic = 0; | ||
33 | int unknown = 0; | ||
34 | |||
35 | double failureRatio() { | ||
36 | return (different + 0.0) / versions; | ||
37 | } | ||
38 | |||
39 | @Override | ||
40 | public String toString() { | ||
41 | return "ExperimentalSetupResult{" + | ||
42 | "versions=" + versions + | ||
43 | ", different=" + different + | ||
44 | ", isomorphic=" + isomorphic + | ||
45 | ", unknown=" + unknown + | ||
46 | ", ratio= " + failureRatio() + | ||
47 | '}'; | ||
48 | } | ||
49 | } | ||
50 | |||
51 | static int MAX = 100000; | ||
52 | |||
53 | public static ExperimentalSetupResult generate(int size, boolean permuteTypes) { | ||
54 | Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false); | ||
55 | Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
56 | |||
57 | var store = ModelStore.builder() | ||
58 | .symbols(person, friend) | ||
59 | .with(StateCoderAdapter | ||
60 | .builder()) | ||
61 | .build(); | ||
62 | |||
63 | Set<Version> versions = new HashSet<>(); | ||
64 | MutableIntObjectMap<List<Version>> codes = IntObjectMaps.mutable.empty(); | ||
65 | |||
66 | var empty = store.createEmptyModel(); | ||
67 | if (!permuteTypes) { | ||
68 | for (int i = 0; i < size; i++) { | ||
69 | empty.getInterpretation(person).put(Tuple.of(i), true); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | var emptyVersion = empty.commit(); | ||
74 | versions.add(emptyVersion); | ||
75 | var emptyCode = empty.getAdapter(StateCoderAdapter.class).calculateModelCode(); | ||
76 | List<Version> emptyList = new ArrayList<>(); | ||
77 | emptyList.add(emptyVersion); | ||
78 | codes.put(emptyCode, emptyList); | ||
79 | |||
80 | var storeAdapter = store.getAdapter(StateCoderStoreAdapter.class); | ||
81 | var result = new ExperimentalSetupResult(); | ||
82 | |||
83 | int steps = 0; | ||
84 | |||
85 | if (permuteTypes) { | ||
86 | for (int i = 0; i < size; i++) { | ||
87 | var previousVersions = new HashSet<>(versions); | ||
88 | for (var version : previousVersions) { | ||
89 | var model = store.createModelForState(version); | ||
90 | model.getInterpretation(person).put(Tuple.of(i), true); | ||
91 | |||
92 | saveAsNewVersion(versions, codes, storeAdapter, result, model); | ||
93 | |||
94 | logProgress(steps++); | ||
95 | if (steps > MAX) { | ||
96 | result.versions = versions.size(); | ||
97 | return result; | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | |||
103 | for (int i = 0; i < size; i++) { | ||
104 | for (int j = 0; j < size; j++) { | ||
105 | var previousVersions = new HashSet<>(versions); | ||
106 | for (var version : previousVersions) { | ||
107 | |||
108 | var model = store.createModelForState(version); | ||
109 | model.getInterpretation(friend).put(Tuple.of(i, j), true); | ||
110 | |||
111 | saveAsNewVersion(versions, codes, storeAdapter, result, model); | ||
112 | |||
113 | logProgress(steps++); | ||
114 | if (steps > MAX) { | ||
115 | result.versions = versions.size(); | ||
116 | return result; | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | |||
122 | result.versions = versions.size(); | ||
123 | return result; | ||
124 | } | ||
125 | |||
126 | private static void saveAsNewVersion(Set<Version> versions, MutableIntObjectMap<List<Version>> codes, | ||
127 | StateCoderStoreAdapter storeAdapter, ExperimentalSetupResult result, | ||
128 | Model model) { | ||
129 | Version version1 = model.commit(); | ||
130 | |||
131 | var stateCode = model.getAdapter(StateCoderAdapter.class).calculateStateCode(); | ||
132 | int code = stateCode.modelCode(); | ||
133 | if (codes.containsKey(code)) { | ||
134 | Version similar = codes.get(code).get(0); | ||
135 | |||
136 | var outcome = storeAdapter.checkEquivalence(version1, similar); | ||
137 | if (outcome == StateEquivalenceChecker.EquivalenceResult.DIFFERENT) { | ||
138 | result.different++; | ||
139 | } else if (outcome == StateEquivalenceChecker.EquivalenceResult.UNKNOWN) { | ||
140 | result.unknown++; | ||
141 | } else { | ||
142 | result.isomorphic++; | ||
143 | } | ||
144 | } else { | ||
145 | versions.add(version1); | ||
146 | |||
147 | List<Version> newList = new ArrayList<>(); | ||
148 | newList.add(version1); | ||
149 | codes.put(code, newList); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | private static void logProgress(int steps) { | ||
154 | if (steps % 10000 == 0) { | ||
155 | System.out.println("Steps: " + steps + " / " + MAX); | ||
156 | } | ||
157 | } | ||
158 | |||
159 | static final double limit = 0.01; | ||
160 | |||
161 | @Test | ||
162 | void test0() { | ||
163 | assertEquals(1, generate(0, true).versions); | ||
164 | } | ||
165 | |||
166 | @ParameterizedTest | ||
167 | @ValueSource(ints = {1, 2, 3, 4}) | ||
168 | void testForSmallUntypedModels(int size) { | ||
169 | var res = generate(size, false); | ||
170 | System.out.println(res); | ||
171 | assertTrue(res.failureRatio() < limit); | ||
172 | } | ||
173 | |||
174 | @ParameterizedTest | ||
175 | @ValueSource(ints = {1, 2, 3}) | ||
176 | void testForSmallTypedModels(int size) { | ||
177 | var res = generate(size, true); | ||
178 | System.out.println(res); | ||
179 | assertTrue(res.failureRatio() < limit); | ||
180 | } | ||
181 | |||
182 | @Test | ||
183 | @Tag("fuzz") | ||
184 | @Tag("slow") | ||
185 | void testForLargeTypedModels() { | ||
186 | var res = generate(10, true); | ||
187 | System.out.println(res); | ||
188 | assertTrue(res.failureRatio() < limit); | ||
189 | } | ||
190 | |||
191 | @Test | ||
192 | @Tag("fuzz") | ||
193 | @Tag("slow") | ||
194 | void testForLargeUntypedModels() { | ||
195 | var res = generate(10, false); | ||
196 | System.out.println(res); | ||
197 | assertTrue(res.failureRatio() < limit); | ||
198 | } | ||
199 | } | ||
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java new file mode 100644 index 00000000..0b738005 --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderBuildTest.java | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.statecoding; | ||
7 | |||
8 | import org.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.model.Interpretation; | ||
10 | import tools.refinery.store.model.ModelStore; | ||
11 | import tools.refinery.store.representation.Symbol; | ||
12 | import tools.refinery.store.tuple.Tuple; | ||
13 | |||
14 | import static org.junit.jupiter.api.Assertions.*; | ||
15 | |||
16 | class StateCoderBuildTest { | ||
17 | Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false); | ||
18 | Symbol<Integer> age = new Symbol<>("age", 1, Integer.class, null); | ||
19 | Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
20 | |||
21 | @Test | ||
22 | void simpleStateCoderBuildTest() { | ||
23 | var store = ModelStore.builder() | ||
24 | .symbols(person, age, friend) | ||
25 | .with(StateCoderAdapter.builder()) | ||
26 | .build(); | ||
27 | |||
28 | var model = store.createEmptyModel(); | ||
29 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
30 | assertNotNull(stateCoder); | ||
31 | |||
32 | var personI = model.getInterpretation(person); | ||
33 | var friendI = model.getInterpretation(friend); | ||
34 | var ageI = model.getInterpretation(age); | ||
35 | |||
36 | fill(personI, friendI, ageI); | ||
37 | |||
38 | stateCoder.calculateStateCode(); | ||
39 | } | ||
40 | |||
41 | @Test | ||
42 | void excludeTest() { | ||
43 | var store = ModelStore.builder() | ||
44 | .symbols(person, age, friend) | ||
45 | .with(StateCoderAdapter.builder() | ||
46 | .exclude(person) | ||
47 | .exclude(age)) | ||
48 | .build(); | ||
49 | |||
50 | var model = store.createEmptyModel(); | ||
51 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
52 | assertNotNull(stateCoder); | ||
53 | |||
54 | var personI = model.getInterpretation(person); | ||
55 | var friendI = model.getInterpretation(friend); | ||
56 | var ageI = model.getInterpretation(age); | ||
57 | fill(personI, friendI, ageI); | ||
58 | |||
59 | int code = stateCoder.calculateStateCode().modelCode(); | ||
60 | |||
61 | ageI.put(Tuple.of(1), 3); | ||
62 | assertEquals(code, stateCoder.calculateStateCode().modelCode()); | ||
63 | |||
64 | ageI.put(Tuple.of(1), null); | ||
65 | assertEquals(code, stateCoder.calculateStateCode().modelCode()); | ||
66 | |||
67 | personI.put(Tuple.of(2), false); | ||
68 | assertEquals(code, stateCoder.calculateStateCode().modelCode()); | ||
69 | } | ||
70 | |||
71 | @Test | ||
72 | void notIndividualTest() { | ||
73 | var store = ModelStore.builder() | ||
74 | .symbols(friend) | ||
75 | .with(StateCoderAdapter.builder()) | ||
76 | .build(); | ||
77 | |||
78 | var model = store.createEmptyModel(); | ||
79 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
80 | |||
81 | var friendI = model.getInterpretation(friend); | ||
82 | |||
83 | friendI.put(Tuple.of(1, 2), true); | ||
84 | int code1 = stateCoder.calculateModelCode(); | ||
85 | |||
86 | friendI.put(Tuple.of(1, 2), false); | ||
87 | friendI.put(Tuple.of(2, 1), true); | ||
88 | int code2 = stateCoder.calculateModelCode(); | ||
89 | |||
90 | assertEquals(code1, code2); | ||
91 | } | ||
92 | |||
93 | @Test | ||
94 | void individualTest() { | ||
95 | var store = ModelStore.builder() | ||
96 | .symbols(friend) | ||
97 | .with(StateCoderAdapter.builder() | ||
98 | .individual(Tuple.of(1))) | ||
99 | .build(); | ||
100 | |||
101 | var model = store.createEmptyModel(); | ||
102 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
103 | |||
104 | var friendI = model.getInterpretation(friend); | ||
105 | |||
106 | friendI.put(Tuple.of(1, 2), true); | ||
107 | int code1 = stateCoder.calculateModelCode(); | ||
108 | |||
109 | friendI.put(Tuple.of(1, 2), false); | ||
110 | friendI.put(Tuple.of(2, 1), true); | ||
111 | int code2 = stateCoder.calculateModelCode(); | ||
112 | |||
113 | assertNotEquals(code1, code2); | ||
114 | } | ||
115 | |||
116 | @Test | ||
117 | void customStateCoderTest() { | ||
118 | final boolean[] called = new boolean[]{false}; | ||
119 | StateCodeCalculator mock = () -> { | ||
120 | called[0] = true; | ||
121 | return null; | ||
122 | }; | ||
123 | |||
124 | var store = ModelStore.builder() | ||
125 | .symbols(friend) | ||
126 | .with(StateCoderAdapter.builder() | ||
127 | .stateCodeCalculatorFactory((interpretations, individuals) -> mock)) | ||
128 | .build(); | ||
129 | |||
130 | var model = store.createEmptyModel(); | ||
131 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
132 | |||
133 | stateCoder.calculateStateCode(); | ||
134 | |||
135 | assertTrue(called[0]); | ||
136 | } | ||
137 | |||
138 | @Test | ||
139 | void customEquivalenceCheckerTest() { | ||
140 | final boolean[] called = new boolean[]{false}; | ||
141 | StateEquivalenceChecker mock = (p1, p2, p3, p4, p5) -> { | ||
142 | called[0] = true; | ||
143 | return StateEquivalenceChecker.EquivalenceResult.UNKNOWN; | ||
144 | }; | ||
145 | |||
146 | var store = ModelStore.builder() | ||
147 | .symbols(friend) | ||
148 | .with(StateCoderAdapter.builder() | ||
149 | .stateEquivalenceChecker(mock)) | ||
150 | .build(); | ||
151 | |||
152 | var model = store.createEmptyModel(); | ||
153 | var v1 = model.commit(); | ||
154 | var v2 = model.commit(); | ||
155 | |||
156 | store.getAdapter(StateCoderStoreAdapter.class).checkEquivalence(v1, v2); | ||
157 | |||
158 | assertTrue(called[0]); | ||
159 | } | ||
160 | |||
161 | |||
162 | private static void fill(Interpretation<Boolean> personI, Interpretation<Boolean> friendI, Interpretation<Integer> ageI) { | ||
163 | personI.put(Tuple.of(1), true); | ||
164 | personI.put(Tuple.of(2), true); | ||
165 | |||
166 | ageI.put(Tuple.of(1), 5); | ||
167 | ageI.put(Tuple.of(2), 4); | ||
168 | |||
169 | friendI.put(Tuple.of(1, 2), true); | ||
170 | } | ||
171 | } | ||
diff --git a/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderUnitTest.java b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderUnitTest.java new file mode 100644 index 00000000..d94df841 --- /dev/null +++ b/subprojects/store/src/test/java/tools/refinery/store/statecoding/StateCoderUnitTest.java | |||
@@ -0,0 +1,195 @@ | |||
1 | /* | ||
2 | * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/> | ||
3 | * | ||
4 | * SPDX-License-Identifier: EPL-2.0 | ||
5 | */ | ||
6 | package tools.refinery.store.statecoding; | ||
7 | |||
8 | import org.junit.jupiter.api.Test; | ||
9 | import tools.refinery.store.model.Model; | ||
10 | import tools.refinery.store.model.ModelStore; | ||
11 | import tools.refinery.store.representation.Symbol; | ||
12 | import tools.refinery.store.tuple.Tuple; | ||
13 | |||
14 | import java.util.Objects; | ||
15 | |||
16 | import static org.junit.jupiter.api.Assertions.*; | ||
17 | |||
18 | class StateCoderUnitTest { | ||
19 | Symbol<Boolean> person = new Symbol<>("Person", 1, Boolean.class, false); | ||
20 | Symbol<Integer> age = new Symbol<>("age", 1, Integer.class, null); | ||
21 | Symbol<Boolean> friend = new Symbol<>("friend", 2, Boolean.class, false); | ||
22 | Symbol<Boolean> parents = new Symbol<>("parents", 3, Boolean.class, false); | ||
23 | Symbol<Integer> population = new Symbol<>("population", 0, Integer.class, 0); | ||
24 | |||
25 | private Model createEmptyModel() { | ||
26 | var store = ModelStore.builder() | ||
27 | .symbols(person, age, friend, parents, population) | ||
28 | .with(StateCoderAdapter.builder()) | ||
29 | .build(); | ||
30 | |||
31 | return store.createEmptyModel(); | ||
32 | } | ||
33 | |||
34 | @Test | ||
35 | void emptyModelCode0() { | ||
36 | Model model = createEmptyModel(); | ||
37 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
38 | |||
39 | assertEquals(0, stateCoder.calculateModelCode()); | ||
40 | |||
41 | var personI = model.getInterpretation(person); | ||
42 | var friendI = model.getInterpretation(friend); | ||
43 | |||
44 | personI.put(Tuple.of(1), true); | ||
45 | personI.put(Tuple.of(2), true); | ||
46 | friendI.put(Tuple.of(1, 2), true); | ||
47 | |||
48 | assertNotEquals(0, stateCoder.calculateModelCode()); | ||
49 | } | ||
50 | |||
51 | @Test | ||
52 | void emptyObjectCode0() { | ||
53 | Model model = createEmptyModel(); | ||
54 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
55 | |||
56 | var personI = model.getInterpretation(person); | ||
57 | var friendI = model.getInterpretation(friend); | ||
58 | |||
59 | assertEquals(0, stateCoder.calculateObjectCode().get(1)); | ||
60 | assertEquals(0, stateCoder.calculateObjectCode().get(17)); | ||
61 | |||
62 | personI.put(Tuple.of(1), true); | ||
63 | personI.put(Tuple.of(2), true); | ||
64 | friendI.put(Tuple.of(1, 2), true); | ||
65 | |||
66 | assertNotEquals(0, stateCoder.calculateObjectCode().get(1)); | ||
67 | assertEquals(0, stateCoder.calculateObjectCode().get(17)); | ||
68 | } | ||
69 | |||
70 | @Test | ||
71 | void nullRelationTest() { | ||
72 | Model model = createEmptyModel(); | ||
73 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
74 | |||
75 | var populationI = model.getInterpretation(population); | ||
76 | |||
77 | final int hashOf0 = Objects.hashCode(0); | ||
78 | |||
79 | assertEquals(hashOf0, stateCoder.calculateModelCode()); | ||
80 | |||
81 | populationI.put(Tuple.of(), 1); | ||
82 | int code1 = stateCoder.calculateModelCode(); | ||
83 | |||
84 | assertNotEquals(hashOf0, stateCoder.calculateModelCode()); | ||
85 | |||
86 | populationI.put(Tuple.of(), 2); | ||
87 | int code2 = stateCoder.calculateModelCode(); | ||
88 | |||
89 | assertNotEquals(code1, code2); | ||
90 | |||
91 | populationI.put(Tuple.of(), 1); | ||
92 | assertEquals(code1, stateCoder.calculateModelCode()); | ||
93 | } | ||
94 | |||
95 | @Test | ||
96 | void unaryBooleanTest() { | ||
97 | Model model = createEmptyModel(); | ||
98 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
99 | |||
100 | var personI = model.getInterpretation(person); | ||
101 | |||
102 | assertEquals(0, stateCoder.calculateModelCode()); | ||
103 | |||
104 | personI.put(Tuple.of(1), true); | ||
105 | int code1 = stateCoder.calculateModelCode(); | ||
106 | |||
107 | assertNotEquals(0, stateCoder.calculateModelCode()); | ||
108 | |||
109 | personI.put(Tuple.of(2), true); | ||
110 | int code2 = stateCoder.calculateModelCode(); | ||
111 | |||
112 | assertNotEquals(code1, code2); | ||
113 | |||
114 | personI.put(Tuple.of(1), false); | ||
115 | assertEquals(code1, stateCoder.calculateModelCode()); | ||
116 | } | ||
117 | |||
118 | @Test | ||
119 | void unaryIntTest() { | ||
120 | Model model = createEmptyModel(); | ||
121 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
122 | |||
123 | var ageI = model.getInterpretation(age); | ||
124 | |||
125 | assertEquals(0, stateCoder.calculateModelCode()); | ||
126 | |||
127 | ageI.put(Tuple.of(1), 4); | ||
128 | int code0 = stateCoder.calculateModelCode(); | ||
129 | |||
130 | assertNotEquals(0, code0); | ||
131 | |||
132 | ageI.put(Tuple.of(1), 5); | ||
133 | int code1 = stateCoder.calculateModelCode(); | ||
134 | |||
135 | assertNotEquals(code0, code1); | ||
136 | |||
137 | ageI.put(Tuple.of(2), 5); | ||
138 | int code2 = stateCoder.calculateModelCode(); | ||
139 | |||
140 | assertNotEquals(code1, code2); | ||
141 | |||
142 | ageI.put(Tuple.of(1), null); | ||
143 | assertEquals(code1, stateCoder.calculateModelCode()); | ||
144 | } | ||
145 | |||
146 | @Test | ||
147 | void binaryTest() { | ||
148 | Model model = createEmptyModel(); | ||
149 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
150 | |||
151 | var friendI = model.getInterpretation(friend); | ||
152 | |||
153 | assertEquals(0, stateCoder.calculateModelCode()); | ||
154 | |||
155 | friendI.put(Tuple.of(1, 2), true); | ||
156 | int code1 = stateCoder.calculateModelCode(); | ||
157 | |||
158 | assertNotEquals(0, code1); | ||
159 | |||
160 | friendI.put(Tuple.of(2, 1), true); | ||
161 | int code2 = stateCoder.calculateModelCode(); | ||
162 | |||
163 | assertNotEquals(code1, code2); | ||
164 | |||
165 | friendI.put(Tuple.of(1, 2), false); | ||
166 | int code3 = stateCoder.calculateModelCode(); | ||
167 | |||
168 | assertEquals(code1, code3); | ||
169 | } | ||
170 | |||
171 | @Test | ||
172 | void NaryTest() { | ||
173 | Model model = createEmptyModel(); | ||
174 | var stateCoder = model.getAdapter(StateCoderAdapter.class); | ||
175 | |||
176 | var parentsI = model.getInterpretation(parents); | ||
177 | |||
178 | assertEquals(0, stateCoder.calculateModelCode()); | ||
179 | |||
180 | parentsI.put(Tuple.of(3, 1, 2), true); | ||
181 | int code1 = stateCoder.calculateModelCode(); | ||
182 | |||
183 | assertNotEquals(0, code1); | ||
184 | |||
185 | parentsI.put(Tuple.of(4, 1, 2), true); | ||
186 | int code2 = stateCoder.calculateModelCode(); | ||
187 | |||
188 | assertNotEquals(code1, code2); | ||
189 | |||
190 | parentsI.put(Tuple.of(3, 1, 2), false); | ||
191 | int code3 = stateCoder.calculateModelCode(); | ||
192 | |||
193 | assertEquals(code1, code3); | ||
194 | } | ||
195 | } | ||