/* * Copyright 2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.data.redis.core; import static org.assertj.core.api.Assertions.*; import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.*; import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.*; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.AfterClass; import org.junit.Before; import org.junit.ClassRule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.springframework.data.geo.Circle; import org.springframework.data.geo.Distance; import org.springframework.data.geo.Metrics; import org.springframework.data.geo.Point; import org.springframework.data.redis.ConnectionFactoryTracker; import org.springframework.data.redis.ObjectFactory; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.test.util.MinimumRedisVersionRule; import org.springframework.test.annotation.IfProfileValue; /** * Integration tests for {@link DefaultReactiveGeoOperations}. * * @author Mark Paluch * @author Christoph Strobl */ @RunWith(Parameterized.class) @IfProfileValue(name = "redisVersion", value = "3.2.0+") public class DefaultReactiveGeoOperationsIntegrationTests<K, V> { public static @ClassRule MinimumRedisVersionRule versionRule = new MinimumRedisVersionRule(); private static final Point POINT_ARIGENTO = new Point(13.583333, 37.316667); private static final Point POINT_CATANIA = new Point(15.087269, 37.502669); private static final Point POINT_PALERMO = new Point(13.361389, 38.115556); private static final double DISTANCE_PALERMO_CATANIA_METERS = 166274.15156960033; private static final double DISTANCE_PALERMO_CATANIA_KILOMETERS = 166.27415156960033; private final ReactiveRedisTemplate<K, V> redisTemplate; private final ReactiveGeoOperations<K, V> geoOperations; private final ObjectFactory<K> keyFactory; private final ObjectFactory<V> valueFactory; @Parameters(name = "{4}") public static Collection<Object[]> testParams() { return ReactiveOperationsTestParams.testParams(); } @AfterClass public static void cleanUp() { ConnectionFactoryTracker.cleanUp(); } /** * @param redisTemplate * @param keyFactory * @param valueFactory * @param label parameterized test label, no further use besides that. */ public DefaultReactiveGeoOperationsIntegrationTests(ReactiveRedisTemplate<K, V> redisTemplate, ObjectFactory<K> keyFactory, ObjectFactory<V> valueFactory, RedisSerializer serializer, String label) { this.redisTemplate = redisTemplate; this.geoOperations = redisTemplate.opsForGeo(); this.keyFactory = keyFactory; this.valueFactory = valueFactory; ConnectionFactoryTracker.add(redisTemplate.getConnectionFactory()); } @Before public void before() { RedisConnectionFactory connectionFactory = (RedisConnectionFactory) redisTemplate.getConnectionFactory(); RedisConnection connection = connectionFactory.getConnection(); connection.flushAll(); connection.close(); } @Test // DATAREDIS-602 public void geoAdd() { K key = keyFactory.instance(); V value = valueFactory.instance(); StepVerifier.create(geoOperations.geoAdd(key, POINT_PALERMO, value)).expectNext(1L).verifyComplete(); } @Test // DATAREDIS-602 public void geoAddLocation() { K key = keyFactory.instance(); V value = valueFactory.instance(); StepVerifier.create(geoOperations.geoAdd(key, new GeoLocation<>(value, POINT_PALERMO))) // .expectNext(1L) // .expectComplete() // .verify(); } @Test // DATAREDIS-602 public void geoAddMapOfLocations() { K key = keyFactory.instance(); Map<V, Point> memberCoordinateMap = new HashMap<>(); memberCoordinateMap.put(valueFactory.instance(), POINT_PALERMO); memberCoordinateMap.put(valueFactory.instance(), POINT_CATANIA); StepVerifier.create(geoOperations.geoAdd(key, memberCoordinateMap)) // .expectNext(2L) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoAddIterableOfLocations() { K key = keyFactory.instance(); List<GeoLocation<V>> geoLocations = Arrays.asList(new GeoLocation<>(valueFactory.instance(), POINT_ARIGENTO), new GeoLocation<>(valueFactory.instance(), POINT_PALERMO)); StepVerifier.create(geoOperations.geoAdd(key, geoLocations)) // .expectNext(2L) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoAddPublisherOfLocations() { K key = keyFactory.instance(); List<GeoLocation<V>> batch1 = Arrays.asList(new GeoLocation<>(valueFactory.instance(), POINT_ARIGENTO), new GeoLocation<>(valueFactory.instance(), POINT_PALERMO)); List<GeoLocation<V>> batch2 = Arrays.asList(new GeoLocation<>(valueFactory.instance(), POINT_CATANIA)); Flux<List<GeoLocation<V>>> geoLocations = Flux.just(batch1, batch2); StepVerifier.create(geoOperations.geoAdd(key, geoLocations)).expectNext(2L) // .expectNext(1L) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoDistShouldReturnDistanceInMetersByDefault() { K key = keyFactory.instance(); V member1 = valueFactory.instance(); V member2 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, member1).block(); geoOperations.geoAdd(key, POINT_CATANIA, member2).block(); StepVerifier.create(geoOperations.geoDist(key, member1, member2)) // .consumeNextWith(actual -> { assertThat(actual.getValue()).isCloseTo(DISTANCE_PALERMO_CATANIA_METERS, offset(0.005)); assertThat(actual.getUnit()).isEqualTo("m"); }) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoDistShouldReturnDistanceInKilometersCorrectly() { K key = keyFactory.instance(); V member1 = valueFactory.instance(); V member2 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, member1).block(); geoOperations.geoAdd(key, POINT_CATANIA, member2).block(); StepVerifier.create(geoOperations.geoDist(key, member1, member2, Metrics.KILOMETERS)) // .consumeNextWith(actual -> { assertThat(actual.getValue()).isCloseTo(DISTANCE_PALERMO_CATANIA_KILOMETERS, offset(0.005)); assertThat(actual.getUnit()).isEqualTo("km"); }) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoHash() { K key = keyFactory.instance(); V v1 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, v1).block(); StepVerifier.create(geoOperations.geoHash(key, v1)) // .expectNext("sqc8b49rny0") // .verifyComplete(); } @Test // DATAREDIS-602 public void geoHashShouldReturnMultipleElements() { K key = keyFactory.instance(); V v1 = valueFactory.instance(); V v2 = valueFactory.instance(); V v3 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, v1).block(); geoOperations.geoAdd(key, POINT_CATANIA, v2).block(); StepVerifier.create(geoOperations.geoHash(key, v1, v3, v2)) // .expectNext(Arrays.asList("sqc8b49rny0", null, "sqdtr74hyu0")) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoPos() { K key = keyFactory.instance(); V v1 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, v1).block(); StepVerifier.create(geoOperations.geoPos(key, v1)) // .consumeNextWith(actual -> { assertThat(actual.getX()).isCloseTo(POINT_PALERMO.getX(), offset(0.005)); assertThat(actual.getY()).isCloseTo(POINT_PALERMO.getY(), offset(0.005)); }) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoPosShouldReturnMultipleElements() { K key = keyFactory.instance(); V v1 = valueFactory.instance(); V v2 = valueFactory.instance(); V v3 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, v1).block(); geoOperations.geoAdd(key, POINT_CATANIA, v2).block(); StepVerifier.create(geoOperations.geoPos(key, v1, v3, v2)) // .consumeNextWith(actual -> { assertThat(actual.get(0).getX()).isCloseTo(POINT_PALERMO.getX(), offset(0.005)); assertThat(actual.get(0).getY()).isCloseTo(POINT_PALERMO.getY(), offset(0.005)); assertThat(actual.get(1)).isNull(); assertThat(actual.get(2)).isNotNull(); }) // .verifyComplete(); } @Test // DATAREDIS-438 public void geoRadius() { K key = keyFactory.instance(); V member1 = valueFactory.instance(); V member2 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, member1).block(); geoOperations.geoAdd(key, POINT_CATANIA, member2).block(); StepVerifier.create(geoOperations.geoRadius(key, new Circle(new Point(15D, 37D), new Distance(200D, KILOMETERS)))) // .expectNextCount(2) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoRadiusShouldReturnLocationsWithDistance() { K key = keyFactory.instance(); V member1 = valueFactory.instance(); V member2 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, member1).block(); geoOperations.geoAdd(key, POINT_CATANIA, member2).block(); StepVerifier .create(geoOperations.geoRadius(key, new Circle(new Point(15D, 37D), new Distance(200D, KILOMETERS)), newGeoRadiusArgs().includeDistance().sortDescending())) // .consumeNextWith(actual -> { assertThat(actual.getDistance().getValue()).isCloseTo(190.4424d, offset(0.005)); assertThat(actual.getContent().getName()).isEqualTo(member1); }) // .consumeNextWith(actual -> { assertThat(actual.getDistance().getValue()).isCloseTo(56.4413d, offset(0.005)); assertThat(actual.getContent().getName()).isEqualTo(member2); }) // .verifyComplete(); } @Test // DATAREDIS-438 public void geoRadiusByMemberShouldReturnMembersCorrectly() { K key = keyFactory.instance(); V member1 = valueFactory.instance(); V member2 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, member1).block(); geoOperations.geoAdd(key, POINT_CATANIA, member2).block(); StepVerifier.create(geoOperations.geoRadius(key, new Circle(new Point(15D, 37D), new Distance(200D, KILOMETERS)))) // .expectNextCount(2) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoRadiusByMemberWithin100_000MetersShouldReturnLocations() { K key = keyFactory.instance(); V member1 = valueFactory.instance(); V member2 = valueFactory.instance(); V member3 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, member1).block(); geoOperations.geoAdd(key, POINT_CATANIA, member2).block(); geoOperations.geoAdd(key, POINT_ARIGENTO, member3).block(); StepVerifier.create(geoOperations.geoRadiusByMember(key, member3, 100_000)) // .consumeNextWith(actual -> { assertThat(actual.getContent().getName()).isEqualTo(member3); }) // .consumeNextWith(actual -> { assertThat(actual.getContent().getName()).isEqualTo(member1); }) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoRadiusByMemberWithin100KMShouldReturnLocations() { K key = keyFactory.instance(); V member1 = valueFactory.instance(); V member2 = valueFactory.instance(); V member3 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, member1).block(); geoOperations.geoAdd(key, POINT_CATANIA, member2).block(); geoOperations.geoAdd(key, POINT_ARIGENTO, member3).block(); StepVerifier.create(geoOperations.geoRadiusByMember(key, member3, new Distance(100D, KILOMETERS))) // .consumeNextWith(actual -> { assertThat(actual.getContent().getName()).isEqualTo(member3); }) // .consumeNextWith(actual -> { assertThat(actual.getContent().getName()).isEqualTo(member1); }) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoRadiusByMemberShouldReturnLocationsWithDistance() { K key = keyFactory.instance(); V member1 = valueFactory.instance(); V member2 = valueFactory.instance(); V member3 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, member1).block(); geoOperations.geoAdd(key, POINT_CATANIA, member2).block(); geoOperations.geoAdd(key, POINT_ARIGENTO, member3).block(); StepVerifier .create(geoOperations.geoRadiusByMember(key, member3, new Distance(100D, KILOMETERS), newGeoRadiusArgs().includeDistance().sortDescending())) // .consumeNextWith(actual -> { assertThat(actual.getDistance().getValue()).isCloseTo(90.9778, offset(0.005)); assertThat(actual.getContent().getName()).isEqualTo(member1); }) // .consumeNextWith(actual -> { assertThat(actual.getDistance().getValue()).isCloseTo(0.0, offset(0.005)); assertThat(actual.getContent().getName()).isEqualTo(member3); }) // .verifyComplete(); } @Test // DATAREDIS-602 public void geoRemove() { K key = keyFactory.instance(); V member1 = valueFactory.instance(); V member2 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, member1).block(); geoOperations.geoAdd(key, POINT_CATANIA, member2).block(); StepVerifier.create(geoOperations.geoRemove(key, member1)) // .expectNext(1L) // .verifyComplete(); StepVerifier.create(geoOperations.geoPos(key, member1)) // .verifyComplete(); } @Test // DATAREDIS-602 public void delete() { K key = keyFactory.instance(); V member1 = valueFactory.instance(); geoOperations.geoAdd(key, POINT_PALERMO, member1).block(); StepVerifier.create(geoOperations.delete(key)) // .expectNext(true) // .verifyComplete(); StepVerifier.create(geoOperations.geoPos(key, member1)) // .verifyComplete(); } }