0

I'm writing Spring Data Neo4J repository tests with @DataNeo4jTest and all is well until I write a test against a custom query that uses a procedure, for example apoc.coll.intersection. The error declares procedure apoc.coll.intersection is unknown. I have the APOC JAR on the classpath so am guessing I need to find a way to register the procedure with the embedded datasource/driver that @DataNeo4jTest uses.

Any help would be appreciated. Thanks.

SingleShot
  • 18,821
  • 13
  • 71
  • 101

2 Answers2

1

Some background to understand the situation: The @DataNeo4jTest annotation provides you the Spring Boot based auto configuration. It will pick up your Neo4j connection configuration in your application.properties (either test or production if no test properties are defined) and create Neo4j-OGM's SessionFactory with the matching configuration for you.

There are two ways to solve you problem:

Define the SessionFactory bean by yourself with embedded instance setup and configuration:

@Bean
public SessionFactory sessionFactory() {
  GraphDatabaseService graphDatabaseService = new GraphDatabaseFactory()
            .newEmbeddedDatabaseBuilder(Paths.get("pathToDb").toFile()).newGraphDatabase();

  registerProcedure(graphDatabaseService, MyProcedure.class);

  EmbeddedDriver driver = new EmbeddedDriver(graphDatabaseService);
  SessionFactory sessionFactory = new SessionFactory(driver, "package");
}

Or during "runtime" with the already existing SessionFactory bean e.g. in your test setup (make sure to do this just once)

EmbeddedDriver loadedDriver = (EmbeddedDriver) sessionFactory.getDriver();
registerProcedure(loadedDriver.getGraphDatabaseService(), MyProcedure.class);

both will call a method like this

public static void registerProcedure(GraphDatabaseService db, Class<?>...procedures) throws KernelException {
    Procedures proceduresService = ((GraphDatabaseAPI) db).getDependencyResolver().resolveDependency(Procedures.class);
    for (Class<?> procedure : procedures) {
        proceduresService.registerProcedure(procedure,true);
        proceduresService.registerFunction(procedure, true);
        proceduresService.registerAggregationFunction(procedure, true);
    }
}

Update: Added example and version definitions.

GraphDatabaseService graphDatabaseService = new GraphDatabaseFactory()
    .newEmbeddedDatabaseBuilder(Paths.get("path/to/db").toFile()).newGraphDatabase();

// Option I
registerProcedure(graphDatabaseService, MyProcedure.class);

EmbeddedDriver driver = new EmbeddedDriver(graphDatabaseService);
SessionFactory sessionFactory = new SessionFactory(driver, "org.neo4j.ogmindex.domain");

// Option II if embedded driver is not directly accessible anymore
EmbeddedDriver loadedDriver = (EmbeddedDriver) sessionFactory.getDriver();
// register the apoc version function
registerProcedure(loadedDriver.getGraphDatabaseService(), Version.class);

// Test call to apoc.version
Session session = sessionFactory.openSession();
session.query("RETURN apoc.version()", emptyMap())
    .forEach(System.out::println); // outputs {apoc.version()=3.4.0.2}

pom.xml definition for the example above:

<dependency>
    <groupId>org.neo4j.test</groupId>
    <artifactId>neo4j-harness-enterprise</artifactId>
    <version>3.4.6</version>
</dependency>
<dependency>
    <groupId>org.neo4j.procedure</groupId>
    <artifactId>apoc</artifactId>
    <version>3.4.0.2</version>
</dependency>
meistermeier
  • 7,942
  • 2
  • 36
  • 45
  • Thanks. I've seen a few answer like this. Unfortunately the register methods on the `Procedures` interface do not exist. I've looked around for similar ones and cannot find any. My APOC JAR version is `3.4.0.2`. – SingleShot Aug 30 '18 at 01:34
  • Would you mind sharing relevant portions of a Maven POM or similar so I can try to mimic the versions? Thanks. – SingleShot Aug 30 '18 at 02:02
  • 1
    Updated my answer – meistermeier Aug 30 '18 at 13:28
  • Thanks for your answer. I played around with it and still could not get the tests to run. After digging through Maven dependencies and some trial and error, I solved it with some dependency tweaks. I'll post my solution. Thanks for your help! I suspect it will still be helpful to others. – SingleShot Sep 02 '18 at 16:34
0

After messing around with this for quite some time, trying different dependency versions and also playing with configuration code as suggested by @meistermeier I found a solution, which was to simply use the correct version of the 2 Neo4J test JARs I was referencing. This is a Spring Boot project so here are all the Neo4J dependencies in my Maven POM that solve the issue:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-neo4j</artifactId>
</dependency>

<dependency>
  <groupId>org.neo4j.test</groupId>
  <artifactId>neo4j-harness</artifactId>
  <version>${neo4j.ogm.version}</version>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.neo4j</groupId>
  <artifactId>neo4j-ogm-embedded-driver</artifactId>
  <version>${neo4j.ogm.version}</version>
  <scope>test</scope>
</dependency>

I set neo4j.ogm.version to match the version specified in the spring-data-neo4j-parent POM (which is brought in transitively).

SingleShot
  • 18,821
  • 13
  • 71
  • 101