/*
* Copyright 2016-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.hamcrest.collection.IsCollectionWithSize.*;
import static org.hamcrest.core.Is.*;
import static org.hamcrest.core.IsEqual.*;
import static org.hamcrest.core.IsNull.*;
import static org.hamcrest.number.IsCloseTo.*;
import static org.junit.Assert.*;
import static org.springframework.data.redis.connection.RedisGeoCommands.DistanceUnit.*;
import static org.springframework.data.redis.connection.RedisGeoCommands.GeoRadiusCommandArgs.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.After;
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.GeoResults;
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.RedisGeoCommands.DistanceUnit;
import org.springframework.data.redis.connection.RedisGeoCommands.GeoLocation;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.data.redis.test.util.MinimumRedisVersionRule;
import org.springframework.test.annotation.IfProfileValue;
/**
* Integration test of {@link org.springframework.data.redis.core.DefaultGeoOperations}
*
* @author Ninad Divadkar
* @author Christoph Strobl
*/
@RunWith(Parameterized.class)
@IfProfileValue(name = "redisVersion", value = "3.2.0+")
public class DefaultGeoOperationsTests<K, M> {
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 static final double DISTANCE_PALERMO_CATANIA_MILES = 103.31822459492733;
private static final double DISTANCE_PALERMO_CATANIA_FEET = 545518.8699790037;
private RedisTemplate<K, M> redisTemplate;
private ObjectFactory<K> keyFactory;
private ObjectFactory<M> valueFactory;
private GeoOperations<K, M> geoOperations;
public DefaultGeoOperationsTests(RedisTemplate<K, M> redisTemplate, ObjectFactory<K> keyFactory,
ObjectFactory<M> valueFactory) {
this.redisTemplate = redisTemplate;
this.keyFactory = keyFactory;
this.valueFactory = valueFactory;
ConnectionFactoryTracker.add(redisTemplate.getConnectionFactory());
}
@Parameters
public static Collection<Object[]> testParams() {
return AbstractOperationsTestParams.testParams();
}
@AfterClass
public static void cleanUp() {
ConnectionFactoryTracker.cleanUp();
}
@Before
public void setUp() {
geoOperations = redisTemplate.opsForGeo();
}
@After
public void tearDown() {
redisTemplate.execute(new RedisCallback<Object>() {
public Object doInRedis(RedisConnection connection) {
connection.flushDb();
return null;
}
});
}
@Test // DATAREDIS-438
public void testGeoAdd() {
Long numAdded = geoOperations.geoAdd(keyFactory.instance(), POINT_PALERMO, valueFactory.instance());
assertThat(numAdded, is(1L));
}
@Test // DATAREDIS-438
public void testGeoAddWithLocationMap() {
Map<M, Point> memberCoordinateMap = new HashMap<M, Point>();
memberCoordinateMap.put(valueFactory.instance(), POINT_PALERMO);
memberCoordinateMap.put(valueFactory.instance(), POINT_CATANIA);
Long numAdded = geoOperations.geoAdd(keyFactory.instance(), memberCoordinateMap);
assertThat(numAdded, is(2L));
}
@Test // DATAREDIS-438
public void geoDistShouldReturnDistanceInMetersByDefault() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
Distance dist = geoOperations.geoDist(key, member1, member2);
assertThat(dist.getValue(), closeTo(DISTANCE_PALERMO_CATANIA_METERS, 0.005));
assertThat(dist.getUnit(), is(equalTo("m")));
}
@Test // DATAREDIS-438
public void geoDistShouldReturnDistanceInKilometersCorrectly() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
Distance dist = geoOperations.geoDist(key, member1, member2, KILOMETERS);
assertThat(dist.getValue(), closeTo(DISTANCE_PALERMO_CATANIA_KILOMETERS, 0.005));
assertThat(dist.getUnit(), is(equalTo("km")));
}
@Test // DATAREDIS-438
public void geoDistShouldReturnDistanceInMilesCorrectly() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
Distance dist = geoOperations.geoDist(key, member1, member2, DistanceUnit.MILES);
assertThat(dist.getValue(), closeTo(DISTANCE_PALERMO_CATANIA_MILES, 0.005));
assertThat(dist.getUnit(), is(equalTo("mi")));
}
@Test // DATAREDIS-438
public void geoDistShouldReturnDistanceInFeeCorrectly() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
Distance dist = geoOperations.geoDist(key, member1, member2, DistanceUnit.FEET);
assertThat(dist.getValue(), closeTo(DISTANCE_PALERMO_CATANIA_FEET, 0.005));
assertThat(dist.getUnit(), is(equalTo("ft")));
}
@Test // DATAREDIS-438
public void testGeoHash() {
K key = keyFactory.instance();
M v1 = valueFactory.instance();
M v2 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, v1);
geoOperations.geoAdd(key, POINT_CATANIA, v2);
List<String> result = geoOperations.geoHash(key, v1, v2);
assertThat(result, hasSize(2));
final RedisSerializer<String> serializer = new StringRedisSerializer();
assertThat(result.get(0), is(equalTo("sqc8b49rny0")));
assertThat(result.get(1), is(equalTo("sqdtr74hyu0")));
}
@Test // DATAREDIS-438
public void testGeoPos() {
K key = keyFactory.instance();
M v1 = valueFactory.instance();
M v2 = valueFactory.instance();
M v3 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, v1);
geoOperations.geoAdd(key, POINT_CATANIA, v2);
List<Point> result = geoOperations.geoPos(key, v1, v2, v3);// v3 is nonexisting
assertThat(result, hasSize(3));
assertThat(result.get(0).getX(), is(closeTo(POINT_PALERMO.getX(), 0.005)));
assertThat(result.get(0).getY(), is(closeTo(POINT_PALERMO.getY(), 0.005)));
assertThat(result.get(1).getX(), is(closeTo(POINT_CATANIA.getX(), 0.005)));
assertThat(result.get(1).getY(), is(closeTo(POINT_CATANIA.getY(), 0.005)));
assertThat(result.get(2), is(nullValue()));
}
@Test // DATAREDIS-438
public void geoRadiusShouldReturnMembersCorrectly() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
GeoResults<GeoLocation<M>> result = geoOperations.geoRadius(key,
new Circle(new Point(15D, 37D), new Distance(200D, KILOMETERS)));
assertThat(result.getContent(), hasSize(2));
}
@Test // DATAREDIS-438
public void geoRadiusShouldReturnLocationsWithDistance() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
GeoResults<GeoLocation<M>> result = geoOperations.geoRadius(key,
new Circle(new Point(15, 37), new Distance(200, KILOMETERS)),
newGeoRadiusArgs().includeDistance().sortDescending());
assertThat(result.getContent(), hasSize(2));
assertThat(result.getContent().get(0).getDistance().getValue(), is(closeTo(190.4424d, 0.005)));
assertThat(result.getContent().get(0).getDistance().getUnit(), is(equalTo("km")));
assertThat(result.getContent().get(0).getContent().getName(), is(member1));
assertThat(result.getContent().get(1).getDistance().getValue(), is(closeTo(56.4413d, 0.005)));
assertThat(result.getContent().get(1).getDistance().getUnit(), is(equalTo("km")));
assertThat(result.getContent().get(1).getContent().getName(), is(member2));
}
@Test // DATAREDIS-438
public void geoRadiusShouldReturnLocationsWithCoordinates() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
GeoResults<GeoLocation<M>> result = geoOperations.geoRadius(key,
new Circle(new Point(15, 37), new Distance(200, KILOMETERS)),
newGeoRadiusArgs().includeCoordinates().sortAscending());
assertThat(result.getContent(), hasSize(2));
assertThat(result.getContent().get(0).getContent().getPoint().getX(), is(closeTo(POINT_CATANIA.getX(), 0.005)));
assertThat(result.getContent().get(0).getContent().getPoint().getY(), is(closeTo(POINT_CATANIA.getY(), 0.005)));
assertThat(result.getContent().get(0).getContent().getName(), is(member2));
assertThat(result.getContent().get(1).getContent().getPoint().getX(), is(closeTo(POINT_PALERMO.getX(), 0.005)));
assertThat(result.getContent().get(1).getContent().getPoint().getY(), is(closeTo(POINT_PALERMO.getY(), 0.005)));
assertThat(result.getContent().get(1).getContent().getName(), is(member1));
}
@Test // DATAREDIS-438
public void geoRadiusShouldReturnLocationsWithCoordinatesAndDistance() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
GeoResults<GeoLocation<M>> result = geoOperations.geoRadius(key,
new Circle(new Point(15, 37), new Distance(200, KILOMETERS)),
newGeoRadiusArgs().includeCoordinates().includeDistance().sortAscending());
assertThat(result.getContent(), hasSize(2));
assertThat(result.getContent().get(0).getDistance().getValue(), is(closeTo(56.4413d, 0.005)));
assertThat(result.getContent().get(0).getDistance().getUnit(), is(equalTo("km")));
assertThat(result.getContent().get(0).getContent().getPoint().getX(), is(closeTo(POINT_CATANIA.getX(), 0.005)));
assertThat(result.getContent().get(0).getContent().getPoint().getY(), is(closeTo(POINT_CATANIA.getY(), 0.005)));
assertThat(result.getContent().get(0).getContent().getName(), is(member2));
assertThat(result.getContent().get(1).getDistance().getValue(), is(closeTo(190.4424d, 0.005)));
assertThat(result.getContent().get(1).getDistance().getUnit(), is(equalTo("km")));
assertThat(result.getContent().get(1).getContent().getPoint().getX(), is(closeTo(POINT_PALERMO.getX(), 0.005)));
assertThat(result.getContent().get(1).getContent().getPoint().getY(), is(closeTo(POINT_PALERMO.getY(), 0.005)));
assertThat(result.getContent().get(1).getContent().getName(), is(member1));
}
@Test // DATAREDIS-438
public void geoRadiusByMemberShouldReturnMembersCorrectly() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
M member3 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
geoOperations.geoAdd(key, POINT_ARIGENTO, member3);
GeoResults<GeoLocation<M>> result = geoOperations.geoRadiusByMember(key, member3, new Distance(200, KILOMETERS));
assertThat(result.getContent(), hasSize(3));
}
@Test // DATAREDIS-438
public void geoRadiusByMemberShouldReturnDistanceCorrectly() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
M member3 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
geoOperations.geoAdd(key, POINT_ARIGENTO, member3);
GeoResults<GeoLocation<M>> result = geoOperations.geoRadiusByMember(key, member3, new Distance(100, KILOMETERS),
newGeoRadiusArgs().includeDistance().sortDescending());
assertThat(result.getContent(), hasSize(2));
assertThat(result.getContent().get(0).getDistance().getValue(), is(closeTo(90.9778d, 0.005)));
assertThat(result.getContent().get(0).getContent().getName(), is(member1));
assertThat(result.getContent().get(1).getDistance().getValue(), is(closeTo(0.0d, 0.005))); // itself
assertThat(result.getContent().get(1).getContent().getName(), is(member3));
}
@Test // DATAREDIS-438
public void geoRadiusByMemberShouldReturnCoordinates() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
M member3 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
geoOperations.geoAdd(key, POINT_ARIGENTO, member3);
GeoResults<GeoLocation<M>> result = geoOperations.geoRadiusByMember(key, member3,
new Distance(100, DistanceUnit.KILOMETERS), newGeoRadiusArgs().includeCoordinates().sortAscending());
assertThat(result.getContent(), hasSize(2));
assertThat(result.getContent().get(0).getContent().getPoint().getX(), is(closeTo(POINT_ARIGENTO.getX(), 0.005)));
assertThat(result.getContent().get(0).getContent().getPoint().getY(), is(closeTo(POINT_ARIGENTO.getY(), 0.005)));
assertThat(result.getContent().get(0).getContent().getName(), is(member3));
assertThat(result.getContent().get(1).getContent().getPoint().getX(), is(closeTo(POINT_PALERMO.getX(), 0.005)));
assertThat(result.getContent().get(1).getContent().getPoint().getY(), is(closeTo(POINT_PALERMO.getY(), 0.005)));
assertThat(result.getContent().get(1).getContent().getName(), is(member1));
}
@Test // DATAREDIS-438
public void geoRadiusByMemberShouldReturnCoordinatesAndDistance() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
M member2 = valueFactory.instance();
M member3 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
geoOperations.geoAdd(key, POINT_CATANIA, member2);
geoOperations.geoAdd(key, POINT_ARIGENTO, member3);
// with coord and dist, ascending
GeoResults<GeoLocation<M>> result = geoOperations.geoRadiusByMember(key, member1, new Distance(100, KILOMETERS),
newGeoRadiusArgs().includeCoordinates().includeDistance().sortAscending());
assertThat(result.getContent(), hasSize(2));
assertThat(result.getContent().get(0).getDistance().getValue(), is(closeTo(0.0d, 0.005)));
assertThat(result.getContent().get(0).getContent().getPoint().getX(), is(closeTo(POINT_PALERMO.getX(), 0.005)));
assertThat(result.getContent().get(0).getContent().getPoint().getY(), is(closeTo(POINT_PALERMO.getY(), 0.005)));
assertThat(result.getContent().get(0).getContent().getName(), is(member1));
assertThat(result.getContent().get(1).getDistance().getValue(), is(closeTo(90.9778d, 0.005)));
assertThat(result.getContent().get(1).getContent().getPoint().getX(), is(closeTo(POINT_ARIGENTO.getX(), 0.005)));
assertThat(result.getContent().get(1).getContent().getPoint().getY(), is(closeTo(POINT_ARIGENTO.getY(), 0.005)));
assertThat(result.getContent().get(1).getContent().getName(), is(member3));
}
@Test // DATAREDIS-438
public void testGeoRemove() {
K key = keyFactory.instance();
M member1 = valueFactory.instance();
geoOperations.geoAdd(key, POINT_PALERMO, member1);
assertThat(geoOperations.geoRemove(key, member1), is(1L));
}
}