From 84ccd669bbf539233d9813ed9a18b06b8c0393af Mon Sep 17 00:00:00 2001 From: Gemma Lamont Date: Mon, 27 Jan 2025 16:10:51 +0100 Subject: [PATCH] Add start/stop db test --- common/build.gradle | 1 + .../main/java/apoc/ApocExtensionFactory.java | 3 +- .../apoc/trigger/TriggerEnterpriseDbTest.java | 85 +++++++++++++++++++ test-utils/build.gradle | 1 + .../rule/EnterpriseImpermanentDbmsRule.java | 65 ++++++++++++++ 5 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 core/src/test/java/apoc/trigger/TriggerEnterpriseDbTest.java create mode 100644 test-utils/src/main/java/org/neo4j/test/rule/EnterpriseImpermanentDbmsRule.java diff --git a/common/build.gradle b/common/build.gradle index 134902217..54589ae57 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -50,6 +50,7 @@ dependencies { testImplementation group: 'com.github.stefanbirkner', name: 'system-rules', version: '1.19.0' testImplementation group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3' testImplementation group: 'org.neo4j.community', name: 'it-test-support', version: neo4jVersionEffective // , classifier: "tests" + testImplementation group: 'com.neo4j', name: 'enterprise-it-test-support', version: neo4jVersionEffective // , classifier: "tests" testImplementation group: 'org.neo4j', name: 'log-test-utils', version: neo4jVersionEffective // , classifier: "tests" testImplementation group: 'org.neo4j', name: 'neo4j-kernel', version: neo4jVersionEffective, classifier: "tests" testImplementation group: 'org.assertj', name: 'assertj-core', version: '3.26.3' diff --git a/common/src/main/java/apoc/ApocExtensionFactory.java b/common/src/main/java/apoc/ApocExtensionFactory.java index 16d51a13e..959b57ad7 100644 --- a/common/src/main/java/apoc/ApocExtensionFactory.java +++ b/common/src/main/java/apoc/ApocExtensionFactory.java @@ -167,7 +167,7 @@ public void stop() { registeredListeners.forEach(availabilityGuard::removeListener); registeredListeners.clear(); } - + @Override public void shutdown() throws Exception { String databaseName = db.databaseName(); @@ -175,7 +175,6 @@ public void shutdown() throws Exception { .registerComponentLifecycle() .cleanUpResolver(databaseName, lifecycle.getClass())); } - public Collection getRegisteredListeners() { return registeredListeners; diff --git a/core/src/test/java/apoc/trigger/TriggerEnterpriseDbTest.java b/core/src/test/java/apoc/trigger/TriggerEnterpriseDbTest.java new file mode 100644 index 000000000..ed508a809 --- /dev/null +++ b/core/src/test/java/apoc/trigger/TriggerEnterpriseDbTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package apoc.trigger; + +import static apoc.ApocConfig.APOC_TRIGGER_ENABLED; +import static apoc.trigger.TriggerTestUtil.TIMEOUT; +import static apoc.util.TestUtil.testCallEventually; +import static org.junit.Assert.assertEquals; +import static org.neo4j.configuration.GraphDatabaseSettings.procedure_unrestricted; + +import apoc.nodes.Nodes; +import apoc.util.TestUtil; +import java.util.List; +import java.util.Map; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.ProvideSystemProperty; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.test.rule.DbmsRule; +import org.neo4j.test.rule.EnterpriseImpermanentDbmsRule; + +public class TriggerEnterpriseDbTest { + // we cannot set via apocConfig().setProperty(apoc.trigger.enabled, ...) in `@Before`, because is too late + @ClassRule + public static final ProvideSystemProperty systemPropertyRule = + new ProvideSystemProperty(APOC_TRIGGER_ENABLED, String.valueOf(true)); + + @Rule + public DbmsRule db = new EnterpriseImpermanentDbmsRule().withSetting(procedure_unrestricted, List.of("apoc*")); + + @Before + public void setUp() { + TestUtil.registerProcedure(db, TriggerNewProcedures.class, Nodes.class); + } + + @After + public void teardown() { + db.shutdown(); + } + + @Test + public void testStopStartOfTrigger() { + GraphDatabaseService sysDb = db.getManagementService().database("system"); + GraphDatabaseService neo4jDb = db.getManagementService().database("neo4j"); + + neo4jDb.executeTransactionally("CREATE (:Counter {count:0})"); + neo4jDb.executeTransactionally("CREATE (f:Foo)"); + final String name = "count-removals"; + String query = "MATCH (c:Counter) SET c.count = c.count + size([f IN $deletedNodes WHERE id(f) > 0])"; + + sysDb.executeTransactionally( + "CALL apoc.trigger.install('neo4j', $name, $query, {})", Map.of("name", name, "query", query)); + + db.getManagementService().shutdownDatabase("neo4j"); + db.getManagementService().startDatabase("neo4j"); + + // Re-fetch db + neo4jDb = db.getManagementService().database("neo4j"); + neo4jDb.executeTransactionally("MATCH (f:Foo) DELETE f"); + testCallEventually( + neo4jDb, + "MATCH (c:Counter) RETURN c.count as count", + (row) -> assertEquals(1L, row.get("count")), + TIMEOUT); + } +} diff --git a/test-utils/build.gradle b/test-utils/build.gradle index 5769fb97f..6e426689d 100644 --- a/test-utils/build.gradle +++ b/test-utils/build.gradle @@ -28,6 +28,7 @@ dependencies { api group: 'org.hamcrest', name: 'hamcrest', version: '2.2' api group: 'org.hamcrest', name: 'hamcrest-library', version: '2.2' api group: 'org.neo4j.community', name: 'it-test-support', version: neo4jVersionEffective // , classifier: "tests" + api group: 'com.neo4j', name: 'enterprise-it-test-support', version: neo4jVersionEffective // , classifier: "tests" api group: 'org.neo4j', name: 'log-test-utils', version: neo4jVersionEffective // , classifier: "tests" api group: 'org.neo4j.driver', name: 'neo4j-java-driver', version: '5.18.0' api group: 'org.apache.hadoop', name: 'hadoop-hdfs', version: '3.4.0', withoutServers.andThen(withoutLoggers) diff --git a/test-utils/src/main/java/org/neo4j/test/rule/EnterpriseImpermanentDbmsRule.java b/test-utils/src/main/java/org/neo4j/test/rule/EnterpriseImpermanentDbmsRule.java new file mode 100644 index 000000000..9339c4723 --- /dev/null +++ b/test-utils/src/main/java/org/neo4j/test/rule/EnterpriseImpermanentDbmsRule.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) "Neo4j" + * Neo4j Sweden AB [http://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.neo4j.test.rule; + +import com.neo4j.test.TestEnterpriseDatabaseManagementServiceBuilder; +import org.neo4j.dbms.api.Neo4jDatabaseManagementServiceBuilder; +import org.neo4j.logging.ExternalLogProviderWrapper; +import org.neo4j.logging.LogProvider; +import org.neo4j.test.TestDatabaseManagementServiceBuilder; + +/** + * JUnit @Rule for configuring, creating and managing an ImpermanentGraphDatabase instance. + */ +public class EnterpriseImpermanentDbmsRule extends DbmsRule { + private final LogProvider userLogProvider; + private final LogProvider internalLogProvider; + + public EnterpriseImpermanentDbmsRule() { + this(null); + } + + public EnterpriseImpermanentDbmsRule(LogProvider logProvider) { + this.userLogProvider = logProvider; + this.internalLogProvider = logProvider; + } + + @Override + public ImpermanentDbmsRule startLazily() { + return (ImpermanentDbmsRule) super.startLazily(); + } + + @Override + protected Neo4jDatabaseManagementServiceBuilder newFactory() { + return maybeSetInternalLogProvider( + maybeSetUserLogProvider(new TestEnterpriseDatabaseManagementServiceBuilder().impermanent())); + } + + protected final TestDatabaseManagementServiceBuilder maybeSetUserLogProvider( + TestDatabaseManagementServiceBuilder factory) { + return (userLogProvider == null) ? factory : factory.setUserLogProvider(userLogProvider); + } + + protected final TestDatabaseManagementServiceBuilder maybeSetInternalLogProvider( + TestDatabaseManagementServiceBuilder factory) { + return (internalLogProvider == null) + ? factory + : factory.setInternalLogProvider(new ExternalLogProviderWrapper(internalLogProvider)); + } +}