Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[gRNAet7B] Fixes trigger procedures in clusters for neo4j 5.x (extended part) #3330

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,6 @@
path = apoc-core
url = https://github.com/neo4j/apoc
branch = dev
[submodule "apoc"]
path = apoc
url = https://[email protected]/neo4j/apoc.git
1 change: 1 addition & 0 deletions apoc
Submodule apoc added at c57579
2 changes: 1 addition & 1 deletion apoc-core
Submodule apoc-core updated 260 files
134 changes: 128 additions & 6 deletions extended/src/test/java/apoc/trigger/TriggerClusterTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,26 @@
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.neo4j.driver.types.Node;
import org.neo4j.driver.Session;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.neo4j.configuration.GraphDatabaseSettings.DEFAULT_DATABASE_NAME;
import static org.neo4j.configuration.GraphDatabaseSettings.SYSTEM_DATABASE_NAME;
import static org.neo4j.driver.SessionConfig.forDatabase;
import static org.neo4j.test.assertion.Assert.assertEventually;

public class TriggerClusterTest {

private static final String DB_FOO = "foo";
private static TestcontainersCausalCluster cluster;

@BeforeClass
Expand All @@ -43,7 +50,6 @@ public void before() {
cluster.getSession().run("MATCH (n) DETACH DELETE n");
}

@Ignore
@Test
public void testTimeStampTriggerForUpdatedProperties() throws Exception {
cluster.getSession().run("CALL apoc.trigger.add('timestamp','UNWIND apoc.trigger.nodesByLabel($assignedNodeProperties,null) AS n SET n.ts = timestamp()',{})");
Expand All @@ -53,7 +59,6 @@ public void testTimeStampTriggerForUpdatedProperties() throws Exception {
});
}

@Ignore
@Test
public void testReplication() throws Exception {
cluster.getSession().run("CALL apoc.trigger.add('timestamp','UNWIND apoc.trigger.nodesByLabel($assignedNodeProperties,null) AS n SET n.ts = timestamp()',{})");
Expand All @@ -63,7 +68,6 @@ public void testReplication() throws Exception {
(value) -> "timestamp".equals(value), 30, TimeUnit.SECONDS);
}

@Ignore
@Test
public void testLowerCaseName() throws Exception {
cluster.getSession().run("create constraint on (p:Person) assert p.id is unique");
Expand All @@ -75,7 +79,6 @@ public void testLowerCaseName() throws Exception {
});
}

