I've a project where I can successfully test my user procedure written using the neo4j traversal framework based on example testing projects.
The relevant part of the pom file is
...
<neo4j.version>5.12.0</neo4j.version>
<neo4j-java-driver.version>5.3.0</neo4j-java-driver.version>
</properties>
<dependencies>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
<version>${neo4j.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.neo4j.test</groupId>
<artifactId>neo4j-harness</artifactId>
<version>${neo4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>${neo4j-java-driver.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.neo4j.procedure/apoc -->
<dependency>
<groupId>org.neo4j.procedure</groupId>
<artifactId>apoc</artifactId>
<version>4.4.0.1</version>
<scope>test</scope>
</dependency>
...
I've set up the embeddedDatabaseServer like this
@BeforeEach
void initializeNeo4j() throws IOException {
var sw = new StringWriter();
try (var in = new BufferedReader(new InputStreamReader(getClass().getResourceAsStream("/getNode/tvlike_test_data.cypher")))) {
in.transferTo(sw);
sw.close();
}
//split into each statement so can be run one by one
List<String> statements = Arrays.asList(sw.toString().split(";\r\n"));
var builder = Neo4jBuilders.newInProcessBuilder()
.withDisabledServer()
.withProcedure(GetNode.class);
for (String statement : statements) {
builder.withFixture(statement);
}
this.embeddedDatabaseServer = builder.build();
}
and the tests run successfully e.g.
@Test
void TryIt() {
try (
var driver = GraphDatabase.driver(embeddedDatabaseServer.boltURI());
var session = driver.session()
) {
var results = session.run("""
match(u:User{userId:'u1'})
where u.isEnabled = true
match(n:Trial{id: 'tr1'})
call cctc.getNode(n, u, { includeFoundPermissions : true })
yield allNodePerms, allPropPerms
return allNodePerms, allPropPerms""")
.single();
var resMap = results.asMap();
//
var allNodePerms = (List<Map<String, Object>>) resMap.get("allNodePerms");
assertThat(allNodePerms.size()).isEqualTo(1);
}
}
I'd like to include apoc procs and functions in my testing, but I can't add the necessary infrastructure successfully. For example, running this
@Test
void TryIt2() {
try (
var driver = GraphDatabase.driver(embeddedDatabaseServer.boltURI());
var session = driver.session()
) {
var results = session.run("""
return apoc.text.code(103) AS output""")
.single();
assertThat(results.get("output")).isEqualTo("g");
}}
gives the error
org.neo4j.driver.exceptions.ClientException: Unknown function 'apoc.text.code' (line 1, column 8 (offset: 7)) "return apoc.text.code(102) AS output"
as you'd expect.
The question is how do I add the apoc library into the embedded server in the set up step? I've tried many examples found in various samples but without success.
The pom file already includes the dependency for the apoc procedures. I've tried amending the @BeforeEach method in various ways, e.g.
but without success.
How can I amend this
var builder = Neo4jBuilders.newInProcessBuilder()
.withDisabledServer()
.withProcedure(GetNode.class);
in my initializeNeo4j method to include apoc?
First of all, you should ensure that your neo4j dependencies have compatible versions. You are currently using wildly different versions:
neo4j
neo4j-java-driver
apoc
.To keep all 3 dependencies consistent, the correct dependencies for the latter 2 artifacts are as follows (notice that the artifactId
for core apoc is apoc-core
in 5.x):
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>${neo4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j.procedure</groupId>
<artifactId>apoc-core</artifactId>
<version>${neo4j.version}</version>
<scope>test</scope>
</dependency>
In general, to use an APOC core function (or procedure) in your embedded server, you need to find the APOC core class that implements the function (or procedure). To do that, you can:
apoc.text.code
, look for a match that looks like
@UserFunction("apoc.text.code")
.apoc.text.Strings
.newInProcessBuilder
, add an import
of that APOC class.withFunction
(or withProcedure
) method and pass it the APOC class. For example, withFunction(Strings.class)
.