1 package de.dlr.shepard.migrations.neo4j;
2
3 import static org.junit.jupiter.api.Assertions.assertEquals;
4 import static org.junit.jupiter.api.Assertions.assertThrows;
5 import static org.neo4j.cypherdsl.core.Cypher.node;
6
7 import com.opencsv.exceptions.CsvValidationException;
8 import de.dlr.shepard.common.neo4j.MigrationsRunner;
9 import de.dlr.shepard.context.collection.entities.Collection;
10 import java.io.IOException;
11 import java.sql.SQLException;
12 import java.util.Map;
13 import org.apache.commons.lang3.RandomStringUtils;
14 import org.junit.jupiter.api.MethodOrderer;
15 import org.junit.jupiter.api.Test;
16 import org.junit.jupiter.api.TestMethodOrder;
17 import org.neo4j.cypherdsl.core.Cypher;
18 import org.neo4j.cypherdsl.core.Node;
19 import org.neo4j.ogm.exception.CypherException;
20
21
22
23
24
25 @TestMethodOrder(MethodOrderer.MethodName.class)
26 public class TestNeo4jMigrations {
27
28 private static final String randomElement = RandomStringUtils.insecure().next(6, true, true);
29 private static final QueryHelper q = new QueryHelper();
30 private static final TestV11 testV11 = new TestV11();
31 private static final TestV13 testV13 = new TestV13();
32 private static final TestV14 testV14 = new TestV14();
33
34 private static void testNodeMigrated(Node old, Node migrated) {
35 assertEquals(0, q.match(old).size());
36 assertEquals(1, q.match(migrated).size());
37 }
38
39 private static void runMigrations(String targetVersion) {
40 new MigrationsRunner(targetVersion).apply();
41 }
42
43 private static <K, V> void assertEqualsMaps(Map<K, V> expected, Map<K, V> actual) {
44 assertEquals(expected.keySet(), actual.keySet());
45 }
46
47 @Test
48 public void testV09() {
49 var collectionWithBadAttributes = node("Collection").withProperties(
50 "name",
51 Cypher.literalOf(randomElement),
52 "attributes.a",
53 Cypher.literalOf(0),
54 "attributes.b.c",
55 Cypher.literalOf(1)
56 );
57 q.create(collectionWithBadAttributes);
58
59 runMigrations("V9");
60
61 var collectionWithGoodAttributes = node("Collection").withProperties(
62 "name",
63 Cypher.literalOf(randomElement),
64 "attributes||a",
65 Cypher.literalOf(0),
66 "attributes||b.c",
67 Cypher.literalOf(1)
68 );
69
70 testNodeMigrated(collectionWithBadAttributes, collectionWithGoodAttributes);
71
72
73 var migratedCollection = q.match(collectionWithGoodAttributes, Collection.class).getFirst();
74 assertEqualsMaps(Map.of("a", "0", "b.c", "1"), migratedCollection.getAttributes());
75 }
76
77 @Test
78 public void testV10() {
79 var legacyAnnotation = node("SemanticAnnotation").withProperties(
80 "name",
81 Cypher.literalOf("prop-" + randomElement + "::" + "value-" + randomElement),
82 "propertyIRI",
83 Cypher.literalOf("piri"),
84 "valueIRI",
85 Cypher.literalOf("viri")
86 );
87 q.create(legacyAnnotation);
88
89 runMigrations("V10");
90
91 var migratedAnnotation = node("SemanticAnnotation").withProperties(
92 "propertyName",
93 Cypher.literalOf("prop-" + randomElement),
94 "valueName",
95 Cypher.literalOf("value-" + randomElement)
96 );
97
98 testNodeMigrated(legacyAnnotation, migratedAnnotation);
99 }
100
101 @Test
102 public void testV11_0_NoException() {
103 testV11.setupPreMigrationData();
104 testV11.runMigration();
105 }
106
107 @Test
108 public void testV11_UniqueTimeseriesUntouched() {
109 testV11.assertUniqueTimeseriesUntouched();
110 }
111
112 @Test
113 public void testV11_DuplicatesEliminated() {
114 testV11.assertDuplicatesEliminated();
115 }
116
117 @Test
118 public void testV11_ReferencesMigrated() {
119 testV11.assertReferencesMigrated();
120 }
121
122 @Test
123 public void testV12() {
124 testV11.cleanup();
125 var legacyReferencedTimeseries = node("Timeseries").withProperties("device", Cypher.literalOf("V12"));
126 q.create(legacyReferencedTimeseries);
127 runMigrations("V12");
128 var migratedTimeseries = node("TimeseriesTuple").withProperties("device", Cypher.literalOf("V12"));
129 testNodeMigrated(legacyReferencedTimeseries, migratedTimeseries);
130 }
131
132 @Test
133 public void testV12_ConstraintHolds() {
134 var ts = node("TimeseriesTuple").withProperties(
135 "measurement",
136 Cypher.literalOf("V12"),
137 "device",
138 Cypher.literalOf("V12"),
139 "location",
140 Cypher.literalOf("V12"),
141 "symbolicName",
142 Cypher.literalOf("V12"),
143 "field",
144 Cypher.literalOf("V12")
145 );
146 q.create(ts);
147 assertThrows(CypherException.class, () -> q.create(ts));
148 }
149
150 @Test
151 public void testV13_0_NoException() throws CsvValidationException, IOException, ClassNotFoundException {
152 testV13.setupPreMigrationData();
153 testV13.runMigration();
154 }
155
156 @Test
157 public void testV13_TimeseriesPresentInGraphDb() {
158 testV13.assertTimeseriesPresentInGraphDb();
159 }
160
161 @Test
162 public void testV13_MetadataDeletedInTimeseriesDb() throws SQLException, ClassNotFoundException {
163 testV13.assertMetadataDeletedInTimeseriesDb();
164 }
165
166 @Test
167 public void testV13_TimeseriesDatapointsIntact() throws SQLException, ClassNotFoundException {
168 testV13.assertTimeseriesDatapointsIntact();
169 }
170
171 @Test
172 public void testV13_NewTimeseriesMergedWithPreexisting() {
173 testV13.assertNewTimeseriesMergedWithPreexisting();
174 }
175
176 @Test
177 public void testV14_0_NoException() {
178 testV14.setupPreMigrationData();
179 runMigrations("V14");
180 }
181
182 @Test
183 public void testV14_SinglyAnnotatedTimeseriesMigrated() {
184 testV14.assertSinglyAnnotatedTimeseriesMigrated();
185 }
186
187 @Test
188 public void testV14_DoublyAnnotatedTimeseriesMigrated() {
189 testV14.assertDoublyAnnotatedTimeseriesMigrated();
190 }
191
192 @Test
193 public void testV14_LegacyAnnotatedTimeseriesDeleted() {
194 testV14.assertLegacyAnnotatedTimeseriesDeleted();
195 }
196 }