diff --git a/core-it/src/test/java/apoc/core/it/CollEnterpriseTest.java b/core-it/src/test/java/apoc/core/it/CollEnterpriseTest.java index 5f2ba5764c..174fe5ca8e 100644 --- a/core-it/src/test/java/apoc/core/it/CollEnterpriseTest.java +++ b/core-it/src/test/java/apoc/core/it/CollEnterpriseTest.java @@ -30,11 +30,7 @@ import org.neo4j.driver.Session; import static apoc.util.TestContainerUtil.createEnterpriseDB; -import static apoc.util.TestUtil.isRunningInCI; import static org.junit.Assert.assertEquals; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; public class CollEnterpriseTest { @@ -43,35 +39,27 @@ public class CollEnterpriseTest { @BeforeAll public static void beforeAll() { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - // We build the project, the artifact will be placed into ./build/libs - neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !TestUtil.isRunningInCI()); - neo4jContainer.start(); - }, Exception.class); - assumeTrue(neo4jContainer.isRunning()); - assumeNotNull(neo4jContainer); - assumeTrue("Neo4j Instance should be up-and-running", neo4jContainer.isRunning()); + // We build the project, the artifact will be placed into ./build/libs + neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !TestUtil.isRunningInCI()); + neo4jContainer.start(); session = neo4jContainer.getSession(); } @AfterAll public static void afterAll() { - if (neo4jContainer != null && neo4jContainer.isRunning()) { - session.close(); - neo4jContainer.close(); - } + session.close(); + neo4jContainer.close(); } @RepeatedTest(50) - public void testMin() throws Exception { + public void testMin() { assertEquals(1L, session.run("RETURN apoc.coll.min([1,2]) as value").next().get("value").asLong()); assertEquals(1L, session.run("RETURN apoc.coll.min([1,2,3]) as value").next().get("value").asLong()); assertEquals(0.5D, session.run("RETURN apoc.coll.min([0.5,1,2.3]) as value").next().get("value").asDouble(), 0.1); } @RepeatedTest(50) - public void testMax() throws Exception { + public void testMax() { assertEquals(3L, session.run("RETURN apoc.coll.max([1,2,3]) as value").next().get("value").asLong()); assertEquals(2.3D, session.run("RETURN apoc.coll.max([0.5,1,2.3]) as value").next().get("value").asDouble(), 0.1); } diff --git a/core-it/src/test/java/apoc/core/it/CypherEnterpriseTest.java b/core-it/src/test/java/apoc/core/it/CypherEnterpriseTest.java index 2cb446bfa7..fa34792bb1 100644 --- a/core-it/src/test/java/apoc/core/it/CypherEnterpriseTest.java +++ b/core-it/src/test/java/apoc/core/it/CypherEnterpriseTest.java @@ -1,6 +1,7 @@ package apoc.core.it; import apoc.util.Neo4jContainerExtension; +import apoc.util.TestUtil; import org.assertj.core.api.Assertions; import org.junit.After; import org.junit.AfterClass; @@ -31,7 +32,7 @@ public class CypherEnterpriseTest { @BeforeClass public static void beforeAll() { - neo4jContainer = createEnterpriseDB(List.of(ApocPackage.CORE), true); + neo4jContainer = createEnterpriseDB(List.of(ApocPackage.CORE), !TestUtil.isRunningInCI()); neo4jContainer.start(); session = neo4jContainer.getSession(); } diff --git a/core-it/src/test/java/apoc/core/it/ExportCsvIT.java b/core-it/src/test/java/apoc/core/it/ExportCsvIT.java index cf0344cf4e..ec91bb5dbe 100644 --- a/core-it/src/test/java/apoc/core/it/ExportCsvIT.java +++ b/core-it/src/test/java/apoc/core/it/ExportCsvIT.java @@ -36,9 +36,6 @@ import static apoc.util.TestUtil.isRunningInCI; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; /** * @author as @@ -51,25 +48,19 @@ public class ExportCsvIT { @BeforeClass public static void beforeAll() { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), true); - neo4jContainer.start(); - }, Exception.class); - assumeNotNull(neo4jContainer); - assumeTrue("Neo4j Instance should be up-and-running", neo4jContainer.isRunning()); + neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !isRunningInCI()); + neo4jContainer.start(); session = neo4jContainer.getSession(); } @AfterClass - public static void afterAll() throws IOException, InterruptedException { - if (neo4jContainer != null && neo4jContainer.isRunning()) { - neo4jContainer.close(); - } + public static void afterAll() { + session.close(); + neo4jContainer.close(); } @Test - public void testExportQueryCsvIssue1188() throws Exception { + public void testExportQueryCsvIssue1188() { String copyright = "\n" + "(c) 2018 Hovsepian, Albanese, et al. \"\"ASCB(r),\"\" \"\"The American Society for Cell Biology(r),\"\" and \"\"Molecular Biology of the Cell(r)\"\" are registered trademarks of The American Society for Cell Biology.\n" + "2018\n" + diff --git a/core-it/src/test/java/apoc/core/it/ExportCypherEnterpriseFeaturesTest.java b/core-it/src/test/java/apoc/core/it/ExportCypherEnterpriseFeaturesTest.java index 2266fc4617..5e4fd846ce 100644 --- a/core-it/src/test/java/apoc/core/it/ExportCypherEnterpriseFeaturesTest.java +++ b/core-it/src/test/java/apoc/core/it/ExportCypherEnterpriseFeaturesTest.java @@ -19,7 +19,6 @@ package apoc.core.it; import apoc.util.Neo4jContainerExtension; -import apoc.util.TestContainerUtil; import apoc.util.TestUtil; import apoc.util.Util; import org.hamcrest.MatcherAssert; @@ -37,13 +36,9 @@ import static apoc.export.cypher.ExportCypherTest.ExportCypherResults.*; import static apoc.util.MapUtil.map; import static apoc.util.TestContainerUtil.*; -import static apoc.util.TestUtil.isRunningInCI; import static apoc.util.TestUtil.readFileToString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; /** * @author as @@ -56,23 +51,15 @@ public class ExportCypherEnterpriseFeaturesTest { @BeforeClass public static void beforeAll() { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - // We build the project, the artifact will be placed into ./build/libs - neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !TestUtil.isRunningInCI()) - .withInitScript("init_neo4j_export_csv.cypher"); - neo4jContainer.start(); - }, Exception.class); - assumeNotNull(neo4jContainer); - assumeTrue("Neo4j Instance should be up-and-running", neo4jContainer.isRunning()); + neo4jContainer = createEnterpriseDB(List.of(ApocPackage.CORE), !TestUtil.isRunningInCI()).withInitScript("init_neo4j_export_csv.cypher"); + neo4jContainer.start(); session = neo4jContainer.getSession(); } @AfterClass public static void afterAll() { - if (neo4jContainer != null && neo4jContainer.isRunning()) { - neo4jContainer.close(); - } + session.close(); + neo4jContainer.close(); } private static void beforeTwoLabelsWithOneCompoundConstraintEach() { diff --git a/core-it/src/test/java/apoc/core/it/GraphRefactoringEnterpriseTest.java b/core-it/src/test/java/apoc/core/it/GraphRefactoringEnterpriseTest.java index 9bb752bb6f..716b1be1c4 100644 --- a/core-it/src/test/java/apoc/core/it/GraphRefactoringEnterpriseTest.java +++ b/core-it/src/test/java/apoc/core/it/GraphRefactoringEnterpriseTest.java @@ -34,12 +34,8 @@ import static apoc.refactor.GraphRefactoringTest.EXTRACT_QUERY; import static apoc.util.TestContainerUtil.createEnterpriseDB; import static apoc.util.TestContainerUtil.testCall; -import static apoc.util.TestUtil.isRunningInCI; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; public class GraphRefactoringEnterpriseTest { private static final String CREATE_REL_FOR_EXTRACT_NODE = "CREATE (:Start)-[r:TO_MOVE {name: 'foobar', surname: 'baz'}]->(:End)"; @@ -49,22 +45,15 @@ public class GraphRefactoringEnterpriseTest { @BeforeClass public static void beforeAll() { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), true); - neo4jContainer.start(); - }, Exception.class); - assumeNotNull(neo4jContainer); - assumeTrue("Neo4j Instance should be up-and-running", neo4jContainer.isRunning()); + neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !TestUtil.isRunningInCI()); + neo4jContainer.start(); session = neo4jContainer.getSession(); } @AfterClass public static void afterAll() { - if (neo4jContainer != null && neo4jContainer.isRunning()) { - session.close(); - neo4jContainer.close(); - } + session.close(); + neo4jContainer.close(); } @Test diff --git a/core-it/src/test/java/apoc/core/it/LoadCoreEnterpriseTest.java b/core-it/src/test/java/apoc/core/it/LoadCoreEnterpriseTest.java index 6caded1c6b..a180c8f088 100644 --- a/core-it/src/test/java/apoc/core/it/LoadCoreEnterpriseTest.java +++ b/core-it/src/test/java/apoc/core/it/LoadCoreEnterpriseTest.java @@ -21,6 +21,7 @@ import apoc.util.CompressionAlgo; import apoc.util.Neo4jContainerExtension; import apoc.util.TestContainerUtil; +import apoc.util.TestUtil; import org.apache.commons.io.FileUtils; import org.assertj.core.api.Assertions; import org.junit.AfterClass; @@ -65,7 +66,7 @@ public class LoadCoreEnterpriseTest { } private static Neo4jContainerExtension createNeo4jWithMaxCompressionRatio(int ratio) { - Neo4jContainerExtension container = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), true) + Neo4jContainerExtension container = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !TestUtil.isRunningInCI()) .withNeo4jConfig("dbms.memory.heap.max_size", "1GB") .withEnv(APOC_MAX_DECOMPRESSION_RATIO, String.valueOf(ratio)); container.start(); diff --git a/core-it/src/test/java/apoc/core/it/MetaEnterpriseFeaturesTest.java b/core-it/src/test/java/apoc/core/it/MetaEnterpriseFeaturesTest.java index 2988e592c1..cf7e789921 100644 --- a/core-it/src/test/java/apoc/core/it/MetaEnterpriseFeaturesTest.java +++ b/core-it/src/test/java/apoc/core/it/MetaEnterpriseFeaturesTest.java @@ -34,12 +34,8 @@ import static apoc.util.TestContainerUtil.createEnterpriseDB; import static apoc.util.TestContainerUtil.testResult; -import static apoc.util.TestUtil.isRunningInCI; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; /** * @author as @@ -52,21 +48,16 @@ public class MetaEnterpriseFeaturesTest { @BeforeClass public static void beforeAll() { - assumeFalse(isRunningInCI()); // We build the project, the artifact will be placed into ./build/libs neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !TestUtil.isRunningInCI()); neo4jContainer.start(); - assumeNotNull(neo4jContainer); - assumeTrue("Neo4j Instance should be up-and-running", neo4jContainer.isRunning()); session = neo4jContainer.getSession(); } @AfterClass public static void afterAll() { - if (neo4jContainer != null && neo4jContainer.isRunning()) { - session.close(); - neo4jContainer.close(); - } + session.close(); + neo4jContainer.close(); } public static boolean hasRecordMatching(List> records, Predicate> predicate) { diff --git a/core-it/src/test/java/apoc/core/it/SchemasEnterpriseFeaturesTest.java b/core-it/src/test/java/apoc/core/it/SchemasEnterpriseFeaturesTest.java index 168117c32d..87552a7815 100644 --- a/core-it/src/test/java/apoc/core/it/SchemasEnterpriseFeaturesTest.java +++ b/core-it/src/test/java/apoc/core/it/SchemasEnterpriseFeaturesTest.java @@ -20,6 +20,7 @@ import apoc.util.Neo4jContainerExtension; import apoc.util.TestContainerUtil; +import apoc.util.TestUtil; import org.apache.commons.lang3.StringUtils; import org.assertj.core.api.Assertions; import org.junit.AfterClass; @@ -55,7 +56,7 @@ public class SchemasEnterpriseFeaturesTest { @BeforeClass public static void beforeAll() { - neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), true); + neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !TestUtil.isRunningInCI()); neo4jContainer.start(); session = neo4jContainer.getSession(); } diff --git a/core-it/src/test/java/apoc/core/it/StartupTest.java b/core-it/src/test/java/apoc/core/it/StartupTest.java index f0ac47ec20..06fb17f6ad 100644 --- a/core-it/src/test/java/apoc/core/it/StartupTest.java +++ b/core-it/src/test/java/apoc/core/it/StartupTest.java @@ -5,31 +5,18 @@ import apoc.util.Neo4jContainerExtension; import apoc.util.TestContainerUtil; import apoc.util.TestUtil; -import org.apache.commons.io.FileUtils; +import apoc.util.TestContainerUtil.Neo4jVersion; +import apoc.util.TestContainerUtil.ApocPackage; import org.junit.Test; -import org.neo4j.driver.Record; import org.neo4j.driver.Session; -import org.neo4j.graphdb.config.Setting; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; -import java.util.function.Supplier; import java.util.stream.Collectors; -import static apoc.ApocConfig.APOC_MAX_DECOMPRESSION_RATIO; -import static apoc.ApocSettings.apoc_export_file_enabled; -import static apoc.ApocSettings.apoc_import_file_enabled; -import static apoc.ApocSettings.apoc_import_file_use__neo4j__config; -import static apoc.ApocSettings.apoc_jobs_pool_num_threads; -import static apoc.ApocSettings.apoc_max_decompression_ratio; -import static apoc.ApocSettings.apoc_ttl_enabled; -import static apoc.ApocSettings.apoc_ttl_schedule; -import static apoc.util.TestContainerUtil.createEnterpriseDB; +import static apoc.util.TestContainerUtil.createDB; +import static apoc.util.TestContainerUtil.dockerImageForNeo4j; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -44,131 +31,106 @@ public class StartupTest { @Test public void check_basic_deployment() { - startNeo4jContainerSession(() -> createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), !TestUtil.isRunningInCI()) - .withNeo4jConfig("dbms.transaction.timeout", "5s"), - session -> { - int procedureCount = session.run("CALL dbms.procedures() YIELD name WHERE name STARTS WITH 'apoc' RETURN count(*) AS count").peek().get("count").asInt(); - int functionCount = session.run("CALL dbms.functions() YIELD name WHERE name STARTS WITH 'apoc' RETURN count(*) AS count").peek().get("count").asInt(); - int coreCount = session.run("CALL apoc.help('') YIELD core WHERE core = true RETURN count(*) AS count").peek().get("count").asInt(); - - assertTrue(procedureCount > 0); - assertTrue(functionCount > 0); - assertTrue(coreCount > 0); - }, neo4jContainer -> {} - ); - } - - @Test - public void compare_with_sources() { - startNeo4jContainerSession(() -> createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), !TestUtil.isRunningInCI()), - this::checkCoreProcsAndFuncsExistence, - neo4jContainer -> {} - ); - - } - - @Test - public void checkFullWithExtraDependenciesJars() throws IOException { - - // we retrieve every full procedure and function via the extended.txt file - final File extendedFile = new File(TestContainerUtil.fullDir, "src/main/resources/extended.txt"); - final List expectedFullProcAndFunNames = FileUtils.readLines(extendedFile, StandardCharsets.UTF_8); - - // we check that with apoc-full jar and all extra-dependencies jars every procedure/function is detected - startNeo4jContainerSession(() -> createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), !TestUtil.isRunningInCI(), true), - session -> { - checkCoreProcsAndFuncsExistence(session); - - // all full procedures and functions are present, also the ones which require extra-deps, e.g. the apoc.export.xls.* - final List actualFullProcAndFunNames = session.run("CALL apoc.help('') YIELD core, type, name WHERE core = false RETURN name").list(i -> i.get("name").asString()); - assertEquals(sorted(expectedFullProcAndFunNames), sorted(actualFullProcAndFunNames)); - }, - neo4jContainer -> {} - ); - } - - @Test - public void checkCoreWithExtraDependenciesJars() { - // we check that with apoc-core jar and all extra-dependencies jars every procedure/function is detected - startNeo4jContainerSession(() -> createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !TestUtil.isRunningInCI(), true), - this::checkCoreProcsAndFuncsExistence, (neo4jContainer) -> {}); - - } - - @Test - public void checkCypherInitializerWaitsForSystemDbToBeAvailable() { - // we check that with apoc-core jar and all extra-dependencies jars every procedure/function is detected - startNeo4jContainerSession(() -> createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !TestUtil.isRunningInCI(), true) - .withEnv("apoc.initializer.system.0", "CREATE USER dummy IF NOT EXISTS SET PASSWORD \"pass12345\" CHANGE NOT REQUIRED") - .withEnv("apoc.initializer.system.1", "GRANT ROLE reader TO dummy"), - session -> { - assertEventually(() -> - session.run( "SHOW USERS YIELD roles, user WHERE user = 'dummy' RETURN roles" ).stream() - .collect( Collectors.toList() ), (result) -> - result.size() > 0 && result.get(0).get( "roles" ).asList().contains("reader" ), - 30, TimeUnit.SECONDS - ); - - - }, neo4jContainer -> { - String logs = neo4jContainer.getLogs(); - assertTrue(logs.contains("successfully initialized: CREATE USER dummy IF NOT EXISTS SET PASSWORD '******' CHANGE NOT REQUIRED")); - assertTrue(logs.contains("successfully initialized: GRANT ROLE reader TO dummy")); - // The password should have been redacted - assertFalse(logs.contains("pass12345")); + for (var version: Neo4jVersion.values()) { + try { + Neo4jContainerExtension neo4jContainer = createDB(version, List.of(ApocPackage.CORE), !TestUtil.isRunningInCI()) + .withNeo4jConfig("dbms.transaction.timeout", "60s"); + + neo4jContainer.start(); + + Session session = neo4jContainer.getSession(); + int procedureCount = session.run("SHOW PROCEDURES YIELD name WHERE name STARTS WITH 'apoc' RETURN count(*) AS count").peek().get("count").asInt(); + int functionCount = session.run("SHOW FUNCTIONS YIELD name WHERE name STARTS WITH 'apoc' RETURN count(*) AS count").peek().get("count").asInt(); + int coreCount = session.run("CALL apoc.help('') YIELD core WHERE core = true RETURN count(*) AS count").peek().get("count").asInt(); + String startupLog = neo4jContainer.getLogs(); + + assertTrue(procedureCount > 0); + assertTrue(functionCount > 0); + assertTrue(coreCount > 0); + // Check there's one and only one logger for apoc inside the container + // and it doesn't override the one inside the database + assertFalse(startupLog.contains("[main] INFO org.eclipse.jetty.server.Server")); + assertFalse(startupLog.contains("SLF4J: No SLF4J providers were found")); + assertFalse(startupLog.contains("SLF4J: Failed to load class \"org.slf4j.impl.StaticLoggerBinder\"")); + assertFalse(startupLog.contains("SLF4J: Class path contains multiple SLF4J providers")); + + session.close(); + neo4jContainer.close(); + } catch (Exception ex) { + // if Testcontainers wasn't able to retrieve the docker image we ignore the test + if (TestContainerUtil.isDockerImageAvailable(ex)) { + ex.printStackTrace(); + fail("Should not have thrown exception when trying to start Neo4j: " + ex); + } else if (!TestUtil.isRunningInCI()) { + fail( "The docker image " + dockerImageForNeo4j(version) + " could not be loaded. Check whether it's available locally / in the CI. Exception:" + ex); } - ); + } + } } @Test - public void checkApocConfigShowsInNeo4jConfig() { - // we check that the apoc config is shown inside dbms.listConfig() - startNeo4jContainerSession(() -> createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !TestUtil.isRunningInCI(), false), - session -> { - var result = session.run( "CALL dbms.listConfig() YIELD name WHERE name STARTS WITH \"apoc\" RETURN name" ).stream().collect(Collectors.toList()); - assertConfigContains(result, apoc_max_decompression_ratio); - assertConfigContains(result, apoc_import_file_enabled); - assertConfigContains(result, apoc_export_file_enabled); - assertConfigContains(result, apoc_ttl_enabled); - assertConfigContains(result, apoc_ttl_schedule); - }, neo4jContainer -> {} - ); - } - - private void assertConfigContains(List configList, Setting setting) { - assertTrue(configList.stream().anyMatch(r -> r.get("name").asString().contains(setting.name()))); - } - - private void startNeo4jContainerSession(Supplier neo4jContainerCreation, - Consumer sessionConsumer, - Consumer containerConsumer) { - try (final Neo4jContainerExtension neo4jContainer = neo4jContainerCreation.get()) { + public void check_cypherInitializer_waits_for_systemDb_to_be_available() { + // we check that with apoc-core jar and all extra-dependencies jars every procedure/function is detected + var version = Neo4jVersion.ENTERPRISE; + try { + Neo4jContainerExtension neo4jContainer = createDB(version, List.of(ApocPackage.CORE), !TestUtil.isRunningInCI()) + .withEnv("apoc.initializer.system.0", "CREATE USER dummy IF NOT EXISTS SET PASSWORD \"pass12345\" CHANGE NOT REQUIRED") + .withEnv("apoc.initializer.system.1", "GRANT ROLE reader TO dummy"); neo4jContainer.start(); - assertTrue("Neo4j Instance should be up-and-running", neo4jContainer.isRunning()); - - final Session session = neo4jContainer.getSession(); - sessionConsumer.accept(session); - containerConsumer.accept(neo4jContainer); + try (Session session = neo4jContainer.getSession()) { + assertEventually(() -> + session.run( "SHOW USERS YIELD roles, user WHERE user = 'dummy' RETURN roles" ).stream() + .collect( Collectors.toList() ), (result) -> + result.size() > 0 && result.get(0).get( "roles" ).asList().contains("reader" ), + 30, TimeUnit.SECONDS + ); + } + + String logs = neo4jContainer.getLogs(); + assertTrue(logs.contains("successfully initialized: CREATE USER dummy IF NOT EXISTS SET PASSWORD '******' CHANGE NOT REQUIRED")); + assertTrue(logs.contains("successfully initialized: GRANT ROLE reader TO dummy")); + // The password should have been redacted + assertFalse(logs.contains("pass12345")); + neo4jContainer.close(); } catch (Exception ex) { - // if Testcontainers wasn't able to retrieve the docker image we ignore the test if (TestContainerUtil.isDockerImageAvailable(ex)) { ex.printStackTrace(); fail("Should not have thrown exception when trying to start Neo4j: " + ex); } else { - fail( "The docker image could not be loaded. Check whether it's available locally / in the CI. Exception:" + ex); + fail( "The docker image " + dockerImageForNeo4j(version) + " could not be loaded. Check whether it's available locally / in the CI. Exception:" + ex); } } } - private void checkCoreProcsAndFuncsExistence(Session session) { - final List functionNames = session.run("CALL apoc.help('') YIELD core, type, name WHERE core = true and type = 'function' RETURN name") - .list(record -> record.get("name").asString()); - final List procedureNames = session.run("CALL apoc.help('') YIELD core, type, name WHERE core = true and type = 'procedure' RETURN name") - .list(record -> record.get("name").asString()); + @Test + public void compare_with_sources() { + for (var version: Neo4jVersion.values()) { + try { + Neo4jContainerExtension neo4jContainer = createDB(version, List.of(ApocPackage.CORE), !TestUtil.isRunningInCI()); + neo4jContainer.start(); + + try (Session session = neo4jContainer.getSession()) { + final List functionNames = session.run("CALL apoc.help('') YIELD core, type, name WHERE core = true and type = 'function' RETURN name") + .list(record -> record.get("name").asString()); + final List procedureNames = session.run("CALL apoc.help('') YIELD core, type, name WHERE core = true and type = 'procedure' RETURN name") + .list(record -> record.get("name").asString()); + + + assertEquals(sorted(ApocSignatures.PROCEDURES), procedureNames); + assertEquals(sorted(ApocSignatures.FUNCTIONS), functionNames); + } - assertEquals(sorted(ApocSignatures.PROCEDURES), procedureNames); - assertEquals(sorted(ApocSignatures.FUNCTIONS), functionNames); + neo4jContainer.close(); + } catch (Exception ex) { + if (TestContainerUtil.isDockerImageAvailable(ex)) { + ex.printStackTrace(); + fail("Should not have thrown exception when trying to start Neo4j: " + ex); + } else { + fail( "The docker image " + dockerImageForNeo4j(version) + " could not be loaded. Check whether it's available locally / in the CI. Exception:" + ex); + } + } + } } private List sorted(List signatures) { diff --git a/core/src/main/java/apoc/util/Util.java b/core/src/main/java/apoc/util/Util.java index e836ce4bd1..beb0d46616 100644 --- a/core/src/main/java/apoc/util/Util.java +++ b/core/src/main/java/apoc/util/Util.java @@ -126,6 +126,7 @@ import static java.lang.String.format; import static java.net.HttpURLConnection.HTTP_NOT_MODIFIED; import static org.eclipse.jetty.util.URIUtil.encodePath; +import static org.neo4j.graphdb.schema.ConstraintType.RELATIONSHIP_PROPERTY_EXISTENCE; /** * @author mh @@ -1239,4 +1240,23 @@ public static boolean constraintIsUnique(ConstraintType type) { type == ConstraintType.UNIQUENESS; } + public static boolean isNodeCategory(ConstraintType type) { + return getConstraintCategory(type) == ConstraintCategory.NODE; + } + public static boolean isRelationshipCategory(ConstraintType type) { + return getConstraintCategory(type) == ConstraintCategory.RELATIONSHIP; + } + + public enum ConstraintCategory { + RELATIONSHIP, + NODE + } + + public static ConstraintCategory getConstraintCategory(ConstraintType type) { + if (type == RELATIONSHIP_PROPERTY_EXISTENCE) { + return ConstraintCategory.RELATIONSHIP; + } else { + return ConstraintCategory.NODE; + } + } } diff --git a/core/src/main/java/org/neo4j/cypher/export/CypherResultSubGraph.java b/core/src/main/java/org/neo4j/cypher/export/CypherResultSubGraph.java index b6ba83d8d6..ddaecbbf32 100644 --- a/core/src/main/java/org/neo4j/cypher/export/CypherResultSubGraph.java +++ b/core/src/main/java/org/neo4j/cypher/export/CypherResultSubGraph.java @@ -18,6 +18,7 @@ */ package org.neo4j.cypher.export; +import apoc.util.Util; import org.neo4j.graphdb.*; import org.neo4j.graphdb.schema.ConstraintDefinition; import org.neo4j.graphdb.schema.IndexDefinition; @@ -119,10 +120,11 @@ public static SubGraph from(Transaction tx, Result result, boolean addBetween, b } } } - for ( ConstraintDefinition def : tx.schema().getConstraints() ) - { - if ( graph.getLabels().contains( def.getLabel() ) ) - { + for (ConstraintDefinition def : tx.schema().getConstraints()) { + if (Util.isNodeCategory( def.getConstraintType() ) && graph.getLabels().contains(def.getLabel())) { + graph.addConstraint(def); + } + else if ( Util.isRelationshipCategory( def.getConstraintType() ) && graph.getTypes().contains(def.getRelationshipType())) { graph.addConstraint( def ); } } diff --git a/core/src/test/java/apoc/export/cypher/ExportCypherTest.java b/core/src/test/java/apoc/export/cypher/ExportCypherTest.java index d39499ba08..7a0ae26e19 100644 --- a/core/src/test/java/apoc/export/cypher/ExportCypherTest.java +++ b/core/src/test/java/apoc/export/cypher/ExportCypherTest.java @@ -25,11 +25,9 @@ import apoc.util.TestUtil; import apoc.util.Util; import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang3.exception.ExceptionUtils; import org.junit.After; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestName; @@ -49,6 +47,8 @@ import java.util.stream.Stream; import static apoc.export.cypher.ExportCypherTest.ExportCypherResults.*; +import static apoc.export.cypher.ExportCypherTest.ExportCypherResults.EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED3; +import static apoc.export.cypher.ExportCypherTest.ExportCypherResults.EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED4; import static apoc.export.util.ExportFormat.*; import static apoc.util.BinaryTestUtil.getDecompressedData; import static apoc.util.TestUtil.assertError; @@ -773,8 +773,7 @@ public void testExportWithCompressionQueryCypherShellUnwindBatchParamsWithOddDat } @Test - @Ignore("non-deterministic index order") - public void testExportAllCypherPlainOptimized() throws Exception { + public void testExportAllCypherPlainOptimized() { String fileName = "queryPlainOptimized.cypher"; TestUtil.testCall(db, "CALL apoc.export.cypher.query('MATCH (f:Foo)-[r:KNOWS]->(b:Bar) return f,r,b', $file,{format:'cypher-shell', useOptimizations: {type: 'unwind_batch'}})", map("file", fileName), @@ -788,7 +787,12 @@ public void testExportAllCypherPlainOptimized() throws Exception { assertTrue("Should get time greater than 0",((long) r.get("time")) >= 0); }); String actual = readFile(fileName); - assertTrue("expected generated output",EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED.equals(actual) || EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED2.equals(actual)); + + assertTrue("expected generated output ", + EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED.equals(actual) || + EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED2.equals(actual) || + EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED3.equals(actual) || + EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED4.equals(actual)); } @Test @@ -836,32 +840,6 @@ public void exportMultiTokenIndex() { }); } - @Ignore("It doesn't fail anymore because it skips not supported indexes") - @Test(expected = QueryExecutionException.class) - public void shouldFailExportMultiTokenIndexForRelationship() { - // given - db.executeTransactionally("CREATE (n:TempNode {value:'value'})"); - db.executeTransactionally("CREATE (n:TempNode2 {value:'value'})"); - db.executeTransactionally("CALL db.index.fulltext.createNodeIndex('MyCoolNodeFulltextIndex',['TempNode', 'TempNode2'],['value'])"); - - // TODO: We can't manage full-text rel indexes because of this bug: https://github.com/neo4j/neo4j/issues/12304 - db.executeTransactionally("CREATE (s:TempNode)-[:REL{rel_value: 'the rel value'}]->(e:TempNode2)"); - db.executeTransactionally("CALL db.index.fulltext.createRelationshipIndex('MyCoolRelFulltextIndex',['REL'],['rel_value'])"); - String query = "MATCH (t:TempNode) return t"; - Map config = map("awaitForIndexes", 3000); - - try { - // when - TestUtil.testCall(db, "CALL apoc.export.cypher.query($query, $file, $config)", - map("query", query, "file", null, "config", config), - (r) -> {}); - } catch (Exception e) { - String expected = "Full-text indexes on relationships are not supported, please delete them in order to complete the process"; - assertEquals(expected, ExceptionUtils.getRootCause(e).getMessage()); - throw e; - } - } - @Test public void shouldNotCreateUniqueImportIdForUniqueConstraint() { db.executeTransactionally("CREATE (n:Bar:Baz{name: 'A'})"); @@ -1078,8 +1056,6 @@ private Map withoutOptimization(Map map) { } public static class ExportCypherResults { - static final String EXPECTED_ISOLATED_NODE = "CREATE (:Bar:`UNIQUE IMPORT LABEL` {age:12, `UNIQUE IMPORT ID`:2});\n"; - static final String EXPECTED_BAR_END_NODE = "CREATE (:Bar {age:42, name:\"bar\"});%n"; static final String EXPECTED_BEGIN_AND_FOO = "BEGIN%n" + "CREATE (:Foo:`UNIQUE IMPORT LABEL` {born:date('2018-10-31'), name:\"foo\", `UNIQUE IMPORT ID`:0});%n"; @@ -1382,6 +1358,20 @@ public static class ExportCypherResults { "CREATE (n:Bar{name: row.name}) SET n += row.properties;%n" + "COMMIT%n"); + static final String EXPECTED_QUERY_NODES_OPTIMIZED3 = String.format("BEGIN%n" + + "UNWIND [{_id:0, properties:{born:date('2018-10-31'), name:\"foo\"}}, {_id:4, properties:{born:date('2017-09-29'), name:\"foo2\"}}] AS row%n" + + "CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Foo;%n" + + "UNWIND [{name:\"bar2\", properties:{age:44}}, {name:\"bar\", properties:{age:42}}] AS row%n" + + "CREATE (n:Bar{name: row.name}) SET n += row.properties;%n" + + "COMMIT%n"); + + static final String EXPECTED_QUERY_NODES_OPTIMIZED4 = String.format("BEGIN%n" + + "UNWIND [{_id:4, properties:{born:date('2017-09-29'), name:\"foo2\"}}, {_id:0, properties:{born:date('2018-10-31'), name:\"foo\"}}] AS row%n" + + "CREATE (n:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row._id}) SET n += row.properties SET n:Foo;%n" + + "UNWIND [{name:\"bar2\", properties:{age:44}}, {name:\"bar\", properties:{age:42}}] AS row%n" + + "CREATE (n:Bar{name: row.name}) SET n += row.properties;%n" + + "COMMIT%n"); + public static final String EXPECTED_RELATIONSHIPS_OPTIMIZED = String.format("BEGIN%n" + "UNWIND [{start: {_id:0}, end: {name:\"bar\"}, properties:{since:2016}}, {start: {_id:4}, end: {name:\"bar2\"}, properties:{since:2015}}] AS row%n" + "MATCH (start:`UNIQUE IMPORT LABEL`{`UNIQUE IMPORT ID`: row.start._id})%n" + @@ -1544,6 +1534,8 @@ public static class ExportCypherResults { static final String EXPECTED_QUERY_NODES = EXPECTED_SCHEMA_OPTIMIZED + EXPECTED_QUERY_NODES_OPTIMIZED + EXPECTED_RELATIONSHIPS_OPTIMIZED + DROP_UNIQUE_OPTIMIZED; static final String EXPECTED_QUERY_NODES2 = EXPECTED_SCHEMA_OPTIMIZED + EXPECTED_QUERY_NODES_OPTIMIZED2 + EXPECTED_RELATIONSHIPS_OPTIMIZED + DROP_UNIQUE_OPTIMIZED; + static final String EXPECTED_QUERY_NODES3 = EXPECTED_SCHEMA + EXPECTED_QUERY_NODES_OPTIMIZED3 + EXPECTED_RELATIONSHIPS_OPTIMIZED + EXPECTED_CLEAN_UP; + static final String EXPECTED_QUERY_NODES4 = EXPECTED_SCHEMA + EXPECTED_QUERY_NODES_OPTIMIZED4 + EXPECTED_RELATIONSHIPS_OPTIMIZED + EXPECTED_CLEAN_UP; static final String EXPECTED_CYPHER_OPTIMIZED_BATCH_SIZE_UNWIND = EXPECTED_SCHEMA_OPTIMIZED + EXPECTED_NODES_OPTIMIZED_BATCH_SIZE_UNWIND + EXPECTED_RELATIONSHIPS_OPTIMIZED + DROP_UNIQUE_OPTIMIZED_BATCH; @@ -1571,17 +1563,13 @@ public static class ExportCypherResults { .replace(NEO4J_SHELL.schemaAwait(), EXPECTED_INDEXES_AWAIT) .replace(NEO4J_SHELL.schemaAwait(), CYPHER_SHELL.schemaAwait()); - static final String EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED = EXPECTED_QUERY_NODES - .replace(NEO4J_SHELL.begin(), CYPHER_SHELL.begin()) - .replace(NEO4J_SHELL.commit(), CYPHER_SHELL.commit()) - .replace(NEO4J_SHELL.schemaAwait(), EXPECTED_INDEXES_AWAIT_QUERY) - .replace(NEO4J_SHELL.schemaAwait(), CYPHER_SHELL.schemaAwait()); + static final String EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED = convertToCypherShellFormat(EXPECTED_QUERY_NODES); - static final String EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED2 = EXPECTED_QUERY_NODES2 - .replace(NEO4J_SHELL.begin(), CYPHER_SHELL.begin()) - .replace(NEO4J_SHELL.commit(), CYPHER_SHELL.commit()) - .replace(NEO4J_SHELL.schemaAwait(), EXPECTED_INDEXES_AWAIT_QUERY) - .replace(NEO4J_SHELL.schemaAwait(), CYPHER_SHELL.schemaAwait()); + static final String EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED2 = convertToCypherShellFormat(EXPECTED_QUERY_NODES2); + + static final String EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED3 = convertToCypherShellFormat(EXPECTED_QUERY_NODES3); + + static final String EXPECTED_QUERY_CYPHER_SHELL_OPTIMIZED4 = convertToCypherShellFormat(EXPECTED_QUERY_NODES4); public static final String EXPECTED_CYPHER_SHELL_OPTIMIZED = EXPECTED_NEO4J_SHELL_OPTIMIZED .replace(NEO4J_SHELL.begin(), CYPHER_SHELL.begin()) @@ -1617,36 +1605,16 @@ public static class ExportCypherResults { public static final String EXPECTED_ONLY_SCHEMA_CYPHER_SHELL = EXPECTED_ONLY_SCHEMA_NEO4J_SHELL.replace(NEO4J_SHELL.begin(), CYPHER_SHELL.begin()) .replace(NEO4J_SHELL.commit(), CYPHER_SHELL.commit()).replace(NEO4J_SHELL.schemaAwait(), CYPHER_SHELL.schemaAwait()) + EXPECTED_INDEXES_AWAIT; - - static final String EXPECTED_NODES_COMPOUND_CONSTRAINT = String.format("BEGIN%n" + - "CREATE (:`Person` {`name`:\"John\", `surname`:\"Snow\"});%n" + - "CREATE (:`Person` {`name`:\"Matt\", `surname`:\"Jackson\"});%n" + - "CREATE (:`Person` {`name`:\"Jenny\", `surname`:\"White\"});%n" + - "CREATE (:`Person` {`name`:\"Susan\", `surname`:\"Brown\"});%n" + - "CREATE (:`Person` {`name`:\"Tom\", `surname`:\"Taylor\"});%n" + - "COMMIT%n"); - - static final String EXPECTED_SCHEMA_COMPOUND_CONSTRAINT = String.format("BEGIN%n" + - "CREATE CONSTRAINT ON (node:`Person`) ASSERT (node.`name`, node.`surname`) IS NODE KEY;%n" + - "COMMIT%n" + - "SCHEMA AWAIT%n"); - - static final String EXPECTED_RELATIONSHIP_COMPOUND_CONSTRAINT = String.format(("BEGIN%n" + - "MATCH (n1:`Person`{`surname`:\"Snow\", `name`:\"John\"}), (n2:`Person`{`surname`:\"Jackson\", `name`:\"Matt\"}) CREATE (n1)-[r:`KNOWS`]->(n2);%n" + - "COMMIT%n")); - - static final String EXPECTED_INDEX_AWAIT_COMPOUND_CONSTRAINT = String.format("CALL db.awaitIndex(':`Person`(`name`,`surname`)');%n"); - public static final List EXPECTED_CONSTRAINTS = List.of( - "CREATE CONSTRAINT SingleUnique FOR (node:Label) REQUIRE (node.prop) IS UNIQUE;", - "CREATE CONSTRAINT CompositeUnique FOR (node:Label) REQUIRE (node.prop1, node.prop2) IS UNIQUE;", - "CREATE CONSTRAINT SingleExists FOR (node:Label2) REQUIRE (node.prop) IS NOT NULL;", - "CREATE CONSTRAINT SingleExistsRel FOR ()-[rel:TYPE2]-() REQUIRE (rel.prop) IS NOT NULL;", - "CREATE CONSTRAINT SingleNodeKey FOR (node:Label3) REQUIRE (node.prop) IS NODE KEY;", - "CREATE CONSTRAINT PersonRequiresNamesConstraint FOR (node:Person) REQUIRE (node.name, node.surname) IS NODE KEY;" + "CREATE CONSTRAINT ON (node:Label) ASSERT (node.prop) IS UNIQUE;", + "CREATE CONSTRAINT ON (node:Label) ASSERT (node.prop1, node.prop2) IS UNIQUE;", + "CREATE CONSTRAINT ON (node:Label2) ASSERT (node.prop) IS NOT NULL;", + "CREATE CONSTRAINT ON ()-[rel:TYPE2]-() ASSERT (rel.prop) IS NOT NULL;", + "CREATE CONSTRAINT ON (node:Label3) ASSERT (node.prop) IS NODE KEY;", + "CREATE CONSTRAINT ON (node:Person) ASSERT (node.name, node.surname) IS NODE KEY;" ); - public static final String EXPECTED_NEO4J_SHELL_WITH_COMPOUND_CONSTRAINT = String.format("BEGIN%n" + + public static final String EXPECTED_NEO4J_SHELL_WITH_COMPOUND_CONSTRAINT = String.format( "COMMIT%n" + "SCHEMA AWAIT%n" + "BEGIN%n" + @@ -1660,7 +1628,7 @@ public static class ExportCypherResults { "CREATE (start)-[r:KNOWS]->(end) SET r += row.properties;%n" + "COMMIT%n"); - public static final String EXPECTED_CYPHER_SHELL_WITH_COMPOUND_CONSTRAINT = String.format(":begin%n" + + public static final String EXPECTED_CYPHER_SHELL_WITH_COMPOUND_CONSTRAINT = String.format( "CREATE CONSTRAINT ON (node:Person) ASSERT (node.name, node.surname) IS NODE KEY;%n" + ":commit%n" + "CALL db.awaitIndexes(300);%n" + diff --git a/core/src/test/java/apoc/export/graphml/ExportGraphMLTest.java b/core/src/test/java/apoc/export/graphml/ExportGraphMLTest.java index 44f6ef6de2..067cad9b8f 100644 --- a/core/src/test/java/apoc/export/graphml/ExportGraphMLTest.java +++ b/core/src/test/java/apoc/export/graphml/ExportGraphMLTest.java @@ -24,7 +24,7 @@ import apoc.util.TestUtil; import apoc.util.Util; import junit.framework.TestCase; -import org.apache.commons.lang.exception.ExceptionUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.StringUtils; import org.junit.After; import org.junit.Assert; @@ -65,6 +65,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import static org.junit.Assume.assumeFalse; import static org.neo4j.configuration.GraphDatabaseSettings.TransactionStateMemoryAllocation.OFF_HEAP; import static org.neo4j.configuration.SettingValueParsers.BYTES; @@ -128,7 +129,7 @@ public void testImportGraphML() throws Exception { TestUtil.testCall(db, "MATCH (c:Bar {age: 12, values: [1,2,3]}) RETURN COUNT(c) AS c", null, (r) -> assertEquals(1L, r.get("c"))); } - + @Test public void testRoundtripInvalidUnicode() { String fileName = new File(directory, "allUnicode.graphml").getAbsolutePath(); @@ -143,13 +144,13 @@ public void testRoundtripInvalidUnicodeWithExportQuery() { String file = new File(directory, "allQuery.graphml").getAbsolutePath(); // trello issue case: https://trello.com/c/6GboqUau/1070-s3cast-software-issue-with-apocimportgraphml final String query = "CALL apoc.export.graphml.query('MATCH (n:Unicode) RETURN n', $file, {useTypes: true, readLabels:true})"; - + testRoundtripInvalidUnicodeCommon(query, file); } private void testRoundtripInvalidUnicodeCommon(String query, String file) { db.executeTransactionally("CREATE (n:Unicode $props)", - map("props", map("propZero", "\u007FnotEscaped'", + map("props", map("propZero", "\u007FnotEscaped'", "propOne", "\u00101628\u000eX", "propTwo", "abcde\u001ef", "propThree", "aj\u0000eje>", @@ -163,7 +164,7 @@ private void testRoundtripInvalidUnicodeCommon(String query, String file) { db.executeTransactionally("MATCH (n:Unicode) DETACH DELETE n"); testImportInvalidUnicode(file); } - + @Test public void testImportInvalidUnicodeFile() { final String file = ClassLoader.getSystemResource("fileWithUnicode.graphml").toString(); @@ -208,13 +209,13 @@ public void testRoundTripWithSeparatedImport() { @Test public void testImportSeparatedFilesWithCustomId() { Map exportConfig = map("useTypes", true, - "source", map("id", "name"), + "source", map("id", "name"), "target", map("id", "age")); - + Map importConfig = map("readLabels", true, - "source", map("label", "Foo", "id", "name"), + "source", map("label", "Foo", "id", "name"), "target", map("label", "Bar", "id", "age")); - + // we specified a source/target in export config // so storeNodeIds config is unnecessary and we search nodes by properties Foo.name and Bar.age separatedFileCommons(exportConfig, importConfig); @@ -277,6 +278,7 @@ private void assertions(Map row, String expectedSource, Long exp assertEquals(expectedTarget, row.get("endAge")); } + // This test causes out of memory issues in the CI @Test public void testImportGraphMLLargeFile() { assumeFalse(isRunningInCI()); @@ -314,6 +316,26 @@ public void testImportGraphMLWithEdgeWithoutDataKeys() throws Exception { TestUtil.testCall(db, "MATCH ()-[c:RELATED]->() RETURN COUNT(c) AS c", null, (r) -> assertEquals(1L, r.get("c"))); } + @Test + public void issue2797WithImportGraphMl() { + db.executeTransactionally("CREATE (n:FOO {name: 'foo'})"); + db.executeTransactionally("CREATE CONSTRAINT unique_foo FOR (n:FOO) REQUIRE n.name IS UNIQUE"); + try { + TestUtil.testCall(db, + "CALL apoc.import.graphml($file, {readLabels:true})", + map("file", new File(directory, "importNodeEdges.graphml").getAbsolutePath()), + (r) -> fail()); + } catch (Exception e) { + String expected = "Failed to invoke procedure `apoc.import.graphml`: Caused by: IndexEntryConflictException{propertyValues=( String(\"foo\") ), addedNodeId=-1, existingNodeId=3}"; + assertEquals(expected, e.getMessage()); + } + + // should return only 1 node due to constraint exception + TestUtil.testCall(db, "MATCH (n:FOO) RETURN properties(n) AS props", + r -> assertEquals(Map.of("name", "foo"), r.get("props"))); + + db.executeTransactionally("DROP CONSTRAINT unique_foo"); + } @Test public void testImportGraphMLWithoutCharactersDataKeys() throws Exception { @@ -349,7 +371,7 @@ public void testImportGraphMLWithoutCharactersDataKeys() throws Exception { " 1\n" + " \n" + ""; - + @Test public void testImportDefaultRelationship() throws Exception { db.executeTransactionally("MATCH (n) DETACH DELETE n"); @@ -366,17 +388,16 @@ public void testImportDefaultRelationship() throws Exception { ); } - @Test(expected = QueryExecutionException.class) + @Test public void testImportGraphMLWithNoImportConfig() { File output = new File(directory, "all.graphml"); - try { - TestUtil.testCall(db, "CALL apoc.import.graphml($file,{readLabels:true})", map("file", output.getAbsolutePath()), (r) -> assertResults(output, r, "database")); - } catch (QueryExecutionException e) { - Throwable except = ExceptionUtils.getRootCause(e); - TestCase.assertTrue(except instanceof RuntimeException); - assertEquals("Import from files not enabled, please set apoc.import.file.enabled=true in your apoc.conf", except.getMessage()); - throw e; - } + QueryExecutionException e = assertThrows(QueryExecutionException.class, + () -> TestUtil.testCall(db, "CALL apoc.import.graphml($file,{readLabels:true})", map("file", output.getAbsolutePath()), + (r) -> assertResults(output, r, "database")) + ); + Throwable except = ExceptionUtils.getRootCause(e); + TestCase.assertTrue(except instanceof RuntimeException); + assertEquals("Import from files not enabled, please set apoc.import.file.enabled=true in your apoc.conf", except.getMessage()); } @Test @@ -394,7 +415,7 @@ public void testImportGraphMLNodeEdge() throws Exception { @Test public void testImportGraphMLNodeEdgeWithBinary() { db.executeTransactionally("MATCH (n) DETACH DELETE n"); - + commonAssertionImportNodeEdge(null, "CALL apoc.import.graphml($file,{readLabels:true, compression: 'DEFLATE'})", map("file", fileToBinary(new File(directory, "importNodeEdges.graphml"), "DEFLATE"))); } @@ -478,12 +499,12 @@ public void testExportAllGraphMLWithCompression() { (r) -> assertResults(output, r, "database")); assertXMLEquals(BinaryTestUtil.readFileToString(output, StandardCharsets.UTF_8, algo), EXPECTED_FALSE); } - + @Test public void testGraphMlRoundtrip() { final CompressionAlgo algo = CompressionAlgo.NONE; File output = new File(directory, "all.graphml.zz"); - final Map params = map("file", output.getAbsolutePath(), + final Map params = map("file", output.getAbsolutePath(), "config", map(CompressionConfig.COMPRESSION, algo.name(), "readLabels", true, "useTypes", true)); TestUtil.testCall(db, "CALL apoc.export.graphml.all($file, $config)", params, (r) -> assertResults(output, r, "database")); @@ -511,7 +532,7 @@ public void testGraphMlRoundtrip() { assertFalse(iterator.hasNext()); }); - + } @Test @@ -537,17 +558,16 @@ public void testExportGraphGraphMLTypes() { assertXMLEquals(output, EXPECTED_TYPES); } - @Test(expected = QueryExecutionException.class) + @Test public void testExportGraphGraphMLTypesWithNoExportConfig() { File output = new File(directory, "all.graphml"); - try { - TestUtil.testCall(db, "CALL apoc.export.graphml.all($file,null)", map("file", output.getAbsolutePath()), (r) -> assertResults(output, r, "database")); - } catch (QueryExecutionException e) { - Throwable except = ExceptionUtils.getRootCause(e); - TestCase.assertTrue(except instanceof RuntimeException); - assertEquals(EXPORT_TO_FILE_ERROR, except.getMessage()); - throw e; - } + QueryExecutionException e = assertThrows(QueryExecutionException.class, + () -> TestUtil.testCall(db, "CALL apoc.export.graphml.all($file,null)", map("file", output.getAbsolutePath()), + (r) -> assertResults(output, r, "database")) + ); + Throwable except = ExceptionUtils.getRootCause(e); + TestCase.assertTrue(except instanceof RuntimeException); + assertEquals(EXPORT_TO_FILE_ERROR, except.getMessage()); } @Test @@ -569,9 +589,9 @@ public void testImportAndExport() throws Exception { (r) -> assertResultEmpty(input, r)); TestUtil.testCall(db, "MATCH (n:Test) RETURN n.name as name, n.limit as limit", null, (r) -> { - assertEquals(StringUtils.EMPTY, r.get("name")); - assertEquals(3L, r.get("limit")); - } + assertEquals(StringUtils.EMPTY, r.get("name")); + assertEquals(3L, r.get("limit")); + } ); db.executeTransactionally("MATCH (n) detach delete (n)"); db.executeTransactionally("CREATE (f:Foo:Foo2:Foo0 {name:'foo'})-[:KNOWS]->(b:Bar {name:'bar',age:42}),(c:Bar {age:12,values:[1,2,3]})"); @@ -804,18 +824,18 @@ public void testExportGraphGraphMLQueryTinkerPopWithArrayCaptionWrong() { assertXMLEquals(output, EXPECTED_TYPES_PATH_CAPTION_TINKER); } - @Test(expected = QueryExecutionException.class) + @Test public void testExportGraphGraphMLQueryGephiWithStringCaption() { File output = new File(directory, "query.graphml"); - try { - TestUtil.testCall(db, "call apoc.export.graphml.query('MATCH p=()-[r]->() RETURN p limit 1000',$file,{useTypes:true, format: 'gephi', caption: 'name'}) ", map("file", output.getAbsolutePath()), - (r) -> {}); - } catch (QueryExecutionException e) { - Throwable except = ExceptionUtils.getRootCause(e); - TestCase.assertTrue(except instanceof RuntimeException); - assertEquals("Only array of Strings are allowed!", except.getMessage()); - throw e; - } + QueryExecutionException e = assertThrows(QueryExecutionException.class, + () -> TestUtil.testCall(db, + "call apoc.export.graphml.query('MATCH p=()-[r]->() RETURN p limit 1000',$file,{useTypes:true, format: 'gephi', caption: 'name'}) ", + map("file", output.getAbsolutePath()), + (r) -> {}) + ); + Throwable except = ExceptionUtils.getRootCause(e); + TestCase.assertTrue(except instanceof RuntimeException); + assertEquals("Only array of Strings are allowed!", except.getMessage()); } @Test @@ -906,7 +926,7 @@ public void testExportAllGraphMLStreamWithCompression() { final CompressionAlgo algo = CompressionAlgo.BZIP2; TestUtil.testCall(db, "CALL apoc.export.graphml.all(null, $config)", map("config", map("compression", algo.name(), "stream", true)), - (r) -> { + (r) -> { assertStreamResults(r, "database"); assertXMLEquals(getDecompressedData(algo, r.get("data")), EXPECTED_FALSE); }); @@ -936,4 +956,4 @@ public void testExportGraphmlAdminOperationErrorMessage() { assertError(e, INVALID_QUERY_MODE_ERROR, RuntimeException.class, "apoc.export.graphml.query"); } } -} +} \ No newline at end of file diff --git a/core/src/test/java/apoc/export/json/ImportJsonEnterpriseFeaturesTest.java b/core/src/test/java/apoc/export/json/ImportJsonEnterpriseFeaturesTest.java index f07d25a224..088270788b 100644 --- a/core/src/test/java/apoc/export/json/ImportJsonEnterpriseFeaturesTest.java +++ b/core/src/test/java/apoc/export/json/ImportJsonEnterpriseFeaturesTest.java @@ -2,6 +2,7 @@ import apoc.util.Neo4jContainerExtension; import apoc.util.TestContainerUtil; +import apoc.util.TestUtil; import junit.framework.TestCase; import org.junit.AfterClass; import org.junit.Assert; @@ -26,7 +27,7 @@ public class ImportJsonEnterpriseFeaturesTest { @BeforeClass public static void beforeAll() { - neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), true); + neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.CORE), !TestUtil.isRunningInCI()); neo4jContainer.start(); session = neo4jContainer.getSession(); diff --git a/core/src/test/java/apoc/util/UtilQuoteTest.java b/core/src/test/java/apoc/util/UtilQuoteTest.java index 0da4e78891..ca0f4549c1 100644 --- a/core/src/test/java/apoc/util/UtilQuoteTest.java +++ b/core/src/test/java/apoc/util/UtilQuoteTest.java @@ -30,7 +30,6 @@ import java.util.Collection; import static org.junit.Assert.assertEquals; -import static org.junit.Assume.assumeTrue; @RunWith(Parameterized.class) public class UtilQuoteTest { @@ -81,8 +80,12 @@ public void shouldQuoteIfNeededForUsageAsParameterName() { @Test public void shouldNotQuoteWhenAvoidQuoteIsTrue() { - assumeTrue(shouldAvoidQuote); - assertEquals(Util.quote(identifier), identifier); + final String expectedIdentifier = shouldAvoidQuote + ? identifier + : '`' + identifier + '`'; + + assertEquals(expectedIdentifier, + Util.quote(identifier)); } } diff --git a/full-it/src/test/java/apoc/full/it/BoltTest.java b/full-it/src/test/java/apoc/full/it/BoltTest.java index 568e36211b..c720b1596e 100644 --- a/full-it/src/test/java/apoc/full/it/BoltTest.java +++ b/full-it/src/test/java/apoc/full/it/BoltTest.java @@ -23,6 +23,7 @@ import apoc.export.cypher.ExportCypher; import apoc.util.Neo4jContainerExtension; import apoc.util.TestContainerUtil; +import apoc.util.TestContainerUtil.ApocPackage; import apoc.util.TestUtil; import apoc.util.Util; import org.junit.AfterClass; @@ -39,22 +40,14 @@ import java.time.LocalTime; import java.time.OffsetTime; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import static apoc.util.Util.map; +import static apoc.util.TestContainerUtil.createEnterpriseDB; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static apoc.util.TestUtil.isRunningInCI; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; import static org.neo4j.driver.Values.isoDuration; import static org.neo4j.driver.Values.point; @@ -68,501 +61,399 @@ public class BoltTest { public static DbmsRule db = new ImpermanentDbmsRule(); private static Neo4jContainerExtension neo4jContainer; - private static String BOLT_URL; @BeforeClass - public static void setUp() throws Exception { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - neo4jContainer = TestContainerUtil.createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), isRunningInCI()) - .withInitScript("init_neo4j_bolt.cypher") - .withLogging() - .withAdminPassword("neo4j2020"); - neo4jContainer.start(); - }, Exception.class); - assumeNotNull(neo4jContainer); - assumeTrue("Neo4j Instance should be up-and-running", neo4jContainer.isRunning()); - BOLT_URL = "'" + "bolt://neo4j:neo4j2020@" + neo4jContainer.getContainerIpAddress() + ":" + neo4jContainer.getMappedPort(7687) + "'"; - - TestUtil.registerProcedure( db, Bolt.class, ExportCypher.class, Cypher.class); + public static void setUp() { + neo4jContainer = createEnterpriseDB(List.of(ApocPackage.FULL), !TestUtil.isRunningInCI()).withInitScript("init_neo4j_bolt.cypher"); + neo4jContainer.start(); + TestUtil.registerProcedure(db, Bolt.class, ExportCypher.class, Cypher.class); } @AfterClass public static void tearDown() { - if (neo4jContainer != null && neo4jContainer.isRunning()) { - neo4jContainer.close(); - } + neo4jContainer.close(); db.shutdown(); } - + @Test public void testNeo4jBolt() { final String uriDbBefore4 = System.getenv("URI_DB_BEFORE_4"); Assume.assumeNotNull(uriDbBefore4); - TestUtil.testCall(db, "CALL apoc.bolt.load($uri, 'RETURN 1', {}, {databaseName: null})", + TestUtil.testCall(db, "CALL apoc.bolt.load($uri, 'RETURN 1', {}, {databaseName: null})", Map.of("uri", uriDbBefore4), r -> assertEquals(Map.of("1", 1L), r.get("row"))); } @Test - public void testLoadNodeVirtual() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'match(p:Person {name:$name}) return p', {name:'Michael'}, {virtual:true})", r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - Node node = (Node) row.get("p"); - assertEquals(true, node.hasLabel(Label.label("Person"))); - assertEquals("Michael", node.getProperty("name")); - assertEquals("Jordan", node.getProperty("surname")); - assertEquals(true, node.getProperty("state")); - assertEquals(54L, node.getProperty("age")); - }); - } - - @Test - public void shouldReturnMapOfCollection() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'MATCH (p:Person {name: $name}) RETURN {nodes: collect(p)} AS map', $params, $config)", - map("params", map("name", "Tom"), - "config", map("virtual", true)), - r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - Map> map = (Map>) row.get("map"); - Collection nodes = map.get("nodes"); - assertEquals(2, nodes.size()); - Set> expected = new HashSet<>(Arrays.asList(map("name", "Tom", "surname", "Loagan"), map("name", "Tom", "surname", "Burton"))); - Set> actual = nodes.stream() - .map(n -> n.getProperties("name", "surname")) - .collect(Collectors.toSet()); - assertEquals(expected, actual); - }); - } - - @Test - public void testLoadNodesVirtual() throws Exception { - TestUtil.testResult(db, "call apoc.bolt.load(" + BOLT_URL + ",'match(n) return n', {}, {virtual:true})", r -> { - assertNotNull(r); - Map row = r.next(); - Map result = (Map) row.get("row"); - Node node = (Node) result.get("n"); - assertEquals(true, node.hasLabel(Label.label("Person"))); - assertEquals("Michael", node.getProperty("name")); - assertEquals("Jordan", node.getProperty("surname")); - assertEquals(true, node.getProperty("state")); - assertEquals(54L, node.getProperty("age")); - row = r.next(); - result = (Map) row.get("row"); - node = (Node) result.get("n"); - assertEquals(true, node.hasLabel(Label.label("Person"))); - assertEquals("Tom", node.getProperty("name")); - assertEquals("Burton", node.getProperty("surname")); - assertEquals(23L, node.getProperty("age")); - row = r.next(); - result = (Map) row.get("row"); - node = (Node) result.get("n"); - assertEquals(true, node.hasLabel(Label.label("Person"))); - assertEquals("John", node.getProperty("name")); - assertEquals("William", node.getProperty("surname")); - assertEquals(22L, node.getProperty("age")); - - r.close(); - }); - } - - @Test - public void testLoadPathVirtual() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'MATCH (neo) WHERE id(neo) = $idNode MATCH path= (neo)-[r:KNOWS*..3]->(other) return path', {idNode:1}, {virtual:true})", r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - List path = (List) row.get("path"); - Node start = (Node) path.get(0); - assertEquals(true, start.hasLabel(Label.label("Person"))); - assertEquals("Tom", start.getProperty("name")); - assertEquals("Burton", start.getProperty("surname")); - Node end = (Node) path.get(2); - assertEquals(true, end.hasLabel(Label.label("Person"))); - assertEquals("John", end.getProperty("name")); - assertEquals("William", end.getProperty("surname")); - Relationship rel = (Relationship) path.get(1); - assertEquals("KNOWS", rel.getType().name()); - assertEquals(2016L, rel.getProperty("since")); - assertEquals(OffsetTime.parse("12:50:35.556+01:00"), rel.getProperty("time")); - }); + public void testLoadNodeVirtual() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'match(p:Person {name:$name}) return p', {name:'Michael'}, {virtual:true})", r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + Node node = (Node) row.get("p"); + assertEquals(true, node.hasLabel(Label.label("Person"))); + assertEquals("Michael", node.getProperty("name")); + assertEquals("Jordan", node.getProperty("surname")); + assertEquals(true, node.getProperty("state")); + assertEquals(54L, node.getProperty("age")); + }); } @Test - public void testLoadRel() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'match(p)-[r]->(c) return r limit 1', {}, {virtual:true})", r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - Relationship rel = (Relationship) row.get("r"); - assertEquals("KNOWS", rel.getType().name()); - assertEquals(2016L, rel.getProperty("since")); - assertEquals(OffsetTime.parse("12:50:35.556+01:00"), rel.getProperty("time")); - }); + public void testLoadNodesVirtual() { + TestUtil.testResult(db, "call apoc.bolt.load(" + getBoltUrl() + ",'match(n) return n', {}, {virtual:true})", r -> { + assertNotNull(r); + Map row = r.next(); + Map result = (Map) row.get("row"); + Node node = (Node) result.get("n"); + assertEquals(true, node.hasLabel(Label.label("Person"))); + assertEquals("Michael", node.getProperty("name")); + assertEquals("Jordan", node.getProperty("surname")); + assertEquals(true, node.getProperty("state")); + assertEquals(54L, node.getProperty("age")); + row = r.next(); + result = (Map) row.get("row"); + node = (Node) result.get("n"); + assertEquals(true, node.hasLabel(Label.label("Person"))); + assertEquals("Tom", node.getProperty("name")); + assertEquals("Burton", node.getProperty("surname")); + assertEquals(23L, node.getProperty("age")); + row = r.next(); + result = (Map) row.get("row"); + node = (Node) result.get("n"); + assertEquals(true, node.hasLabel(Label.label("Person"))); + assertEquals("John", node.getProperty("name")); + assertEquals("William", node.getProperty("surname")); + assertEquals(22L, node.getProperty("age")); + + r.close(); + }); } @Test - public void testLoadRelWithNodeProperties() { - // given - String query = "MATCH (:Person{name: 'John', surname: 'Green'})-[r]->(:Person{name: 'Jim', surname: 'Brown'}) RETURN r"; - - // when - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",$query, null, $config)", - map("query", query, "config", map("virtual", true, "withRelationshipNodeProperties", true)), - r -> { - // then - assertNotNull(r); - Map row = (Map) r.get("row"); - final Relationship rel = (Relationship) row.get("r"); - assertEquals("KNOWS", rel.getType().name()); - final Map expectedRel = map("born", point(4979, 56.7, 12.78, 100.0).asPoint(), "since", OffsetTime.parse("12:50:35.556+01:00")); - assertEquals(expectedRel, rel.getAllProperties()); - final Node start = rel.getStartNode(); - final Map expectedStartNode = map("name", "John", "surname", "Green", "born", point(7203, 2.3, 4.5).asPoint()); - assertEquals(expectedStartNode, start.getAllProperties()); - final Node end = rel.getEndNode(); - final Map expectedEndNode = map("name", "Jim", "surname", "Brown"); - assertEquals(expectedEndNode, end.getAllProperties()); - }); + public void testLoadPathVirtual() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'MATCH (neo) WHERE neo.surname = $surnameNode MATCH path= (neo)-[r:KNOWS*..3]->(other) return path', {surnameNode:'Burton'}, {virtual:true})", r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + List path = (List) row.get("path"); + Node start = (Node) path.get(0); + assertEquals(true, start.hasLabel(Label.label("Person"))); + assertEquals("Tom", start.getProperty("name")); + assertEquals("Burton", start.getProperty("surname")); + Node end = (Node) path.get(2); + assertEquals(true, end.hasLabel(Label.label("Person"))); + assertEquals("John", end.getProperty("name")); + assertEquals("William", end.getProperty("surname")); + Relationship rel = (Relationship) path.get(1); + assertEquals("KNOWS", rel.getType().name()); + assertEquals(2016L, rel.getProperty("since")); + assertEquals(OffsetTime.parse("12:50:35.556+01:00"), rel.getProperty("time")); + }); } @Test - public void testLoadFromLocalRelWithNodeProperties() { - db.executeTransactionally("create (:LocalNode {name: 'John', surname: 'Green'})"); - - // given - String localStatement = "MATCH (local:LocalNode) RETURN local.name as name"; - String remoteStatement = "MATCH (:Person{name: name, surname: 'Green'})-[r]->(:Person{name: 'Jim', surname: 'Brown'}) RETURN r"; - - // when - TestUtil.testCall(db, "call apoc.bolt.load.fromLocal(" + BOLT_URL + ", $localStatement, $remoteStatement, $config)", - map("localStatement", localStatement, "remoteStatement", remoteStatement, "config", map("virtual", true, "withRelationshipNodeProperties", true)), - r -> { - // then - assertNotNull(r); - Map row = (Map) r.get("row"); - final Relationship rel = (Relationship) row.get("r"); - assertEquals("KNOWS", rel.getType().name()); - final Map expectedRel = map("born", point(4979, 56.7, 12.78, 100.0).asPoint(), "since", OffsetTime.parse("12:50:35.556+01:00")); - assertEquals(expectedRel, rel.getAllProperties()); - final Node start = rel.getStartNode(); - final Map expectedStartNode = map("name", "John", "surname", "Green", "born", point(7203, 2.3, 4.5).asPoint()); - assertEquals(expectedStartNode, start.getAllProperties()); - final Node end = rel.getEndNode(); - final Map expectedEndNode = map("name", "Jim", "surname", "Brown"); - assertEquals(expectedEndNode, end.getAllProperties()); - }); - - db.executeTransactionally("match (n:LocalNode) delete n"); + public void testLoadRel() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'match(p)-[r]->(c) return r limit 1', {}, {virtual:true})", r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + Relationship rel = (Relationship) row.get("r"); + assertEquals("KNOWS", rel.getType().name()); + assertEquals(2016L, rel.getProperty("since")); + assertEquals(OffsetTime.parse("12:50:35.556+01:00"), rel.getProperty("time")); + }); } @Test - public void testLoadRelsAndNodes() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'match(p:Person {surname:$surnameP})-[r]->(c:Person {surname:$surnameC}) return *', {surnameP:\"Burton\", surnameC:\"William\"}, {virtual:true})", r -> { - Map result = (Map) r.get("row"); - Node node = (Node) result.get("p"); - assertEquals(true, node.hasLabel(Label.label("Person"))); - assertEquals("Tom", node.getProperty("name")); - assertEquals("Burton", node.getProperty("surname")); - assertEquals(23L, node.getProperty("age")); - node = (Node) result.get("c"); - assertEquals(true, node.hasLabel(Label.label("Person"))); - assertEquals("John", node.getProperty("name")); - assertEquals("William", node.getProperty("surname")); - assertEquals(22L, node.getProperty("age")); - }); + public void testLoadRelsAndNodes() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'match(p:Person {surname:$surnameP})-[r]->(c:Person {surname:$surnameC}) return *', {surnameP:\"Burton\", surnameC:\"William\"}, {virtual:true})", r -> { + Map result = (Map) r.get("row"); + Node node = (Node) result.get("p"); + assertEquals(true, node.hasLabel(Label.label("Person"))); + assertEquals("Tom", node.getProperty("name")); + assertEquals("Burton", node.getProperty("surname")); + assertEquals(23L, node.getProperty("age")); + node = (Node) result.get("c"); + assertEquals(true, node.hasLabel(Label.label("Person"))); + assertEquals("John", node.getProperty("name")); + assertEquals("William", node.getProperty("surname")); + assertEquals(22L, node.getProperty("age")); + }); } @Test - public void testLoadNullParams() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load("+BOLT_URL+",\"match(p:Person {name:'Michael'}) return p\")", r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - Map node = (Map) row.get("p"); - assertTrue(node.containsKey("entityType")); - assertEquals("NODE", node.get("entityType")); - assertTrue(node.containsKey("properties")); - Map properties = (Map) node.get("properties"); - assertEquals("Michael", properties.get("name")); - assertEquals("Jordan", properties.get("surname")); - assertEquals(54L, properties.get("age")); - assertEquals(true, properties.get("state")); - }); + public void testLoadNullParams() { + TestUtil.testCall(db, "call apoc.bolt.load("+getBoltUrl()+",\"match(p:Person {name:'Michael'}) return p\")", r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + Map node = (Map) row.get("p"); + assertTrue(node.containsKey("entityType")); + assertEquals("NODE", node.get("entityType")); + assertTrue(node.containsKey("properties")); + Map properties = (Map) node.get("properties"); + assertEquals("Michael", properties.get("name")); + assertEquals("Jordan", properties.get("surname")); + assertEquals(54L, properties.get("age")); + assertEquals(true, properties.get("state")); + }); } @Test - public void testLoadNode() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'match (p:Person {name:$name}) return p', {name:'Michael'})", r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - Map node = (Map) row.get("p"); - assertTrue(node.containsKey("entityType")); - assertEquals("NODE", node.get("entityType")); - assertTrue(node.containsKey("properties")); - Map properties = (Map) node.get("properties"); - assertEquals("Michael", properties.get("name")); - assertEquals("Jordan", properties.get("surname")); - assertEquals(54L, properties.get("age")); - assertEquals(true, properties.get("state")); - }); + public void testLoadNode() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'match (p:Person {name:$name}) return p', {name:'Michael'})", r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + Map node = (Map) row.get("p"); + assertTrue(node.containsKey("entityType")); + assertEquals("NODE", node.get("entityType")); + assertTrue(node.containsKey("properties")); + Map properties = (Map) node.get("properties"); + assertEquals("Michael", properties.get("name")); + assertEquals("Jordan", properties.get("surname")); + assertEquals(54L, properties.get("age")); + assertEquals(true, properties.get("state")); + }); } @Test - public void testLoadScalarSingleReusult() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'match (n:Person {name:$name}) return n.age as Age', {name:'Michael'})", (r) -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - assertTrue(row.containsKey("Age")); - assertEquals(54L, row.get("Age")); - }); + public void testLoadScalarSingleReusult() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'match (n:Person {name:$name}) return n.age as Age', {name:'Michael'})", (r) -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + assertTrue(row.containsKey("Age")); + assertEquals(54L, row.get("Age")); + }); } @Test - public void testLoadMixedContent() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'match (n:Person {name:$name}) return n.age, n.name, n.state', {name:'Michael'})", - r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - assertTrue(row.containsKey("n.age")); - assertEquals(54L, row.get("n.age")); - assertTrue(row.containsKey("n.name")); - assertEquals("Michael", row.get("n.name")); - assertTrue(row.containsKey("n.state")); - assertEquals(true, row.get("n.state")); - }); + public void testLoadMixedContent() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'match (n:Person {name:$name}) return n.age, n.name, n.state', {name:'Michael'})", + r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + assertTrue(row.containsKey("n.age")); + assertEquals(54L, row.get("n.age")); + assertTrue(row.containsKey("n.name")); + assertEquals("Michael", row.get("n.name")); + assertTrue(row.containsKey("n.state")); + assertEquals(true, row.get("n.state")); + }); } @Test - public void testLoadList() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'match (p:Person {name:$name}) with collect({personName:p.name}) as rows return rows', {name:'Michael'})", r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - List p = (List) row.get("rows"); - Map result = (Map) p.get(0); - assertTrue(result.containsKey("personName")); - assertEquals("Michael", result.get("personName")); - }); + public void testLoadList() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'match (p:Person {name:$name}) with collect({personName:p.name}) as rows return rows', {name:'Michael'})", r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + List p = (List) row.get("rows"); + Map result = (Map) p.get(0); + assertTrue(result.containsKey("personName")); + assertEquals("Michael", result.get("personName")); + }); } @Test - public void testLoadMap() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'match (p:Person {name:$name}) with p,collect({personName:p.name}) as rows return p{.*, rows:rows}', {name:'Michael'})", r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - Map p = (Map) row.get("p"); - assertTrue(p.containsKey("name")); - assertEquals("Michael", p.get("name")); - assertTrue(p.containsKey("age")); - assertEquals(54L, p.get("age")); - assertTrue(p.containsKey("surname")); - assertEquals("Jordan", p.get("surname")); - assertTrue(p.containsKey("state")); - assertEquals(true, p.get("state")); - }); + public void testLoadMap() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'match (p:Person {name:$name}) with p,collect({personName:p.name}) as rows return p{.*, rows:rows}', {name:'Michael'})", r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + Map p = (Map) row.get("p"); + assertTrue(p.containsKey("name")); + assertEquals("Michael", p.get("name")); + assertTrue(p.containsKey("age")); + assertEquals(54L, p.get("age")); + assertTrue(p.containsKey("surname")); + assertEquals("Jordan", p.get("surname")); + assertTrue(p.containsKey("state")); + assertEquals(true, p.get("state")); + }); } @Test - public void testLoadPath() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'MATCH path= (neo)-[r:KNOWS*..3]->(other) where id(neo) = $idNode return path', {idNode:1}, {})", r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - List path = (List) row.get("path"); - Map startNode = (Map) path.get(0); - assertEquals("NODE", startNode.get("entityType")); - assertEquals(Arrays.asList("Person"), startNode.get("labels")); - Map startNodeProperties = (Map) startNode.get("properties"); - assertEquals("Tom", startNodeProperties.get("name")); - assertEquals("Burton", startNodeProperties.get("surname")); - Map endNode = (Map) path.get(2); - assertEquals("NODE", startNode.get("entityType")); - assertEquals(Arrays.asList("Person"), startNode.get("labels")); - Map endNodeProperties = (Map) endNode.get("properties"); - assertEquals("John", endNodeProperties.get("name")); - assertEquals("William", endNodeProperties.get("surname")); - Map rel = (Map) path.get(1); - assertEquals("RELATIONSHIP", rel.get("entityType")); - assertEquals("KNOWS", rel.get("type")); - Map relProperties = (Map) rel.get("properties"); - assertEquals(2016L, relProperties.get("since")); - assertEquals(OffsetTime.parse("12:50:35.556+01:00"), relProperties.get("time")); - }); + public void testLoadPath() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'MATCH path= (neo)-[r:KNOWS*..3]->(other) where neo.surname = $surnameNode return path', {surnameNode: 'Burton'}, {})", r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + List path = (List) row.get("path"); + Map startNode = (Map) path.get(0); + assertEquals("NODE", startNode.get("entityType")); + assertEquals(Arrays.asList("Person"), startNode.get("labels")); + Map startNodeProperties = (Map) startNode.get("properties"); + assertEquals("Tom", startNodeProperties.get("name")); + assertEquals("Burton", startNodeProperties.get("surname")); + Map endNode = (Map) path.get(2); + assertEquals("NODE", startNode.get("entityType")); + assertEquals(Arrays.asList("Person"), startNode.get("labels")); + Map endNodeProperties = (Map) endNode.get("properties"); + assertEquals("John", endNodeProperties.get("name")); + assertEquals("William", endNodeProperties.get("surname")); + Map rel = (Map) path.get(1); + assertEquals("RELATIONSHIP", rel.get("entityType")); + assertEquals("KNOWS", rel.get("type")); + Map relProperties = (Map) rel.get("properties"); + assertEquals(2016L, relProperties.get("since")); + assertEquals(OffsetTime.parse("12:50:35.556+01:00"), relProperties.get("time")); + }); } @Test - public void testLoadRels() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'match (n)-[r]->(c) return r as rel limit 1', {})", (r) -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - Map rel = (Map) row.get("rel"); - assertEquals(1L, rel.get("start")); - assertEquals(2L, rel.get("end")); - assertEquals("RELATIONSHIP", rel.get("entityType")); - assertEquals("KNOWS", rel.get("type")); - Map properties = (Map) rel.get("properties"); - assertEquals(2016L, properties.get("since")); - assertEquals(OffsetTime.parse("12:50:35.556+01:00"), properties.get("time")); - }); + public void testLoadRels() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'match (n)-[r]->(c) return r as rel limit 1', {})", (r) -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + Map rel = (Map) row.get("rel"); + assertEquals(1L, rel.get("start")); + assertEquals(2L, rel.get("end")); + assertEquals("RELATIONSHIP", rel.get("entityType")); + assertEquals("KNOWS", rel.get("type")); + Map properties = (Map) rel.get("properties"); + assertEquals(2016L, properties.get("since")); + assertEquals(OffsetTime.parse("12:50:35.556+01:00"), properties.get("time")); + }); } @Test - public void testExecuteCreateNodeStatistic() throws Exception { - TestUtil.testResult(db, "call apoc.bolt.execute(" + BOLT_URL + ",'create(n:Node {name:$name})', {name:'Node1'}, {statistics:true})", Collections.emptyMap(), - r -> { - assertNotNull(r); - Map row = r.next(); - Map result = (Map) row.get("row"); - assertEquals(1L, (long) Util.toLong(result.get("nodesCreated"))); - assertEquals(1L, (long) Util.toLong(result.get("labelsAdded"))); - assertEquals(1L, (long) Util.toLong(result.get("propertiesSet"))); - assertEquals(false, r.hasNext()); - }); + public void testExecuteCreateNodeStatistic() { + TestUtil.testResult(db, "call apoc.bolt.execute(" + getBoltUrl() + ",'create(n:Node {name:$name})', {name:'Node1'}, {statistics:true})", Collections.emptyMap(), + r -> { + assertNotNull(r); + Map row = r.next(); + Map result = (Map) row.get("row"); + assertEquals(1L, (long) Util.toLong(result.get("nodesCreated"))); + assertEquals(1L, (long) Util.toLong(result.get("labelsAdded"))); + assertEquals(1L, (long) Util.toLong(result.get("propertiesSet"))); + assertEquals(false, r.hasNext()); + }); } @Test - public void testExecuteCreateVirtualNode() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.execute(" + BOLT_URL + ",'create(n:Node {name:$name}) return n', {name:'Node1'}, {virtual:true})", - r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - Node node = (Node) row.get("n"); - assertEquals(true, node.hasLabel(Label.label("Node"))); - assertEquals("Node1", node.getProperty("name")); - }); + public void testExecuteCreateVirtualNode() { + TestUtil.testCall(db, "call apoc.bolt.execute(" + getBoltUrl() + ",'create(n:Node {name:$name}) return n', {name:'Node1'}, {virtual:true})", + r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + Node node = (Node) row.get("n"); + assertEquals(true, node.hasLabel(Label.label("Node"))); + assertEquals("Node1", node.getProperty("name")); + }); } @Test - public void testLoadNoVirtual() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load("+BOLT_URL+",\"match(p:Person {name:'Michael'}) return p\", {}, {virtual:false, test:false})", - r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - Map node = (Map) row.get("p"); - assertTrue(node.containsKey("entityType")); - assertEquals("NODE", node.get("entityType")); - assertTrue(node.containsKey("properties")); - Map properties = (Map) node.get("properties"); - assertEquals("Michael", properties.get("name")); - assertEquals("Jordan", properties.get("surname")); - assertEquals(54L, properties.get("age")); - assertEquals(true, properties.get("state")); - }); + public void testLoadNoVirtual() { + TestUtil.testCall(db, "call apoc.bolt.load("+getBoltUrl()+",\"match(p:Person {name:'Michael'}) return p\", {}, {virtual:false, test:false})", + r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + Map node = (Map) row.get("p"); + assertTrue(node.containsKey("entityType")); + assertEquals("NODE", node.get("entityType")); + assertTrue(node.containsKey("properties")); + Map properties = (Map) node.get("properties"); + assertEquals("Michael", properties.get("name")); + assertEquals("Jordan", properties.get("surname")); + assertEquals(54L, properties.get("age")); + assertEquals(true, properties.get("state")); + }); } @Test - public void testLoadNodeWithDriverConfig() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",\"match(p:Person {name:$nameP}) return p\", {nameP:'Michael'}, " + - "{driverConfig:{logging:'WARNING', encryption: false,logLeakedSessions:true, maxIdleConnectionPoolSize:10, idleTimeBeforeConnectionTest:-1," + - " routingFailureLimit: 1, routingRetryDelayMillis:500, connectionTimeoutMillis:500, maxRetryTimeMs:30000 , trustStrategy:'TRUST_ALL_CERTIFICATES'}})", - r -> { - assertNotNull(r); - Map row = (Map) r.get("row"); - Map node = (Map) row.get("p"); - assertTrue(node.containsKey("entityType")); - assertEquals("NODE", node.get("entityType")); - assertTrue(node.containsKey("properties")); - Map properties = (Map) node.get("properties"); - assertEquals("Michael", properties.get("name")); - assertEquals("Jordan", properties.get("surname")); - assertEquals(54L, properties.get("age")); - assertEquals(true, properties.get("state")); - }); + public void testLoadNodeWithDriverConfig() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",\"match(p:Person {name:$nameP}) return p\", {nameP:'Michael'}, " + + "{driverConfig:{logging:'WARNING', encryption: false,logLeakedSessions:true, maxIdleConnectionPoolSize:10, idleTimeBeforeConnectionTest:-1," + + " routingFailureLimit: 1, routingRetryDelayMillis:500, connectionTimeoutMillis:500, maxRetryTimeMs:30000 , trustStrategy:'TRUST_ALL_CERTIFICATES'}})", + r -> { + assertNotNull(r); + Map row = (Map) r.get("row"); + Map node = (Map) row.get("p"); + assertTrue(node.containsKey("entityType")); + assertEquals("NODE", node.get("entityType")); + assertTrue(node.containsKey("properties")); + Map properties = (Map) node.get("properties"); + assertEquals("Michael", properties.get("name")); + assertEquals("Jordan", properties.get("surname")); + assertEquals(54L, properties.get("age")); + assertEquals(true, properties.get("state")); + }); } @Test - public void testLoadBigPathVirtual() throws Exception { - TestUtil.testCall(db, "call apoc.bolt.load(" + BOLT_URL + ",'MATCH path= (neo)-[r:KNOWS*3]->(other) WHERE id(neo) = $idNode return path', {idNode:3}, {virtual:true})", r -> { - Map row = (Map) r.get("row"); - List path = (List) row.get("path"); - Node start = (Node) path.get(0); - assertEquals(true, start.hasLabel(Label.label("Person"))); - assertEquals("Tom", start.getProperty("name")); - assertEquals("Loagan", start.getProperty("surname")); - assertEquals(isoDuration(5, 1, 43200, 0).asIsoDuration(), start.getProperty("duration")); - Relationship rel = (Relationship) path.get(1); - assertEquals("KNOWS", rel.getType().name()); - assertEquals(LocalTime.parse("12:50:35.556"), rel.getProperty("since")); - assertEquals(point(4326, 56.7, 12.78).asPoint(), rel.getProperty("born")); - Node end = (Node) path.get(2); - assertEquals(true, end.hasLabel(Label.label("Person"))); - assertEquals("John", end.getProperty("name")); - assertEquals("Green", end.getProperty("surname")); - assertEquals(point(7203, 2.3, 4.5).asPoint(), end.getProperty("born")); - start = (Node) path.get(3); - assertEquals(true, start.hasLabel(Label.label("Person"))); - assertEquals("John", start.getProperty("name")); - assertEquals("Green", start.getProperty("surname")); - assertEquals(point(7203, 2.3, 4.5).asPoint(), end.getProperty("born")); - rel = (Relationship) path.get(4); - assertEquals("KNOWS", rel.getType().name()); - assertEquals(OffsetTime.parse("12:50:35.556+01:00"), rel.getProperty("since")); - assertEquals(point(4979, 56.7, 12.78, 100.0).asPoint(), rel.getProperty("born")); - end = (Node) path.get(5); - assertEquals(true, end.hasLabel(Label.label("Person"))); - assertEquals("Jim", end.getProperty("name")); - assertEquals("Brown", end.getProperty("surname")); - start = (Node) path.get(6); - assertEquals(true, start.hasLabel(Label.label("Person"))); - assertEquals("Jim", start.getProperty("name")); - assertEquals("Brown", start.getProperty("surname")); - rel = (Relationship) path.get(7); - assertEquals("KNOWS", rel.getType().name()); - assertEquals(2013L, rel.getProperty("since")); - end = (Node) path.get(8); - assertEquals(true, end.hasLabel(Label.label("Person"))); - assertEquals("Anne", end.getProperty("name")); - assertEquals("Olsson", end.getProperty("surname")); - assertEquals(point(9157,2.3, 4.5, 1.2).asPoint(), end.getProperty("born")); - }); + public void testLoadBigPathVirtual() { + TestUtil.testCall(db, "call apoc.bolt.load(" + getBoltUrl() + ",'MATCH path= (neo)-[r:KNOWS*3]->(other) WHERE neo.surname = $surnameNode return path', {surnameNode: 'Loagan'}, {virtual:true})", r -> { + Map row = (Map) r.get("row"); + List path = (List) row.get("path"); + Node start = (Node) path.get(0); + assertEquals(true, start.hasLabel(Label.label("Person"))); + assertEquals("Tom", start.getProperty("name")); + assertEquals("Loagan", start.getProperty("surname")); + assertEquals(isoDuration(5, 1, 43200, 0).asIsoDuration(), start.getProperty("duration")); + Relationship rel = (Relationship) path.get(1); + assertEquals("KNOWS", rel.getType().name()); + assertEquals(LocalTime.parse("12:50:35.556"), rel.getProperty("since")); + assertEquals(point(4326, 56.7, 12.78).asPoint(), rel.getProperty("born")); + Node end = (Node) path.get(2); + assertEquals(true, end.hasLabel(Label.label("Person"))); + assertEquals("John", end.getProperty("name")); + assertEquals("Green", end.getProperty("surname")); + assertEquals(point(7203, 2.3, 4.5).asPoint(), end.getProperty("born")); + start = (Node) path.get(3); + assertEquals(true, start.hasLabel(Label.label("Person"))); + assertEquals("John", start.getProperty("name")); + assertEquals("Green", start.getProperty("surname")); + assertEquals(point(7203, 2.3, 4.5).asPoint(), end.getProperty("born")); + rel = (Relationship) path.get(4); + assertEquals("KNOWS", rel.getType().name()); + assertEquals(OffsetTime.parse("12:50:35.556+01:00"), rel.getProperty("since")); + assertEquals(point(4979, 56.7, 12.78, 100.0).asPoint(), rel.getProperty("born")); + end = (Node) path.get(5); + assertEquals(true, end.hasLabel(Label.label("Person"))); + assertEquals("Jim", end.getProperty("name")); + assertEquals("Brown", end.getProperty("surname")); + start = (Node) path.get(6); + assertEquals(true, start.hasLabel(Label.label("Person"))); + assertEquals("Jim", start.getProperty("name")); + assertEquals("Brown", start.getProperty("surname")); + rel = (Relationship) path.get(7); + assertEquals("KNOWS", rel.getType().name()); + assertEquals(2013L, rel.getProperty("since")); + end = (Node) path.get(8); + assertEquals(true, end.hasLabel(Label.label("Person"))); + assertEquals("Anne", end.getProperty("name")); + assertEquals("Olsson", end.getProperty("surname")); + assertEquals(point(9157,2.3, 4.5, 1.2).asPoint(), end.getProperty("born")); + }); } @Test - public void testLoadFromLocal() throws Exception { - final String countQuery = "MATCH p = (s:Source{id:1})-[:REL]->(t:Target{id: 2}) RETURN count(p) AS count"; - long localCount = db.executeTransactionally(countQuery, Collections.emptyMap(), - result -> result.columnAs("count").next()); - assertEquals(0L, localCount); - db.executeTransactionally("CREATE (s:Source{id:1})-[:REL]->(t:Target{id: 2})"); - String localStatement = "call apoc.export.cypher.all(null, {format:'plain', stream:true}) YIELD cypherStatements\n" + - "UNWIND [statement IN split(cypherStatements, \";\\n\") WHERE statement STARTS WITH 'UNWIND'] AS statement\n" + - "RETURN statement"; - String remoteStatement = - "CALL apoc.cypher.doIt(statement, {}) YIELD value\n" + - "RETURN value"; - final Map map = Util.map("url", BOLT_URL.replaceAll("'", ""), + public void testLoadFromLocal() { + String localStatement = "RETURN 'foobar' AS foobar"; + String remoteStatement = "CREATE (n: TestLoadFromLocalNode { m: foobar })"; + final Map map = Util.map( + "url", getBoltUrl().replaceAll("'", ""), "localStatement", localStatement, "remoteStatement", remoteStatement, "config", Util.map("readOnly", false)); db.executeTransactionally("call apoc.bolt.load.fromLocal($url, $localStatement, $remoteStatement, $config) YIELD row return row", map); - final long remoteCount = neo4jContainer.getSession() - .readTransaction(tx -> (long) tx.run("MATCH p = (s:Source{id:1})-[:REL]->(t:Target{id: 2}) RETURN count(p) AS count") - .next().asMap().get("count")); + final long remoteCount = neo4jContainer.getSession().readTransaction(tx -> + (long) tx.run("MATCH (n: TestLoadFromLocalNode { m: 'foobar' }) RETURN count(n) AS count").next().asMap().get("count")); assertEquals(1L, remoteCount); - final String deleteQuery = "MATCH p = (s:Source{id:1})-[:REL]->(t:Target{id: 2}) DELETE p"; - db.executeTransactionally(deleteQuery); - neo4jContainer.getSession().writeTransaction(tx -> tx.run(deleteQuery)); } @Test - public void testLoadFromLocalStream() throws Exception { - final String countQuery = "MATCH p = (s:Source{id:1})-[:REL]->(t:Target{id: 2}) RETURN count(p) AS count"; - long localCount = db.executeTransactionally(countQuery, Collections.emptyMap(), - result -> result.columnAs("count").next()); - assertEquals(0L, localCount); - db.executeTransactionally("CREATE (s:Source{id:1})-[:REL]->(t:Target{id: 2})"); - String localStatement = "call apoc.export.cypher.all(null, {format:'plain', stream:true}) YIELD cypherStatements\n" + - "UNWIND split(cypherStatements, \";\\n\") AS statement\n" + - "RETURN statement"; - final Map map = Util.map("url", BOLT_URL.replaceAll("'", ""), + public void testLoadFromLocalStream() { + String localStatement = "RETURN \"CREATE (n: TestLoadFromLocalStream)\" AS statement"; + final Map map = Util.map( + "url", getBoltUrl().replaceAll("'", ""), "localStatement", localStatement, "remoteStatement", null, "config", Util.map("readOnly", false, "streamStatements", true)); db.executeTransactionally("call apoc.bolt.load.fromLocal($url, $localStatement, $remoteStatement, $config)", map); - final long remoteCount = neo4jContainer.getSession() - .readTransaction(tx -> (long) tx.run("MATCH p = (s:Source{id:1})-[:REL]->(t:Target{id: 2}) RETURN count(p) AS count") - .next().asMap().get("count")); + final long remoteCount = neo4jContainer.getSession().readTransaction(tx -> + (long) tx.run("MATCH (n: TestLoadFromLocalStream) RETURN count(n) AS count").next().asMap().get("count")); assertEquals(1L, remoteCount); - final String deleteQuery = "MATCH p = (s:Source{id:1})-[:REL]->(t:Target{id: 2}) DELETE p"; - db.executeTransactionally(deleteQuery); - neo4jContainer.getSession().writeTransaction(tx -> tx.run(deleteQuery)); + } + + private String getBoltUrl() { + return String.format("'bolt://neo4j:%s@%s:%s'", + TestContainerUtil.password, + neo4jContainer.getContainerIpAddress(), + neo4jContainer.getMappedPort(7687)); } } \ No newline at end of file diff --git a/full-it/src/test/java/apoc/full/it/CoreExtendedTest.java b/full-it/src/test/java/apoc/full/it/CoreExtendedTest.java index 457b78beb4..fbd7e08766 100644 --- a/full-it/src/test/java/apoc/full/it/CoreExtendedTest.java +++ b/full-it/src/test/java/apoc/full/it/CoreExtendedTest.java @@ -56,8 +56,6 @@ public void checkForCoreAndExtended() { neo4jContainer.start(); - assumeTrue("Neo4j Instance should be up-and-running", neo4jContainer.isRunning()); - Session session = neo4jContainer.getSession(); int coreCount = session.run("CALL apoc.help('') YIELD core WHERE core = true RETURN count(*) AS count").peek().get("count").asInt(); int extendedCount = session.run("CALL apoc.help('') YIELD core WHERE core = false RETURN count(*) AS count").peek().get("count").asInt(); diff --git a/full-it/src/test/java/apoc/full/it/CypherEnterpriseExtendedTest.java b/full-it/src/test/java/apoc/full/it/CypherEnterpriseExtendedTest.java index 0e964afa2c..2b2ffadfe0 100644 --- a/full-it/src/test/java/apoc/full/it/CypherEnterpriseExtendedTest.java +++ b/full-it/src/test/java/apoc/full/it/CypherEnterpriseExtendedTest.java @@ -68,9 +68,8 @@ public class CypherEnterpriseExtendedTest { public static void beforeAll() { // We build the project, the artifact will be placed into ./build/libs neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), !TestUtil.isRunningInCI()) - .withNeo4jConfig("dbms.transaction.timeout", "5s"); + .withNeo4jConfig("dbms.transaction.timeout", "60s"); neo4jContainer.start(); - session = neo4jContainer.getSession(); // create cypher files diff --git a/full-it/src/test/java/apoc/full/it/CypherProceduresClusterTest.java b/full-it/src/test/java/apoc/full/it/CypherProceduresClusterTest.java index 593634085f..831bc5b058 100644 --- a/full-it/src/test/java/apoc/full/it/CypherProceduresClusterTest.java +++ b/full-it/src/test/java/apoc/full/it/CypherProceduresClusterTest.java @@ -19,50 +19,51 @@ package apoc.full.it; import apoc.util.TestContainerUtil; -import apoc.util.TestUtil; +import apoc.util.TestContainerUtil.ApocPackage; import apoc.util.TestcontainersCausalCluster; import org.junit.*; import org.neo4j.driver.Session; import org.neo4j.driver.exceptions.DatabaseException; -import org.neo4j.internal.helpers.collection.MapUtil; import java.util.Collections; import java.util.List; import java.util.Map; -import static apoc.util.TestUtil.isRunningInCI; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeTrue; + +// TODO: Remove the @Ignore annotations after fixing clustering +// I investigated the clustering setup over the course of a couple of days and could not get it to work either. Nor our +// existing setup or nor Michael's setup [1] work reliably 100% of the time. There is a real possibility +// that clustering might be broken in dev because it is undergoing many changes. +// [1] https://github.com/michael-simons/junit-jupiter-causal-cluster-testcontainer-extension public class CypherProceduresClusterTest { private static TestcontainersCausalCluster cluster; @BeforeClass public static void setupCluster() { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> cluster = TestContainerUtil - .createEnterpriseCluster(List.of(TestContainerUtil.ApocPackage.FULL), 3, 1, Collections.emptyMap(), MapUtil.stringMap("apoc.custom.procedures.refresh", "100")), - Exception.class); - Assume.assumeNotNull(cluster); - assumeTrue("Neo4j Cluster should be up-and-running", cluster.isRunning()); + cluster = TestContainerUtil.createEnterpriseCluster( + List.of(ApocPackage.FULL), + 3, + 1, + Collections.emptyMap(), + Map.of("apoc.custom.procedures.refresh", "100")); } @AfterClass public static void bringDownCluster() { - if (cluster != null) { - cluster.close(); - } + cluster.close(); } @Test + @Ignore public void shouldRecreateCustomFunctionsOnOtherClusterMembers() throws InterruptedException { // given - + try(Session session = cluster.getDriver().session()) { - session.writeTransaction(tx -> tx.run("call apoc.custom.asFunction('answer1', 'RETURN 42 as answer')")); // we create a function + session.writeTransaction(tx -> tx.run("call apoc.custom.declareFunction('answer1() :: (output::LONG)', 'RETURN 42 as answer')")); // we create a function } // whencypher procedures @@ -80,13 +81,14 @@ public void shouldRecreateCustomFunctionsOnOtherClusterMembers() throws Interrup } @Test + @Ignore public void shouldUpdateCustomFunctionsOnOtherClusterMembers() throws InterruptedException { // given - cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.asFunction('answer2', 'RETURN 42 as answer')")); // we create a function + cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.declareFunction('answer2() :: (output::LONG)', 'RETURN 42 as answer')")); // we create a function TestContainerUtil.testCall(cluster.getSession(), "return custom.answer2() as row", (row) -> assertEquals(42L, ((Map)((List)row.get("row")).get(0)).get("answer"))); // when - cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.asFunction('answer2', 'RETURN 52 as answer')")); // we update the function + cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.declareFunction('answer2() :: (output::LONG)', 'RETURN 52 as answer')")); // we update the function Thread.sleep(1000); // then @@ -95,9 +97,10 @@ public void shouldUpdateCustomFunctionsOnOtherClusterMembers() throws Interrupte } @Test + @Ignore public void shouldRegisterSimpleStatementOnOtherClusterMembers() throws InterruptedException { // given - cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.asProcedure('answerProcedure1', 'RETURN 33 as answer', 'read', [['answer','long']])")); // we create a procedure + cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.declareProcedure('answerProcedure1() :: LONG', 'RETURN 33 as answer', 'read'")); // we create a procedure // when TestContainerUtil.testCall(cluster.getSession(), "call custom.answerProcedure1()", (row) -> Assert.assertEquals(33L, row.get("answer"))); @@ -107,13 +110,14 @@ public void shouldRegisterSimpleStatementOnOtherClusterMembers() throws Interrup } @Test + @Ignore public void shouldUpdateSimpleStatementOnOtherClusterMembers() throws InterruptedException { // given - cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.asProcedure('answerProcedure2', 'RETURN 33 as answer', 'read', [['answer','long']])")); // we create a procedure + cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.declareProcedure('answerProcedure2() :: LONG', 'RETURN 33 as answer')")); // we create a procedure TestContainerUtil.testCall(cluster.getSession(), "call custom.answerProcedure2()", (row) -> Assert.assertEquals(33L, row.get("answer"))); // when - cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.asProcedure('answerProcedure2', 'RETURN 55 as answer', 'read', [['answer','long']])")); // we create a procedure + cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.declareProcedure('answerProcedure2() :: LONG', 'RETURN 55 as answer')")); // we create a procedure Thread.sleep(1000); // then @@ -121,9 +125,10 @@ public void shouldUpdateSimpleStatementOnOtherClusterMembers() throws Interrupte } @Test(expected = DatabaseException.class) + @Ignore public void shouldRemoveProcedureOnOtherClusterMembers() throws InterruptedException { // given - cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.asProcedure('answerToRemove', 'RETURN 33 as answer', 'read', [['answer','long']])")); // we create a procedure + cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.declareProcedure('answerToRemove() :: LONG', 'RETURN 33 as answer')")); // we create a procedure Thread.sleep(1000); try { TestContainerUtil.testCallInReadTransaction(cluster.getSession(), "call custom.answerToRemove()", (row) -> Assert.assertEquals(33L, row.get("answer"))); @@ -147,9 +152,10 @@ public void shouldRemoveProcedureOnOtherClusterMembers() throws InterruptedExcep } @Test(expected = DatabaseException.class) + @Ignore public void shouldRemoveFunctionOnOtherClusterMembers() throws InterruptedException { // given - cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.asFunction('answerFunctionToRemove', 'RETURN 42 as answer')")); // we create a function + cluster.getSession().writeTransaction(tx -> tx.run("call apoc.custom.declareFunction('answerFunctionToRemove()', 'RETURN 42 as answer')")); // we create a function Thread.sleep(1000); try { TestContainerUtil.testCallInReadTransaction(cluster.getSession(), "return custom.answerFunctionToRemove() as row", (row) -> assertEquals(42L, ((Map)((List)row.get("row")).get(0)).get("answer"))); diff --git a/full-it/src/test/java/apoc/full/it/DiffFullTest.java b/full-it/src/test/java/apoc/full/it/DiffFullTest.java index 04fedddb15..34b23d2f0f 100644 --- a/full-it/src/test/java/apoc/full/it/DiffFullTest.java +++ b/full-it/src/test/java/apoc/full/it/DiffFullTest.java @@ -70,7 +70,7 @@ public class DiffFullTest { @BeforeClass public static void setup() { - neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), true) + neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), !TestUtil.isRunningInCI()) .withInitScript("init_neo4j_diff.cypher") .withLogging() .withoutAuthentication(); diff --git a/full-it/src/test/java/apoc/full/it/MetricsTest.java b/full-it/src/test/java/apoc/full/it/MetricsTest.java index ade5763d72..5ca53a007c 100644 --- a/full-it/src/test/java/apoc/full/it/MetricsTest.java +++ b/full-it/src/test/java/apoc/full/it/MetricsTest.java @@ -24,6 +24,7 @@ import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.neo4j.driver.Session; import org.neo4j.internal.helpers.collection.Iterators; @@ -40,49 +41,34 @@ import static apoc.util.TestContainerUtil.createEnterpriseDB; import static apoc.util.TestContainerUtil.testCall; import static apoc.util.TestContainerUtil.testResult; -import static apoc.util.TestUtil.isRunningInCI; import static apoc.util.Util.map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; -/** - * @author as - * @since 13.02.19 - */ +// TODO Investigate why this test is not working. Possibly increase timeout for container +@Ignore public class MetricsTest { private static Neo4jContainerExtension neo4jContainer; private static Session session; @BeforeClass - public static void beforeAll() throws InterruptedException { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), true) - .withNeo4jConfig("apoc.import.file.enabled", "true") - .withNeo4jConfig("metrics.enabled", "true") - .withNeo4jConfig("metrics.csv.interval", "1s") - .withNeo4jConfig("metrics.namespaces.enabled", "true"); - neo4jContainer.start(); - }, Exception.class); - assumeNotNull(neo4jContainer); - assumeTrue("Neo4j Instance should be up-and-running", neo4jContainer.isRunning()); + public static void beforeAll() { + neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), !TestUtil.isRunningInCI()) + .withNeo4jConfig("apoc.import.file.enabled", "true") + .withNeo4jConfig("metrics.enabled", "true") + .withNeo4jConfig("metrics.csv.interval", "1s") + .withNeo4jConfig("metrics.namespaces.enabled", "true"); + neo4jContainer.start(); session = neo4jContainer.getSession(); - } @AfterClass public static void afterAll() { - if (neo4jContainer != null && neo4jContainer.isRunning()) { - neo4jContainer.close(); - } - if (session != null) { session.close(); } + neo4jContainer.close(); } @Test @@ -95,7 +81,9 @@ public void shouldNotGetFileOutsideMetricsDir() { } } + // TODO: Investigate broken test. It hangs for more than 30 seconds for no reason. @Test + @Ignore public void shouldGetMetrics() { session.readTransaction(tx -> tx.run("RETURN 1 AS num;")); String metricKey = "neo4j.database.system.check_point.total_time"; diff --git a/full-it/src/test/java/apoc/full/it/SystemDbEnterpriseTest.java b/full-it/src/test/java/apoc/full/it/SystemDbEnterpriseTest.java index 290eca67e4..39c37e76ff 100644 --- a/full-it/src/test/java/apoc/full/it/SystemDbEnterpriseTest.java +++ b/full-it/src/test/java/apoc/full/it/SystemDbEnterpriseTest.java @@ -20,6 +20,8 @@ import apoc.util.Neo4jContainerExtension; import apoc.util.TestContainerUtil; +import apoc.util.TestUtil; +import org.apache.commons.io.FileUtils; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -27,6 +29,7 @@ import org.neo4j.driver.types.Node; import java.io.File; +import java.io.IOException; import java.util.List; import java.util.UUID; @@ -40,22 +43,26 @@ public class SystemDbEnterpriseTest { private static final String USERNAME = "nonadmin"; private static final String PASSWORD = "keystore-password"; + private static final String KEYSTORE_NAME_PKCS_12 = "keystore-name.pkcs12"; + // we put the keystore file in the import folder for simplicity (because it's bound during the creation of the container) + private static File KEYSTORE_FILE; + private static Neo4jContainerExtension neo4jContainer; private static Session session; - - + @BeforeClass public static void beforeClass() throws Exception { final String randomKeyAlias = UUID.randomUUID().toString(); - // we put the keystore file in the import folder for simplicity (because it's bound during the creation of the container) - final String keystoreName = "keystore-name.pkcs12"; - final File keystoreFile = new File(importFolder, keystoreName); + if (!importFolder.exists()) { + importFolder.mkdir(); + } + KEYSTORE_FILE = new File(importFolder, KEYSTORE_NAME_PKCS_12); // certificate file creation final String[] args = new String[] { "keytool", "-genseckey", "-keyalg", "aes", "-keysize", "256", "-storetype", "pkcs12", - "-keystore", keystoreFile.getCanonicalPath(), + "-keystore", KEYSTORE_FILE.getCanonicalPath(), "-alias", randomKeyAlias, "-storepass", PASSWORD}; @@ -63,10 +70,10 @@ public static void beforeClass() throws Exception { proc.waitFor(); // We build the project, the artifact will be placed into ./build/libs - final String pathPwdValue = "/var/lib/neo4j/import/" + keystoreName; - - // we add config useful to create a remote db alias - neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), true) + final String pathPwdValue = "/var/lib/neo4j/import/" + KEYSTORE_FILE.getName(); + + // we add config useful to create a remote db alias + neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), !TestUtil.isRunningInCI()) .withNeo4jConfig("systemdb.secrets.keystore.path", pathPwdValue) .withNeo4jConfig("systemdb.secrets.keystore.password", PASSWORD) .withNeo4jConfig("systemdb.secrets.key.name", randomKeyAlias); @@ -75,9 +82,11 @@ public static void beforeClass() throws Exception { session = neo4jContainer.getSession(); } - + @AfterClass - public static void afterClass() { + public static void afterClass() throws IOException { + FileUtils.forceDelete(KEYSTORE_FILE); + session.close(); neo4jContainer.close(); } diff --git a/full-it/src/test/java/apoc/full/it/TTLMultiDbTest.java b/full-it/src/test/java/apoc/full/it/TTLMultiDbTest.java index f67fa44ebb..fb4abb8032 100644 --- a/full-it/src/test/java/apoc/full/it/TTLMultiDbTest.java +++ b/full-it/src/test/java/apoc/full/it/TTLMultiDbTest.java @@ -19,15 +19,12 @@ package apoc.full.it; import apoc.util.Neo4jContainerExtension; -import apoc.util.TestContainerUtil; import apoc.util.TestUtil; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; -import org.neo4j.driver.AuthTokens; import org.neo4j.driver.Driver; -import org.neo4j.driver.GraphDatabase; import org.neo4j.driver.Record; import org.neo4j.driver.Session; import org.neo4j.driver.SessionConfig; @@ -35,159 +32,125 @@ import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import static apoc.util.TestContainerUtil.createEnterpriseDB; +import static apoc.util.TestContainerUtil.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static apoc.util.TestUtil.isRunningInCI; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; import static org.neo4j.test.assertion.Assert.assertEventually; public class TTLMultiDbTest { private static Neo4jContainerExtension neo4jContainer; private static Driver driver; + private static Session neo4jSession; + private static Session testSession; + private static Session fooSession; + private static Session barSession; - private static final String DB_NEO4J = "neo4j"; private static final String DB_TEST = "dbtest"; private static final String DB_FOO = "dbfoo"; private static final String DB_BAR = "dbbar"; @BeforeClass public static void setupContainer() { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), !TestUtil.isRunningInCI()) - .withEnv(Map.of("apoc.ttl.enabled." + DB_TEST, "false", - "apoc.ttl.enabled", "true", - "apoc.ttl.schedule", "2", - "apoc.ttl.schedule." + DB_FOO, "7", - "apoc.ttl.limit", "200", - "apoc.ttl.limit." + DB_BAR, "2000")); - neo4jContainer.start(); - }, Exception.class); - assumeNotNull(neo4jContainer); - assumeTrue("Neo4j Instance should be up-and-running", neo4jContainer.isRunning()); - - driver = GraphDatabase.driver(neo4jContainer.getBoltUrl(), AuthTokens.basic("neo4j", "apoc")); - - try (Session session = driver.session()) { - session.writeTransaction(tx -> tx.run("CREATE DATABASE " + DB_TEST + ";")); - session.writeTransaction(tx -> tx.run("CREATE DATABASE " + DB_FOO + ";")); - session.writeTransaction(tx -> tx.run("CREATE DATABASE " + DB_BAR + ";")); - } - - try(Session session = driver.session(SessionConfig.forDatabase("system"))) { - assertEventually(() -> { - final List list = session.run("SHOW DATABASES YIELD name, currentStatus") - .list(); - return list.stream().allMatch(i -> i.get("currentStatus").asString().equals("online")) - && list.stream().map(i -> i.get("name").asString()).collect(Collectors.toList()) - .containsAll(List.of(DB_TEST , DB_FOO , DB_BAR)); - }, value -> value, 30L, TimeUnit.SECONDS); - } - + neo4jContainer = createEnterpriseDB(List.of(ApocPackage.FULL), !TestUtil.isRunningInCI()) + .withEnv(Map.of("apoc.ttl.enabled." + DB_TEST, "false", + "apoc.ttl.enabled", "true", + "apoc.ttl.schedule", "2", + "apoc.ttl.schedule." + DB_FOO, "7", + "apoc.ttl.limit", "200", + "apoc.ttl.limit." + DB_BAR, "2000")); + neo4jContainer.start(); + driver = neo4jContainer.getDriver(); + createDatabases(); + createSessions(); } @After public void cleanDb() { - try (Session session = driver.session()) { - session.writeTransaction(tx -> tx.run("MATCH (n) DETACH DELETE n;")); - } + neo4jSession.writeTransaction(tx -> tx.run("MATCH (n) DETACH DELETE n;")); + testSession.writeTransaction(tx -> tx.run("MATCH (n) DETACH DELETE n;")); + fooSession.writeTransaction(tx -> tx.run("MATCH (n) DETACH DELETE n;")); + barSession.writeTransaction(tx -> tx.run("MATCH (n) DETACH DELETE n;")); } @AfterClass public static void bringDownContainer() { - if (neo4jContainer != null && neo4jContainer.isRunning()) { - neo4jContainer.close(); - } + neo4jSession.close(); + testSession.close(); + fooSession.close(); + barSession.close(); + driver.close(); + neo4jContainer.close(); } @Test - public void testWithSpecificDatabaseWithTTLDisabled() throws Exception { - try (Session session = driver.session(SessionConfig.forDatabase(DB_TEST))) { - TestContainerUtil.testCall( - session, - "RETURN apoc.ttl.config() AS value", - (row) -> { - Map value = (Map) row.get("value"); - assertFalse((Boolean) value.get("enabled")); - }); - } + public void testWithSpecificDatabaseWithTTLDisabled() { + testCall(testSession, "RETURN apoc.ttl.config() AS value", (row) -> { + Map value = (Map) row.get("value"); + assertFalse((Boolean) value.get("enabled")); + }); } @Test - public void testWithDefaultDatabaseWithTTLEnabled() throws Exception { - - try (Session session = driver.session(SessionConfig.forDatabase(DB_NEO4J))) { - TestContainerUtil.testCall( - session, - "RETURN apoc.ttl.config() AS value", - (row) -> { - Map value = (Map) row.get("value"); - assertTrue((Boolean) value.get("enabled")); - assertEquals(2L, value.get("schedule")); - assertEquals(200L, value.get("limit")); - }); - } + public void testWithDefaultDatabaseWithTTLEnabled() { + testCall(neo4jSession, "RETURN apoc.ttl.config() AS value", (row) -> { + Map value = (Map) row.get("value"); + assertTrue((Boolean) value.get("enabled")); + assertEquals(2L, value.get("schedule")); + assertEquals(200L, value.get("limit")); + }); } @Test - public void testWithDefaultDatabaseAndSpecificDbWithScheduleSpecified() throws Exception { - try (Session session = driver.session(SessionConfig.forDatabase(DB_NEO4J))) { - TestContainerUtil.testCall( - session, - "RETURN apoc.ttl.config() AS value", - (row) -> { - Map value = (Map) row.get("value"); - assertTrue((Boolean) value.get("enabled")); - assertEquals(2L, value.get("schedule")); - assertEquals(200L, value.get("limit")); - }); - } - - try (Session session = driver.session(SessionConfig.forDatabase(DB_FOO))) { - TestContainerUtil.testCall( - session, - "RETURN apoc.ttl.config() AS value", - (row) -> { - Map value = (Map) row.get("value"); - assertTrue((Boolean) value.get("enabled")); - assertEquals(7L, value.get("schedule")); - assertEquals(200L, value.get("limit")); - }); - } + public void testWithDefaultDatabaseAndSpecificDbWithScheduleSpecified() { + testCall(neo4jSession, "RETURN apoc.ttl.config() AS value", (row) -> { + Map value = (Map) row.get("value"); + assertTrue((Boolean) value.get("enabled")); + assertEquals(2L, value.get("schedule")); + assertEquals(200L, value.get("limit")); + }); + + testCall(fooSession, "RETURN apoc.ttl.config() AS value", (row) -> { + Map value = (Map) row.get("value"); + assertTrue((Boolean) value.get("enabled")); + assertEquals(7L, value.get("schedule")); + assertEquals(200L, value.get("limit")); + }); } @Test - public void testWithDefaultDatabaseAndSpecificDbWithLimitSpecified() throws Exception { - - try (Session session = driver.session(SessionConfig.forDatabase(DB_NEO4J))) { - TestContainerUtil.testCall( - session, - "RETURN apoc.ttl.config() AS value", - (row) -> { - Map value = (Map) row.get("value"); - assertTrue((Boolean) value.get("enabled")); - assertEquals(2L, value.get("schedule")); - assertEquals(200L, value.get("limit")); - }); - } + public void testWithDefaultDatabaseAndSpecificDbWithLimitSpecified() { + testCall(neo4jSession, "RETURN apoc.ttl.config() AS value", (row) -> { + Map value = (Map) row.get("value"); + assertTrue((Boolean) value.get("enabled")); + assertEquals(2L, value.get("schedule")); + assertEquals(200L, value.get("limit")); + }); + + testCall(barSession, "RETURN apoc.ttl.config() AS value", (row) -> { + Map value = (Map) row.get("value"); + assertTrue((Boolean) value.get("enabled")); + assertEquals(2L, value.get("schedule")); + assertEquals(2000L, value.get("limit")); + }); + } - try (Session session = driver.session(SessionConfig.forDatabase(DB_BAR))) { - TestContainerUtil.testCall( - session, - "RETURN apoc.ttl.config() AS value", - (row) -> { - Map value = (Map) row.get("value"); - assertTrue((Boolean) value.get("enabled")); - assertEquals(2L, value.get("schedule")); - assertEquals(2000L, value.get("limit")); - }); + private static void createDatabases() { + try(Session systemSession = driver.session(SessionConfig.forDatabase("system"))) { + systemSession.writeTransaction(tx -> { + tx.run("CREATE DATABASE " + DB_TEST + " WAIT;"); + tx.run("CREATE DATABASE " + DB_FOO + " WAIT;"); + return tx.run("CREATE DATABASE " + DB_BAR + " WAIT;"); + }); } } -} + + private static void createSessions() { + neo4jSession = neo4jContainer.getSession(); + testSession = driver.session(SessionConfig.forDatabase(DB_TEST)); + fooSession = driver.session(SessionConfig.forDatabase(DB_FOO)); + barSession = driver.session(SessionConfig.forDatabase(DB_BAR)); + } +} \ No newline at end of file diff --git a/full-it/src/test/java/apoc/full/it/TriggerClusterTest.java b/full-it/src/test/java/apoc/full/it/TriggerClusterTest.java index 004308da4a..e694e1fe13 100644 --- a/full-it/src/test/java/apoc/full/it/TriggerClusterTest.java +++ b/full-it/src/test/java/apoc/full/it/TriggerClusterTest.java @@ -19,12 +19,11 @@ package apoc.full.it; import apoc.util.TestContainerUtil; -import apoc.util.TestUtil; import apoc.util.TestcontainersCausalCluster; import org.junit.AfterClass; -import org.junit.Assume; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.neo4j.driver.Session; import org.neo4j.driver.types.Node; @@ -35,10 +34,8 @@ import java.util.Map; import java.util.concurrent.TimeUnit; -import static apoc.util.TestUtil.isRunningInCI; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assume.assumeFalse; import static org.junit.Assert.assertTrue; import static org.neo4j.configuration.GraphDatabaseSettings.DEFAULT_DATABASE_NAME; import static org.neo4j.configuration.GraphDatabaseSettings.SYSTEM_DATABASE_NAME; @@ -52,24 +49,17 @@ public class TriggerClusterTest { @BeforeClass public static void setupCluster() { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> cluster = TestContainerUtil - .createEnterpriseCluster(List.of(TestContainerUtil.ApocPackage.FULL), 3, 1, Collections.emptyMap(), MapUtil.stringMap( - "apoc.trigger.refresh", "100", - "apoc.trigger.enabled", "true" - )), - Exception.class); - Assume.assumeNotNull(cluster); - Assume.assumeTrue(cluster.isRunning()); - - cluster.getSession().run("CREATE DATABASE " + DB_FOO); + cluster = TestContainerUtil.createEnterpriseCluster( + List.of(TestContainerUtil.ApocPackage.CORE, TestContainerUtil.ApocPackage.FULL), + 3, + 1, + Collections.emptyMap(), + MapUtil.stringMap("apoc.trigger.refresh", "100", "apoc.trigger.enabled", "true")); } @AfterClass public static void bringDownCluster() { - if (cluster != null) { - cluster.close(); - } + cluster.close(); } @Before @@ -79,17 +69,19 @@ public void before() { } + @Ignore @Test - public void testTimeStampTriggerForUpdatedProperties() throws Exception { + public void testTimeStampTriggerForUpdatedProperties() { cluster.getSession().run("CALL apoc.trigger.add('timestamp','UNWIND apoc.trigger.nodesByLabel($assignedNodeProperties,null) AS n SET n.ts = timestamp()',{})"); cluster.getSession().run("CREATE (f:Foo) SET f.foo='bar'"); TestContainerUtil.testCall(cluster.getSession(), "MATCH (f:Foo) RETURN f", (row) -> { - assertEquals(true, ((Node)row.get("f")).containsKey("ts")); + assertTrue(((Node) row.get("f")).containsKey("ts")); }); } + @Ignore @Test - public void testReplication() throws Exception { + public void testReplication() { cluster.getSession().run("CALL apoc.trigger.add('timestamp','UNWIND apoc.trigger.nodesByLabel($assignedNodeProperties,null) AS n SET n.ts = timestamp()',{})"); // Test that the trigger is present in another instance org.neo4j.test.assertion.Assert.assertEventually(() -> cluster.getDriver().session() @@ -97,8 +89,9 @@ public void testReplication() throws Exception { (value) -> "timestamp".equals(value), 30, TimeUnit.SECONDS); } + @Ignore @Test - public void testLowerCaseName() throws Exception { + public void testLowerCaseName() { cluster.getSession().run("create constraint on (p:Person) assert p.id is unique"); cluster.getSession().run("CALL apoc.trigger.add('lowercase','UNWIND apoc.trigger.nodesByLabel($assignedLabels,\"Person\") AS n SET n.id = toLower(n.name)',{})"); cluster.getSession().run("CREATE (f:Person {name:'John Doe'})"); @@ -107,14 +100,15 @@ public void testLowerCaseName() throws Exception { assertEquals("John Doe", ((Node)row.get("f")).get("name").asString()); }); } + @Ignore @Test - public void testSetLabels() throws Exception { + public void testSetLabels() { cluster.getSession().run("CREATE (f {name:'John Doe'})"); cluster.getSession().run("CALL apoc.trigger.add('setlabels','UNWIND apoc.trigger.nodesByLabel($assignedLabels,\"Person\") AS n SET n:Man',{})"); cluster.getSession().run("MATCH (f) SET f:Person"); TestContainerUtil.testCall(cluster.getSession(), "MATCH (f:Man) RETURN f", (row) -> { assertEquals("John Doe", ((Node)row.get("f")).get("name").asString()); - assertEquals(true, ((Node)row.get("f")).hasLabel("Person")); + assertTrue(((Node) row.get("f")).hasLabel("Person")); }); long count = TestContainerUtil.singleResultFirstColumn(cluster.getSession(), "MATCH (f:Man) RETURN count(*) as c"); @@ -122,8 +116,9 @@ public void testSetLabels() throws Exception { } + @Ignore @Test - public void testTxIdAfterAsync() throws Exception { + public void testTxIdAfterAsync() { cluster.getSession().run("CALL apoc.trigger.add('triggerTest','UNWIND apoc.trigger.propertiesByKey($assignedNodeProperties, \"_executed\") as prop " + " WITH prop.node as n " + " CREATE (z:SON {father:id(n)}) " + @@ -139,8 +134,9 @@ public void testTxIdAfterAsync() throws Exception { // test cases duplicated, regarding new procedures // + @Ignore @Test - public void testTimeStampTriggerForUpdatedPropertiesNewProcedures() throws Exception { + public void testTimeStampTriggerForUpdatedPropertiesNewProcedures() { 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()',{})", @@ -155,8 +151,9 @@ public void testTimeStampTriggerForUpdatedPropertiesNewProcedures() throws Excep } } + @Ignore @Test - public void testReplicationNewProcedures() throws Exception { + public void testReplicationNewProcedures() { 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()',{})"); } @@ -164,6 +161,7 @@ public void testReplicationNewProcedures() throws Exception { awaitProcedureInstalled(cluster.getDriver().session(), "timestamp"); } + @Ignore @Test public void testLowerCaseNameNewProcedures() { final String name = "lowercase"; @@ -183,8 +181,9 @@ public void testLowerCaseNameNewProcedures() { } } + @Ignore @Test - public void testSetLabelsNewProcs() throws Exception { + public void testSetLabelsNewProcs() { 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',{})", @@ -206,8 +205,9 @@ public void testSetLabelsNewProcs() throws Exception { } } + @Ignore @Test - public void testTxIdAfterAsyncNewProcedures() throws Exception { + public void testTxIdAfterAsyncNewProcedures() { 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 " + @@ -235,6 +235,7 @@ private static void awaitProcedureInstalled(Session session, String name) { 30, TimeUnit.SECONDS); } + @Ignore @Test public void testTriggerCreatedInCorrectDatabase() { final String name = "testDatabase"; diff --git a/full-it/src/test/java/apoc/full/it/UUIDMultiDbTest.java b/full-it/src/test/java/apoc/full/it/UUIDMultiDbTest.java index 94f2f64b54..8d6e28cc60 100644 --- a/full-it/src/test/java/apoc/full/it/UUIDMultiDbTest.java +++ b/full-it/src/test/java/apoc/full/it/UUIDMultiDbTest.java @@ -19,7 +19,8 @@ package apoc.full.it; import apoc.util.Neo4jContainerExtension; -import apoc.util.TestContainerUtil; +import apoc.util.SystemDbTestUtil; +import apoc.util.TestContainerUtil.ApocPackage; import apoc.util.TestUtil; import org.junit.After; import org.junit.AfterClass; @@ -39,17 +40,13 @@ import static apoc.ApocConfig.APOC_UUID_ENABLED; import static apoc.ApocConfig.APOC_UUID_ENABLED_DB; -import static apoc.util.SystemDbTestUtil.TIMEOUT; import static apoc.util.TestContainerUtil.createEnterpriseDB; -import static apoc.util.TestUtil.isRunningInCI; import static apoc.uuid.UUIDTestUtils.assertIsUUID; import static apoc.uuid.UuidHandler.APOC_UUID_REFRESH; import static apoc.uuid.UuidHandler.NOT_ENABLED_ERROR; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; +import static org.junit.Assert.fail; import static org.neo4j.configuration.GraphDatabaseSettings.SYSTEM_DATABASE_NAME; import static org.neo4j.test.assertion.Assert.assertEventually; @@ -57,44 +54,37 @@ public class UUIDMultiDbTest { private static Neo4jContainerExtension neo4jContainer; private static Driver driver; - private static final String dbTest = "dbtest"; - private static final String dbEnabled = "dbenabled"; + private static Session neo4jSession; + private static Session dbTestSession; + private static final String DB_TEST = "dbtest"; + private static final String DB_ENABLED = "dbenabled"; private static SessionConfig SYS_CONF; @BeforeClass public static void setupContainer() { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - neo4jContainer = createEnterpriseDB(List.of(TestContainerUtil.ApocPackage.FULL), true) - .withEnv(Map.of(String.format(APOC_UUID_ENABLED_DB, dbTest), "false", - APOC_UUID_ENABLED, "true", - APOC_UUID_REFRESH, "1000")); - neo4jContainer.start(); - }, Exception.class); - assumeNotNull(neo4jContainer); - assumeTrue("Neo4j Instance should be up-and-running", neo4jContainer.isRunning()); - + neo4jContainer = createEnterpriseDB(List.of(ApocPackage.FULL), !TestUtil.isRunningInCI()) + .withEnv(String.format(APOC_UUID_ENABLED_DB, DB_TEST), "false") + .withEnv(APOC_UUID_ENABLED, "true") + .withEnv(APOC_UUID_REFRESH, "1000"); + neo4jContainer.start(); driver = neo4jContainer.getDriver(); SYS_CONF = SessionConfig.forDatabase(SYSTEM_DATABASE_NAME); - - try (Session session = driver.session()) { - Stream.of(dbTest, dbEnabled).forEach( - db -> session.run(String.format("CREATE DATABASE %s", db)) - ); - } + createDatabases(); + createSessions(); } @AfterClass public static void bringDownContainer() { - if (neo4jContainer != null && neo4jContainer.isRunning()) { - neo4jContainer.close(); - } + neo4jSession.close(); + dbTestSession.close(); + driver.close(); + neo4jContainer.close(); } @After public void after() { try (Session session = driver.session(SYS_CONF)) { - Stream.of("neo4j", dbEnabled).forEach( + Stream.of("neo4j", DB_ENABLED).forEach( db -> session.run("CALL apoc.uuid.dropAll($db)", Map.of("db", db)) ); @@ -102,65 +92,52 @@ public void after() { } @Test(expected = RuntimeException.class) - public void testWithSpecificDatabaseWithUUIDDisabled() throws Exception { - - Session session = driver.session(SessionConfig.forDatabase(dbTest)); + public void testWithSpecificDatabaseWithUUIDDisabled() { try { - - session.writeTransaction(tx -> tx.run( - "CREATE CONSTRAINT ON (foo:Foo) ASSERT foo.uuid IS UNIQUE") - ); - - session.writeTransaction(tx -> tx.run( - "CALL apoc.uuid.install('Foo') YIELD label RETURN label") - ); - + dbTestSession.writeTransaction(tx -> tx.run("CREATE CONSTRAINT FOR (foo:Foo) REQUIRE foo.uuid IS UNIQUE")); + dbTestSession.writeTransaction(tx -> { + tx.run("CREATE (d:Foo {name:'Test'})-[:WORK]->(l:Bar {name:'Baz'})"); + return tx.run("CALL apoc.uuid.install('Foo', {addToExistingNodes: false }) YIELD label RETURN label"); + }); } catch (RuntimeException e) { String expectedMessage = "Failed to invoke procedure `apoc.uuid.install`: " + - "Caused by: java.lang.RuntimeException: " + String.format(NOT_ENABLED_ERROR, dbTest); + "Caused by: java.lang.RuntimeException: " + String.format(NOT_ENABLED_ERROR, DB_TEST); assertEquals(expectedMessage, e.getMessage()); throw e; } } @Test - public void testWithDefaultDatabaseWithUUIDEnabled() throws InterruptedException { - try (Session session = driver.session(SessionConfig.forDatabase("neo4j"))) { - - session.writeTransaction(tx -> tx.run( - "CREATE CONSTRAINT ON (foo:Foo) ASSERT foo.uuid IS UNIQUE") - ); - - session.writeTransaction(tx -> tx.run( - "CALL apoc.uuid.install('Foo') YIELD label RETURN label") - ); - session.writeTransaction(tx -> tx.run( - "CREATE (d:Foo {name:'Test'})-[:WORK]->(l:Bar {name:'Baz'})") - ); - - String call = "MATCH (n:Foo) RETURN n.uuid as uuid"; - AtomicBoolean nodeHasUUID = new AtomicBoolean(false); - Consumer>> resultConsumer = (result) -> { - Map r = result.next(); - nodeHasUUID.set(r.get("uuid") != null); - }; - - long timeout = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(5); - while (System.currentTimeMillis() < timeout && !nodeHasUUID.get()) { - session.writeTransaction(tx -> { - Map p = Collections.emptyMap(); - resultConsumer.accept(tx.run(call, p).list() - .stream() - .map(Record::asMap) - .collect(Collectors.toList()).iterator()); - tx.commit(); - return null; - }); - } - assertTrue("UUID not set on node after 5 seconds", nodeHasUUID.get()); + public void testWithDefaultDatabaseWithUUIDEnabled() { + neo4jSession.writeTransaction(tx -> tx.run("CREATE CONSTRAINT FOR (foo:Foo) REQUIRE foo.uuid IS UNIQUE")); + neo4jSession.writeTransaction(tx -> { + tx.run("CALL apoc.uuid.install('Foo', {addToExistingNodes: false }) YIELD label RETURN label"); + return tx.run("CREATE (d:Foo {name:'Test'})-[:WORK]->(l:Bar {name:'Baz'})"); + }); + + String call = "MATCH (n:Foo) RETURN n.uuid as uuid"; + AtomicBoolean nodeHasUUID = new AtomicBoolean(false); + Consumer>> resultConsumer = (result) -> { + Map r = result.next(); + nodeHasUUID.set(r.get("uuid") != null); + }; + + long timeout = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(10); + while (System.currentTimeMillis() < timeout && !nodeHasUUID.get()) { + neo4jSession.writeTransaction(tx -> { + Map p = Collections.emptyMap(); + resultConsumer.accept(tx.run(call, p).list() + .stream() + .map(org.neo4j.driver.Record::asMap) + .collect(Collectors.toList()).iterator()); + tx.commit(); + return null; + }); } + assertTrue("UUID not set on node after 5 seconds", nodeHasUUID.get()); } + // // New procedures tests // @@ -168,12 +145,14 @@ public void testWithDefaultDatabaseWithUUIDEnabled() throws InterruptedException @Test(expected = RuntimeException.class) public void createUUIDWithSpecificDbWithUUIDDisabled() { try(Session session = driver.session(SYS_CONF)) { - session.run("CALL apoc.uuid.setup('Baz', $db) YIELD label RETURN label", - Map.of("db", dbTest) - ); + session.writeTransaction(tx -> tx.run( + "CALL apoc.uuid.setup('Disabled', $db) YIELD label RETURN label", + Map.of("db", DB_TEST) + )); + fail("Should fail due to uuid disabled"); } catch (RuntimeException e) { String expectedMessage = "Failed to invoke procedure `apoc.uuid.setup`: " + - "Caused by: java.lang.RuntimeException: " + String.format(NOT_ENABLED_ERROR, dbTest); + "Caused by: java.lang.RuntimeException: " + String.format(NOT_ENABLED_ERROR, DB_TEST); assertEquals(expectedMessage, e.getMessage()); throw e; } @@ -182,35 +161,34 @@ public void createUUIDWithSpecificDbWithUUIDDisabled() { @Test public void createUUIDWithDefaultDbWithUUIDEnabled() { driver.session(SYS_CONF) - .run("CALL apoc.uuid.setup('Baz')"); + .writeTransaction(tx -> tx.run("CALL apoc.uuid.setup('Baz', 'neo4j', {addToExistingNodes: false })")); - try(Session session = driver.session()) { - // check uuid set - awaitUuidSet(session, "Baz"); + // check uuid set + awaitUuidSet(neo4jSession, "Baz"); - session.run("CREATE (:Baz)"); + neo4jSession.writeTransaction(tx -> tx.run("CREATE (:Baz)")); - assertEventually(() -> { - Result res = session.run("MATCH (n:Baz) RETURN n.uuid AS uuid"); - assertTrue(res.hasNext()); - String uuid = res.single().get("uuid").asString(); - assertIsUUID(uuid); - return true; - }, (val) -> val, 10L, TimeUnit.SECONDS); - } + assertEventually(() -> { + Result res = neo4jSession.run("MATCH (n:Baz) RETURN n.uuid AS uuid"); + assertTrue(res.hasNext()); + String uuid = res.single().get("uuid").asString(); + assertIsUUID(uuid); + return true; + }, (val) -> val, 10L, TimeUnit.SECONDS); } @Test - public void createUUIDInNotDefaultDbWithUUIDEnabled() throws InterruptedException { + public void setupUUIDInNotDefaultDbWithUUIDEnabled() throws InterruptedException { driver.session(SYS_CONF) - .run("CALL apoc.uuid.setup('Another', $db)", - Map.of("db", dbEnabled)); + .writeTransaction(tx -> tx.run("CALL apoc.uuid.setup('Another', $db, {addToExistingNodes: false })", + Map.of("db", DB_ENABLED)) + ); - try(Session session = driver.session(SessionConfig.forDatabase(dbEnabled))) { + try(Session session = driver.session(SessionConfig.forDatabase(DB_ENABLED))) { // check uuid set awaitUuidSet(session, "Another"); - session.run("CREATE (:Another)"); + session.writeTransaction(tx -> tx.run("CREATE (:Another)")); Result res = session.run("MATCH (n:Another) RETURN n.uuid AS uuid"); String uuid = res.single().get("uuid").asString(); @@ -235,7 +213,20 @@ private static void awaitUuidSet(Session session, String expected) { assertTrue(res.hasNext()); String label = res.single().get("label").asString(); return expected.equals(label); - }, (val) -> val, TIMEOUT, TimeUnit.SECONDS); + }, (val) -> val, SystemDbTestUtil.TIMEOUT, TimeUnit.SECONDS); } -} + private static void createDatabases() { + try (Session systemSession = driver.session(SessionConfig.forDatabase("system"))) { + Stream.of(DB_TEST, DB_ENABLED).forEach( + db -> systemSession.writeTransaction( + tx -> tx.run(String.format("CREATE DATABASE %s WAIT;", db)) + )); + } + } + + private static void createSessions() { + neo4jSession = neo4jContainer.getSession(); + dbTestSession = driver.session(SessionConfig.forDatabase(DB_TEST)); + } +} \ No newline at end of file diff --git a/full/build.gradle b/full/build.gradle index bd84dcb17c..02190fdc27 100644 --- a/full/build.gradle +++ b/full/build.gradle @@ -147,7 +147,7 @@ dependencies { // schemacrawler compile group: 'us.fatehi', name: 'schemacrawler', version: '15.04.01' - testCompile group: 'us.fatehi', name: 'schemacrawler-mysql', version: '16.19.2' + testCompile group: 'us.fatehi', name: 'schemacrawler-mysql', version: '15.04.01' testCompile group: 'org.apache.hive', name: 'hive-jdbc', version: '1.2.2', withoutServers diff --git a/full/src/main/java/apoc/systemdb/SystemDb.java b/full/src/main/java/apoc/systemdb/SystemDb.java index 0c5c51c7ce..b8479b46cf 100644 --- a/full/src/main/java/apoc/systemdb/SystemDb.java +++ b/full/src/main/java/apoc/systemdb/SystemDb.java @@ -23,13 +23,13 @@ import apoc.Extended; import apoc.export.cypher.ExportFileManager; import apoc.export.cypher.FileManagerFactory; +import apoc.export.util.ExportConfig; import apoc.export.util.ProgressReporter; import apoc.result.ProgressInfo; import apoc.result.RowResult; import apoc.result.VirtualNode; import apoc.result.VirtualRelationship; import apoc.systemdb.metadata.ExportMetadata; -import apoc.util.Util; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Label; import org.neo4j.graphdb.Node; @@ -37,8 +37,6 @@ import org.neo4j.graphdb.Transaction; import org.neo4j.internal.helpers.collection.Iterables; import org.neo4j.internal.helpers.collection.Pair; -import org.neo4j.internal.kernel.api.procs.ProcedureCallContext; -import org.neo4j.internal.kernel.api.security.SecurityContext; import org.neo4j.kernel.impl.coreapi.TransactionImpl; import org.neo4j.procedure.Admin; import org.neo4j.procedure.Context; @@ -57,7 +55,6 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; - @Extended public class SystemDb { public static final String REMOTE_SENSITIVE_PROP = "password"; @@ -66,12 +63,6 @@ public class SystemDb { @Context public ApocConfig apocConfig; - @Context - public SecurityContext securityContext; - - @Context - public ProcedureCallContext callContext; - @Context public GraphDatabaseService db; @@ -95,7 +86,7 @@ public Stream metadata(@Name(value = "config",defaultValue = "{}") ProgressInfo progressInfo = new ProgressInfo(fileName, null, "cypher"); ProgressReporter progressReporter = new ProgressReporter(null, null, progressInfo); - ExportFileManager cypherFileManager = FileManagerFactory.createFileManager(fileName + ".cypher", true); + ExportFileManager cypherFileManager = FileManagerFactory.createFileManager(fileName + ".cypher", true, ExportConfig.EMPTY); withSystemDbTransaction(tx -> { tx.getAllNodes() .stream() @@ -121,9 +112,9 @@ public Stream metadata(@Name(value = "config",defaultValue = "{}") return progressReporter.stream(); } + @Admin @Procedure public Stream graph() { - Util.checkAdmin(securityContext, callContext,"apoc.systemdb.graph"); return withSystemDbTransaction(tx -> { Map virtualNodes = new HashMap<>(); for (Node node: tx.getAllNodes()) { @@ -145,10 +136,9 @@ public Stream graph() { }); } + @Admin @Procedure public Stream execute(@Name("DDL commands, either a string or a list of strings") Object ddlStringOrList, @Name(value="params", defaultValue = "{}") Map params) { - Util.checkAdmin(securityContext, callContext, "apoc.systemdb.execute"); - List commands; if (ddlStringOrList instanceof String) { commands = Collections.singletonList((String)ddlStringOrList); diff --git a/full/src/test/java/apoc/couchbase/CouchbaseTestUtils.java b/full/src/test/java/apoc/couchbase/CouchbaseTestUtils.java index 09c3663058..f1376a49df 100644 --- a/full/src/test/java/apoc/couchbase/CouchbaseTestUtils.java +++ b/full/src/test/java/apoc/couchbase/CouchbaseTestUtils.java @@ -18,16 +18,12 @@ */ package apoc.couchbase; -import apoc.couchbase.document.CouchbaseJsonDocument; -import apoc.util.TestUtil; -import com.couchbase.client.core.env.SeedNode; import com.couchbase.client.core.io.CollectionIdentifier; import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; import com.couchbase.client.java.Collection; import com.couchbase.client.java.json.JsonArray; import com.couchbase.client.java.json.JsonObject; -import com.couchbase.client.java.env.ClusterEnvironment; import com.couchbase.client.java.manager.collection.CollectionManager; import com.couchbase.client.java.manager.collection.CollectionSpec; import com.couchbase.client.java.query.QueryResult; @@ -36,23 +32,20 @@ import org.testcontainers.couchbase.BucketDefinition; import org.testcontainers.couchbase.CouchbaseContainer; +import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.Optional; import java.util.stream.Stream; import java.util.stream.Collectors; import java.util.stream.IntStream; import static apoc.util.TestUtil.isRunningInCI; -import static com.couchbase.client.java.ClusterOptions.clusterOptions; import static com.couchbase.client.java.query.QueryOptions.queryOptions; import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeTrue; -import static org.junit.Assume.assumeNotNull; public class CouchbaseTestUtils { @@ -106,7 +99,7 @@ public static boolean fillDB(Cluster cluster) { } public static String getUrl(CouchbaseContainer couchbaseContainer) { - return String.format("couchbase://%s:%s@%s:%s", USERNAME, PASSWORD, couchbaseContainer.getContainerIpAddress(), couchbaseContainer.getMappedPort(8091)); + return String.format("couchbase://%s:%s@%s:%s", USERNAME, PASSWORD, couchbaseContainer.getContainerIpAddress(), couchbaseContainer.getFirstMappedPort()); } @SuppressWarnings("unchecked") @@ -126,13 +119,12 @@ public static void checkResult(Map result) { Map content = (Map) result.get(BUCKET_NAME); assertTrue(content.get("notableWorks") instanceof List); List notableWorks = (List) content.get("notableWorks"); - //@eclipse-formatter:off + checkDocumentContent( (String) content.get("firstName"), (String) content.get("secondName"), (String) content.get("lastName"), notableWorks); - //@eclipse-formatter:on } public static void checkDocumentContent(String firstName, String secondName, String lastName, List notableWorks) { @@ -147,37 +139,20 @@ public static void checkDocumentContent(String firstName, String secondName, Str assertTrue(notableWorks.contains("Sorrow")); } - protected static void checkDocumentMetadata(CouchbaseJsonDocument jsonDocumentCreatedForThisTest, String id, long expiry, long cas, Map mutationToken) { - assertEquals(jsonDocumentCreatedForThisTest.id, id); - assertEquals(jsonDocumentCreatedForThisTest.expiry, expiry); - assertEquals(jsonDocumentCreatedForThisTest.cas, cas); - assertEquals(jsonDocumentCreatedForThisTest.mutationToken, mutationToken); - } - protected static void createCouchbaseContainer() { assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - // 7.0 support stably multi collections and scopes - couchbase = new CouchbaseContainer("couchbase/server:7.0.0") - .withStartupAttempts(3) - .withCredentials(USERNAME, PASSWORD) - .withBucket(new BucketDefinition(BUCKET_NAME)); - couchbase.start(); - }, Exception.class); - assumeNotNull(couchbase); - assumeTrue("couchbase must be running", couchbase.isRunning()); - - ClusterEnvironment environment = ClusterEnvironment.create(); - + // 7.0 support stably multi collections and scopes + couchbase = new CouchbaseContainer("couchbase/server:7.0.0") + .withCredentials(USERNAME, PASSWORD) + .withExposedPorts(8091, 8092, 8093, 8094, 11207, 11210, 11211, 18091, 18092, 18093) + .withBucket(new BucketDefinition(BUCKET_NAME)); + couchbase.start(); COUCHBASE_HOST = couchbase.getHost(); - Set seedNodes = Set.of(SeedNode.create(COUCHBASE_HOST, - Optional.of(couchbase.getBootstrapCarrierDirectPort()), - Optional.of(couchbase.getBootstrapHttpDirectPort()))); - Cluster cluster = Cluster.connect(seedNodes, clusterOptions(USERNAME, PASSWORD).environment(environment)); + Cluster cluster = Cluster.connect(couchbase.getConnectionString(), couchbase.getUsername(), couchbase.getPassword()); + cluster.waitUntilReady(Duration.of(30, ChronoUnit.SECONDS)); - boolean isFilled = fillDB(cluster); - assumeTrue("should fill Couchbase with data", isFilled); + fillDB(cluster); HOST = getUrl(couchbase); Bucket bucket = cluster.bucket(BUCKET_NAME); collection = bucket.defaultCollection(); diff --git a/full/src/test/java/apoc/dv/DataVirtualizationCatalogTest.java b/full/src/test/java/apoc/dv/DataVirtualizationCatalogTest.java index fdbca27c0f..8d1bbf0a95 100644 --- a/full/src/test/java/apoc/dv/DataVirtualizationCatalogTest.java +++ b/full/src/test/java/apoc/dv/DataVirtualizationCatalogTest.java @@ -47,15 +47,11 @@ import java.util.stream.Collectors; import static apoc.util.TestUtil.getUrlFileName; -import static apoc.util.TestUtil.isRunningInCI; import static apoc.util.TestUtil.testCall; import static apoc.util.TestUtil.testCallEmpty; import static apoc.util.TestUtil.testResult; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; public class DataVirtualizationCatalogTest { @@ -79,20 +75,13 @@ public void teardown() { @BeforeClass public static void setUpContainer() { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - mysql = new MySQLContainer().withInitScript("init_mysql.sql"); - mysql.start(); - },Exception.class); - assumeNotNull("MySQL container has to exist", mysql); - assumeTrue("MySQL must be running", mysql.isRunning()); + mysql = new MySQLContainer().withInitScript("init_mysql.sql"); + mysql.start(); } @AfterClass public static void tearDownContainer() { - if (mysql != null) { - mysql.stop(); - } + mysql.stop(); } @Test diff --git a/full/src/test/java/apoc/es/ElasticSearchTest.java b/full/src/test/java/apoc/es/ElasticSearchTest.java index fd27b68a64..580fccd993 100644 --- a/full/src/test/java/apoc/es/ElasticSearchTest.java +++ b/full/src/test/java/apoc/es/ElasticSearchTest.java @@ -35,9 +35,7 @@ import java.io.IOException; import java.util.*; -import static apoc.util.TestUtil.isRunningInCI; import static org.junit.Assert.*; -import static org.junit.Assume.*; /** * @author mh @@ -68,13 +66,8 @@ public class ElasticSearchTest { @BeforeClass public static void setUp() throws Exception { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - elastic = new ElasticsearchContainer(); - elastic.start(); - }, Exception.class); - assumeNotNull(elastic); - assumeTrue("Elastic Search must be running", elastic.isRunning()); + elastic = new ElasticsearchContainer(); + elastic.start(); defaultParams.put("host", elastic.getHttpHostAddress()); TestUtil.registerProcedure(db, ElasticSearch.class); insertDocuments(); @@ -82,10 +75,7 @@ public static void setUp() throws Exception { @AfterClass public static void tearDown() { - if (elastic != null) { - elastic.stop(); - } - + elastic.stop(); db.shutdown(); } diff --git a/full/src/test/java/apoc/gephi/GephiMock.java b/full/src/test/java/apoc/gephi/GephiMock.java new file mode 100644 index 0000000000..cf1f46bbd5 --- /dev/null +++ b/full/src/test/java/apoc/gephi/GephiMock.java @@ -0,0 +1,161 @@ +/* + * 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.gephi; + +import org.mockserver.client.MockServerClient; +import org.mockserver.integration.ClientAndServer; +import org.mockserver.model.RegexBody; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.mockserver.model.Header.header; +import static org.mockserver.model.HttpRequest.request; +import static org.mockserver.model.HttpResponse.response; +import static org.mockserver.model.Parameter.param; +import static org.mockserver.model.RegexBody.regex; + +/** + * Mocks the API of a Gephi Server with the GraphStreaming plugin added. This could not be mocked in Docker directly, + * although some (dubious) Gephi images exist. The reason it could not be mocked is that APOC uses Gephi's + * GraphStreaming API which doesn't come package with Gephi by default. The GephiStreaming plugin is designed to be + * installed by Gephi inside of a special graphical user interface that has buttons a human is expected to click. The + * plugin would be very hard to install programmatically. + * + * https://github.com/gephi/gephi/wiki/GraphStreaming + */ +public class GephiMock { + private final ClientAndServer server; + + public GephiMock() { + this.server = ClientAndServer.startClientAndServer(8080); + } + + public void clearAllExpectations() { + this.server.reset(); + } + + public void shutdown() { + this.server.stop(); + } + + public void mockSuccess(String workspace, GephiEntity... entities) { + new MockServerClient("localhost", 8080) + .when(request() + .withMethod("POST") + .withPath("/" + workspace) + .withQueryStringParameter(param("operation", "updateGraph")) + .withHeader(header("Content-Type", "application/json; charset=utf-8")) + .withBody(bodyMatcher(entities)) + ).respond(response() + .withStatusCode(201) + ); + } + + /** + * https://5-2.mock-server.com/mock_server/creating_expectations_request_matchers.html + * We had to chose to go with the RegEx body matcher rather than the String or JSON or JSONSchema matchers because: + * - the JSON that Gephi accepts is not valid JSON (JSON or JSONSchema doesn't work) + * - the JSON that we send to Gephi contains random values which change from run to run (String doesn't work) + */ + private RegexBody bodyMatcher(GephiEntity... entities) { + return regex( + Arrays.stream(entities) + .map(GephiEntity::toRegexPattern) + .collect(Collectors.joining("\r\n"))); + } + + public interface GephiEntity { + String toRegexPattern(); + + default String numberPattern() { + return "-?[\\d\\.]+"; + } + } + + public static final class Node implements GephiEntity { + + private final int id; + private final String label; + + public Node(int id, String label) { + this.id = id; + this.label = label; + } + + @Override + public String toRegexPattern() { + return String.format( + "\\{\"an\":\\{\"%d\":\\{\"label\":\"%s\",\"TYPE\":\"%s\",\"size\":10,\"x\":%s,\"y\":%s,\"r\":%s,\"g\":%s,\"b\":%s\\}\\}\\}", + id, label, label, numberPattern(), numberPattern(), numberPattern(), numberPattern(), numberPattern()); + } + + public static Node node(int id, String label) { + return new Node(id, label); + } + } + + public static final class Relationship implements GephiEntity { + + private final int id; + private final String label; + private final int source; + private final int target; + private final String weight; + private final Set properties; + + public Relationship(int id, String label, int source, int target, String weight, Set properties) { + this.id = id; + this.label = label; + this.source = source; + this.target = target; + this.weight = weight; + this.properties = properties; + } + + private String propertiesPattern() { + final var joined = properties.stream() + .map(property -> String.format("\"%s\":\"%s\"", property, property)) + .collect(Collectors.joining(",")); + + return properties.isEmpty() ? "" : String.format(",%s", joined); + } + + @Override + public String toRegexPattern() { + return String.format( + "\\{\"ae\":\\{\"%d\":\\{\"label\":\"%s\",\"TYPE\":\"%s\",\"source\":\"%d\",\"target\":\"%d\",\"directed\":true,\"weight\":%s,\"r\":%s,\"g\":%s,\"b\":%s%s\\}\\}\\}", + id, label, label, source, target, weight, numberPattern(), numberPattern(), numberPattern(), propertiesPattern()); + } + + public static Relationship relationship(int id, String label, int source, int target, String weight, Set properties) { + return new Relationship(id, label, source, target, weight, properties); + } + + public static Relationship relationship(int id, String label, int source, int target, String weight) { + return relationship(id, label, source, target, weight, new HashSet<>()); + } + + public static Relationship relationship(int id, String label, int source, int target) { + return relationship(id, label, source, target, "1.0"); + } + } +} diff --git a/full/src/test/java/apoc/gephi/GephiTest.java b/full/src/test/java/apoc/gephi/GephiTest.java index 3cf78ad3a5..a07ba6a96f 100644 --- a/full/src/test/java/apoc/gephi/GephiTest.java +++ b/full/src/test/java/apoc/gephi/GephiTest.java @@ -18,22 +18,18 @@ */ package apoc.gephi; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Test; +import org.junit.*; import org.neo4j.test.rule.DbmsRule; import org.neo4j.test.rule.ImpermanentDbmsRule; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; +import java.util.Set; +import static apoc.gephi.GephiMock.Node.node; +import static apoc.gephi.GephiMock.Relationship.relationship; import static apoc.util.TestUtil.registerProcedure; import static apoc.util.TestUtil.testCall; import static apoc.util.Util.map; import static org.junit.Assert.assertEquals; -import static org.junit.Assume.assumeTrue; /** * @author mh @@ -43,36 +39,36 @@ public class GephiTest { private static final String GEPHI_WORKSPACE = "workspace1"; + public static GephiMock gephiMock; + @ClassRule public static DbmsRule db = new ImpermanentDbmsRule(); - private static boolean isGephiRunning() { - try { - URL url = new URL(String.format("http://localhost:8080/%s", GEPHI_WORKSPACE)); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("HEAD"); - try (InputStream in = con.getInputStream()) { - return true; - } - } catch (Exception e) { - return false; - } - } - @BeforeClass public static void setUp() throws Exception { - assumeTrue(isGephiRunning()); + gephiMock = new GephiMock(); registerProcedure(db, Gephi.class); db.executeTransactionally("CREATE (:Foo {name:'Foo'})-[:KNOWS{weight:7.2,foo:'foo',bar:3.0,directed:'error',label:'foo'}]->(:Bar {name:'Bar'})"); } @AfterClass - public static void teardown() { + public static void tearDown() { db.shutdown(); + gephiMock.shutdown(); + } + + @Before + public void clearMockExpectations() { + gephiMock.clearAllExpectations(); } @Test - public void testAdd() throws Exception { + public void testAdd() { + gephiMock.mockSuccess( + GEPHI_WORKSPACE, + node(0, "Foo"), + node(1, "Bar"), + relationship(0, "KNOWS",0, 1)); testCall(db, "MATCH p = (:Foo)-->() WITH p CALL apoc.gephi.add(null,$workspace,p) yield nodes, relationships, format return *", map("workspace", GEPHI_WORKSPACE), r -> { @@ -81,8 +77,14 @@ public void testAdd() throws Exception { assertEquals("gephi", r.get("format")); }); } + @Test - public void testWeightParameter() throws Exception { + public void testWeightParameter() { + gephiMock.mockSuccess( + GEPHI_WORKSPACE, + node(0, "Foo"), + node(1, "Bar"), + relationship(0, "KNOWS",0, 1, "7.2")); testCall(db, "MATCH p = (:Foo)-->() WITH p CALL apoc.gephi.add(null,$workspace,p,'weight') yield nodes, relationships, format return *", map("workspace", GEPHI_WORKSPACE), r -> { @@ -93,7 +95,12 @@ public void testWeightParameter() throws Exception { } @Test - public void testWrongWeightParameter() throws Exception { + public void testWrongWeightParameter() { + gephiMock.mockSuccess( + GEPHI_WORKSPACE, + node(0, "Foo"), + node(1, "Bar"), + relationship(0, "KNOWS",0, 1)); testCall(db, "MATCH p = (:Foo)-->() WITH p CALL apoc.gephi.add(null,$workspace,p,'test') yield nodes, relationships, format return *", map("workspace", GEPHI_WORKSPACE), r -> { @@ -104,7 +111,12 @@ public void testWrongWeightParameter() throws Exception { } @Test - public void testRightExportParameter() throws Exception { + public void testRightExportParameter() { + gephiMock.mockSuccess( + GEPHI_WORKSPACE, + node(0, "Foo"), + node(1, "Bar"), + relationship(0, "KNOWS",0, 1, "7.2", Set.of("foo"))); testCall(db, "MATCH p = (:Foo)-->() WITH p CALL apoc.gephi.add(null,$workspace,p,'weight',['foo']) yield nodes, relationships, format return *", map("workspace", GEPHI_WORKSPACE), r -> { @@ -115,7 +127,12 @@ public void testRightExportParameter() throws Exception { } @Test - public void testWrongExportParameter() throws Exception { + public void testWrongExportParameter() { + gephiMock.mockSuccess( + GEPHI_WORKSPACE, + node(0, "Foo"), + node(1, "Bar"), + relationship(0, "KNOWS",0, 1, "7.2")); testCall(db, "MATCH p = (:Foo)-->() WITH p CALL apoc.gephi.add(null,$workspace,p,'weight',['faa','fee']) yield nodes, relationships, format return *", map("workspace", GEPHI_WORKSPACE), r -> { @@ -126,7 +143,12 @@ public void testWrongExportParameter() throws Exception { } @Test - public void reservedExportParameter() throws Exception { + public void reservedExportParameter() { + gephiMock.mockSuccess( + GEPHI_WORKSPACE, + node(0, "Foo"), + node(1, "Bar"), + relationship(0, "KNOWS",0, 1, "7.2")); testCall(db, "MATCH p = (:Foo)-->() WITH p CALL apoc.gephi.add(null,$workspace,p,'weight',['directed','label']) yield nodes, relationships, format return *", map("workspace", GEPHI_WORKSPACE), r -> { diff --git a/full/src/test/java/apoc/load/CassandraJdbcTest.java b/full/src/test/java/apoc/load/CassandraJdbcTest.java index 8bb61634db..017befd010 100644 --- a/full/src/test/java/apoc/load/CassandraJdbcTest.java +++ b/full/src/test/java/apoc/load/CassandraJdbcTest.java @@ -33,11 +33,9 @@ import java.sql.SQLException; import java.util.Map; -import static apoc.util.TestUtil.isRunningInCI; import static apoc.util.TestUtil.testCall; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; -import static org.junit.Assume.*; public class CassandraJdbcTest extends AbstractJdbcTest { @@ -48,14 +46,9 @@ public class CassandraJdbcTest extends AbstractJdbcTest { @BeforeClass public static void setUp() throws Exception { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - cassandra = new CassandraContainer(); - cassandra.withInitScript("init_cassandra.cql"); - cassandra.start(); - },Exception.class); - assumeNotNull("Cassandra container has to exist", cassandra); - assumeTrue("Cassandra must be running", cassandra.isRunning()); + cassandra = new CassandraContainer(); + cassandra.withInitScript("init_cassandra.cql"); + cassandra.start(); TestUtil.registerProcedure(db, Jdbc.class); db.executeTransactionally("CALL apoc.load.driver('com.github.adejanovski.cassandra.jdbc.CassandraDriver')"); @@ -63,15 +56,12 @@ public static void setUp() throws Exception { @AfterClass public static void tearDown() throws SQLException { - if (cassandra != null) { - cassandra.stop(); - } - + cassandra.stop(); db.shutdown(); } @Test - public void testLoadJdbc() throws Exception { + public void testLoadJdbc() { testCall(db, "CALL apoc.load.jdbc($url,'\"PERSON\"')", Util.map("url", getUrl(), "config", Util.map("schema", "test", "credentials", Util.map("user", cassandra.getUsername(), "password", cassandra.getPassword()))), @@ -79,7 +69,7 @@ public void testLoadJdbc() throws Exception { } @Test - public void testLoadJdbcSelect() throws Exception { + public void testLoadJdbcSelect() { testCall(db, "CALL apoc.load.jdbc($url,'SELECT * FROM \"PERSON\"')", Util.map("url", getUrl(), "config", Util.map("schema", "test", "credentials", Util.map("user", cassandra.getUsername(), "password", cassandra.getPassword())) @@ -88,7 +78,7 @@ public void testLoadJdbcSelect() throws Exception { } @Test - public void testLoadJdbcUpdate() throws Exception { + public void testLoadJdbcUpdate() { TestUtil.singleResultFirstColumn(db, "CALL apoc.load.jdbcUpdate($url,'UPDATE \"PERSON\" SET \"SURNAME\" = ? WHERE \"NAME\" = ?', ['DOE', 'John'])", Util.map("url", getUrl(), "config", Util.map("schema", "test","credentials", Util.map("user", cassandra.getUsername(), "password", cassandra.getPassword())) @@ -108,7 +98,7 @@ public void testLoadJdbcUpdate() throws Exception { } @Test - public void testLoadJdbcParams() throws Exception { + public void testLoadJdbcParams() { testCall(db, "CALL apoc.load.jdbc($url,'SELECT * FROM \"PERSON\" WHERE \"NAME\" = ?', ['John'])", Util.map("url", getUrl(), "config", Util.map("schema", "test", "credentials", Util.map("user", cassandra.getUsername(), "password", cassandra.getPassword())) diff --git a/full/src/test/java/apoc/load/LoadCsvTest.java b/full/src/test/java/apoc/load/LoadCsvTest.java index cd6f0cca7f..495d80004a 100644 --- a/full/src/test/java/apoc/load/LoadCsvTest.java +++ b/full/src/test/java/apoc/load/LoadCsvTest.java @@ -75,6 +75,11 @@ public static void stopServer() { mockServer.stop(); } + @After + public void cleanup() { + db.shutdown(); + } + @Rule public DbmsRule db = new ImpermanentDbmsRule() .withSetting(ApocSettings.apoc_import_file_enabled, true) @@ -555,14 +560,10 @@ public void testLoadCsvNoFailOnError() throws Exception { @Test(expected = QueryExecutionException.class) public void testLoadRedirectWithProtocolChange() { - TestUtil.ignoreException(() -> { - httpServer = new GenericContainer("alpine") - .withCommand("/bin/sh", "-c", "while true; do { echo -e 'HTTP/1.1 301 Moved Permanently\\r\\nLocation: file:/etc/passwd'; echo ; } | nc -l -p 8000; done") - .withExposedPorts(8000); - httpServer.start(); - }, Exception.class); - Assume.assumeNotNull(httpServer); - Assume.assumeTrue(httpServer.isRunning()); + httpServer = new GenericContainer("alpine") + .withCommand("/bin/sh", "-c", "while true; do { echo -e 'HTTP/1.1 301 Moved Permanently\\r\\nLocation: file:/etc/passwd'; echo ; } | nc -l -p 8000; done") + .withExposedPorts(8000); + httpServer.start(); String url = String.format("http://%s:%s", httpServer.getContainerIpAddress(), httpServer.getMappedPort(8000)); try { testResult(db, "CALL apoc.load.csv($url)", map("url", url), diff --git a/full/src/test/java/apoc/load/LoadS3Test.java b/full/src/test/java/apoc/load/LoadS3Test.java index b072f7126d..6fa9e4f401 100644 --- a/full/src/test/java/apoc/load/LoadS3Test.java +++ b/full/src/test/java/apoc/load/LoadS3Test.java @@ -40,7 +40,6 @@ import static apoc.util.TestUtil.testResult; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; -import static org.junit.Assume.assumeTrue; public class LoadS3Test { @@ -68,7 +67,6 @@ public static void destroy() { public void setUp() throws Exception { TestUtil.registerProcedure(db, LoadCsv.class, LoadJson.class, Xml.class); minio = new S3Container(); - assumeTrue(minio.isRunning()); } @After diff --git a/full/src/test/java/apoc/load/MySQLJdbcTest.java b/full/src/test/java/apoc/load/MySQLJdbcTest.java new file mode 100644 index 0000000000..0a753046e3 --- /dev/null +++ b/full/src/test/java/apoc/load/MySQLJdbcTest.java @@ -0,0 +1,64 @@ +package apoc.load; + +import apoc.util.MySQLContainerExtension; +import apoc.util.TestUtil; +import apoc.util.Util; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.Test; +import org.neo4j.test.rule.DbmsRule; +import org.neo4j.test.rule.ImpermanentDbmsRule; + +import java.util.Map; + +import static apoc.util.TestUtil.testCall; +import static org.junit.Assert.assertEquals; + +public class MySQLJdbcTest extends AbstractJdbcTest { + + @ClassRule + public static MySQLContainerExtension mysql = new MySQLContainerExtension(); + + @ClassRule + public static DbmsRule db = new ImpermanentDbmsRule(); + + @BeforeClass + public static void setUpContainer() { + mysql.start(); + TestUtil.registerProcedure(db, Jdbc.class); + } + + @AfterClass + public static void tearDown() { + mysql.stop(); + db.shutdown(); + } + + @Test + public void testLoadJdbc() { + testCall(db, "CALL apoc.load.jdbc($url, $table, [])", + Util.map( + "url", mysql.getJdbcUrl(), + "table", "country"), + row -> { + Map expected = Util.map( + "Code", "NLD", + "Name", "Netherlands", + "Continent", "Europe", + "Region", "Western Europe", + "SurfaceArea", 41526f, + "IndepYear", 1581, + "Population", 15864000, + "LifeExpectancy", 78.3f, + "GNP", 371362f, + "GNPOld", 360478f, + "LocalName", "Nederland", + "GovernmentForm", "Constitutional Monarchy", + "HeadOfState", "Beatrix", + "Capital", 5, + "Code2", "NL"); + assertEquals(expected, row.get("row")); + }); + } +} diff --git a/full/src/test/java/apoc/load/PostgresJdbcTest.java b/full/src/test/java/apoc/load/PostgresJdbcTest.java index 9437009d5a..13576bd903 100644 --- a/full/src/test/java/apoc/load/PostgresJdbcTest.java +++ b/full/src/test/java/apoc/load/PostgresJdbcTest.java @@ -31,10 +31,8 @@ import java.sql.SQLException; -import static apoc.util.TestUtil.isRunningInCI; import static apoc.util.TestUtil.testCall; import static org.junit.Assert.assertEquals; -import static org.junit.Assume.*; public class PostgresJdbcTest extends AbstractJdbcTest { @@ -48,28 +46,20 @@ public class PostgresJdbcTest extends AbstractJdbcTest { @BeforeClass public static void setUp() throws Exception { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - postgress = new PostgreSQLContainer().withInitScript("init_postgres.sql"); - postgress.start(); - },Exception.class); - assumeNotNull("Postgres container has to exist", postgress); - assumeTrue("Postgres must be running", postgress.isRunning()); + postgress = new PostgreSQLContainer().withInitScript("init_postgres.sql"); + postgress.start(); TestUtil.registerProcedure(db,Jdbc.class); db.executeTransactionally("CALL apoc.load.driver('org.postgresql.Driver')"); } @AfterClass public static void tearDown() throws SQLException { - if (postgress != null) { - postgress.stop(); - } - + postgress.stop(); db.shutdown(); } @Test - public void testLoadJdbc() throws Exception { + public void testLoadJdbc() { testCall(db, "CALL apoc.load.jdbc($url,'PERSON',[], $config)", Util.map("url", postgress.getJdbcUrl(), "config", Util.map("schema", "test", "credentials", Util.map("user", postgress.getUsername(), "password", postgress.getPassword()))), @@ -77,7 +67,7 @@ public void testLoadJdbc() throws Exception { } @Test - public void testLoadJdbSelect() throws Exception { + public void testLoadJdbSelect() { testCall(db, "CALL apoc.load.jdbc($url,'SELECT * FROM PERSON',[], $config)", Util.map("url", postgress.getJdbcUrl(), "config", Util.map("schema", "test", "credentials", Util.map("user", postgress.getUsername(), "password", postgress.getPassword()))), @@ -85,7 +75,7 @@ public void testLoadJdbSelect() throws Exception { } @Test - public void testLoadJdbcUpdate() throws Exception { + public void testLoadJdbcUpdate() { testCall(db, "CALL apoc.load.jdbcUpdate($url,'UPDATE PERSON SET \"SURNAME\" = ? WHERE \"NAME\" = ?', ['DOE', 'John'], $config)", Util.map("url", postgress.getJdbcUrl(), "config", Util.map("schema", "test", @@ -94,7 +84,7 @@ public void testLoadJdbcUpdate() throws Exception { } @Test - public void testLoadJdbcParams() throws Exception { + public void testLoadJdbcParams() { testCall(db, "CALL apoc.load.jdbc($url,'SELECT * FROM PERSON WHERE \"NAME\" = ?',['John'], $config)", // YIELD row RETURN row Util.map("url", postgress.getJdbcUrl(), "config", Util.map("schema", "test", diff --git a/full/src/test/java/apoc/model/ModelTest.java b/full/src/test/java/apoc/model/ModelTest.java index f42c316579..64b65d0d23 100644 --- a/full/src/test/java/apoc/model/ModelTest.java +++ b/full/src/test/java/apoc/model/ModelTest.java @@ -34,37 +34,29 @@ import java.util.List; import java.util.stream.Collectors; -import static apoc.util.TestUtil.isRunningInCI; import static apoc.util.TestUtil.testCall; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assume.*; public class ModelTest { - public static String JDBC_URL; @Rule public TestName testName = new TestName(); public static JdbcDatabaseContainer mysql; + private static String mysqlUrl; + @BeforeClass public static void setUpContainer() { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - mysql = new MySQLContainer().withInitScript("init_mysql.sql"); - mysql.start(); - },Exception.class); - assumeNotNull("MySQL container has to exist", mysql); - assumeTrue("MySQL must be running", mysql.isRunning()); - JDBC_URL = mysql.getJdbcUrl() + "?useSSL=false"; + mysql = new MySQLContainer().withInitScript("init_mysql.sql"); + mysql.start(); + mysqlUrl = mysql.getJdbcUrl() + "?enabledTLSProtocols=TLSv1.2"; } @AfterClass public static void tearDownContainer() { - if (mysql != null) { - mysql.stop(); - } + mysql.stop(); } @Rule @@ -72,19 +64,18 @@ public static void tearDownContainer() { @Before public void initDb() { - //ApocConfiguration.initialize((GraphDatabaseAPI)db); TestUtil.registerProcedure(db, Model.class); } @After - public void teardown() { + public void cleanUp() { db.shutdown(); } @Test public void testLoadJdbcSchema() { testCall(db, "CALL apoc.model.jdbc($url, $config)", - Util.map("url", JDBC_URL, + Util.map("url", mysqlUrl, "config", Util.map("schema", "test", "credentials", Util.map("user", mysql.getUsername(), "password", mysql.getPassword()))), (row) -> { @@ -136,11 +127,11 @@ public void testLoadJdbcSchema() { @Test public void testLoadJdbcSchemaWithWriteOperation() { db.executeTransactionally("CALL apoc.model.jdbc($url, $config)", - Util.map("url", JDBC_URL, + Util.map("url", mysqlUrl, "config", Util.map("schema", "test", "write", true, "credentials", Util.map("user", mysql.getUsername(), "password", mysql.getPassword()))), - innerResult -> Iterators.single(innerResult) + Iterators::single ); try (Transaction tx = db.beginTx()) { @@ -190,7 +181,7 @@ public void testLoadJdbcSchemaWithWriteOperation() { @Test public void testLoadJdbcSchemaWithFiltering() { testCall(db, "CALL apoc.model.jdbc($url, $config)", - Util.map("url", JDBC_URL, + Util.map("url", mysqlUrl, "config", Util.map("schema", "test", "credentials", Util.map("user", mysql.getUsername(), "password", mysql.getPassword()), "filters", Util.map("tables", Arrays.asList("country\\w*"), "columns", Arrays.asList("(?i)code", "(?i)name", "(?i)Language")))), diff --git a/full/src/test/java/apoc/mongodb/MongoDBTest.java b/full/src/test/java/apoc/mongodb/MongoDBTest.java index c87f71ddd2..0608869a51 100644 --- a/full/src/test/java/apoc/mongodb/MongoDBTest.java +++ b/full/src/test/java/apoc/mongodb/MongoDBTest.java @@ -23,21 +23,17 @@ import apoc.util.TestUtil; import apoc.util.UrlResolver; import com.mongodb.MongoClient; -import org.apache.commons.lang3.time.DateUtils; import org.bson.types.ObjectId; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.neo4j.graphdb.QueryExecutionException; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; @@ -135,27 +131,6 @@ public void testCompatibleValues() { assertFalse("should not have an exception", hasException); } - @Test - public void testGet() { - TestUtil.testResult(db, "CALL apoc.mongodb.get($host,$db,$collection,null)", params, - res -> assertResult(res)); - } - - @Test - public void testGetCompatible() throws Exception { - TestUtil.testResult(db, "CALL apoc.mongodb.get($host,$db,$collection,null,true)", params, - res -> assertResult(res, LocalDateTime.from(currentTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime()))); - } - - @Test - public void testFirst() throws Exception { - TestUtil.testCall(db, "CALL apoc.mongodb.first($host,$db,$collection,{name:'testDocument'})", params, r -> { - Map doc = (Map) r.get("value"); - assertNotNull(doc.get("_id")); - assertEquals("testDocument", doc.get("name")); - }); - } - @Test public void testGetByObjectId() throws Exception { List refsIds = productReferences.stream().map(ObjectId::toString).collect(Collectors.toList()); @@ -170,7 +145,7 @@ public void testGetByObjectId() throws Exception { assertEquals("Sherlock", doc.get("name")); assertEquals(25L, doc.get("age")); assertEquals(refsIds, doc.get("bought")); - }); + }); } @@ -188,7 +163,7 @@ public void testGetByObjectIdWithCustomIdFieldName() throws Exception { ); assertEquals(40L, doc.get("age")); assertEquals(refsIds, doc.get("bought")); - }); + }); } @Test @@ -203,129 +178,4 @@ public void testGetByObjectIdWithConfigs() throws Exception { assertBoughtReferences(doc, false, false); }); } - - @Test - public void testFind() throws Exception { - TestUtil.testResult(db, "CALL apoc.mongodb.find($host,$db,$collection,{name:'testDocument'},null,null)", - params, res -> assertResult(res)); - } - - @Test - public void testFindSort() throws Exception { - TestUtil.testResult(db, "CALL apoc.mongodb.find($host,$db,$collection,{name:'testDocument'},null,{name:1})", - params, res -> assertResult(res)); - } - - @Test - public void testCount() throws Exception { - TestUtil.testCall(db, "CALL apoc.mongodb.count($host,$db,$collection,{name:'testDocument'})", params, r -> { - assertEquals(NUM_OF_RECORDS, r.get("value")); - }); - } - - @Test - public void testCountAll() throws Exception { - TestUtil.testCall(db, "CALL apoc.mongodb.count($host,$db,$collection,null)", params, r -> { - assertEquals(NUM_OF_RECORDS, r.get("value")); - }); - } - - @Test - public void testUpdate() throws Exception { - TestUtil.testCall(db, "CALL apoc.mongodb.update($host,$db,$collection,{name:'testDocument'},{`$set`:{age:42}})", params, r -> { - long affected = (long) r.get("value"); - assertEquals(NUM_OF_RECORDS, affected); - }); - } - - @Test - public void testInsert() throws Exception { - TestUtil.testResult(db, "CALL apoc.mongodb.insert($host,$db,$collection,[{John:'Snow'}])", params, (r) -> { - assertFalse("should be empty", r.hasNext()); - }); - TestUtil.testCall(db, "CALL apoc.mongodb.first($host,$db,$collection,{John:'Snow'})", params, r -> { - Map doc = (Map) r.get("value"); - assertNotNull(doc.get("_id")); - assertEquals("Snow", doc.get("John")); - }); - } - - @Test - public void testDelete() throws Exception { - TestUtil.testResult(db, "CALL apoc.mongodb.insert($host,$db,$collection,[{foo:'bar'}])", params, (r) -> { - assertFalse("should be empty", r.hasNext()); - }); - TestUtil.testCall(db, "CALL apoc.mongodb.delete($host,$db,$collection,{foo:'bar'})", params, r -> { - long affected = (long) r.get("value"); - assertEquals(1L, affected); - }); - TestUtil.testResult(db, "CALL apoc.mongodb.first($host,$db,$collection,{foo:'bar'})", params, r -> { - assertFalse("should be empty", r.hasNext()); - }); - } - - @Test - public void testInsertFailsDupKey() { - // Three apoc.mongodb.insert each call gets the error: E11000 duplicate key error collection - TestUtil.ignoreException(() -> { - TestUtil.testResult(db, "CALL apoc.mongodb.insert($host,$db,'error',[{foo:'bar', _id: 1}, {foo:'bar', _id: 1}])", params, (r) -> { - assertFalse("should be empty", r.hasNext()); - }); - }, QueryExecutionException.class); - TestUtil.ignoreException(() -> { - TestUtil.testResult(db, "CALL apoc.mongodb.insert($host,$db,'error',[{foo:'bar', _id: 1}, {foo:'bar', _id: 1}])", params, (r) -> { - assertFalse("should be empty", r.hasNext()); - }); - }, QueryExecutionException.class); - TestUtil.ignoreException(() -> { - TestUtil.testResult(db, "CALL apoc.mongodb.insert($host,$db,'error',[{foo:'bar', _id: 1}, {foo:'bar', _id: 1}])", params, (r) -> { - assertFalse("should be empty", r.hasNext()); - }); - }, QueryExecutionException.class); - } - - @Test - public void shouldInsertDataIntoNeo4jWithFromDocument() throws Exception { - Date date = DateUtils.parseDate("11-10-1935", "dd-MM-yyyy"); - TestUtil.testResult(db, "CALL apoc.mongodb.first($host, $db, $collection, $filter, $compatibleValues, $extractReferences) YIELD value " + - "CALL apoc.graph.fromDocument(value, $fromDocConfig) YIELD graph AS g1 " + - "RETURN g1", - map("host", HOST, - "db", "test", - "collection", "person", - "filter", Collections.emptyMap(), - "compatibleValues", true, - "extractReferences", true, - "fromDocConfig", map("write", true, "skipValidation", true, "mappings", map("$", "Person:Customer{!name,bought,coordinates,born}", "$.bought", "Product{!name,price,tags}"))), - r -> assertionsInsertDataWithFromDocument(date, r)); - } - - @Ignore("this does not throw an exception") //TODO: check why test is failing - @Test - public void shouldFailTheInsertWithoutCompatibleValuesFlag() { - thrown.expect(QueryExecutionException.class); - TestUtil.testResult(db, "CALL apoc.mongodb.first($host, $db, $collection, $filter, $compatibleValues, $extractReferences) YIELD value " + - "CALL apoc.graph.fromDocument(value, $fromDocConfig) YIELD graph AS g1 " + - "RETURN g1", - map("host", HOST, - "db", "test", - "collection", "person", - "filter", Collections.emptyMap(), - "compatibleValues", false, - "extractReferences", true, - "fromDocConfig", map("write", true, "skipValidation", true, "mappings", map("$", "Person:Customer{!name,bought,coordinates,born}", "$.bought", "Product{!name,price,tags}"))), - r -> {}); - } - - @Test - public void shouldUseMongoUrlKey() { - TestUtil.testResult(db, "CALL apoc.mongodb.first($host, $db, $collection, $filter, $compatibleValues, $extractReferences)", - map("host", HOST, - "db", "test", - "collection", "person", - "filter", Collections.emptyMap(), - "compatibleValues", false, - "extractReferences", true), - r -> assertTrue(r.hasNext())); - } } diff --git a/full/src/test/java/apoc/mongodb/MongoTest.java b/full/src/test/java/apoc/mongodb/MongoTest.java index 1848ddc237..048b1780d7 100644 --- a/full/src/test/java/apoc/mongodb/MongoTest.java +++ b/full/src/test/java/apoc/mongodb/MongoTest.java @@ -39,6 +39,7 @@ import org.bson.types.ObjectId; import org.bson.types.Symbol; import org.junit.BeforeClass; +import org.junit.Ignore; import org.junit.Test; import org.neo4j.graphdb.QueryExecutionException; import org.neo4j.graphdb.ResourceIterator; @@ -204,7 +205,7 @@ public void shouldFailIfNeitherUriNorConfigHasCollection() { @Test public void shouldNotFailsIfUriHasNotCollectionNameButIsPresentInConfig() { - testCall(db, "CALL apoc.mongo.count($uri, {name:'testDocument'}, {collection: 'test'})", + testCall(db, "CALL apoc.mongo.count($uri, {name:'testDocument'}, {collection: 'test'})", map("uri", String.format("mongodb://admin:pass@%s:%s/test?authSource=admin", mongo.getContainerIpAddress(), mongo.getMappedPort(MONGO_DEFAULT_PORT))), r -> assertEquals(NUM_OF_RECORDS, r.get("value"))); } @@ -253,24 +254,24 @@ public void testWithSkipAndLimit() { @Test public void testAggregation() { - testResult(db, "CALL apoc.mongo.aggregate($uri, [{`$match`: {foo: 'custom'}}, {`$sort`: {name: -1}}, {`$skip`: 1}, {`$limit`: 2}, {`$set`: {aggrField: 'Y'} }], $conf)", + testResult(db, "CALL apoc.mongo.aggregate($uri, [{`$match`: {foo: 'custom'}}, {`$sort`: {name: -1}}, {`$skip`: 1}, {`$limit`: 2}, {`$set`: {aggrField: 'Y'} }], $conf)", map("uri", PERSON_URI, "conf", map("objectIdAsMap", false)), res -> { - final ResourceIterator> value = res.columnAs("value"); - final Map first = value.next(); - assertEquals("custom", first.get("foo")); - assertEquals("vvv", first.get("name")); - assertEquals("baa", first.get("baz")); - assertEquals("Y", first.get("aggrField")); - assertEquals(200L, first.get("age")); - assertTrue(first.get("_id") instanceof String); - final Map second = value.next(); - assertEquals("custom", second.get("foo")); - assertEquals("two", second.get("name")); - assertEquals("Y", second.get("aggrField")); - assertEquals(11L, second.get("age")); - assertTrue(second.get("_id") instanceof String); - assertFalse(value.hasNext()); - }); + final ResourceIterator> value = res.columnAs("value"); + final Map first = value.next(); + assertEquals("custom", first.get("foo")); + assertEquals("vvv", first.get("name")); + assertEquals("baa", first.get("baz")); + assertEquals("Y", first.get("aggrField")); + assertEquals(200L, first.get("age")); + assertTrue(first.get("_id") instanceof String); + final Map second = value.next(); + assertEquals("custom", second.get("foo")); + assertEquals("two", second.get("name")); + assertEquals("Y", second.get("aggrField")); + assertEquals(11L, second.get("age")); + assertTrue(second.get("_id") instanceof String); + assertFalse(value.hasNext()); + }); } @Test @@ -352,7 +353,7 @@ public void testFindWithExtractReferencesTrue() { map("uri", PERSON_URI), r -> { Map doc = (Map) r.get("value"); assertionsPersonAl(doc, false, true); - }); + }); } @Test @@ -369,14 +370,14 @@ public void testUpdate() { map("uri", PERSON_URI), r -> { long affected = (long) r.get("value"); assertEquals(1, affected); - }); + }); // reset property as previously testCall(db, "CALL apoc.mongo.update($uri, {foo: {`$oid`: '57e193d7a9cc81b4027499c4'}},{`$set`:{code: {`$code`: 'function() {}'}}})", map("uri", PERSON_URI), r -> { long affected = (long) r.get("value"); assertEquals(1, affected); - }); + }); } @Test @@ -447,10 +448,11 @@ public void testInsertFailsWithDuplicateKey() { } } + @Ignore @Test public void shouldInsertDataIntoNeo4jWithFromDocument() throws Exception { Date date = DateUtils.parseDate("11-10-1935", "dd-MM-yyyy"); - testResult(db, "CALL apoc.mongo.find($uri, {name: 'Andrea Santurbano'}, {extractReferences: true}) YIELD value " + + testResult(db, "CALL apoc.mongo.find($uri, null, {extractReferences: true}) YIELD value " + "CALL apoc.graph.fromDocument(value, $fromDocConfig) YIELD graph AS g1 " + "RETURN g1", map("uri", PERSON_URI, diff --git a/full/src/test/java/apoc/mongodb/MongoTestBase.java b/full/src/test/java/apoc/mongodb/MongoTestBase.java index d1d9cb1b4f..f375558e1e 100644 --- a/full/src/test/java/apoc/mongodb/MongoTestBase.java +++ b/full/src/test/java/apoc/mongodb/MongoTestBase.java @@ -19,7 +19,6 @@ package apoc.mongodb; import apoc.util.JsonUtil; -import apoc.util.TestUtil; import com.mongodb.MongoClient; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; @@ -60,7 +59,6 @@ import java.util.stream.StreamSupport; import static apoc.util.MapUtil.map; -import static apoc.util.TestUtil.isRunningInCI; import static java.net.HttpURLConnection.HTTP_OK; import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; import static org.junit.Assert.assertArrayEquals; @@ -68,9 +66,6 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; public class MongoTestBase { private long numConnections = -1; @@ -100,9 +95,7 @@ public class MongoTestBase { @AfterClass public static void tearDown() { - if (mongo != null) { - mongo.stop(); - } + mongo.stop(); db.shutdown(); } @@ -119,29 +112,23 @@ public void after() { } public static void createContainer(boolean withAuth) { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - mongo = new GenericContainer("mongo:4") - .withNetworkAliases("mongo-" + Base58.randomString(6)) - .withExposedPorts(MONGO_DEFAULT_PORT) - .waitingFor(new HttpWaitStrategy() - .forPort(MONGO_DEFAULT_PORT) - .forStatusCodeMatching(response -> response == HTTP_OK || response == HTTP_UNAUTHORIZED) - .withStartupTimeout(Duration.ofMinutes(2))); + mongo = new GenericContainer("mongo:4") + .withNetworkAliases("mongo-" + Base58.randomString(6)) + .withExposedPorts(MONGO_DEFAULT_PORT) + .waitingFor(new HttpWaitStrategy() + .forPort(MONGO_DEFAULT_PORT) + .forStatusCodeMatching(response -> response == HTTP_OK || response == HTTP_UNAUTHORIZED) + .withStartupTimeout(Duration.ofMinutes(2))); - if (withAuth) { - mongo.withEnv("MONGO_INITDB_ROOT_USERNAME", "admin") + if (withAuth) { + mongo.withEnv("MONGO_INITDB_ROOT_USERNAME", "admin") .withEnv("MONGO_INITDB_ROOT_PASSWORD", "pass"); - commands = new String[]{"mongo", "admin", "--eval", "db.auth('admin', 'pass'); db.serverStatus().connections;"}; - } else { - commands = new String[]{"mongo", "test", "--eval", "db.serverStatus().connections"}; - } - mongo.start(); - - }, Exception.class); - assumeNotNull(mongo); - assumeTrue("Mongo DB must be running", mongo.isRunning()); + commands = new String[]{"mongo", "admin", "--eval", "db.auth('admin', 'pass'); db.serverStatus().connections;"}; + } else { + commands = new String[]{"mongo", "test", "--eval", "db.serverStatus().connections"}; + } + mongo.start(); } protected static void fillDb(MongoClient mongoClient) throws ParseException { diff --git a/full/src/test/java/apoc/redis/RedisTest.java b/full/src/test/java/apoc/redis/RedisTest.java index 727bf39dec..a2c99a45c3 100644 --- a/full/src/test/java/apoc/redis/RedisTest.java +++ b/full/src/test/java/apoc/redis/RedisTest.java @@ -41,13 +41,9 @@ import java.util.stream.Collectors; import static apoc.util.MapUtil.map; -import static apoc.util.TestUtil.isRunningInCI; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assume.assumeFalse; -import static org.junit.Assume.assumeNotNull; -import static org.junit.Assume.assumeTrue; import static org.neo4j.test.assertion.Assert.assertEventually; @RunWith(Parameterized.class) @@ -67,25 +63,18 @@ public class RedisTest { @BeforeClass public static void beforeClass() { - assumeFalse(isRunningInCI()); - TestUtil.ignoreException(() -> { - redis = new GenericContainer("redis:" + REDIS_VERSION) - .withCommand("redis-server --requirepass " + PASSWORD) - .withExposedPorts(REDIS_DEFAULT_PORT); - redis.start(); - }, Exception.class); + redis = new GenericContainer("redis:" + REDIS_VERSION) + .withCommand("redis-server --requirepass " + PASSWORD) + .withExposedPorts(REDIS_DEFAULT_PORT); + redis.start(); TestUtil.registerProcedure(db, Redis.class); - assumeNotNull(redis); - assumeTrue("Redis must be running", redis.isRunning()); URI = String.format("redis://%s@%s:%s", PASSWORD, redis.getHost(), redis.getMappedPort(REDIS_DEFAULT_PORT)); BEFORE_CONNECTION = getNumConnections(); } @AfterClass public static void tearDown() { - if (redis != null) { - redis.stop(); - } + redis.stop(); db.shutdown(); } diff --git a/full/src/test/java/apoc/util/s3/S3Container.java b/full/src/test/java/apoc/util/s3/S3Container.java index d59e23ee15..98f4620764 100644 --- a/full/src/test/java/apoc/util/s3/S3Container.java +++ b/full/src/test/java/apoc/util/s3/S3Container.java @@ -18,49 +18,37 @@ */ package apoc.util.s3; -import apoc.util.JsonUtil; -import apoc.util.TestUtil; import apoc.util.Util; import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; -import com.amazonaws.services.s3.model.S3Object; -import com.amazonaws.services.s3.model.S3ObjectInputStream; -import org.apache.commons.io.FileUtils; import org.testcontainers.containers.localstack.LocalStackContainer; +import org.testcontainers.utility.DockerImageName; import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.nio.file.Paths; -import static org.junit.Assert.assertEquals; import static org.testcontainers.containers.localstack.LocalStackContainer.Service.S3; public class S3Container implements AutoCloseable { private final static String S3_BUCKET_NAME = "test-bucket"; - private LocalStackContainer localstack; + private final LocalStackContainer localstack; private final AmazonS3 s3; - public S3Container() { - TestUtil.ignoreException(() -> { - localstack = new LocalStackContainer("0.8.10") - .withStartupAttempts(3) - .withServices(S3); - localstack.start(); - }, Exception.class); - if (localstack != null) { - s3 = AmazonS3ClientBuilder - .standard() - .withEndpointConfiguration(getEndpointConfiguration()) - .withCredentials(getCredentialsProvider()) - .build(); - s3.createBucket(getBucket()); - } else { - s3 = null; - } + localstack = new LocalStackContainer(DockerImageName.parse("localstack/localstack:1.2.0")) + .withServices(S3); + localstack.addExposedPorts(4566); + localstack.start(); + + s3 = AmazonS3ClientBuilder + .standard() + .withEndpointConfiguration(getEndpointConfiguration()) + .withCredentials(getCredentialsProvider()) + .build(); + s3.createBucket(S3_BUCKET_NAME); } public void close() { @@ -72,73 +60,23 @@ public AwsClientBuilder.EndpointConfiguration getEndpointConfiguration() { } public AWSCredentialsProvider getCredentialsProvider() { - return localstack.getDefaultCredentialsProvider(); - } - - public String getBucket() { - return S3_BUCKET_NAME; + return new AWSStaticCredentialsProvider(new BasicAWSCredentials(localstack.getAccessKey(), localstack.getSecretKey())); } public String getUrl(String key) { return String.format("s3://%s.%s/%s/%s?accessKey=%s&secretKey=%s", - localstack.getEndpointConfiguration(S3).getSigningRegion(), - localstack.getEndpointConfiguration(S3).getServiceEndpoint() + getEndpointConfiguration().getSigningRegion(), + getEndpointConfiguration().getServiceEndpoint() .replace("http://", ""), S3_BUCKET_NAME, key, - localstack.getDefaultCredentialsProvider().getCredentials().getAWSAccessKeyId(), - localstack.getDefaultCredentialsProvider().getCredentials().getAWSSecretKey()); + getCredentialsProvider().getCredentials().getAWSAccessKeyId(), + getCredentialsProvider().getCredentials().getAWSSecretKey()); } public String putFile(String fileName) { final File file = new File(fileName); - s3.putObject(getBucket(), file.getName(), file); + s3.putObject(S3_BUCKET_NAME, file.getName(), file); return getUrl(file.getName()); } - - public void verifyUpload(File directory, String fileName, String expected) throws IOException { - String s3Url = getUrl(fileName); - S3Container.readFile(s3Url, Paths.get(directory.toString(), fileName).toString()); - assertEquals(expected, readFileToString(directory.getAbsolutePath(), fileName)); - } - - public static void verifyUpload(File directoryExpected, File directory, String s3Url, String fileName) throws IOException { - readFile(s3Url, Paths.get(directory.toString(), fileName).toString()); - assertFileEquals(directoryExpected, fileName); - } - - public static void assertFileEquals(File directoryExpected, String fileName) { - String actualText = TestUtil.readFileToString(new File(directoryExpected, fileName)); - assertStreamEquals(directoryExpected, fileName, actualText); - } - - public static void assertStreamEquals(File directoryExpected, String fileName, String actualText) { - String expectedText = TestUtil.readFileToString(new File(directoryExpected, fileName)); - String[] actualArray = actualText.split("\n"); - String[] expectArray = expectedText.split("\n"); - assertEquals(expectArray.length, actualArray.length); - for (int i = 0; i < actualArray.length; i++) { - assertEquals(JsonUtil.parse(expectArray[i],null, Object.class), JsonUtil.parse(actualArray[i],null, Object.class)); - } - } - - public static void readFile(String s3Url, String pathname) throws IOException { - S3Params s3Params = S3ParamsExtractor.extract(new URL(s3Url)); - S3Aws s3Aws = new S3Aws(s3Params, s3Params.getRegion()); - AmazonS3 s3Client = s3Aws.getClient(); - - S3Object s3object = s3Client.getObject(s3Params.getBucket(), s3Params.getKey()); - S3ObjectInputStream inputStream = s3object.getObjectContent(); - FileUtils.copyInputStreamToFile(inputStream, new File(pathname)); - } - - private static String readFileToString(String directory, String fileName) { - return TestUtil.readFileToString(new File(directory, fileName)); - } - - public boolean isRunning() { - return localstack != null ? localstack.isRunning() : false; - } - - } diff --git a/full/src/test/kotlin/apoc/nlp/NodeMatcher.kt b/full/src/test/kotlin/apoc/nlp/NodeMatcher.kt index d4fa562fb5..4315a56312 100644 --- a/full/src/test/kotlin/apoc/nlp/NodeMatcher.kt +++ b/full/src/test/kotlin/apoc/nlp/NodeMatcher.kt @@ -18,16 +18,25 @@ */ package apoc.nlp -import apoc.nlp.aws.AWSProceduresAPITest import org.hamcrest.Description import org.neo4j.graphdb.Label import org.neo4j.graphdb.Node import java.util.stream.Collectors data class NodeMatcher(private val labels: List