Skip to content

Commit

Permalink
Missing procedures fix
Browse files Browse the repository at this point in the history
  • Loading branch information
gem-neo4j committed Jan 30, 2025
1 parent 188ff80 commit 7c939a9
Show file tree
Hide file tree
Showing 14 changed files with 115 additions and 39 deletions.
29 changes: 22 additions & 7 deletions core/src/test/java/apoc/convert/ConvertJsonTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,7 @@ public void testToTreeIssue1685() {
testCall(
db,
"""
CYPHER 5
MATCH path = (k:Person {name:'Keanu Reeves'})-[*..5]-(x)
WITH collect(path) AS paths
CALL apoc.convert.toTree(paths)
Expand Down Expand Up @@ -486,6 +487,7 @@ public void testToTreeIssue2190() {
testCall(
db,
"""
CYPHER 5
MATCH(root:TreeNode) WHERE root.name = "root"
MATCH path = (root)-[cl:CHILD*]->(c:TreeNode)
WITH path, [r IN relationships(path) | r.order] AS orders
Expand All @@ -507,9 +509,11 @@ WITH COLLECT(path) AS paths
public void testToTree() {
testCall(
db,
"CREATE p1=(m:Movie {title:'M'})<-[:ACTED_IN {role:'R1'}]-(:Actor {name:'A1'}), "
+ " p2 = (m)<-[:ACTED_IN {role:'R2'}]-(:Actor {name:'A2'}) WITH [p1,p2] as paths "
+ " CALL apoc.convert.toTree(paths) YIELD value RETURN value",
"""
CYPHER 5 CREATE p1=(m:Movie {title:'M'})<-[:ACTED_IN {role:'R1'}]-(:Actor {name:'A1'}),
p2 = (m)<-[:ACTED_IN {role:'R2'}]-(:Actor {name:'A2'}) WITH [p1,p2] as paths
CALL apoc.convert.toTree(paths) YIELD value RETURN value
""",
(row) -> {
Map root = (Map) row.get("value");
assertEquals("Movie", root.get("_type"));
Expand All @@ -526,9 +530,11 @@ public void testToTree() {
public void testToTreeUpperCaseRels() {
testCall(
db,
"CREATE p1=(m:Movie {title:'M'})<-[:ACTED_IN {role:'R1'}]-(:Actor {name:'A1'}), "
+ " p2 = (m)<-[:ACTED_IN {role:'R2'}]-(:Actor {name:'A2'}) WITH [p1,p2] as paths "
+ " CALL apoc.convert.toTree(paths,false) YIELD value RETURN value",
"""
CYPHER 5
CREATE p1=(m:Movie {title:'M'})<-[:ACTED_IN {role:'R1'}]-(:Actor {name:'A1'}),
p2 = (m)<-[:ACTED_IN {role:'R2'}]-(:Actor {name:'A2'}) WITH [p1,p2] as paths
CALL apoc.convert.toTree(paths,false) YIELD value RETURN value""",
(row) -> {
Map root = (Map) row.get("value");
assertEquals("Movie", root.get("_type"));
Expand All @@ -543,7 +549,7 @@ public void testToTreeUpperCaseRels() {

@Test
public void testTreeOfEmptyList() {
testCall(db, " CALL apoc.convert.toTree([]) YIELD value RETURN value", (row) -> {
testCall(db, "CYPHER 5 CALL apoc.convert.toTree([]) YIELD value RETURN value", (row) -> {
Map root = (Map) row.get("value");
assertTrue(root.isEmpty());
});
Expand All @@ -561,6 +567,7 @@ public void testToTreeLeafNodes() {

String call =
"""
CYPHER 5
MATCH p=(n:Category)-[:subcategory*]->(m)
WHERE NOT (m)-[:subcategory]->() AND NOT ()-[:subcategory]->(n)
WITH COLLECT(p) AS ps
Expand Down Expand Up @@ -632,6 +639,7 @@ RETURN r.id as givenId, id(r) as id, elementId(r) as elementId

String call =
"""
CYPHER 5
MATCH (parent:Bib {id: '57523a6f-fda9-4a61-c4f6-08d47cdcf0cd'})
WITH parent
OPTIONAL MATCH childFlagPath=(parent)-[:HAS]->(:Comm)<-[:Flag]-(:User)
Expand Down Expand Up @@ -747,6 +755,7 @@ public void testToTreeLeafNodesWithConfigInclude() {
statementForConfig(db);
String call =
"""
CYPHER 5
MATCH p=(n:Category)-[:subcategory*]->(m)
WHERE NOT (m)-[:subcategory]->() AND NOT ()-[:subcategory]->(n)
WITH COLLECT(p) AS ps
Expand Down Expand Up @@ -778,6 +787,7 @@ public void testToTreeLeafNodesWithConfigExclude() {
statementForConfig(db);
String call =
"""
CYPHER 5
MATCH p=(n:Category)-[:subcategory*]->(m)
WHERE NOT (m)-[:subcategory]->() AND NOT ()-[:subcategory]->(n)
WITH COLLECT(p) AS ps
Expand Down Expand Up @@ -809,6 +819,7 @@ public void testToTreeLeafNodesWithConfigExcludeInclude() {
statementForConfig(db);
String call =
"""
CYPHER 5
MATCH p=(n:Category)-[:subcategory*]->(m)
WHERE NOT (m)-[:subcategory]->() AND NOT ()-[:subcategory]->(n)
WITH COLLECT(p) AS ps
Expand Down Expand Up @@ -840,6 +851,7 @@ public void testToTreeLeafNodesWithConfigOnlyInclude() {
statementForConfig(db);
String call =
"""
CYPHER 5
MATCH p=(n:Category)-[:subcategory*]->(m)
WHERE NOT (m)-[:subcategory]->() AND NOT ()-[:subcategory]->(n)
WITH COLLECT(p) AS ps
Expand Down Expand Up @@ -871,6 +883,7 @@ public void testToTreeLeafNodesWithConfigErrorInclude() {
statementForConfig(db);
String call =
"""
CYPHER 5
MATCH p=(n:Category)-[:subcategory*]->(m)
WHERE NOT (m)-[:subcategory]->() AND NOT ()-[:subcategory]->(n)
WITH COLLECT(p) AS ps
Expand Down Expand Up @@ -898,6 +911,7 @@ public void testToTreeDoesNotRemoveNonDuplicateRels() {

String query =
"""
CYPHER 5
MATCH p1 = (n:N {id:'n21'})-[e1]->(m1:N)
WITH COLLECT(p1) as paths
CALL apoc.convert.toTree(paths, false)
Expand Down Expand Up @@ -933,6 +947,7 @@ public void testToTreeLeafNodesWithConfigErrorExclude() {
statementForConfig(db);
String call =
"""
CYPHER 5
MATCH p=(n:Category)-[:subcategory*]->(m)
WHERE NOT (m)-[:subcategory]->() AND NOT ()-[:subcategory]->(n)
WITH COLLECT(p) AS ps
Expand Down
1 change: 1 addition & 0 deletions core/src/test/java/apoc/convert/PathsToJsonTreeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,7 @@ public void testToTreeMultiLabelFiltersForOldProcedure() {

var query =
"""
CYPHER 5
MATCH path = (n)-[r]->(m)
WITH COLLECT(path) AS paths
CALL apoc.convert.toTree(paths, true, {nodes: { A: ['-nodeName'] } }) YIELD value AS tree
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static apoc.export.SecurityTestUtil.ALLOWED_EXCEPTIONS;
import static apoc.export.SecurityTestUtil.IMPORT_PROCEDURES;
import static apoc.export.SecurityTestUtil.LOAD_PROCEDURES;
import static apoc.export.SecurityTestUtil.cypher5OnlyProcedures;
import static apoc.export.SecurityTestUtil.setImportFileApocConfigs;
import static apoc.util.FileTestUtil.createTempFolder;
import static apoc.util.FileUtils.ACCESS_OUTSIDE_DIR_ERROR;
Expand Down Expand Up @@ -89,7 +90,8 @@ public class ImportAndLoadCoreSecurityTest {
private final String fileName;

public ImportAndLoadCoreSecurityTest(String method, String methodArguments, String fileName) {
this.apocProcedure = "CALL " + method + methodArguments;
var cypherVersion = cypher5OnlyProcedures.contains(method) ? "CYPHER 5 " : "";
this.apocProcedure = cypherVersion + "CALL " + method + methodArguments;
this.importMethod = method;
this.fileName = fileName;
}
Expand Down
2 changes: 2 additions & 0 deletions core/src/test/java/apoc/export/SecurityTestUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ public class SecurityTestUtil {
Pair.of("xml", "($fileName, '', {}, false)"),
Pair.of("arrow", "($fileName)"));

public static List<String> cypher5OnlyProcedures = List.of("apoc.load.arrow", "apoc.load.jsonParams");

public static void assertPathTraversalError(
GraphDatabaseService db, String query, Map<String, Object> params, Consumer<Map> exceptionConsumer) {

Expand Down
9 changes: 8 additions & 1 deletion core/src/test/java/apoc/export/arrow/ArrowTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,15 @@
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.neo4j.configuration.GraphDatabaseInternalSettings;
import org.neo4j.configuration.GraphDatabaseSettings;
import org.neo4j.graphdb.Result;
import org.neo4j.test.rule.DbmsRule;
import org.neo4j.test.rule.ImpermanentDbmsRule;

/**
* CYPHER 5 only; moved to extended for Cypher 25
*/
public class ArrowTest {

private static File directory = new File("target/arrow import");
Expand All @@ -60,7 +64,10 @@ public class ArrowTest {
public static DbmsRule db = new ImpermanentDbmsRule()
.withSetting(
GraphDatabaseSettings.load_csv_file_url_root,
directory.toPath().toAbsolutePath());
directory.toPath().toAbsolutePath())
.withSetting(
GraphDatabaseInternalSettings.default_cypher_version,
GraphDatabaseInternalSettings.CypherVersion.Cypher5);

public static final List<Map<String, Object>> EXPECTED = List.of(
new HashMap<>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,15 @@
import org.junit.experimental.runners.Enclosed;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.neo4j.configuration.GraphDatabaseInternalSettings;
import org.neo4j.configuration.GraphDatabaseSettings;
import org.neo4j.graphdb.QueryExecutionException;
import org.neo4j.test.rule.DbmsRule;
import org.neo4j.test.rule.ImpermanentDbmsRule;

/**
* CYPHER 5 only; moved to extended for Cypher 25
*/
@RunWith(Enclosed.class)
public class ExportArrowSecurityTest {
public static final File directory = new File("target/import");
Expand All @@ -84,7 +88,10 @@ public class ExportArrowSecurityTest {
public static DbmsRule db = new ImpermanentDbmsRule()
.withSetting(
GraphDatabaseSettings.load_csv_file_url_root,
directory.toPath().toAbsolutePath());
directory.toPath().toAbsolutePath())
.withSetting(
GraphDatabaseInternalSettings.default_cypher_version,
GraphDatabaseInternalSettings.CypherVersion.Cypher5);

@BeforeClass
public static void setUp() {
Expand Down
40 changes: 34 additions & 6 deletions core/src/test/java/apoc/help/HelpTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,39 +55,67 @@ public void teardown() {
}

@Test
public void info() {
TestUtil.testCall(db, "CALL apoc.help($text)", map("text", "bitwise"), (row) -> {
public void infoCypher5() {
TestUtil.testCall(db, "CYPHER 5 CALL apoc.help($text)", map("text", "bitwise"), (row) -> {
assertEquals("function", row.get("type"));
assertEquals("apoc.bitwise.op", row.get("name"));
assertTrue(((String) row.get("text")).contains("bitwise operation"));
assertFalse(((Boolean) row.get("isDeprecated")));
});
TestUtil.testCall(
db,
"CALL apoc.help($text)",
"CYPHER 5 CALL apoc.help($text)",
map("text", "operation+"),
(row) -> assertEquals("apoc.bitwise.op", row.get("name")));
TestUtil.testCall(db, "CALL apoc.help($text)", map("text", "toSet"), (row) -> {
TestUtil.testCall(db, "CYPHER 5 CALL apoc.help($text)", map("text", "toSet"), (row) -> {
assertEquals("function", row.get("type"));
assertEquals("apoc.coll.toSet", row.get("name"));
assertTrue(((String) row.get("text")).contains("unique `LIST<ANY>`"));
assertFalse(((Boolean) row.get("isDeprecated")));
});
TestUtil.testCall(db, "CALL apoc.help($text)", map("text", "diff.nodes"), (row) -> {
TestUtil.testCall(db, "CYPHER 5 CALL apoc.help($text)", map("text", "diff.nodes"), (row) -> {
assertEquals("function", row.get("type"));
assertEquals("apoc.diff.nodes", row.get("name"));
assertTrue(((String) row.get("text"))
.contains("Returns a `MAP` detailing the differences between the two given `NODE` values."));
assertFalse(((Boolean) row.get("isDeprecated")));
});
TestUtil.testCall(db, "CALL apoc.help($text)", map("text", "apoc.create.uuids"), (row) -> {
TestUtil.testCall(db, "CYPHER 5 CALL apoc.help($text)", map("text", "apoc.create.uuids"), (row) -> {
assertEquals("procedure", row.get("type"));
assertEquals("apoc.create.uuids", row.get("name"));
assertTrue(((String) row.get("text")).contains("Returns a stream of UUIDs."));
assertTrue(((Boolean) row.get("isDeprecated")));
});
}

@Test
public void infoCypher25() {
TestUtil.testCall(db, "CYPHER 25 CALL apoc.help($text)", map("text", "bitwise"), (row) -> {
assertEquals("function", row.get("type"));
assertEquals("apoc.bitwise.op", row.get("name"));
assertTrue(((String) row.get("text")).contains("bitwise operation"));
assertFalse(((Boolean) row.get("isDeprecated")));
});
TestUtil.testCall(
db,
"CYPHER 25 CALL apoc.help($text)",
map("text", "operation+"),
(row) -> assertEquals("apoc.bitwise.op", row.get("name")));
TestUtil.testCall(db, "CYPHER 25 CALL apoc.help($text)", map("text", "toSet"), (row) -> {
assertEquals("function", row.get("type"));
assertEquals("apoc.coll.toSet", row.get("name"));
assertTrue(((String) row.get("text")).contains("unique `LIST<ANY>`"));
assertFalse(((Boolean) row.get("isDeprecated")));
});
TestUtil.testCall(db, "CYPHER 25 CALL apoc.help($text)", map("text", "diff.nodes"), (row) -> {
assertEquals("function", row.get("type"));
assertEquals("apoc.diff.nodes", row.get("name"));
assertTrue(((String) row.get("text"))
.contains("Returns a `MAP` detailing the differences between the two given `NODE` values."));
assertFalse(((Boolean) row.get("isDeprecated")));
});
}

@Test
public void indicateCore() {
TestUtil.testCall(
Expand Down
6 changes: 3 additions & 3 deletions core/src/test/java/apoc/load/LoadJsonTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ public void testLoadJson() {
public void testLoadMultiJsonWithBinary() {
testResult(
db,
"CALL apoc.load.jsonParams($url, null, null, null, $config)",
"CYPHER 5 CALL apoc.load.jsonParams($url, null, null, null, $config)",
map(
"url",
fileToBinary(
Expand Down Expand Up @@ -441,7 +441,7 @@ public void testLoadJsonParamsWithAuth() throws Exception {

testCall(
db,
"call apoc.load.jsonParams($url, $config, $payload)",
"CYPHER 5 CALL apoc.load.jsonParams($url, $config, $payload)",
map(
"payload",
"{\"query\":\"pagecache\",\"version\":\"3.5\"}",
Expand Down Expand Up @@ -471,7 +471,7 @@ public void testLoadJsonParams() {

testCall(
db,
"call apoc.load.jsonParams($url, $config, $json)",
"CYPHER 5 CALL apoc.load.jsonParams($url, $config, $json)",
map(
"json",
"{\"query\":\"pagecache\",\"version\":\"3.5\"}",
Expand Down
2 changes: 1 addition & 1 deletion core/src/test/java/apoc/map/MapsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ public void testSetKey() {

@Test
public void testSetEntry() {
TestUtil.testCall(db, "RETURN apoc.map.setEntry({a:1},'a',2) AS value", (r) -> {
TestUtil.testCall(db, "CYPHER 5 RETURN apoc.map.setEntry({a:1},'a',2) AS value", (r) -> {
assertEquals(map("a", 2L), r.get("value"));
});
}
Expand Down
10 changes: 5 additions & 5 deletions core/src/test/java/apoc/text/StringsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ public void testReplace() {

testCall(
db,
"RETURN apoc.text.regreplace($text,$regex,$replacement) AS value",
"CYPHER 5 RETURN apoc.text.regreplace($text,$regex,$replacement) AS value",
map("text", text, "regex", regex, "replacement", replacement),
row -> assertEquals(expected, row.get("value")));
}
Expand All @@ -169,17 +169,17 @@ public void testReplaceAllWithNull() {
String replacement = "";
testCall(
db,
"RETURN apoc.text.regreplace($text,$regex,$replacement) AS value",
"CYPHER 5 RETURN apoc.text.regreplace($text,$regex,$replacement) AS value",
map("text", null, "regex", regex, "replacement", replacement),
row -> assertEquals(null, row.get("value")));
testCall(
db,
"RETURN apoc.text.regreplace($text,$regex,$replacement) AS value",
"CYPHER 5 RETURN apoc.text.regreplace($text,$regex,$replacement) AS value",
map("text", text, "regex", null, "replacement", replacement),
row -> assertEquals(null, row.get("value")));
testCall(
db,
"RETURN apoc.text.regreplace($text,$regex,$replacement) AS value",
"CYPHER 5 RETURN apoc.text.regreplace($text,$regex,$replacement) AS value",
map("text", text, "regex", regex, "replacement", null),
row -> assertEquals(null, row.get("value")));
}
Expand Down Expand Up @@ -397,7 +397,7 @@ public void testFuzzyMatchIntegration() {
public void testDocReplace() {
testCall(
db,
"RETURN apoc.text.regreplace('Hello World!', '[^a-zA-Z]', '') AS value",
"CYPHER 5 RETURN apoc.text.regreplace('Hello World!', '[^a-zA-Z]', '') AS value",
row -> assertEquals("HelloWorld", row.get("value")));
}

Expand Down
9 changes: 6 additions & 3 deletions core/src/test/java/apoc/trigger/TriggerDisabledTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.neo4j.configuration.GraphDatabaseInternalSettings;
import org.neo4j.graphdb.Result;
import org.neo4j.test.rule.DbmsRule;
import org.neo4j.test.rule.ImpermanentDbmsRule;

/**
* @author alexiudice
* @since 14.07.18
* CYPHER 5 only; moved to extended for Cypher 25
* <p>
* Tests for fix of #845.
* <p>
Expand All @@ -47,7 +47,10 @@
public class TriggerDisabledTest {

@ClassRule
public static DbmsRule db = new ImpermanentDbmsRule();
public static DbmsRule db = new ImpermanentDbmsRule()
.withSetting(
GraphDatabaseInternalSettings.default_cypher_version,
GraphDatabaseInternalSettings.CypherVersion.Cypher5);

@BeforeClass
public static void setUp() {
Expand Down
Loading

0 comments on commit 7c939a9

Please sign in to comment.