@Test public void shouldDiffGetTheDiffBetweenTwoStatesCorrectly() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (s:State:From {keep:'keep', update:'old', delete:'delete'})"); session.run("CREATE (s:State:To {keep:'keep', update:'new', new:'new'})"); // When StatementResult result = session .run("MATCH (stateTo:State:To), (stateFrom:State:From) WITH stateFrom, stateTo CALL graph.versioner.diff(stateFrom, stateTo) YIELD operation, label, oldValue, newValue RETURN operation, label, oldValue, newValue"); // Then assertThat(result.next().values().stream().map(Value::asString).collect(Collectors.toList()), contains(Utility.DIFF_OPERATION_REMOVE, "delete", "delete", "null")); assertThat(result.next().values().stream().map(Value::asString).collect(Collectors.toList()), contains(Utility.DIFF_OPERATION_UPDATE, "update", "old", "new")); assertThat(result.next().values().stream().map(Value::asString).collect(Collectors.toList()), contains(Utility.DIFF_OPERATION_ADD, "new", "null", "new")); assertThat(result.hasNext(), is(false)); } }
@Test public void shouldDiffGetTheDiffBetweenTwoStatesCorrectlyWithDifferentObjectTypes() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (s:State:From {a:1, b:1, c:'stringA', d:'string', e: [1, 2], f: [1, 2]})"); session.run("CREATE (s:State:To {a:2, b:1, c:'stringB', d:'string', e:[1, 2], f: [1, 3]})"); // When StatementResult result = session .run("MATCH (stateTo:State:To), (stateFrom:State:From) WITH stateFrom, stateTo CALL graph.versioner.diff(stateFrom, stateTo) YIELD operation, label, oldValue, newValue RETURN operation, label, oldValue, newValue"); // Then assertThat(result.next().values().stream().map(value -> value.asObject().toString()).collect(Collectors.toList()), contains(Utility.DIFF_OPERATION_UPDATE, "a", "1", "2")); assertThat(result.next().values().stream().map(value -> value.asObject().toString()).collect(Collectors.toList()), contains(Utility.DIFF_OPERATION_UPDATE, "c", "stringA", "stringB")); assertThat(result.next().values().stream().map(value -> value.asObject().toString()).collect(Collectors.toList()), contains(Utility.DIFF_OPERATION_UPDATE, "f", "[1, 2]", "[1, 3]")); assertThat(result.hasNext(), is(false)); } }
@Test public void shouldCreateAnRNodeConnectedToTheEntity() throws Throwable { try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { StatementResult result = session.run("CALL graph.versioner.init('Entity')"); StatementResult rPath = session.run("MATCH rPath = (:R)-[:FOR]->(:Entity) RETURN rPath"); Assertions.assertThat(result.single().get("node").asNode().id()).isEqualTo(0L); Assertions.assertThat(rPath) .hasSize(1) .allMatch(path -> path.get("rPath").asPath().length() == 1); } } }
@Test public void shouldNotCreateTheRelationshipIfDestinationIsNotAnEntity() throws Throwable { try (Driver driver = GraphDatabase .driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given Node entityA = initEntity(session); Node entityB = session.run("CREATE (e:Entity) RETURN e").single().get("e").asNode(); //Not an entity because missing states and R String testType = "testType"; // When String query = "MATCH (a:Entity), (b:Entity) WHERE id(a) = %d AND id(b) = %d WITH a, b CALL graph.versioner.relationship.create(a, b, '%s') YIELD relationship RETURN relationship"; assertThat(session.run(String.format(query, entityA.id(), entityB.id(), testType))); Throwable thrown = catchThrowable(() -> session.run(String.format(query, entityA.id(), entityB.id(), testType))); //Then assertThat(thrown).hasMessageContaining("The given node is not a Versioner Core Entity"); } }
@Test public void shouldCreateAnEntityAndAStateNodeWithoutPropsIfEmptyMapIsPassed() throws Throwable { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase .driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // When StatementResult result = session.run("CALL graph.versioner.init('Entity')"); StatementResult stateResult = session.run("MATCH (s:State) RETURN s"); StatementResult currentResult = session.run("MATCH (e:Entity)-[:CURRENT]->(s:State) RETURN id(e) as id"); Node state = stateResult.single().get("s").asNode(); // Then assertThat(result.single().get("node").asNode().id(), equalTo(0L)); assertThat(state.id(), equalTo(1L)); assertThat(currentResult.single().get("id").asLong(), equalTo(0L)); } }
@Test (expected = ClientException.class) public void shouldNotCreateACopyOfTheGivenStateSinceItsADifferentEntityState() throws Throwable { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase .driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (e:Entity {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'})"); session.run("MATCH (e:Entity {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'}) CREATE (e)-[:HAS_STATE {startDate:localdatetime('1988-10-27T00:00:00')}]->(s)"); session.run("MATCH (e:Entity) CREATE (e)-[:HAS_STATE {startDate:localdatetime('1988-10-26T00:00:00'), endDate:localdatetime('1988-10-27T00:00:00')}]->(s:State:Test {key:'initialValue'})"); session.run("MATCH (sc:State)<-[:CURRENT]-(e:Entity)-[:HAS_STATE]->(s:Test) CREATE (sc)-[:PREVIOUS {date:localdatetime('1988-10-26T00:00:00')}]->(s)"); session.run("CREATE (e:EntityBis {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'})"); session.run("MATCH (e:EntityBis)-[:CURRENT]->(s:State) CREATE (e)-[:HAS_STATE {startDate:localdatetime('1988-10-27T00:00:00')}]->(s)"); StatementResult result = session.run("MATCH (e:Entity), (:EntityBis)-[:HAS_STATE]->(s:State) WITH e, s CALL graph.versioner.patch.from(e, s) YIELD node RETURN node"); Node currentState = result.single().get("node").asNode(); } } }
@Test public void shouldNotCreateTheRelationshipIfSourceIsNotAnEntity() throws Throwable { try (Driver driver = GraphDatabase .driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given Node entityA = session.run("CREATE (e:Entity) RETURN e").single().get("e").asNode(); //Not an entity because missing states and R Node entityB = initEntity(session); String testType = "testType"; // When String query = "MATCH (a:Entity), (b:Entity) WHERE id(a) = %d AND id(b) = %d WITH a, b CALL graph.versioner.relationship.create(a, b, '%s') YIELD relationship RETURN relationship"; assertThat(session.run(String.format(query, entityA.id(), entityB.id(), testType))); Throwable thrown = catchThrowable(() -> session.run(String.format(query, entityA.id(), entityB.id(), testType))); //Then assertThat(thrown).hasMessageContaining("The given node is not a Versioner Core Entity"); } }
@Test public void shouldGetNullIfTheGivenNodeHasAlreadyBeenRolledBack() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase .driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (e:Entity {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'})"); session.run("MATCH (e:Entity {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'}) CREATE (e)-[:HAS_STATE {startDate:localdatetime('1988-10-27T00:00:00')}]->(s)"); session.run("MATCH (e:Entity) CREATE (e)-[:HAS_STATE {startDate:localdatetime('1988-10-26T00:00:00'), endDate:localdatetime('1988-10-27T00:00:00')}]->(s:State:Test {key:'initialValue'})"); session.run("MATCH (sc:State)<-[:CURRENT]-(e:Entity)-[:HAS_STATE]->(s:Test) CREATE (sc)-[:PREVIOUS {date:localdatetime('1988-10-26T00:00:00')}]->(s)"); session.run("MATCH (p:State)<-[:PREVIOUS]-(s:State) CREATE (p)<-[:ROLLBACK]-(s)"); // When StatementResult result = session.run("MATCH (e:Entity)-[:CURRENT]->(s:State) WITH e, s CALL graph.versioner.rollback.to(e, s) YIELD node RETURN node"); // Then Assertions.assertThat(result).isEmpty(); } }
@Test (expected = ClientException.class) public void shouldNotRollbackToTheGivenStateSinceItsADifferentEntityState() throws Throwable { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase .driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (e:Entity {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'})"); session.run("MATCH (e:Entity {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'}) CREATE (e)-[:HAS_STATE {startDate:localdatetime('1988-10-27T00:00:00')}]->(s)"); session.run("MATCH (e:Entity) CREATE (e)-[:HAS_STATE {startDate:localdatetime('1988-10-26T00:00:00'), endDate:localdatetime('1988-10-27T00:00:00')}]->(s:State:Test {key:'initialValue'})"); session.run("MATCH (sc:State)<-[:CURRENT]-(e:Entity)-[:HAS_STATE]->(s:Test) CREATE (sc)-[:PREVIOUS {date:localdatetime('1988-10-26T00:00:00')}]->(s)"); session.run("CREATE (e:EntityBis {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'})"); session.run("MATCH (e:EntityBis)-[:CURRENT]->(s:State) CREATE (e)-[:HAS_STATE {startDate:localdatetime('1988-10-27T00:00:00')}]->(s)"); StatementResult result = session.run("MATCH (e:Entity), (:EntityBis)-[:HAS_STATE]->(s:State) WITH e, s CALL graph.versioner.rollback.to(e, s) YIELD node RETURN node"); } }
@Test public void shouldGetCurrentStateByGivenEntity() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase .driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (e:Entity {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'})"); Node state = session.run("MATCH (s:State) RETURN s").single().get("s").asNode(); // When StatementResult result = session.run("MATCH (e:Entity) WITH e CALL graph.versioner.get.current.state(e) YIELD node RETURN node"); // Then assertThat(result.single().get("node").asNode(), equalTo(state)); } }
@Test public void shouldCreateANewStateFromAnEntityWithoutAStateUsingPatch() throws Throwable { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase .driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (e:Entity {key:'immutableValue'})"); // When StatementResult result = session.run("MATCH (e:Entity) WITH e CALL graph.versioner.patch(e, {key:'newValue'}, 'Error', localdatetime('1988-10-27T02:46:40')) YIELD node RETURN node"); StatementResult correctResult = session.run("MATCH (e:Entity)-[:CURRENT]->(s:State) RETURN id(s) as stateId"); // Then assertThat(correctResult.single().get("stateId").asLong(), equalTo(20L)); } }
@Test public void shouldGetNullIfTheGivenNodeIsTheCurrentState() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase .driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (e:Entity {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'})"); session.run("MATCH (e:Entity {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'}) CREATE (e)-[:HAS_STATE {startDate:localdatetime('1988-10-27T00:00:00')}]->(s)"); // When StatementResult result = session.run("MATCH (e:Entity)-[:CURRENT]->(s:State) WITH e, s CALL graph.versioner.rollback.to(e, s) YIELD node RETURN node"); // Then Assertions.assertThat(result).isEmpty(); } }
@Test public void shouldCreateANewStateFromAnEntityWithoutAState() throws Throwable { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase .driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (e:Entity {key:'immutableValue'})"); // When StatementResult result = session.run("MATCH (e:Entity) WITH e CALL graph.versioner.update(e, {key:'newValue'}, 'Error', localdatetime('1988-10-27T02:46:40')) YIELD node RETURN node"); StatementResult correctResult = session.run("MATCH (e:Entity)-[:CURRENT]->(s:State) RETURN id(s) as stateId"); // Then assertThat(correctResult.single().get("stateId").asLong(), equalTo(20L)); } }
@Test public void shouldDiffFromCurrentGetNoDiffIfGivenCurrentState() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (:Entity)"); session.run("MATCH (e:Entity) CREATE (e)-[:HAS_STATE]->(s:State:To {keep:'keep', update:'new', new:'new'})"); session.run("MATCH (to:To)-[:HAS_STATE]-(e:Entity) CREATE (e)-[:CURRENT]->(to)"); // When StatementResult result = session .run("MATCH (stateTo:To) WITH stateTo CALL graph.versioner.diff.from.current(stateTo) YIELD operation, label, oldValue, newValue RETURN operation, label, oldValue, newValue"); // Then assertThat(result.hasNext(), is(false)); } }
@Test public void shouldGetNullIfThereIsNoPreviousState() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase .driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (e:Entity {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'})"); session.run("MATCH (e:Entity {key:'immutableValue'})-[:CURRENT {date:localdatetime('1988-10-27T00:00:00')}]->(s:State {key:'initialValue'}) CREATE (e)-[:HAS_STATE {startDate:localdatetime('1988-10-27T00:00:00')}]->(s)"); // When StatementResult result = session.run("MATCH (e:Entity) WITH e CALL graph.versioner.rollback(e) YIELD node RETURN node"); // Then Assertions.assertThat(result).isEmpty(); } }
@Test public void shouldDiffGetNoDiffIfStatesAreEqual() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (s:State:From {keep:'keep', update:'update', delete:'delete'})"); session.run("CREATE (s:State:To {keep:'keep', update:'update', delete:'delete'})"); // When StatementResult result = session .run("MATCH (stateTo:State:To), (stateFrom:State:From) WITH stateFrom, stateTo CALL graph.versioner.diff(stateFrom, stateTo) YIELD operation, label, oldValue, newValue RETURN operation, label, oldValue, newValue"); // Then assertThat(result.hasNext(), is(false)); } }
@Test public void shouldDiffFromPreviousGetNoDiffIfOneOfTheTwoStatesAreNull() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given // An empty database // When StatementResult result = session .run("MATCH (stateFrom:State:From) WITH stateFrom CALL graph.versioner.diff.from.previous(stateFrom) YIELD operation, label, oldValue, newValue RETURN operation, label, oldValue, newValue"); // Then assertThat(result.hasNext(), is(false)); } }
@Test public void shouldDiffFromPreviousGetNoDiffIfNoPreviousState() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given session.run("CREATE (s:State:To {keep:'keep', update:'update', delete:'delete'})"); // When StatementResult result = session .run("MATCH (stateTo:To) WITH stateTo CALL graph.versioner.diff.from.previous(stateTo) YIELD operation, label, oldValue, newValue RETURN operation, label, oldValue, newValue"); // Then assertThat(result.hasNext(), is(false)); } }
@Test public void shouldDiffFromCurrentGetNoDiffIfInputStateDoesNotExist() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given // A db with no states // When StatementResult result = session .run("MATCH (stateTo:Entity) WITH stateTo CALL graph.versioner.diff.from.current(stateTo) YIELD operation, label, oldValue, newValue RETURN operation, label, oldValue, newValue"); // Then assertThat(result.hasNext(), is(false)); } }
@Test public void shouldDiffGetNoDiffIfOneOfTheTwoStatesIsNull() { // This is in a try-block, to make sure we close the driver after the test try (Driver driver = GraphDatabase.driver(neo4j.boltURI(), Config.build().withEncryption().toConfig()); Session session = driver.session()) { // Given // An empty database // When StatementResult result = session .run("MATCH (stateTo:Entity), (stateFrom:State:From) WITH stateFrom, stateTo CALL graph.versioner.diff(stateFrom, stateTo) YIELD operation, label, oldValue, newValue RETURN operation, label, oldValue, newValue"); // Then assertThat(result.hasNext(), is(false)); } }