Интеграционное тестирование с репозиториями SDN4 с использованием запросов neo4j-spatial cypher

Я начинаю использовать neo4j-spatial в своем коде. Я думал, что смогу протестировать интеграционный код neo4j-spatial, включив пространственный сервер lib в качестве зависимости maven в свой проект. Однако это не сработало для меня. Я нигде не могу найти документацию по этому поводу.

Как я могу заставить мои интеграционные тесты работать?

Любые советы? :)

Просто чтобы дать представление о том, что я делаю, я вставил фрагмент кода моего контроллера, службы и репозитория ниже, а окончательный код — это мои тесты, которые не работают со встроенным TestServer.

Репозиторий

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);

}

Сервис

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);
    }

}

Контроллер

...

/**
     * 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) ;
    }

...

Тест обслуживания

(Это мои тесты, которые я не могу заставить работать как часть стандартной сборки для встроенного 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 */

    }
}

person John Deverall    schedule 22.08.2016    source источник


Ответы (2)


Пространственная функциональность еще не предусмотрена в SDN 4. Если вы интегрируете библиотеку neo4j-spatial, то единственный вариант, который у вас есть на данный момент, — это использовать ее напрямую — поддержки репозитория не будет и т. д. Однако работа по пространственной интеграции в настоящее время продолжается, поэтому некоторые базовые функции должны быть представлены в следующий выпуск.

person Luanne    schedule 23.08.2016
comment
Возможно, стоит отметить: если вы используете Neo4j 3.x, пространственные функции доступны из CYPHER. Итак, хотя специальной поддержки нет, вы можете сделать что-то вроде: session.queryForObject(Restaurant.class, "MATCH (r:Restaurant) WHERE distance(point(r),point({latitude:37.0, longitude:-118.0})) < {distance}*1000 RETURN r;", parameters); - person Jasper Blues; 23.08.2016
comment
Да, я использую 3.0.3, поэтому я думал, что смогу создать @Query в классе репозитория, включить туда некоторый пространственный шифр, включить библиотеку пространственного сервера в мой путь к классу - и все будет просто Работа. Таким образом я работаю со своими собственными серверными плагинами, и они работают с интеграционным тестированием. Любая идея, почему это не работает? - person John Deverall; 23.08.2016
comment
@JohnDeverall, не могли бы вы прислать нам какой-нибудь код здесь, или вы знаете, где меня найти :-) - person Luanne; 23.08.2016
comment
Как-нибудь сегодня я выложу свой последний материал и отмечу вас в нем :D - person John Deverall; 23.08.2016

Мы используем SDN 4.1.2, OGM 2.0.3, и мои тесты работают с этой настройкой:

Добавлена ​​зависимость maven с использованием описание на странице github. К моменту написания этого комментария необходимое дополнение к pom.xml было

<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>

Определение следующих абстрактных классов для всех пространственных тестов:

@RunWith(SpringJUnit4ClassRunner::class)
@SpringApplicationConfiguration(classes = arrayOf(Application::class))
@ActiveProfiles("test")
@Transactional
abstract class AbstractIntegrationTests() {}

а также

@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)
        }
    }
}

и дополнительно

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)
        }
    }
}

вы должны запустить свои тесты, если LocationServiceTest extends AbstractIntegrationTestsWithProcedures.

person Christoph Möbius    schedule 14.12.2016