aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/store/src/test
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2021-12-12 17:48:47 +0100
committerLibravatar Kristóf Marussy <kristof@marussy.com>2021-12-12 17:48:47 +0100
commitfc7e9312d00e60171ed77c477ed91231d3dbfff9 (patch)
treecc185dd088b5fa6e9357aab3c9062a70626d1953 /subprojects/store/src/test
parentbuild: refactor java-application conventions (diff)
downloadrefinery-fc7e9312d00e60171ed77c477ed91231d3dbfff9.tar.gz
refinery-fc7e9312d00e60171ed77c477ed91231d3dbfff9.tar.zst
refinery-fc7e9312d00e60171ed77c477ed91231d3dbfff9.zip
build: move modules into subproject directory
Diffstat (limited to 'subprojects/store/src/test')
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java22
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java96
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java143
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java117
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java97
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java101
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java92
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java89
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java109
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java113
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java64
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java33
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java214
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/model/hashTests/HashEfficiencyTest.java161
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java148
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTest.java445
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTransactionTest.java58
-rw-r--r--subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java78
18 files changed, 2180 insertions, 0 deletions
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
new file mode 100644
index 00000000..f0d5d927
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/MapUnitTests.java
@@ -0,0 +1,22 @@
1package tools.refinery.store.map.tests;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4
5import org.junit.jupiter.api.Test;
6
7import tools.refinery.store.map.VersionedMapStore;
8import tools.refinery.store.map.VersionedMapStoreImpl;
9import tools.refinery.store.model.Tuple;
10import tools.refinery.store.model.TupleHashProvider;
11
12class MapUnitTests {
13 @Test
14 void defaultTest() {
15 VersionedMapStore<Tuple, Boolean> store = new VersionedMapStoreImpl<Tuple, Boolean>(TupleHashProvider.singleton(), false);
16 var map = store.createMap();
17 var out1 = map.put(Tuple.of(0), true);
18 assertEquals(false, out1);
19 var out2 = map.put(Tuple.of(1), true);
20 assertEquals(false, out2);
21 }
22}
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
new file mode 100644
index 00000000..1f9d022f
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/CommitFuzzTest.java
@@ -0,0 +1,96 @@
1package tools.refinery.store.map.tests.fuzz;
2
3import static org.junit.jupiter.api.Assertions.fail;
4
5import java.util.Random;
6import java.util.stream.Stream;
7
8import org.junit.jupiter.api.Tag;
9import org.junit.jupiter.api.Timeout;
10import org.junit.jupiter.params.ParameterizedTest;
11import org.junit.jupiter.params.provider.Arguments;
12import org.junit.jupiter.params.provider.MethodSource;
13
14import tools.refinery.store.map.ContinousHashProvider;
15import tools.refinery.store.map.VersionedMapStore;
16import tools.refinery.store.map.VersionedMapStoreImpl;
17import tools.refinery.store.map.internal.VersionedMapImpl;
18import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
19import tools.refinery.store.map.tests.utils.MapTestEnvironment;
20
21class CommitFuzzTest {
22 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency,
23 boolean evilHash) {
24 String[] values = MapTestEnvironment.prepareValues(maxValue);
25 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash);
26
27 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]);
28 VersionedMapImpl<Integer, String> sut = (VersionedMapImpl<Integer, String>) store.createMap();
29 MapTestEnvironment<Integer, String> e = new MapTestEnvironment<Integer, String>(sut);
30
31 Random r = new Random(seed);
32
33 iterativeRandomPutsAndCommits(scenario, steps, maxKey, values, e, r, commitFrequency);
34 }
35
36 private void iterativeRandomPutsAndCommits(String scenario, int steps, int maxKey, String[] values,
37 MapTestEnvironment<Integer, String> e, Random r, int commitFrequency) {
38 int stopAt = -1;
39 for (int i = 0; i < steps; i++) {
40 int index = i + 1;
41 int nextKey = r.nextInt(maxKey);
42 String nextValue = values[r.nextInt(values.length)];
43 if (index == stopAt) {
44 System.out.println("issue!");
45 System.out.println("State before:");
46 e.printComparison();
47 e.sut.prettyPrint();
48 System.out.println("Next: put(" + nextKey + "," + nextValue + ")");
49 }
50 try {
51 e.put(nextKey, nextValue);
52 if (index == stopAt) {
53 e.sut.prettyPrint();
54 }
55 e.checkEquivalence(scenario + ":" + index);
56 } catch (Exception exception) {
57 exception.printStackTrace();
58 fail(scenario + ":" + index + ": exception happened: " + exception);
59 }
60 MapTestEnvironment.printStatus(scenario, index, steps, null);
61 if (index % commitFrequency == 0) {
62 e.sut.commit();
63 }
64 }
65 }
66
67 @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
68 @MethodSource
69 @Timeout(value = 10)
70 @Tag("fuzz")
71 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
72 boolean evilHash) {
73 runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
74 commitFrequency, evilHash);
75 }
76
77 static Stream<Arguments> parametrizedFastFuzz() {
78 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 },
79 new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 },
80 new Object[] { false, true });
81 }
82
83 @ParameterizedTest(name = "Commit {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
84 @MethodSource
85 @Tag("fuzz")
86 @Tag("slow")
87 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
88 boolean evilHash) {
89 runFuzzTest("CommitS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
90 commitFrequency, evilHash);
91 }
92
93 static Stream<Arguments> parametrizedSlowFuzz() {
94 return FuzzTestUtils.changeStepCount(parametrizedFastFuzz(), 1);
95 }
96}
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
new file mode 100644
index 00000000..263cb2cd
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/ContentEqualsFuzzTest.java
@@ -0,0 +1,143 @@
1package tools.refinery.store.map.tests.fuzz;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4import static org.junit.jupiter.api.Assertions.fail;
5
6import java.util.AbstractMap.SimpleEntry;
7import java.util.Collections;
8import java.util.LinkedList;
9import java.util.List;
10import java.util.Random;
11import java.util.stream.Stream;
12
13import org.junit.jupiter.api.Tag;
14import org.junit.jupiter.api.Timeout;
15import org.junit.jupiter.params.ParameterizedTest;
16import org.junit.jupiter.params.provider.Arguments;
17import org.junit.jupiter.params.provider.MethodSource;
18
19import tools.refinery.store.map.ContinousHashProvider;
20import tools.refinery.store.map.Cursor;
21import tools.refinery.store.map.VersionedMap;
22import tools.refinery.store.map.VersionedMapStore;
23import tools.refinery.store.map.VersionedMapStoreImpl;
24import tools.refinery.store.map.internal.VersionedMapImpl;
25import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
26import tools.refinery.store.map.tests.utils.MapTestEnvironment;
27
28class ContentEqualsFuzzTest {
29 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency,
30 boolean evilHash) {
31 String[] values = MapTestEnvironment.prepareValues(maxValue);
32 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash);
33
34 Random r = new Random(seed);
35
36 iterativeRandomPutsAndCommitsThenCompare(scenario, chp, steps, maxKey, values, r, commitFrequency);
37 }
38
39 private void iterativeRandomPutsAndCommitsThenCompare(String scenario, ContinousHashProvider<Integer> chp, int steps, int maxKey, String[] values, Random r, int commitFrequency) {
40
41 VersionedMapStore<Integer, String> store1 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]);
42 VersionedMap<Integer, String> sut1 = store1.createMap();
43
44 // Fill one map
45 for (int i = 0; i < steps; i++) {
46 int index1 = i + 1;
47 int nextKey = r.nextInt(maxKey);
48 String nextValue = values[r.nextInt(values.length)];
49 try {
50 sut1.put(nextKey, nextValue);
51 } catch (Exception exception) {
52 exception.printStackTrace();
53 fail(scenario + ":" + index1 + ": exception happened: " + exception);
54 }
55 MapTestEnvironment.printStatus(scenario, index1, steps, "Fill");
56 if (index1 % commitFrequency == 0) {
57 sut1.commit();
58 }
59 }
60
61 // Get the content of the first map
62 List<SimpleEntry<Integer, String>> content = new LinkedList<>();
63 Cursor<Integer, String> cursor = sut1.getAll();
64 while (cursor.move()) {
65 content.add(new SimpleEntry<>(cursor.getKey(), cursor.getValue()));
66 }
67
68 // Randomize the order of the content
69 Collections.shuffle(content, r);
70
71 VersionedMapStore<Integer, String> store2 = new VersionedMapStoreImpl<Integer, String>(chp, values[0]);
72 VersionedMap<Integer, String> sut2 = store2.createMap();
73 int index2 = 1;
74 for (SimpleEntry<Integer, String> entry : content) {
75 sut2.put(entry.getKey(), entry.getValue());
76 if(index2++%commitFrequency == 0)
77 sut2.commit();
78 }
79
80 // Check the integrity of the maps
81 ((VersionedMapImpl<Integer,String>) sut1).checkIntegrity();
82 ((VersionedMapImpl<Integer,String>) sut2).checkIntegrity();
83
84// // Compare the two maps
85 // By size
86 assertEquals(sut1.getSize(), content.size());
87 assertEquals(sut2.getSize(), content.size());
88
89
90
91 // By cursors
92 Cursor<Integer, String> cursor1 = sut1.getAll();
93 Cursor<Integer, String> cursor2 = sut2.getAll();
94 int index3 = 1;
95 boolean canMove = true;
96 do{
97 boolean canMove1 = cursor1.move();
98 boolean canMove2 = cursor2.move();
99 assertEquals(canMove1, canMove2, scenario + ":" + index3 +" Cursors stopped at different times!");
100 assertEquals(cursor1.getKey(), cursor2.getKey(), scenario + ":" + index3 +" Cursors have different keys!");
101 assertEquals(cursor1.getValue(), cursor2.getValue(), scenario + ":" + index3 +" Cursors have different values!");
102
103 canMove = canMove1;
104 MapTestEnvironment.printStatus(scenario, index3++, content.size(), "Compare");
105 } while (canMove);
106
107 // By hashcode
108 assertEquals(sut1.hashCode(), sut2.hashCode(), "Hash codes are not equal!");
109
110 // By equals
111 assertEquals(sut1, sut2, "Maps are not equals");
112 }
113
114 @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
115 @MethodSource
116 @Timeout(value = 10)
117 @Tag("fuzz")
118 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
119 boolean evilHash) {
120 runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
121 commitFrequency, evilHash);
122 }
123
124 static Stream<Arguments> parametrizedFastFuzz() {
125 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 },
126 new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 },
127 new Object[] { false, true });
128 }
129
130 @ParameterizedTest(name = "Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
131 @MethodSource
132 @Tag("fuzz")
133 @Tag("slow")
134 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
135 boolean evilHash) {
136 runFuzzTest("CompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
137 commitFrequency, evilHash);
138 }
139
140 static Stream<Arguments> parametrizedSlowFuzz() {
141 return FuzzTestUtils.changeStepCount(parametrizedFastFuzz(), 1);
142 }
143}
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
new file mode 100644
index 00000000..e6334224
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/DiffCursorFuzzTest.java
@@ -0,0 +1,117 @@
1package tools.refinery.store.map.tests.fuzz;
2
3import static org.junit.jupiter.api.Assertions.fail;
4
5import java.util.Random;
6import java.util.stream.Stream;
7
8import org.junit.jupiter.api.Tag;
9import org.junit.jupiter.api.Timeout;
10import org.junit.jupiter.params.ParameterizedTest;
11import org.junit.jupiter.params.provider.Arguments;
12import org.junit.jupiter.params.provider.MethodSource;
13
14import tools.refinery.store.map.ContinousHashProvider;
15import tools.refinery.store.map.DiffCursor;
16import tools.refinery.store.map.VersionedMapStore;
17import tools.refinery.store.map.VersionedMapStoreImpl;
18import tools.refinery.store.map.internal.VersionedMapImpl;
19import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
20import tools.refinery.store.map.tests.utils.MapTestEnvironment;
21
22class DiffCursorFuzzTest {
23 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency,
24 boolean evilHash) {
25 String[] values = MapTestEnvironment.prepareValues(maxValue);
26 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash);
27
28 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]);
29 iterativeRandomPutsAndCommitsThenDiffcursor(scenario, store, steps, maxKey, values, seed, commitFrequency);
30 }
31
32 private void iterativeRandomPutsAndCommitsThenDiffcursor(String scenario, VersionedMapStore<Integer, String> store,
33 int steps, int maxKey, String[] values, int seed, int commitFrequency) {
34 // 1. build a map with versions
35 Random r = new Random(seed);
36 VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap();
37 int largestCommit = -1;
38
39 for (int i = 0; i < steps; i++) {
40 int index = i + 1;
41 int nextKey = r.nextInt(maxKey);
42 String nextValue = values[r.nextInt(values.length)];
43 try {
44 versioned.put(nextKey, nextValue);
45 } catch (Exception exception) {
46 exception.printStackTrace();
47 fail(scenario + ":" + index + ": exception happened: " + exception);
48 }
49 if (index % commitFrequency == 0) {
50 long version = versioned.commit();
51 largestCommit = (int) version;
52 }
53 if (index % 10000 == 0)
54 System.out.println(scenario + ":" + index + "/" + steps + " building finished");
55 }
56 // 2. create a non-versioned map,
57 VersionedMapImpl<Integer, String> moving = (VersionedMapImpl<Integer, String>) store.createMap();
58 Random r2 = new Random(seed + 1);
59
60 final int diffTravelFrequency = commitFrequency * 2;
61 for (int i = 0; i < steps; i++) {
62 int index = i + 1;
63 if (index % diffTravelFrequency == 0) {
64 // difftravel
65 long travelToVersion = r2.nextInt(largestCommit + 1);
66 DiffCursor<Integer, String> diffCursor = moving.getDiffCursor(travelToVersion);
67 moving.putAll(diffCursor);
68
69 } else {
70 // random puts
71 int nextKey = r2.nextInt(maxKey);
72 String nextValue = values[r2.nextInt(values.length)];
73 try {
74 moving.put(nextKey, nextValue);
75 } catch (Exception exception) {
76 exception.printStackTrace();
77 fail(scenario + ":" + index + ": exception happened: " + exception);
78 }
79 if (index % commitFrequency == 0) {
80 versioned.commit();
81 }
82 if (index % 10000 == 0)
83 System.out.println(scenario + ":" + index + "/" + steps + " building finished");
84 }
85 }
86
87 }
88
89 @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
90 @MethodSource
91 @Timeout(value = 10)
92 @Tag("fuzz")
93 void parametrizedFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
94 boolean evilHash) {
95 runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps,
96 noKeys, noValues, commitFrequency, evilHash);
97 }
98
99 static Stream<Arguments> parametrizedFuzz() {
100 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 },
101 new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 },
102 new Object[] { false, true });
103 }
104 @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
105 @MethodSource
106 @Tag("fuzz")
107 @Tag("slow")
108 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
109 boolean evilHash) {
110 runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
111 commitFrequency, evilHash);
112 }
113
114 static Stream<Arguments> parametrizedSlowFuzz() {
115 return FuzzTestUtils.changeStepCount(parametrizedFuzz(), 1);
116 }
117}
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
new file mode 100644
index 00000000..1ab431a8
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadFuzzTest.java
@@ -0,0 +1,97 @@
1package tools.refinery.store.map.tests.fuzz;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4import static org.junit.jupiter.api.Assertions.fail;
5
6import java.util.Collections;
7import java.util.LinkedList;
8import java.util.List;
9import java.util.stream.Stream;
10
11import org.junit.jupiter.api.Tag;
12import org.junit.jupiter.api.Timeout;
13import org.junit.jupiter.params.ParameterizedTest;
14import org.junit.jupiter.params.provider.Arguments;
15import org.junit.jupiter.params.provider.MethodSource;
16
17import tools.refinery.store.map.ContinousHashProvider;
18import tools.refinery.store.map.VersionedMapStore;
19import tools.refinery.store.map.VersionedMapStoreImpl;
20import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
21import tools.refinery.store.map.tests.utils.MapTestEnvironment;
22
23class MultiThreadFuzzTest {
24 public static final int noThreads = 32;
25
26 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency,
27 boolean evilHash) {
28 String[] values = MapTestEnvironment.prepareValues(maxValue);
29 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash);
30
31 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]);
32
33 // initialize runnables
34 MultiThreadTestRunnable[] runnables = new MultiThreadTestRunnable[noThreads];
35 for(int i = 0; i<noThreads; i++) {
36 runnables[i] = new MultiThreadTestRunnable(scenario+"-T"+(i+1), store, steps, maxKey, values, seed, commitFrequency);
37 }
38
39 // initialize threads
40 Thread[] threads = new Thread[noThreads];
41 for(int i = 0; i<noThreads; i++) {
42 threads[i] = new Thread(runnables[i]);
43 }
44
45 // start threads;
46 for(int i = 0; i<noThreads; i++) {
47 threads[i].start();
48 }
49
50 // wait all the threads;
51 for(int i = 0; i<noThreads; i++) {
52 try {
53 threads[i].join();
54 } catch (InterruptedException e) {
55 fail("Thread "+i+" interrupted.");
56 }
57 }
58
59 // collect errors
60 List<Throwable> errors = new LinkedList<>();
61 for(int i = 0; i<noThreads; i++) {
62 errors.addAll(runnables[i].getErrors());
63 }
64
65 assertEquals(Collections.EMPTY_LIST, errors);
66 }
67
68 @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
69 @MethodSource
70 @Timeout(value = 10)
71 @Tag("fuzz")
72 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
73 boolean evilHash) {
74 runFuzzTest("MultithreadS" + steps + "K" + noKeys + "V" + noValues + "CF" + commitFrequency + "s" + seed, seed, steps, noKeys, noValues,
75 commitFrequency, evilHash);
76 }
77
78 static Stream<Arguments> parametrizedFastFuzz() {
79 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 },
80 new Object[] { 2, 3 }, new Object[] { 10, 100 }, new Object[] { 1, 2, 3 },
81 new Object[] { false, true });
82 }
83
84 @ParameterizedTest(name = "Multithread {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
85 @MethodSource
86 @Tag("fuzz")
87 @Tag("slow")
88 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
89 boolean evilHash) {
90 runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
91 commitFrequency, evilHash);
92 }
93
94 static Stream<Arguments> parametrizedSlowFuzz() {
95 return FuzzTestUtils.changeStepCount(RestoreFuzzTest.parametrizedFastFuzz(), 1);
96 }
97}
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
new file mode 100644
index 00000000..f77f9ee5
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MultiThreadTestRunnable.java
@@ -0,0 +1,101 @@
1package tools.refinery.store.map.tests.fuzz;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.HashMap;
6import java.util.LinkedList;
7import java.util.List;
8import java.util.Map;
9import java.util.Random;
10
11import tools.refinery.store.map.VersionedMapStore;
12import tools.refinery.store.map.internal.VersionedMapImpl;
13import tools.refinery.store.map.tests.utils.MapTestEnvironment;
14
15public class MultiThreadTestRunnable implements Runnable {
16 String scenario;
17 VersionedMapStore<Integer, String> store;
18 int steps;
19 int maxKey;
20 String[] values;
21 int seed;
22 int commitFrequency;
23 List<Throwable> errors = new LinkedList<>();
24
25 public MultiThreadTestRunnable(String scenario, VersionedMapStore<Integer, String> store, int steps,
26 int maxKey, String[] values, int seed, int commitFrequency) {
27 super();
28 this.scenario = scenario;
29 this.store = store;
30 this.steps = steps;
31 this.maxKey = maxKey;
32 this.values = values;
33 this.seed = seed;
34 this.commitFrequency = commitFrequency;
35 }
36
37 private void logAndThrowError(String message) {
38 AssertionError error = new AssertionError(message);
39 errors.add(error);
40 }
41
42 public List<Throwable> getErrors() {
43 return errors;
44 }
45
46 @Override
47 public void run() {
48 // 1. build a map with versions
49 Random r = new Random(seed);
50 VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap();
51 Map<Integer, Long> index2Version = new HashMap<>();
52
53 for (int i = 0; i < steps; i++) {
54 int index = i + 1;
55 int nextKey = r.nextInt(maxKey);
56 String nextValue = values[r.nextInt(values.length)];
57 try {
58 versioned.put(nextKey, nextValue);
59 } catch (Exception exception) {
60 exception.printStackTrace();
61 logAndThrowError(scenario + ":" + index + ": exception happened: " + exception);
62 }
63 if (index % commitFrequency == 0) {
64 long version = versioned.commit();
65 index2Version.put(i, version);
66 }
67 MapTestEnvironment.printStatus(scenario, index, steps, "building");
68 }
69 // 2. create a non-versioned
70 VersionedMapImpl<Integer, String> reference = (VersionedMapImpl<Integer, String>) store.createMap();
71 r = new Random(seed);
72 Random r2 = new Random(seed+1);
73
74 for (int i = 0; i < steps; i++) {
75 int index = i + 1;
76 int nextKey = r.nextInt(maxKey);
77 String nextValue = values[r.nextInt(values.length)];
78 try {
79 reference.put(nextKey, nextValue);
80 } catch (Exception exception) {
81 exception.printStackTrace();
82 logAndThrowError(scenario + ":" + index + ": exception happened: " + exception);
83 }
84 // go back to an existing state and compare to the reference
85 if (index % (commitFrequency) == 0) {
86 versioned.restore(index2Version.get(i));
87 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned,errors);
88
89 // go back to a random state (probably created by another thread)
90 List<Long> states = new ArrayList<>(store.getStates());
91 Collections.shuffle(states, r2);
92 for(Long state : states.subList(0, Math.min(states.size(), 100))) {
93 versioned.restore(state);
94 }
95 versioned.restore(index2Version.get(i));
96 }
97
98 MapTestEnvironment.printStatus(scenario, index, steps, "comparison");
99 }
100 }
101}
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
new file mode 100644
index 00000000..d40c49c4
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableFuzzTest.java
@@ -0,0 +1,92 @@
1package tools.refinery.store.map.tests.fuzz;
2
3import static org.junit.jupiter.api.Assertions.fail;
4
5import java.util.Random;
6import java.util.stream.Stream;
7
8import org.junit.jupiter.api.Tag;
9import org.junit.jupiter.api.Timeout;
10import org.junit.jupiter.params.ParameterizedTest;
11import org.junit.jupiter.params.provider.Arguments;
12import org.junit.jupiter.params.provider.MethodSource;
13
14import tools.refinery.store.map.ContinousHashProvider;
15import tools.refinery.store.map.VersionedMapStore;
16import tools.refinery.store.map.VersionedMapStoreImpl;
17import tools.refinery.store.map.internal.VersionedMapImpl;
18import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
19import tools.refinery.store.map.tests.utils.MapTestEnvironment;
20
21class MutableFuzzTest {
22 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, boolean evilHash) {
23 String[] values = MapTestEnvironment.prepareValues(maxValue);
24 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash);
25
26 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]);
27 VersionedMapImpl<Integer, String> sut = (VersionedMapImpl<Integer, String>) store.createMap();
28 MapTestEnvironment<Integer, String> e = new MapTestEnvironment<Integer, String>(sut);
29
30 Random r = new Random(seed);
31
32 iterativeRandomPuts(scenario, steps, maxKey, values, e, r);
33 }
34
35 private void iterativeRandomPuts(String scenario, int steps, int maxKey, String[] values,
36 MapTestEnvironment<Integer, String> e, Random r) {
37 int stopAt = -1;
38 for (int i = 0; i < steps; i++) {
39 int index = i + 1;
40 int nextKey = r.nextInt(maxKey);
41 String nextValue = values[r.nextInt(values.length)];
42 if (index == stopAt) {
43 System.out.println("issue!");
44 System.out.println("State before:");
45 e.printComparison();
46 e.sut.prettyPrint();
47 System.out.println("Next: put(" + nextKey + "," + nextValue + ")");
48 }
49 try {
50 e.put(nextKey, nextValue);
51 if (index == stopAt) {
52 e.sut.prettyPrint();
53 }
54 e.checkEquivalence(scenario + ":" + index);
55 } catch (Exception exception) {
56 exception.printStackTrace();
57 fail(scenario + ":" + index + ": exception happened: " + exception);
58 }
59 MapTestEnvironment.printStatus(scenario, index, steps, null);
60 }
61 }
62
63 @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} seed={4} evil-hash={5}")
64 @MethodSource
65 @Timeout(value = 10)
66 @Tag("fuzz")
67 void parametrizedFuzz(int test, int steps, int noKeys, int noValues, int seed, boolean evilHash) {
68 runFuzzTest(
69 "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"),
70 seed, steps, noKeys, noValues, evilHash);
71 }
72
73 static Stream<Arguments> parametrizedFuzz() {
74 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT },
75 new Object[] { 3, 32, 32 * 32, 32 * 32 * 32 * 32 }, new Object[] { 2, 3 }, new Object[] { 1, 2, 3 },
76 new Object[] { false, true });
77 }
78
79 @ParameterizedTest(name = "Mutable {index}/{0} Steps={1} Keys={2} Values={3} seed={4} evil-hash={5}")
80 @MethodSource
81 @Tag("fuzz")
82 @Tag("slow")
83 void parametrizedSlowFuzz(int test, int steps, int noKeys, int noValues, int seed, boolean evilHash) {
84 runFuzzTest(
85 "MutableS" + steps + "K" + noKeys + "V" + noValues + "s" + seed + "H" + (evilHash ? "Evil" : "Normal"),
86 seed, steps, noKeys, noValues, evilHash);
87 }
88
89 static Stream<Arguments> parametrizedSlowFuzz() {
90 return FuzzTestUtils.changeStepCount(parametrizedFuzz(), 1);
91 }
92}
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
new file mode 100644
index 00000000..410705a2
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/MutableImmutableCompareFuzzTest.java
@@ -0,0 +1,89 @@
1package tools.refinery.store.map.tests.fuzz;
2
3import static org.junit.jupiter.api.Assertions.fail;
4
5import java.util.Random;
6import java.util.stream.Stream;
7
8import org.junit.jupiter.api.Tag;
9import org.junit.jupiter.api.Timeout;
10import org.junit.jupiter.params.ParameterizedTest;
11import org.junit.jupiter.params.provider.Arguments;
12import org.junit.jupiter.params.provider.MethodSource;
13
14import tools.refinery.store.map.ContinousHashProvider;
15import tools.refinery.store.map.VersionedMapStore;
16import tools.refinery.store.map.VersionedMapStoreImpl;
17import tools.refinery.store.map.internal.VersionedMapImpl;
18import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
19import tools.refinery.store.map.tests.utils.MapTestEnvironment;
20
21class MutableImmutableCompareFuzzTest {
22 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency,
23 boolean evilHash) {
24 String[] values = MapTestEnvironment.prepareValues(maxValue);
25 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash);
26
27 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]);
28 VersionedMapImpl<Integer, String> immutable = (VersionedMapImpl<Integer, String>) store.createMap();
29 VersionedMapImpl<Integer, String> mutable = (VersionedMapImpl<Integer, String>) store.createMap();
30
31 Random r = new Random(seed);
32
33 iterativeRandomPutsAndCommitsAndCompare(scenario, immutable, mutable, steps, maxKey, values, r,
34 commitFrequency);
35 }
36
37 private void iterativeRandomPutsAndCommitsAndCompare(String scenario, VersionedMapImpl<Integer, String> immutable,
38 VersionedMapImpl<Integer, String> mutable, int steps, int maxKey, String[] values, Random r,
39 int commitFrequency) {
40 for (int i = 0; i < steps; i++) {
41 int index = i + 1;
42 int nextKey = r.nextInt(maxKey);
43 String nextValue = values[r.nextInt(values.length)];
44 try {
45 immutable.put(nextKey, nextValue);
46 mutable.put(nextKey, nextValue);
47 } catch (Exception exception) {
48 exception.printStackTrace();
49 fail(scenario + ":" + index + ": exception happened: " + exception);
50 }
51 if (index % commitFrequency == 0) {
52 immutable.commit();
53 }
54 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, immutable, mutable);
55
56 MapTestEnvironment.printStatus(scenario, index, steps, null);
57 }
58 }
59
60 @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
61 @MethodSource
62 @Timeout(value = 10)
63 @Tag("fuzz")
64 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
65 boolean evilHash) {
66 runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps,
67 noKeys, noValues, commitFrequency, evilHash);
68 }
69
70 static Stream<Arguments> parametrizedFastFuzz() {
71 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 },
72 new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 },
73 new Object[] { false, true });
74 }
75
76 @ParameterizedTest(name = "Mutable-Immutable Compare {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
77 @MethodSource
78 @Tag("fuzz")
79 @Tag("slow")
80 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
81 boolean evilHash) {
82 runFuzzTest("MutableImmutableCompareS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps,
83 noKeys, noValues, commitFrequency, evilHash);
84 }
85
86 static Stream<Arguments> parametrizedSlowFuzz() {
87 return FuzzTestUtils.changeStepCount(MutableImmutableCompareFuzzTest.parametrizedFastFuzz(), 1);
88 }
89}
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
new file mode 100644
index 00000000..2e29a03f
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/RestoreFuzzTest.java
@@ -0,0 +1,109 @@
1package tools.refinery.store.map.tests.fuzz;
2
3import static org.junit.jupiter.api.Assertions.fail;
4
5import java.util.HashMap;
6import java.util.Map;
7import java.util.Random;
8import java.util.stream.Stream;
9
10import org.junit.jupiter.api.Tag;
11import org.junit.jupiter.api.Timeout;
12import org.junit.jupiter.params.ParameterizedTest;
13import org.junit.jupiter.params.provider.Arguments;
14import org.junit.jupiter.params.provider.MethodSource;
15
16import tools.refinery.store.map.ContinousHashProvider;
17import tools.refinery.store.map.VersionedMapStore;
18import tools.refinery.store.map.VersionedMapStoreImpl;
19import tools.refinery.store.map.internal.VersionedMapImpl;
20import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
21import tools.refinery.store.map.tests.utils.MapTestEnvironment;
22
23class RestoreFuzzTest {
24 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency,
25 boolean evilHash) {
26 String[] values = MapTestEnvironment.prepareValues(maxValue);
27 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash);
28
29 VersionedMapStore<Integer, String> store = new VersionedMapStoreImpl<Integer, String>(chp, values[0]);
30
31 iterativeRandomPutsAndCommitsThenRestore(scenario, store, steps, maxKey, values, seed, commitFrequency);
32 }
33
34 private void iterativeRandomPutsAndCommitsThenRestore(String scenario, VersionedMapStore<Integer, String> store,
35 int steps, int maxKey, String[] values, int seed, int commitFrequency) {
36 // 1. build a map with versions
37 Random r = new Random(seed);
38 VersionedMapImpl<Integer, String> versioned = (VersionedMapImpl<Integer, String>) store.createMap();
39 Map<Integer, Long> index2Version = new HashMap<>();
40
41 for (int i = 0; i < steps; i++) {
42 int index = i + 1;
43 int nextKey = r.nextInt(maxKey);
44 String nextValue = values[r.nextInt(values.length)];
45 try {
46 versioned.put(nextKey, nextValue);
47 } catch (Exception exception) {
48 exception.printStackTrace();
49 fail(scenario + ":" + index + ": exception happened: " + exception);
50 }
51 if (index % commitFrequency == 0) {
52 long version = versioned.commit();
53 index2Version.put(i, version);
54 }
55 MapTestEnvironment.printStatus(scenario, index, steps, "building");
56 }
57 // 2. create a non-versioned and
58 VersionedMapImpl<Integer, String> reference = (VersionedMapImpl<Integer, String>) store.createMap();
59 r = new Random(seed);
60
61 for (int i = 0; i < steps; i++) {
62 int index = i + 1;
63 int nextKey = r.nextInt(maxKey);
64 String nextValue = values[r.nextInt(values.length)];
65 try {
66 reference.put(nextKey, nextValue);
67 } catch (Exception exception) {
68 exception.printStackTrace();
69 fail(scenario + ":" + index + ": exception happened: " + exception);
70 }
71 if (index % commitFrequency == 0) {
72 versioned.restore(index2Version.get(i));
73 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference, versioned);
74 }
75 MapTestEnvironment.printStatus(scenario, index, steps, "comparison");
76 }
77
78 }
79
80 @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
81 @MethodSource
82 @Timeout(value = 10)
83 @Tag("smoke")
84 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
85 boolean evilHash) {
86 runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
87 commitFrequency, evilHash);
88 }
89
90 static Stream<Arguments> parametrizedFastFuzz() {
91 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 },
92 new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 },
93 new Object[] { false, true });
94 }
95
96 @ParameterizedTest(name = "Restore {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
97 @MethodSource
98 @Tag("smoke")
99 @Tag("slow")
100 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
101 boolean evilHash) {
102 runFuzzTest("RestoreS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
103 commitFrequency, evilHash);
104 }
105
106 static Stream<Arguments> parametrizedSlowFuzz() {
107 return FuzzTestUtils.changeStepCount(RestoreFuzzTest.parametrizedFastFuzz(), 1);
108 }
109}
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
new file mode 100644
index 00000000..914a0f63
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/SharedStoreFuzzTest.java
@@ -0,0 +1,113 @@
1package tools.refinery.store.map.tests.fuzz;
2
3import java.util.HashMap;
4import java.util.LinkedList;
5import java.util.List;
6import java.util.Map;
7import java.util.Random;
8import java.util.stream.Stream;
9
10import org.junit.jupiter.api.Tag;
11import org.junit.jupiter.api.Timeout;
12import org.junit.jupiter.params.ParameterizedTest;
13import org.junit.jupiter.params.provider.Arguments;
14import org.junit.jupiter.params.provider.MethodSource;
15
16import tools.refinery.store.map.ContinousHashProvider;
17import tools.refinery.store.map.VersionedMapStore;
18import tools.refinery.store.map.VersionedMapStoreImpl;
19import tools.refinery.store.map.internal.VersionedMapImpl;
20import tools.refinery.store.map.tests.fuzz.utils.FuzzTestUtils;
21import tools.refinery.store.map.tests.utils.MapTestEnvironment;
22
23class SharedStoreFuzzTest {
24 private void runFuzzTest(String scenario, int seed, int steps, int maxKey, int maxValue, int commitFrequency,
25 boolean evilHash) {
26 String[] values = MapTestEnvironment.prepareValues(maxValue);
27 ContinousHashProvider<Integer> chp = MapTestEnvironment.prepareHashProvider(evilHash);
28
29 List<VersionedMapStore<Integer, String>> stores = VersionedMapStoreImpl.createSharedVersionedMapStores(5, chp, values[0]);
30
31 iterativeRandomPutsAndCommitsThenRestore(scenario, stores, steps, maxKey, values, seed, commitFrequency);
32 }
33
34 private void iterativeRandomPutsAndCommitsThenRestore(String scenario, List<VersionedMapStore<Integer, String>> stores,
35 int steps, int maxKey, String[] values, int seed, int commitFrequency) {
36 // 1. maps with versions
37 Random r = new Random(seed);
38 List<VersionedMapImpl<Integer, String>> versioneds = new LinkedList<>();
39 for(VersionedMapStore<Integer, String> store : stores) {
40 versioneds.add((VersionedMapImpl<Integer, String>) store.createMap());
41 }
42
43 List<Map<Integer, Long>> index2Version = new LinkedList<>();
44 for(int i = 0; i<stores.size(); i++) {
45 index2Version.add(new HashMap<>());
46 }
47
48 for (int i = 0; i < steps; i++) {
49 int stepIndex = i + 1;
50 for (int storeIndex = 0; storeIndex<versioneds.size(); storeIndex++) {
51 int nextKey = r.nextInt(maxKey);
52 String nextValue = values[r.nextInt(values.length)];
53 versioneds.get(storeIndex).put(nextKey, nextValue);
54 if (stepIndex % commitFrequency == 0) {
55 long version = versioneds.get(storeIndex).commit();
56 index2Version.get(storeIndex).put(i, version);
57 }
58 MapTestEnvironment.printStatus(scenario, stepIndex, steps, "building");
59 }
60 }
61 // 2. create a non-versioned and
62 List<VersionedMapImpl<Integer, String>> reference = new LinkedList<>();
63 for(VersionedMapStore<Integer, String> store : stores) {
64 reference.add((VersionedMapImpl<Integer, String>) store.createMap());
65 }
66 r = new Random(seed);
67
68 for (int i = 0; i < steps; i++) {
69 int index = i + 1;
70 for (int storeIndex = 0; storeIndex<versioneds.size(); storeIndex++) {
71 int nextKey = r.nextInt(maxKey);
72 String nextValue = values[r.nextInt(values.length)];
73 reference.get(storeIndex).put(nextKey, nextValue);
74 if (index % commitFrequency == 0) {
75 versioneds.get(storeIndex).restore(index2Version.get(storeIndex).get(i));
76 MapTestEnvironment.compareTwoMaps(scenario + ":" + index, reference.get(storeIndex), versioneds.get(storeIndex));
77 }
78 }
79 MapTestEnvironment.printStatus(scenario, index, steps, "comparison");
80 }
81
82 }
83
84 @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
85 @MethodSource
86 @Timeout(value = 10)
87 @Tag("smoke")
88 void parametrizedFastFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
89 boolean evilHash) {
90 runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
91 commitFrequency, evilHash);
92 }
93
94 static Stream<Arguments> parametrizedFastFuzz() {
95 return FuzzTestUtils.permutationWithSize(new Object[] { FuzzTestUtils.FAST_STEP_COUNT }, new Object[] { 3, 32, 32 * 32 },
96 new Object[] { 2, 3 }, new Object[] { 1, 10, 100 }, new Object[] { 1, 2, 3 },
97 new Object[] { false, true });
98 }
99
100 @ParameterizedTest(name = "Shared Store {index}/{0} Steps={1} Keys={2} Values={3} commit frequency={4} seed={5} evil-hash={6}")
101 @MethodSource
102 @Tag("smoke")
103 @Tag("slow")
104 void parametrizedSlowFuzz(int tests, int steps, int noKeys, int noValues, int commitFrequency, int seed,
105 boolean evilHash) {
106 runFuzzTest("SharedS" + steps + "K" + noKeys + "V" + noValues + "s" + seed, seed, steps, noKeys, noValues,
107 commitFrequency, evilHash);
108 }
109
110 static Stream<Arguments> parametrizedSlowFuzz() {
111 return FuzzTestUtils.changeStepCount(RestoreFuzzTest.parametrizedFastFuzz(), 1);
112 }
113}
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
new file mode 100644
index 00000000..e75d7f5a
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtils.java
@@ -0,0 +1,64 @@
1package tools.refinery.store.map.tests.fuzz.utils;
2
3import java.util.Arrays;
4import java.util.LinkedList;
5import java.util.List;
6import java.util.stream.Stream;
7
8import org.junit.jupiter.params.provider.Arguments;
9
10public final class FuzzTestUtils {
11 public static final int FAST_STEP_COUNT = 500;
12 public static final int SLOW_STEP_COUNT = 32 * 32 * 32 * 32;
13
14 private FuzzTestUtils() {
15 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
16 }
17
18 public static Stream<Arguments> changeStepCount(Stream<Arguments> arguments, int parameterIndex) {
19 return arguments.map(x -> Arguments.of(updatedStepCount(x.get(), parameterIndex)));
20 }
21
22 public static Object[] updatedStepCount(Object[] arguments, int parameterIndex) {
23 Object[] copy = Arrays.copyOf(arguments, arguments.length);
24 copy[parameterIndex] = SLOW_STEP_COUNT;
25 return copy;
26 }
27
28 static List<List<Object>> permutationInternal(int from, Object[]... valueOption) {
29 if (valueOption.length == from) {
30 return List.of(List.of());
31 } else {
32 Object[] permuteThis = valueOption[from];
33 List<List<Object>> otherCombination = permutationInternal(from + 1, valueOption);
34 List<List<Object>> result = new LinkedList<>();
35 for (Object permuteThisElement : permuteThis) {
36 for (List<Object> otherCombinationList : otherCombination) {
37 List<Object> newResult = new LinkedList<>();
38 newResult.add(permuteThisElement);
39 newResult.addAll(otherCombinationList);
40 result.add(newResult);
41 }
42 }
43 return result;
44 }
45 }
46
47 public static Stream<Arguments> permutation(Object[]... valueOption) {
48 List<List<Object>> permutations = permutationInternal(0, valueOption);
49 return permutations.stream().map(x -> Arguments.of(x.toArray()));
50 }
51
52 public static Stream<Arguments> permutationWithSize(Object[]... valueOption) {
53 int size = 1;
54 for (int i = 0; i < valueOption.length; i++) {
55 size *= valueOption[i].length;
56 }
57 Object[][] newValueOption = new Object[valueOption.length + 1][];
58 newValueOption[0] = new Object[] { size };
59 for (int i = 1; i < newValueOption.length; i++) {
60 newValueOption[i] = valueOption[i - 1];
61 }
62 return permutation(newValueOption);
63 }
64}
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
new file mode 100644
index 00000000..72f2a46c
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/fuzz/utils/FuzzTestUtilsTest.java
@@ -0,0 +1,33 @@
1package tools.refinery.store.map.tests.fuzz.utils;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4
5import java.util.List;
6
7import org.junit.jupiter.api.Test;
8
9class FuzzTestUtilsTest {
10 @Test
11 void permutationInternalTest() {
12 List<List<Object>> res = FuzzTestUtils.permutationInternal(0, new Object[] { 1, 2, 3 },
13 new Object[] { 'a', 'b', 'c' }, new Object[] { "alpha", "beta", "gamma", "delta" });
14 assertEquals(3 * 3 * 4, res.size());
15 }
16
17 @Test
18 void permutationTest1() {
19 var res = FuzzTestUtils.permutation(new Object[] { 1, 2, 3 }, new Object[] { 'a', 'b', 'c' },
20 new Object[] { "alpha", "beta", "gamma", "delta" });
21 assertEquals(3 * 3 * 4, res.count());
22 }
23
24 @Test
25 void permutationTest2() {
26 var res = FuzzTestUtils.permutation(new Object[] { 1, 2, 3 }, new Object[] { 'a', 'b', 'c' },
27 new Object[] { "alpha", "beta", "gamma", "delta" });
28 var arguments = res.findFirst().get().get();
29 assertEquals(1, arguments[0]);
30 assertEquals('a', arguments[1]);
31 assertEquals("alpha", arguments[2]);
32 }
33}
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
new file mode 100644
index 00000000..991b4f51
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/map/tests/utils/MapTestEnvironment.java
@@ -0,0 +1,214 @@
1package tools.refinery.store.map.tests.utils;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4import static org.junit.jupiter.api.Assertions.assertTrue;
5import static org.junit.jupiter.api.Assertions.fail;
6
7import java.util.HashMap;
8import java.util.Iterator;
9import java.util.List;
10import java.util.Map;
11import java.util.Map.Entry;
12
13import tools.refinery.store.map.ContinousHashProvider;
14import tools.refinery.store.map.Cursor;
15import tools.refinery.store.map.VersionedMap;
16import tools.refinery.store.map.internal.VersionedMapImpl;
17
18import java.util.TreeMap;
19
20public class MapTestEnvironment<K, V> {
21 public static String[] prepareValues(int maxValue) {
22 String[] values = new String[maxValue];
23 values[0] = "DEFAULT";
24 for (int i = 1; i < values.length; i++) {
25 values[i] = "VAL" + i;
26 }
27 return values;
28 }
29
30 public static ContinousHashProvider<Integer> prepareHashProvider(final boolean evil) {
31 // Use maxPrime = 2147483629
32
33 ContinousHashProvider<Integer> chp = new ContinousHashProvider<Integer>() {
34
35 @Override
36 public int getHash(Integer key, int index) {
37 if (evil && index < 15 && index < key / 3) {
38 return 7;
39 }
40 int result = 1;
41 final int prime = 31;
42
43 result = prime * result + key;
44 result = prime * result + index;
45
46 return result;
47 }
48 };
49 return chp;
50 }
51
52 public static void printStatus(String scenario, int actual, int max, String stepName) {
53 if (actual % 10000 == 0) {
54 String printStepName = stepName == null ? "" : stepName;
55 System.out.format(scenario + ":%d/%d (%d%%) " + printStepName + "%n", actual, max, actual * 100 / max);
56 }
57
58 }
59
60 public static <K, V> void compareTwoMaps(String title, VersionedMapImpl<K, V> map1,
61 VersionedMapImpl<K, V> map2) {
62 compareTwoMaps(title, map1, map2, null);
63 }
64 public static <K, V> void compareTwoMaps(String title, VersionedMapImpl<K, V> map1,
65 VersionedMapImpl<K, V> map2, List<Throwable> errors) {
66 // 1. Comparing cursors.
67 Cursor<K, V> cursor1 = map1.getAll();
68 Cursor<K, V> cursor2 = map2.getAll();
69 while (!cursor1.isTerminated()) {
70 if (cursor2.isTerminated()) {
71 fail("cursor 2 terminated before cursor1");
72 }
73 assertEqualsList(cursor1.getKey(), cursor2.getKey(),"Keys not equal", errors);
74 assertEqualsList(cursor2.getValue(), cursor2.getValue(), "Values not equal", errors);
75 cursor1.move();
76 cursor2.move();
77 }
78 if (!cursor2.isTerminated())
79 fail("cursor 1 terminated before cursor 2");
80
81 // 2.1. comparing hash codes
82 assertEqualsList(map1.hashCode(), map2.hashCode(), title + ": hash code check",errors);
83 assertEqualsList(map1, map2, title + ": 1.equals(2)",errors);
84 assertEqualsList(map2, map1, title + ": 2.equals(1)",errors);
85 }
86 private static void assertEqualsList(Object o1, Object o2, String message, List<Throwable> errors) {
87 if(errors == null) {
88 assertEquals(o1, o2, message);
89 } else {
90 if(o1 != null) {
91 if(!(o1.equals(o2))) {
92 AssertionError error = new AssertionError((message != null ? message+" " : "") + "expected: " + o1 + " but was : " + o2);
93 errors.add(error);
94 }
95 }
96 }
97 }
98
99 public VersionedMapImpl<K, V> sut;
100 Map<K, V> oracle = new HashMap<K, V>();
101
102 public MapTestEnvironment(VersionedMapImpl<K, V> sut) {
103 this.sut = sut;
104 }
105
106 public void put(K key, V value) {
107 V oldSutValue = sut.put(key, value);
108 V oldOracleValue;
109 if (value != sut.getDefaultValue()) {
110 oldOracleValue = oracle.put(key, value);
111 } else {
112 oldOracleValue = oracle.remove(key);
113 }
114 if(oldSutValue == sut.getDefaultValue() && oldOracleValue != null) {
115 fail("After put, SUT old value was default, but oracle old walue was " + oldOracleValue);
116 }
117 if(oldSutValue != sut.getDefaultValue()) {
118 assertEquals(oldOracleValue, oldSutValue);
119 }
120 }
121
122 public void checkEquivalence(String title) {
123 // 0. Checking integrity
124 try {
125 sut.checkIntegrity();
126 } catch (IllegalStateException e) {
127 fail(title + ": " + e.getMessage());
128 }
129
130 // 1. Checking: if Reference contains <key,value> pair, then SUT contains
131 // <key,value> pair.
132 // Tests get functions
133 for (Entry<K, V> entry : oracle.entrySet()) {
134 V sutValue = sut.get(entry.getKey());
135 V oracleValue = entry.getValue();
136 if (sutValue != oracleValue) {
137 printComparison();
138 fail(title + ": Non-equivalent get(" + entry.getKey() + ") results: SUT=" + sutValue + ", Oracle="
139 + oracleValue + "!");
140 }
141 }
142
143 // 2. Checking: if SUT contains <key,value> pair, then Reference contains
144 // <key,value> pair.
145 // Tests iterators
146 int elementsInSutEntrySet = 0;
147 Cursor<K, V> cursor = sut.getAll();
148 while (cursor.move()) {
149 elementsInSutEntrySet++;
150 K key = cursor.getKey();
151 V sutValue = cursor.getValue();
152 // System.out.println(key + " -> " + sutValue);
153 V oracleValue = oracle.get(key);
154 if (sutValue != oracleValue) {
155 printComparison();
156 fail(title + ": Non-equivalent entry in iterator: SUT=<" + key + "," + sutValue + ">, Oracle=<" + key
157 + "," + oracleValue + ">!");
158 }
159
160 }
161
162 // 3. Checking sizes
163 // Counting of non-default value pairs.
164 int oracleSize = oracle.entrySet().size();
165 long sutSize = sut.getSize();
166 if (oracleSize != sutSize || oracleSize != elementsInSutEntrySet) {
167 printComparison();
168 fail(title + ": Non-eqivalent size() result: SUT.getSize()=" + sutSize + ", SUT.entryset.size="
169 + elementsInSutEntrySet + ", Oracle=" + oracleSize + "!");
170 }
171 }
172
173 public static <K,V> void checkOrder(String scenario, VersionedMap<K,V> versionedMap) {
174 K previous = null;
175 Cursor<K, V> cursor = versionedMap.getAll();
176 while(cursor.move()) {
177 System.out.println(cursor.getKey() + " " + ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().getHash(cursor.getKey(), 0));
178 if(previous != null) {
179 int comparisonResult = ((VersionedMapImpl<K, V>) versionedMap).getHashProvider().compare(previous, cursor.getKey());
180 assertTrue(comparisonResult<0,scenario+" Cursor order is not incremental!");
181 }
182 previous = cursor.getKey();
183 }
184 System.out.println();
185 }
186
187 public void printComparison() {
188 System.out.println("SUT:");
189 printEntrySet(sut.getAll());
190 System.out.println("Oracle:");
191 printEntrySet(oracle.entrySet().iterator());
192 }
193
194 private void printEntrySet(Iterator<Entry<K, V>> iterator) {
195 TreeMap<K, V> treemap = new TreeMap<>();
196 while (iterator.hasNext()) {
197 Entry<K, V> entry = iterator.next();
198 treemap.put(entry.getKey(), entry.getValue());
199 }
200 for (Entry<K, V> e : treemap.entrySet()) {
201 System.out.println("\t" + e.getKey() + " -> " + e.getValue());
202 }
203 }
204
205 private void printEntrySet(Cursor<K, V> cursor) {
206 TreeMap<K, V> treemap = new TreeMap<>();
207 while (cursor.move()) {
208 treemap.put(cursor.getKey(), cursor.getValue());
209 }
210 for (Entry<K, V> e : treemap.entrySet()) {
211 System.out.println("\t" + e.getKey() + " -> " + e.getValue());
212 }
213 }
214}
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
new file mode 100644
index 00000000..7d070380
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/model/hashTests/HashEfficiencyTest.java
@@ -0,0 +1,161 @@
1package tools.refinery.store.model.hashTests;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4
5import java.util.ArrayList;
6import java.util.LinkedList;
7import java.util.List;
8import java.util.Random;
9
10import org.junit.jupiter.api.Test;
11
12import tools.refinery.store.map.ContinousHashProvider;
13import tools.refinery.store.model.Tuple;
14import tools.refinery.store.model.TupleHashProvider;
15import tools.refinery.store.model.TupleHashProviderBitMagic;
16
17class HashEfficiencyTest {
18
19 private static List<Tuple> permutations(int range, int arity) {
20 if(arity == 1) {
21 List<Tuple> result = new ArrayList<>(range);
22 for(int i=0; i<range; i++) {
23 result.add(Tuple.of(i));
24 }
25 return result;
26 } else if(arity > 1) {
27 List<Tuple> smallers = permutations(range, arity-1);
28 List<Tuple> result = new ArrayList<>(range*smallers.size());
29 for(Tuple smaller : smallers) {
30 for(int i=0; i<range; i++) {
31 int[] larger = new int[arity];
32 for(int x = 0; x<smaller.getSize(); x++) {
33 larger[x] = smaller.get(x);
34 }
35 larger[arity-1] = i;
36 result.add(Tuple.of(larger));
37 }
38 }
39 return result;
40 } else throw new IllegalArgumentException();
41 }
42
43 private static int amountToRange(int arity, int n) {
44 int range = 1;
45 while(Math.pow(range,arity)<n+0.1) {
46 range++;
47 }
48 return 1024;
49 }
50
51 public static List<Tuple> nPermutations(int arity, int n) {
52 int range = amountToRange(arity, n);
53 List<Tuple> permutations = permutations(range, arity);
54 return permutations.subList(0, n);
55 }
56
57 public static List<Tuple> nRandoms(int arity, int n, int seed) {
58 int range = amountToRange(arity, n);
59 List<Tuple> permutations = new ArrayList<>(n);
60 Random r = new Random(seed);
61 for(int i = 0; i<n; i++) {
62 int[] tuple = new int[arity];
63 for(int j=0; j<arity; j++) {
64 tuple[j] = r.nextInt(range);
65 }
66 permutations.add(Tuple.of(tuple));
67 }
68 return permutations;
69 }
70
71 @Test
72 void permutationTest() {
73 List<Tuple> p = permutations(10, 2);
74 assertEquals(p.size(),10*10);
75 }
76// private void printTuples(List<Tuple> p) {
77// for(Tuple element : p) {
78// System.out.println(element);
79// }
80// }
81 @Test
82 void nPermutationTest() {
83 final int amount = 500;
84 List<Tuple> p = nPermutations(2, amount);
85 assertEquals(amount,p.size());
86 }
87 @Test
88 void nRandomTest() {
89 final int amount = 500;
90 List<Tuple> p = nRandoms(2, amount, 1);;
91 assertEquals(amount,p.size());
92 }
93 private static double calculateHashClashes(List<Tuple> tuples, ContinousHashProvider<Tuple> chp) {
94 int sumClashes = 0;
95
96 for(int i = 0; i<tuples.size(); i++) {
97 int height = 0;
98 for(int j=0; j<tuples.size(); j++) {
99 int clashes = calculateHashClash(chp, tuples.get(i), tuples.get(j));
100 height = Math.max(height, clashes);
101 }
102 sumClashes += height;
103 }
104 return (sumClashes+0.0) / tuples.size();
105 }
106 private static int calculateHashClash(ContinousHashProvider<Tuple> chp, Tuple a, Tuple b) {
107 if(a.equals(b)) return 0;
108 final int bits = 5;
109 final int segments = Integer.SIZE/bits;
110 final int mask = (1<<bits)-1;
111 for(int i = 0;;i++) {
112 int index = i/segments;
113 int depth = i%segments;
114 int aHash = (chp.getHash(a, index)>>(depth*5))&mask;
115 int bHash = (chp.getHash(b, index)>>(depth*5))&mask;
116 if(aHash != bHash) {
117 return i+1;
118 }
119 if(i>400) {
120 throw new IllegalStateException(a+" vs "+b);
121 }
122 }
123 }
124 private static double caclulateOptimalHashClash(int size) {
125 return (Math.log(size)/Math.log(32));
126 }
127 public static void main(String[] args) {
128 List<String> hashNames = new LinkedList<>();
129 List<ContinousHashProvider<Tuple>> hashes = new LinkedList<>();
130 hashNames.add("PrimeGroup");
131 hashes.add(new TupleHashProvider());
132 hashNames.add("BitMagic");
133 hashes.add(new TupleHashProviderBitMagic());
134
135 int[] arities = new int[] {2,3,4,5};
136 int[] sizes = new int[] {32*32,32*32*8};
137
138 System.out.println("Size,Arity,DataSource,Hash,Chashes,Optimal,Badness");
139 for(int size : sizes) {
140 double optimalClashes = caclulateOptimalHashClash(size);
141 for(int arity : arities) {
142 List<String> dataSourceNames = new LinkedList<>();
143 List<List<Tuple>> dataSources = new LinkedList<>();
144
145// dataSourceNames.add("Permutation");
146// dataSources.add(nPermutations(arity, size));
147 dataSourceNames.add("Random");
148 dataSources.add(nRandoms(arity, size, 0));
149
150 for(int dataSourceIndex = 0; dataSourceIndex<dataSourceNames.size(); dataSourceIndex++) {
151 for(int hashIndex = 0; hashIndex<hashNames.size(); hashIndex++) {
152 double clashes = calculateHashClashes(dataSources.get(dataSourceIndex),hashes.get(hashIndex));
153 System.out.println(
154 size+","+arity+","+dataSourceNames.get(dataSourceIndex)+","+hashNames.get(hashIndex)+","+
155 clashes+","+optimalClashes+","+(clashes+0.0)/optimalClashes);
156 }
157 }
158 }
159 }
160 }
161}
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
new file mode 100644
index 00000000..9d90b1e1
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/model/tests/ModelTest.java
@@ -0,0 +1,148 @@
1package tools.refinery.store.model.tests;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4import static org.junit.jupiter.api.Assertions.assertFalse;
5import static org.junit.jupiter.api.Assertions.assertTrue;
6
7import java.util.Set;
8
9import org.junit.jupiter.api.Assertions;
10import org.junit.jupiter.api.Test;
11
12import tools.refinery.store.model.Model;
13import tools.refinery.store.model.ModelStore;
14import tools.refinery.store.model.ModelStoreImpl;
15import tools.refinery.store.model.Tuple;
16import tools.refinery.store.model.representation.Relation;
17
18class ModelTest {
19
20 @Test
21 void modelConstructionTest() {
22 Relation<Boolean> person = new Relation<>("Person", 1, false);
23 Relation<Boolean> friend = new Relation<>("friend", 2, false);
24
25 ModelStore store = new ModelStoreImpl(Set.of(person, friend));
26 Model model = store.createModel();
27
28 assertTrue(store.getDataRepresentations().contains(person));
29 assertTrue(store.getDataRepresentations().contains(friend));
30 assertTrue(model.getDataRepresentations().contains(person));
31 assertTrue(model.getDataRepresentations().contains(friend));
32
33 Relation<Integer> other = new Relation<Integer>("other", 2, null);
34 assertFalse(model.getDataRepresentations().contains(other));
35 }
36
37 @Test
38 void modelBuildingTest() {
39 Relation<Boolean> person = new Relation<>("Person", 1, false);
40 Relation<Integer> age = new Relation<Integer>("age", 1, null);
41 Relation<Boolean> friend = new Relation<>("friend", 2, false);
42
43 ModelStore store = new ModelStoreImpl(Set.of(person, age, friend));
44 Model model = store.createModel();
45
46 model.put(person, Tuple.of(0), true);
47 model.put(person, Tuple.of(1), true);
48 model.put(age, Tuple.of(0), 3);
49 model.put(age, Tuple.of(1), 1);
50 model.put(friend, Tuple.of(0, 1), true);
51 model.put(friend, Tuple.of(1, 0), true);
52
53 assertTrue(model.get(person, Tuple.of(0)));
54 assertTrue(model.get(person, Tuple.of(1)));
55 assertFalse(model.get(person, Tuple.of(2)));
56
57 assertEquals(3, model.get(age, Tuple.of(0)));
58 assertEquals(1, model.get(age, Tuple.of(1)));
59 assertEquals(null, model.get(age, Tuple.of(2)));
60
61 assertTrue(model.get(friend, Tuple.of(0, 1)));
62 assertFalse(model.get(friend, Tuple.of(0, 5)));
63 }
64
65 @Test
66 void modelBuildingArityFailTest() {
67 Relation<Boolean> person = new Relation<>("Person", 1, false);
68 ModelStore store = new ModelStoreImpl(Set.of(person));
69 Model model = store.createModel();
70
71 final Tuple tuple3 = Tuple.of(1, 1, 1);
72 Assertions.assertThrows(IllegalArgumentException.class, () -> model.put(person, tuple3, true));
73 Assertions.assertThrows(IllegalArgumentException.class, () -> model.get(person, tuple3));
74 }
75
76 @Test
77 void modelBuildingNullFailTest() {
78 Relation<Integer> age = new Relation<Integer>("age", 1, null);
79 ModelStore store = new ModelStoreImpl(Set.of(age));
80 Model model = store.createModel();
81
82 model.put(age, Tuple.of(1), null); // valid
83 Assertions.assertThrows(IllegalArgumentException.class, () -> model.put(age, null, 1));
84 Assertions.assertThrows(IllegalArgumentException.class, () -> model.get(age, null));
85
86 }
87
88 @Test
89 void modelUpdateTest() {
90 Relation<Boolean> person = new Relation<>("Person", 1, false);
91 Relation<Integer> age = new Relation<Integer>("age", 1, null);
92 Relation<Boolean> friend = new Relation<>("friend", 2, false);
93
94 ModelStore store = new ModelStoreImpl(Set.of(person, age, friend));
95 Model model = store.createModel();
96
97 model.put(person, Tuple.of(0), true);
98 model.put(person, Tuple.of(1), true);
99 model.put(age, Tuple.of(0), 3);
100 model.put(age, Tuple.of(1), 1);
101 model.put(friend, Tuple.of(0, 1), true);
102 model.put(friend, Tuple.of(1, 0), true);
103
104 assertEquals(3, model.get(age, Tuple.of(0)));
105 assertTrue(model.get(friend, Tuple.of(0, 1)));
106
107 model.put(age, Tuple.of(0), 4);
108 model.put(friend, Tuple.of(0, 1), false);
109
110 assertEquals(4, model.get(age, Tuple.of(0)));
111 assertFalse(model.get(friend, Tuple.of(0, 1)));
112 }
113
114 @Test
115 void restoreTest() {
116 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
117 Relation<Boolean> friend = new Relation<Boolean>("friend", 2, false);
118
119 ModelStore store = new ModelStoreImpl(Set.of(person, friend));
120 Model model = store.createModel();
121
122 model.put(person, Tuple.of(0), true);
123 model.put(person, Tuple.of(1), true);
124 model.put(friend, Tuple.of(0, 1), true);
125 model.put(friend, Tuple.of(1, 0), true);
126 long state1 = model.commit();
127
128 assertFalse(model.get(person, Tuple.of(2)));
129 assertFalse(model.get(friend, Tuple.of(0, 2)));
130
131 model.put(person, Tuple.of(2), true);
132 model.put(friend, Tuple.of(0, 2), true);
133 long state2 = model.commit();
134
135 assertTrue(model.get(person, Tuple.of(2)));
136 assertTrue(model.get(friend, Tuple.of(0, 2)));
137
138 model.restore(state1);
139
140 assertFalse(model.get(person, Tuple.of(2)));
141 assertFalse(model.get(friend, Tuple.of(0, 2)));
142
143 model.restore(state2);
144
145 assertTrue(model.get(person, Tuple.of(2)));
146 assertTrue(model.get(friend, Tuple.of(0, 2)));
147 }
148}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTest.java b/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTest.java
new file mode 100644
index 00000000..02381bcd
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTest.java
@@ -0,0 +1,445 @@
1package tools.refinery.store.query.test;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4
5import java.util.ArrayList;
6import java.util.Arrays;
7import java.util.Collections;
8import java.util.HashSet;
9import java.util.List;
10import java.util.Set;
11import java.util.stream.Stream;
12
13import org.junit.jupiter.api.Test;
14
15import tools.refinery.store.model.Tuple;
16import tools.refinery.store.model.representation.Relation;
17import tools.refinery.store.model.representation.TruthValue;
18import tools.refinery.store.query.QueriableModel;
19import tools.refinery.store.query.QueriableModelStore;
20import tools.refinery.store.query.QueriableModelStoreImpl;
21import tools.refinery.store.query.building.DNFAnd;
22import tools.refinery.store.query.building.DNFPredicate;
23import tools.refinery.store.query.building.EquivalenceAtom;
24import tools.refinery.store.query.building.PredicateAtom;
25import tools.refinery.store.query.building.RelationAtom;
26import tools.refinery.store.query.building.Variable;
27import tools.refinery.store.query.view.FilteredRelationView;
28import tools.refinery.store.query.view.KeyOnlyRelationView;
29import tools.refinery.store.query.view.RelationView;
30
31class QueryTest {
32
33 static void compareMatchSets(Stream<Object[]> matchSet, Set<List<Tuple>> expected) {
34 Set<List<Tuple>> translatedMatchSet = new HashSet<>();
35 var interator = matchSet.iterator();
36 while (interator.hasNext()) {
37 var element = interator.next();
38 List<Tuple> elementToTranslatedMatchSet = new ArrayList<>();
39 for (int i = 0; i < element.length; i++) {
40 elementToTranslatedMatchSet.add((Tuple) element[i]);
41 }
42 translatedMatchSet.add(elementToTranslatedMatchSet);
43 }
44
45 assertEquals(expected, translatedMatchSet);
46 }
47
48 @Test
49 void typeConstraintTest() {
50 Relation<Boolean> person = new Relation<>("Person", 1, false);
51 Relation<Boolean> asset = new Relation<>("Asset", 1, false);
52 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
53
54 List<Variable> parameters = Arrays.asList(new Variable("p1"));
55 RelationAtom personRelationAtom = new RelationAtom(persionView, parameters);
56 DNFAnd clause = new DNFAnd(Collections.emptySet(), Arrays.asList(personRelationAtom));
57 DNFPredicate predicate = new DNFPredicate("TypeConstraint", parameters, Arrays.asList(clause));
58
59 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, asset), Set.of(persionView),
60 Set.of(predicate));
61 QueriableModel model = store.createModel();
62
63 model.put(person, Tuple.of(0), true);
64 model.put(person, Tuple.of(1), true);
65 model.put(asset, Tuple.of(1), true);
66 model.put(asset, Tuple.of(2), true);
67
68 model.flushChanges();
69 assertEquals(2, model.countResults(predicate));
70 compareMatchSets(model.allResults(predicate), Set.of(List.of(Tuple.of(0)), List.of(Tuple.of(1))));
71 }
72
73 @Test
74 void relationConstraintTest() {
75 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
76 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
77 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
78 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
79
80 Variable p1 = new Variable("p1");
81 Variable p2 = new Variable("p2");
82 List<Variable> parameters = Arrays.asList(p1, p2);
83
84 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
85 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
86 RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
87 DNFAnd clause = new DNFAnd(Collections.emptySet(),
88 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom));
89 DNFPredicate predicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
90
91 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
92 Set.of(persionView, friendMustView), Set.of(predicate));
93 QueriableModel model = store.createModel();
94
95 assertEquals(0, model.countResults(predicate));
96
97 model.put(person, Tuple.of(0), true);
98 model.put(person, Tuple.of(1), true);
99 model.put(person, Tuple.of(2), true);
100 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
101 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
102 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
103
104 assertEquals(0, model.countResults(predicate));
105
106 model.flushChanges();
107 assertEquals(3, model.countResults(predicate));
108 compareMatchSets(model.allResults(predicate), Set.of(List.of(Tuple.of(0), Tuple.of(1)),
109 List.of(Tuple.of(1), Tuple.of(0)), List.of(Tuple.of(1), Tuple.of(2))));
110 }
111
112 @Test
113 void andTest() {
114 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
115 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
116 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
117 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
118
119 Variable p1 = new Variable("p1");
120 Variable p2 = new Variable("p2");
121 List<Variable> parameters = Arrays.asList(p1, p2);
122
123 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
124 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
125 RelationAtom friendRelationAtom1 = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
126 RelationAtom friendRelationAtom2 = new RelationAtom(friendMustView, Arrays.asList(p2, p1));
127 DNFAnd clause = new DNFAnd(Collections.emptySet(),
128 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom1, friendRelationAtom2));
129 DNFPredicate predicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
130
131 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
132 Set.of(persionView, friendMustView), Set.of(predicate));
133 QueriableModel model = store.createModel();
134
135 assertEquals(0, model.countResults(predicate));
136
137 model.put(person, Tuple.of(0), true);
138 model.put(person, Tuple.of(1), true);
139 model.put(person, Tuple.of(2), true);
140
141 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
142 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE);
143
144 model.flushChanges();
145 assertEquals(0, model.countResults(predicate));
146
147 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
148 model.flushChanges();
149 assertEquals(2, model.countResults(predicate));
150 compareMatchSets(model.allResults(predicate),
151 Set.of(List.of(Tuple.of(0), Tuple.of(1)), List.of(Tuple.of(1), Tuple.of(0))));
152
153 model.put(friend, Tuple.of(2, 0), TruthValue.TRUE);
154 model.flushChanges();
155 assertEquals(4, model.countResults(predicate));
156 compareMatchSets(model.allResults(predicate),
157 Set.of(List.of(Tuple.of(0), Tuple.of(1)), List.of(Tuple.of(1), Tuple.of(0)),
158 List.of(Tuple.of(0), Tuple.of(2)), List.of(Tuple.of(2), Tuple.of(0))));
159 }
160
161 @Test
162 void existTest() {
163 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
164 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
165 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
166 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
167
168 Variable p1 = new Variable("p1");
169 Variable p2 = new Variable("p2");
170 List<Variable> parameters = Arrays.asList(p1);
171
172 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
173 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
174 RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
175 DNFAnd clause = new DNFAnd(Set.of(p2),
176 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom));
177 DNFPredicate predicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
178
179 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
180 Set.of(persionView, friendMustView), Set.of(predicate));
181 QueriableModel model = store.createModel();
182
183 assertEquals(0, model.countResults(predicate));
184
185 model.put(person, Tuple.of(0), true);
186 model.put(person, Tuple.of(1), true);
187 model.put(person, Tuple.of(2), true);
188 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
189 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
190 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
191
192 assertEquals(0, model.countResults(predicate));
193
194 model.flushChanges();
195 assertEquals(2, model.countResults(predicate));
196 compareMatchSets(model.allResults(predicate), Set.of(List.of(Tuple.of(0)), List.of(Tuple.of(1))));
197 }
198
199 @Test
200 void orTest() {
201 Relation<Boolean> person = new Relation<>("Person", 1, false);
202 Relation<Boolean> animal = new Relation<>("Animal", 1, false);
203 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
204 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
205 RelationView<Boolean> animalView = new KeyOnlyRelationView(animal);
206 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
207
208 Variable p1 = new Variable("p1");
209 Variable p2 = new Variable("p2");
210 List<Variable> parameters = Arrays.asList(p1, p2);
211
212 // Person-Person friendship
213 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
214 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
215 RelationAtom friendRelationAtom1 = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
216 DNFAnd clause1 = new DNFAnd(Collections.emptySet(),
217 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom1));
218
219 // Animal-Animal friendship
220 RelationAtom animalRelationAtom1 = new RelationAtom(animalView, Arrays.asList(p1));
221 RelationAtom animalRelationAtom2 = new RelationAtom(animalView, Arrays.asList(p2));
222 RelationAtom friendRelationAtom2 = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
223 DNFAnd clause2 = new DNFAnd(Collections.emptySet(),
224 Arrays.asList(animalRelationAtom1, animalRelationAtom2, friendRelationAtom2));
225
226 // No inter-species friendship
227
228 DNFPredicate predicate = new DNFPredicate("Or", parameters, Arrays.asList(clause1, clause2));
229
230 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, animal, friend),
231 Set.of(persionView, animalView, friendMustView), Set.of(predicate));
232 QueriableModel model = store.createModel();
233
234 model.put(person, Tuple.of(0), true);
235 model.put(person, Tuple.of(1), true);
236 model.put(animal, Tuple.of(2), true);
237 model.put(animal, Tuple.of(3), true);
238 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
239 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE);
240 model.put(friend, Tuple.of(2, 3), TruthValue.TRUE);
241 model.put(friend, Tuple.of(3, 0), TruthValue.TRUE);
242
243 model.flushChanges();
244 assertEquals(2, model.countResults(predicate));
245 compareMatchSets(model.allResults(predicate),
246 Set.of(List.of(Tuple.of(0), Tuple.of(1)), List.of(Tuple.of(2), Tuple.of(3))));
247 }
248
249 @Test
250 void equalityTest() {
251 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
252 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
253
254 Variable p1 = new Variable("p1");
255 Variable p2 = new Variable("p2");
256 List<Variable> parameters = Arrays.asList(p1, p2);
257
258 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
259 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
260 EquivalenceAtom equivalenceAtom = new EquivalenceAtom(true, p1, p2);
261 DNFAnd clause = new DNFAnd(Collections.emptySet(),
262 Arrays.asList(personRelationAtom1, personRelationAtom2, equivalenceAtom));
263 DNFPredicate predicate = new DNFPredicate("Equality", parameters, Arrays.asList(clause));
264
265 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person), Set.of(persionView), Set.of(predicate));
266 QueriableModel model = store.createModel();
267
268 model.put(person, Tuple.of(0), true);
269 model.put(person, Tuple.of(1), true);
270 model.put(person, Tuple.of(2), true);
271
272 model.flushChanges();
273 assertEquals(3, model.countResults(predicate));
274 compareMatchSets(model.allResults(predicate), Set.of(List.of(Tuple.of(0), Tuple.of(0)),
275 List.of(Tuple.of(1), Tuple.of(1)), List.of(Tuple.of(2), Tuple.of(2))));
276 }
277
278 @Test
279 void inequalityTest() {
280 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
281 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
282 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
283 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
284
285 Variable p1 = new Variable("p1");
286 Variable p2 = new Variable("p2");
287 Variable p3 = new Variable("p3");
288 List<Variable> parameters = Arrays.asList(p1, p2, p3);
289
290 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
291 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
292 RelationAtom friendRelationAtom1 = new RelationAtom(friendMustView, Arrays.asList(p1, p3));
293 RelationAtom friendRelationAtom2 = new RelationAtom(friendMustView, Arrays.asList(p2, p3));
294 EquivalenceAtom inequivalenceAtom = new EquivalenceAtom(false, p1, p2);
295 DNFAnd clause = new DNFAnd(Collections.emptySet(), Arrays.asList(personRelationAtom1, personRelationAtom2,
296 friendRelationAtom1, friendRelationAtom2, inequivalenceAtom));
297 DNFPredicate predicate = new DNFPredicate("Inequality", parameters, Arrays.asList(clause));
298
299 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
300 Set.of(persionView, friendMustView), Set.of(predicate));
301 QueriableModel model = store.createModel();
302
303 model.put(person, Tuple.of(0), true);
304 model.put(person, Tuple.of(1), true);
305 model.put(person, Tuple.of(2), true);
306 model.put(friend, Tuple.of(0, 2), TruthValue.TRUE);
307 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
308
309 model.flushChanges();
310 assertEquals(2, model.countResults(predicate));
311 compareMatchSets(model.allResults(predicate),
312 Set.of(List.of(Tuple.of(0), Tuple.of(1), Tuple.of(2)), List.of(Tuple.of(1), Tuple.of(0), Tuple.of(2))));
313 }
314
315 @Test
316 void patternCallTest() {
317 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
318 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
319 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
320 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
321
322 Variable p1 = new Variable("p1");
323 Variable p2 = new Variable("p2");
324 List<Variable> parameters = Arrays.asList(p1, p2);
325
326 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
327 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
328 RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
329 DNFAnd clause = new DNFAnd(Collections.emptySet(),
330 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom));
331 DNFPredicate friendPredicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
332
333 Variable p3 = new Variable("p3");
334 Variable p4 = new Variable("p4");
335 List<Variable> substitution = Arrays.asList(p3, p4);
336 RelationAtom personRelationAtom3 = new RelationAtom(persionView, Arrays.asList(p3));
337 RelationAtom personRelationAtom4 = new RelationAtom(persionView, Arrays.asList(p4));
338 PredicateAtom friendPredicateAtom = new PredicateAtom(true, false, friendPredicate, substitution);
339 DNFAnd patternCallClause = new DNFAnd(Collections.emptySet(),
340 Arrays.asList(personRelationAtom3, personRelationAtom4, friendPredicateAtom));
341 DNFPredicate predicate = new DNFPredicate("PatternCall", substitution, Arrays.asList(patternCallClause));
342
343 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
344 Set.of(persionView, friendMustView), Set.of(friendPredicate, predicate));
345 QueriableModel model = store.createModel();
346
347 model.put(person, Tuple.of(0), true);
348 model.put(person, Tuple.of(1), true);
349 model.put(person, Tuple.of(2), true);
350 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
351 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
352 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
353
354 model.flushChanges();
355
356 assertEquals(3, model.countResults(friendPredicate));
357 }
358
359 @Test
360 void negativePatternCallTest() {
361 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
362 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
363 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
364 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
365
366 Variable p1 = new Variable("p1");
367 Variable p2 = new Variable("p2");
368 List<Variable> parameters = Arrays.asList(p1, p2);
369
370 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
371 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
372 RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
373 DNFAnd clause = new DNFAnd(Collections.emptySet(),
374 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom));
375 DNFPredicate friendPredicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
376
377 Variable p3 = new Variable("p3");
378 Variable p4 = new Variable("p4");
379 List<Variable> substitution = Arrays.asList(p3, p4);
380 RelationAtom personRelationAtom3 = new RelationAtom(persionView, Arrays.asList(p3));
381 RelationAtom personRelationAtom4 = new RelationAtom(persionView, Arrays.asList(p4));
382 PredicateAtom friendPredicateAtom = new PredicateAtom(false, false, friendPredicate, substitution);
383 DNFAnd negativePatternCallClause = new DNFAnd(Collections.emptySet(),
384 Arrays.asList(personRelationAtom3, personRelationAtom4, friendPredicateAtom));
385 DNFPredicate predicate = new DNFPredicate("NegativePatternCall", substitution,
386 Arrays.asList(negativePatternCallClause));
387
388 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
389 Set.of(persionView, friendMustView), Set.of(friendPredicate, predicate));
390 QueriableModel model = store.createModel();
391
392 model.put(person, Tuple.of(0), true);
393 model.put(person, Tuple.of(1), true);
394 model.put(person, Tuple.of(2), true);
395 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
396 model.put(friend, Tuple.of(1, 0), TruthValue.TRUE);
397 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
398
399 model.flushChanges();
400 assertEquals(6, model.countResults(predicate));
401 }
402
403 @Test
404 void transitivePatternCallTest() {
405 Relation<Boolean> person = new Relation<Boolean>("Person", 1, false);
406 Relation<TruthValue> friend = new Relation<>("friend", 2, TruthValue.FALSE);
407 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
408 RelationView<TruthValue> friendMustView = new FilteredRelationView<TruthValue>(friend, (k, v) -> v.must());
409
410 Variable p1 = new Variable("p1");
411 Variable p2 = new Variable("p2");
412 List<Variable> parameters = Arrays.asList(p1, p2);
413
414 RelationAtom personRelationAtom1 = new RelationAtom(persionView, Arrays.asList(p1));
415 RelationAtom personRelationAtom2 = new RelationAtom(persionView, Arrays.asList(p2));
416 RelationAtom friendRelationAtom = new RelationAtom(friendMustView, Arrays.asList(p1, p2));
417 DNFAnd clause = new DNFAnd(Collections.emptySet(),
418 Arrays.asList(personRelationAtom1, personRelationAtom2, friendRelationAtom));
419 DNFPredicate friendPredicate = new DNFPredicate("RelationConstraint", parameters, Arrays.asList(clause));
420
421 Variable p3 = new Variable("p3");
422 Variable p4 = new Variable("p4");
423 List<Variable> substitution = Arrays.asList(p3, p4);
424 RelationAtom personRelationAtom3 = new RelationAtom(persionView, Arrays.asList(p3));
425 RelationAtom personRelationAtom4 = new RelationAtom(persionView, Arrays.asList(p4));
426 PredicateAtom friendPredicateAtom = new PredicateAtom(true, true, friendPredicate, substitution);
427 DNFAnd patternCallClause = new DNFAnd(Collections.emptySet(),
428 Arrays.asList(personRelationAtom3, personRelationAtom4, friendPredicateAtom));
429 DNFPredicate predicate = new DNFPredicate("TransitivePatternCall", substitution,
430 Arrays.asList(patternCallClause));
431
432 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, friend),
433 Set.of(persionView, friendMustView), Set.of(friendPredicate, predicate));
434 QueriableModel model = store.createModel();
435
436 model.put(person, Tuple.of(0), true);
437 model.put(person, Tuple.of(1), true);
438 model.put(person, Tuple.of(2), true);
439 model.put(friend, Tuple.of(0, 1), TruthValue.TRUE);
440 model.put(friend, Tuple.of(1, 2), TruthValue.TRUE);
441
442 model.flushChanges();
443 assertEquals(3, model.countResults(predicate));
444 }
445} \ No newline at end of file
diff --git a/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTransactionTest.java b/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTransactionTest.java
new file mode 100644
index 00000000..e72186b9
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/query/test/QueryTransactionTest.java
@@ -0,0 +1,58 @@
1package tools.refinery.store.query.test;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4
5import java.util.Arrays;
6import java.util.Collections;
7import java.util.List;
8import java.util.Set;
9
10import org.junit.jupiter.api.Test;
11
12import tools.refinery.store.model.Tuple;
13import tools.refinery.store.model.representation.Relation;
14import tools.refinery.store.query.QueriableModel;
15import tools.refinery.store.query.QueriableModelStore;
16import tools.refinery.store.query.QueriableModelStoreImpl;
17import tools.refinery.store.query.building.DNFAnd;
18import tools.refinery.store.query.building.DNFPredicate;
19import tools.refinery.store.query.building.RelationAtom;
20import tools.refinery.store.query.building.Variable;
21import tools.refinery.store.query.view.KeyOnlyRelationView;
22import tools.refinery.store.query.view.RelationView;
23
24class QueryTransactionTest {
25 @Test
26 void flushTest() {
27 Relation<Boolean> person = new Relation<>("Person", 1, false);
28 Relation<Boolean> asset = new Relation<>("Asset", 1, false);
29 RelationView<Boolean> persionView = new KeyOnlyRelationView(person);
30
31 List<Variable> parameters = Arrays.asList(new Variable("p1"));
32 RelationAtom personRelationAtom = new RelationAtom(persionView, parameters);
33 DNFAnd clause = new DNFAnd(Collections.emptySet(), Arrays.asList(personRelationAtom));
34 DNFPredicate predicate = new DNFPredicate("TypeConstraint", parameters, Arrays.asList(clause));
35
36 QueriableModelStore store = new QueriableModelStoreImpl(Set.of(person, asset), Set.of(persionView),
37 Set.of(predicate));
38 QueriableModel model = store.createModel();
39
40 assertEquals(0, model.countResults(predicate));
41
42 model.put(person, Tuple.of(0), true);
43 model.put(person, Tuple.of(1), true);
44 model.put(asset, Tuple.of(1), true);
45 model.put(asset, Tuple.of(2), true);
46
47 assertEquals(0, model.countResults(predicate));
48
49 model.flushChanges();
50 assertEquals(2, model.countResults(predicate));
51
52 model.put(person, Tuple.of(4), true);
53 assertEquals(2, model.countResults(predicate));
54
55 model.flushChanges();
56 assertEquals(3, model.countResults(predicate));
57 }
58}
diff --git a/subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java b/subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java
new file mode 100644
index 00000000..171be0e5
--- /dev/null
+++ b/subprojects/store/src/test/java/tools/refinery/store/util/CollectionsUtilTests.java
@@ -0,0 +1,78 @@
1package tools.refinery.store.util;
2
3import static org.junit.jupiter.api.Assertions.assertEquals;
4import static tools.refinery.store.util.CollectionsUtil.filter;
5import static tools.refinery.store.util.CollectionsUtil.map;
6
7import java.util.ArrayList;
8import java.util.Iterator;
9import java.util.List;
10import java.util.NoSuchElementException;
11
12import org.junit.jupiter.api.Assertions;
13import org.junit.jupiter.api.Test;
14
15class CollectionsUtilTests {
16 List<Integer> list10 = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
17 List<String> listTen = List.of("1", "2", "3", "4", "5", "6", "7", "8", "9", "10");
18
19 private static <T> void compare(Iterable<T> a, Iterable<T> b) {
20 List<T> listA = toList(a);
21 List<T> listB = toList(b);
22 assertEquals(listA, listB);
23 }
24
25 private static <T> List<T> toList(Iterable<T> a) {
26 List<T> result = new ArrayList<T>();
27 Iterator<T> iterator = a.iterator();
28 while (iterator.hasNext()) {
29 result.add(iterator.next());
30 }
31 return result;
32 }
33
34 @Test
35 void testFilterEven() {
36 compare(List.of(2, 4, 6, 8, 10), filter(list10, (x -> x % 2 == 0)));
37 }
38
39 @Test
40 void testFilterOdd() {
41 compare(List.of(1, 3, 5, 7, 9), filter(list10, (x -> x % 2 == 1)));
42 }
43
44 @Test
45 void testFilterFalse() {
46 compare(List.of(), filter(list10, (x -> false)));
47 }
48
49 @Test
50 void testFilterTrue() {
51 compare(list10, filter(list10, (x -> true)));
52 }
53
54 @Test
55 void testFilterEmpty() {
56 compare(List.of(), filter(List.of(), (x -> true)));
57 }
58
59 @Test()
60 void testNoSuchElement() {
61 Iterable<Integer> iterable = filter(list10, (x -> x % 2 == 0));
62 Iterator<Integer> iterator = iterable.iterator();
63 while (iterator.hasNext()) {
64 iterator.next();
65 }
66 Assertions.assertThrows(NoSuchElementException.class, () -> iterator.next());
67 }
68
69 @Test()
70 void mapTest() {
71 compare(listTen, map(list10, x -> x.toString()));
72 }
73
74 @Test()
75 void mapEmtyTest() {
76 compare(List.of(), map(List.of(), x -> x.toString()));
77 }
78}