Reputation: 6282
I'm starting to use neo4j-spatial in some of my code. I thought I would be able to integration test neo4j-spatial code by including the spatial server lib as a maven dependency in my project. This has not worked for me though. I can't find any documentation anywhere on this.
How can I get my integration tests to work?
Any tips anyone? :)
Just to give an idea of what I'm doing, I've pasted a segment of my controller, service and repository code below, with the final code posting being my tests that don't work against an embedded TestServer.
Repository
package nz.co.domain.core.repository.location;
import org.springframework.data.neo4j.annotation.Query;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import nz.co.domain.model.pojos.Location;
@Repository
public interface LocationRepository extends GraphRepository<Location> {
@Query("match (n:Location {domainId : {domainId}}) with n call spatial.addNode({layerName}, n) yield node return node;")
public Location indexLocation(@Param("domainId") String locationId, @Param("layerName") String layerName);
@Query("call spatial.withinDistance({layerName},{longitude: {longitude},latitude: {latitude}}, {rangeInKms});")
public Iterable<Location> findLocationsWithinRange(@Param("longitude") String longitude, @Param("latitude") String latitude, @Param("rangeInKms") String rangeInKms, @Param("layerName") String layerName);
@Query("call spatial.addPointLayer({layerName});")
public void createLayer(@Param("layerName") String layerName);
@Query("match ()-[:LAYER]->(n) where n.layer = {layerName} return count(n) > 0;")
public boolean hasLayer(@Param("layerName") String layerName);
public Location findByDomainSpecificId(String domainSpecificId);
public Location findByGooglePlaceId(String googlePlaceId);
}
Service
package nz.co.domain.core.location;
import javax.inject.Inject;
import org.springframework.stereotype.Service;
import nz.co.domain.core.repository.location.LocationRepository;
import nz.co.domain.model.UniqueIDGenerator;
import nz.co.domain.model.pojos.Location;
@Service
public class LocationService {
@Inject
private LocationRepository locationRepository;
public void createLayer(String layerName) {
locationRepository.createLayer(layerName);
}
public Location createLocation(double latitude, double longitude, String googlePlaceId, String layerName) {
Location location = new Location(UniqueIDGenerator.randomID(), googlePlaceId, latitude, longitude);
boolean hasLayer = locationRepository.hasLayer(layerName);
if (!hasLayer) {
locationRepository.createLayer(layerName);
}
Location preExistingLocation = locationRepository.findByGooglePlaceId(googlePlaceId);
if (preExistingLocation == null) {
location = locationRepository.save(location);
location = locationRepository.indexLocation(location.getDomainId(), layerName);
} else {
location = preExistingLocation;
}
return location;
}
public Iterable<Location> findLocationsWithinRange(String latitude, String longitude, String rangeInKms, String layerName) {
return locationRepository.findLocationsWithinRange(longitude, latitude, rangeInKms, layerName);
}
public Location loadLocationByGooglePlaceId(String googlePlaceId) {
return locationRepository.findByGooglePlaceId(googlePlaceId);
}
public Location loadLocationByDomainId(String domainId) {
return locationRepository.findByDomainId(domainId);
}
}
Controller
...
/**
* Add location.
* @param profiletypes
* @param profileId
* @return
*/
@RequestMapping(value = "/{profileType}/{profileId}/location", method = RequestMethod.POST, produces = "application/hal+json")
public HttpEntity<LocationResource> addLocation(@PathVariable String profileType,
@PathVariable String profileId, @RequestBody CreateLocationRequest locationRequest, @ApiIgnore LocationResourceAssembler locationResourceAssembler) {
Profile profile = profileService.loadProfileByDomainId(profileId);
Location location = locationService.createLocation(locationRequest.getLatitude(), locationRequest.getLongitude(), locationRequest.getGooglePlaceId(), profileType + "-layer");
profile.setLocation(location);
profileService.save(profile);
location = locationService.loadLocationByGooglePlaceId(location.getGooglePlaceId());
LocationResource resource = locationResourceAssembler.toResource(location);
return new ResponseEntity<>(resource, HttpStatus.CREATED) ;
}
...
Service test
(It is my tests here that I can't get working as part of a standard build against an embedded TestServer)
package nz.co.domain.core.location;
import javax.inject.Inject;
import org.junit.Ignore;
import org.junit.Test;
import nz.co.domain.core.AbstractTest;
import nz.co.domain.model.pojos.Location;
public class LocationServiceTest extends AbstractTest {
@Inject
private LocationService locationService;
@Test
public void indexLocationTest() {
// The Rogue and Vagabond
Location rogueAndVagabond = locationService.createLocation(51.469150, 7.23212, "ChIJmwfKGdivOG0R9eTCVFOngnU", "test-layer");
/* more test code here */
// Te Papa Museum
Location tePapaMuseum = locationService.createLocation(-41.289964, 174.778354, "ChIJfxn9AdGvOG0RpLRGGO3tRX8", "test-layer");
/* more test code here */
// Porirua Club
Location poriruaClub = locationService.createLocation(-41.136048, 174.836409, "ChIJ9wl16m1TP20R3G3npuEokak", "test-layer");
/* more test code here */
Iterable<Location> findLocationsWithinRange = locationService.findLocationsWithinRange("-41.289964", "longitude", "5", "test-layer");
/* more test code here */
}
}
Upvotes: 1
Views: 92
Reputation: 1402
We're using SDN 4.1.2, OGM 2.0.3 and I got my tests working with this setup:
Added the maven dependency using the description on the github page. By the time of writing this comment the necessary addition to the pom.xml
was
<repositories>
<repository>
<id>neo4j-contrib-releases</id>
<url>https://raw.github.com/neo4j-contrib/m2/master/releases</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>neo4j-contrib-snapshots</id>
<url>https://raw.github.com/neo4j-contrib/m2/master/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<!-- ... -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-spatial</artifactId>
<version>0.19-neo4j-3.0.3</version>
</dependency>
Defining the following abstract classes for all spatial-related tests:
@RunWith(SpringJUnit4ClassRunner::class)
@SpringApplicationConfiguration(classes = arrayOf(Application::class))
@ActiveProfiles("test")
@Transactional
abstract class AbstractIntegrationTests() {}
and
@WebAppConfiguration
abstract class AbstractIntegrationTestsWithProcedures : AbstractIntegrationTests() {
lateinit var databaseService: GraphDatabaseService
val layerName = "layer"
@Before()
open fun before() {
if (ProcedureTestUtil.registeredProcedures.contains(SpatialProcedures::class.java)) {
return
}
val driver = Components.driver()
if (driver is EmbeddedDriver) {
databaseService = driver.graphDatabaseService
ProcedureTestUtil.registerProcedure(databaseService, SpatialProcedures::class.java)
val spatialPlugin = SpatialPlugin()
spatialPlugin.addSimplePointLayer(databaseService, layerName, "latitude", "longitude")
} else {
throw UnsupportedOperationException("Expected an embedded Neo4j instance, but was " + driver.javaClass.name)
}
}
}
and additionally
class ProcedureTestUtil {
companion object {
@JvmStatic
var registeredProcedures: MutableList<Class<*>> = ArrayList()
@JvmStatic
@Throws(KernelException::class)
fun registerProcedure(db: GraphDatabaseService, procedure: Class<*>) {
val proceduresService = (db as GraphDatabaseAPI).dependencyResolver.resolveDependency(Procedures::class.java)
proceduresService.register(procedure)
registeredProcedures.add(procedure)
}
}
}
you should get your tests running if
LocationServiceTest extends AbstractIntegrationTestsWithProcedures
.
Upvotes: 0
Reputation: 19373
Spatial functionality is not provided in SDN 4 yet. If you integrate the neo4j-spatial lib then the only option you have at the moment is to use it directly- there will be no repository support etc. However, spatial integration work is currently in progress, so some basic functionality should be introduced in the next release.
Upvotes: 1