View Javadoc
1   package de.dlr.shepard.data.migrations.neo4j;
2   
3   import static org.junit.jupiter.api.Assertions.assertEquals;
4   import static org.neo4j.cypherdsl.core.Cypher.*;
5   
6   import de.dlr.shepard.common.neo4j.MigrationsRunner;
7   import de.dlr.shepard.common.neo4j.NeoConnector;
8   import java.util.Collection;
9   import java.util.Collections;
10  import java.util.List;
11  import java.util.Map;
12  import java.util.stream.StreamSupport;
13  import org.apache.commons.lang3.RandomStringUtils;
14  import org.junit.jupiter.api.BeforeAll;
15  import org.junit.jupiter.api.MethodOrderer;
16  import org.junit.jupiter.api.Test;
17  import org.junit.jupiter.api.TestMethodOrder;
18  import org.neo4j.cypherdsl.core.Cypher;
19  import org.neo4j.cypherdsl.core.Node;
20  import org.neo4j.cypherdsl.core.Statement;
21  import org.neo4j.cypherdsl.core.renderer.Renderer;
22  import org.neo4j.ogm.model.Result;
23  import org.neo4j.ogm.session.Session;
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 Renderer cypherRenderer = Renderer.getDefaultRenderer();
30    private static Session session;
31  
32    @BeforeAll
33    public static void setUp() {
34      var conn = NeoConnector.getInstance();
35      conn.connect();
36      session = conn.getNeo4jSession();
37    }
38  
39    private static Result query(Statement statement) {
40      var cypherQuery = cypherRenderer.render(statement);
41      return session.query(cypherQuery, Collections.emptyMap());
42    }
43  
44    private static void testNodeMigrated(Node old, Node migrated) {
45      assertEquals(0, match(old).size());
46      assertEquals(1, match(migrated).size());
47    }
48  
49    private static void runMigrations(String targetVersion) {
50      new MigrationsRunner(targetVersion).apply();
51    }
52  
53    private static void create(Node node) {
54      var statement = Cypher.create(node).build();
55      query(statement);
56    }
57  
58    private static List<Object> match(Node node) {
59      var statement = Cypher.match(node).returning(node).build();
60      var result = query(statement);
61      return StreamSupport.stream(result.spliterator(), false).map(Map::values).flatMap(Collection::stream).toList();
62    }
63  
64    private static <K, V> void assertEqualsMaps(Map<K, V> expected, Map<K, V> actual) {
65      assertEquals(expected.keySet(), actual.keySet());
66    }
67  
68    @Test
69    public void testV09() {
70      var collectionWithBadAttributes = node("Collection").withProperties(
71        "name",
72        Cypher.literalOf(randomElement),
73        "attributes.a",
74        Cypher.literalOf(0),
75        "attributes.b.c",
76        Cypher.literalOf(1)
77      );
78      create(collectionWithBadAttributes);
79  
80      runMigrations("V9");
81  
82      var collectionWithGoodAttributes = node("Collection").withProperties(
83        "name",
84        Cypher.literalOf(randomElement),
85        "attributes||a",
86        Cypher.literalOf(0),
87        "attributes||b.c",
88        Cypher.literalOf(1)
89      );
90  
91      testNodeMigrated(collectionWithBadAttributes, collectionWithGoodAttributes);
92  
93      // test that the migration has not touched the attribute values
94      var migratedCollection = (de.dlr.shepard.context.collection.entities.Collection) match(
95        collectionWithGoodAttributes
96      ).get(0);
97      assertEqualsMaps(Map.of("a", "0", "b.c", "1"), migratedCollection.getAttributes());
98    }
99  
100   @Test
101   public void testV10() {
102     var legacyAnnotation = node("SemanticAnnotation").withProperties(
103       "name",
104       Cypher.literalOf("prop-" + randomElement + "::" + "value-" + randomElement),
105       "propertyIRI",
106       Cypher.literalOf("piri"),
107       "valueIRI",
108       Cypher.literalOf("viri")
109     );
110     create(legacyAnnotation);
111 
112     runMigrations("V10");
113 
114     var migratedAnnotation = node("SemanticAnnotation").withProperties(
115       "propertyName",
116       Cypher.literalOf("prop-" + randomElement),
117       "valueName",
118       Cypher.literalOf("value-" + randomElement)
119     );
120 
121     testNodeMigrated(legacyAnnotation, migratedAnnotation);
122   }
123 }