@Ignore
@Test
public void testSetLabels() throws Exception {
cluster.getSession().run("CREATE (f {name:'John Doe'})");
Expand All @@ -90,7 +93,6 @@ public void testSetLabels() throws Exception {
assertEquals(1L, count);
}

@Ignore
@Test
public void testTxIdAfterAsync() throws Exception {
cluster.getSession().run("CALL apoc.trigger.add('triggerTest','UNWIND apoc.trigger.propertiesByKey($assignedNodeProperties, \"_executed\") as prop " +
Expand All @@ -103,4 +105,124 @@ public void testTxIdAfterAsync() throws Exception {
org.neo4j.test.assertion.Assert.assertEventually(() -> TestContainerUtil.<Long>singleResultFirstColumn(cluster.getSession(), "MATCH p = ()-[r:GENERATED]->() RETURN count(p) AS count"),
(value) -> value == 2L, 30, TimeUnit.SECONDS);
}


//
// test cases duplicated, regarding new procedures
//

@Test
public void testTimeStampTriggerForUpdatedPropertiesNewProcedures() throws Exception {
final String name = "timestampUpdate";
try (final Session session = cluster.getDriver().session(forDatabase(SYSTEM_DATABASE_NAME))) {
session.run("CALL apoc.trigger.install('neo4j', $name,'UNWIND apoc.trigger.nodesByLabel($assignedNodeProperties,null) AS n SET n.ts = timestamp()',{})",
Map.of("name", name));
}
try (final Session session = cluster.getSession()) {
awaitProcedureInstalled(session, "timestampUpdate");
session.run("CREATE (f:Foo) SET f.foo='bar'");
TestContainerUtil.testCall(session, "MATCH (f:Foo) RETURN f", (row) -> {
assertTrue(((Node) row.get("f")).containsKey("ts"));
});
}
}

@Test
public void testReplicationNewProcedures() throws Exception {
try (final Session session = cluster.getDriver().session(forDatabase(SYSTEM_DATABASE_NAME))) {
session.run("CALL apoc.trigger.install('neo4j', 'timestamp','UNWIND apoc.trigger.nodesByLabel($assignedNodeProperties,null) AS n SET n.ts = timestamp()',{})");
}
// Test that the trigger is present in another instance
awaitProcedureInstalled(cluster.getDriver().session(), "timestamp");
}

@Test
public void testLowerCaseNameNewProcedures() {
final String name = "lowercase";
try (final Session session = cluster.getDriver().session(forDatabase(SYSTEM_DATABASE_NAME))) {
session.run("CALL apoc.trigger.install('neo4j', $name, 'UNWIND apoc.trigger.nodesByLabel($assignedLabels,\"Person\") AS n SET n.id = toLower(n.name)',{})",
Map.of("name", name));
}
try (final Session session = cluster.getSession()) {
session.run("create constraint on (p:Person) assert p.id is unique");
awaitProcedureInstalled(session, name);

session.run("CREATE (f:Person {name:'John Doe'})");
TestContainerUtil.testCall(session, "MATCH (f:Person) RETURN f", (row) -> {
assertEquals("john doe", ((Node) row.get("f")).get("id").asString());
assertEquals("John Doe", ((Node) row.get("f")).get("name").asString());
});
}
}

@Test
public void testSetLabelsNewProcs() throws Exception {
final String name = "testSetLabels";
try (final Session session = cluster.getDriver().session(forDatabase(SYSTEM_DATABASE_NAME))) {
session.run("CALL apoc.trigger.install('neo4j', $name,'UNWIND apoc.trigger.nodesByLabel($assignedLabels,\"Person\") AS n SET n:Man',{})",
Map.of("name", name));
}
try (final Session session = cluster.getSession()) {
session.run("CREATE (f:Test {name:'John Doe'})");

awaitProcedureInstalled(session, name);

session.run("MATCH (f:Test) SET f:Person");
TestContainerUtil.testCall(session, "MATCH (f:Man) RETURN f", (row) -> {
assertEquals("John Doe", ((Node) row.get("f")).get("name").asString());
assertTrue(((Node) row.get("f")).hasLabel("Person"));
});

long count = TestContainerUtil.singleResultFirstColumn(session, "MATCH (f:Man) RETURN count(*) as c");
assertEquals(1L, count);
}
}

@Test
public void testTxIdAfterAsyncNewProcedures() throws Exception {
final String name = "testTxIdAfterAsync";
try (final Session session = cluster.getDriver().session(forDatabase(SYSTEM_DATABASE_NAME))) {
session.run("CALL apoc.trigger.install('neo4j', $name, 'UNWIND apoc.trigger.propertiesByKey($assignedNodeProperties, \"_executed\") as prop " +
" WITH prop.node as n " +
" CREATE (z:SON {father:id(n)}) " +
" CREATE (n)-[:GENERATED]->(z)', " +
"{phase:'afterAsync'})",
Map.of("name", name));
}
try (final Session session = cluster.getSession()) {
awaitProcedureInstalled(session, name);

session.run("CREATE (:TEST {name:'x', _executed:0})");
session.run("CREATE (:TEST {name:'y', _executed:0})");
assertEventually(() -> TestContainerUtil.<Long>singleResultFirstColumn(session, "MATCH p = ()-[r:GENERATED]->() RETURN count(p) AS count"),
(value) -> value == 2L, 30, TimeUnit.SECONDS);
}
}

private static void awaitProcedureInstalled(Session session, String name) {
assertEventually(() -> session
.readTransaction(tx -> tx.run("CALL apoc.trigger.list")
.single().get("name").asString()),
name::equals,
30, TimeUnit.SECONDS);
}

@Test
public void testTriggerCreatedInCorrectDatabase() {
final String name = "testDatabase";
try (final Session session = cluster.getDriver().session(forDatabase(SYSTEM_DATABASE_NAME))) {
session.run("CALL apoc.trigger.install($dbName, $name, 'RETURN 1', " +
"{phase:'afterAsync'})",
Map.of("dbName", DB_FOO, "name", name));
}
try (final Session session = cluster.getDriver().session(forDatabase(DB_FOO))) {
awaitProcedureInstalled(session, name);
}
try (final Session session = cluster.getDriver().session(forDatabase(DEFAULT_DATABASE_NAME))) {
TestContainerUtil.testResult(session, "CALL apoc.trigger.list() " +
"YIELD name WHERE name = $name RETURN name",
Map.of("name", name),
res -> assertFalse(res.hasNext()));
}
}
}
Loading