diff --git a/src/main/java/com/redislabs/university/RU102J/dao/SiteGeoDaoRedisImpl.java b/src/main/java/com/redislabs/university/RU102J/dao/SiteGeoDaoRedisImpl.java index 364e71d..a637939 100644 --- a/src/main/java/com/redislabs/university/RU102J/dao/SiteGeoDaoRedisImpl.java +++ b/src/main/java/com/redislabs/university/RU102J/dao/SiteGeoDaoRedisImpl.java @@ -5,7 +5,7 @@ import com.redislabs.university.RU102J.api.Site; import java.util.ArrayList; -import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -74,41 +74,39 @@ public Set findByGeo( GeoQuery query ) { // Challenge #5 private Set findSitesByGeoWithCapacity( GeoQuery query ) { - return Collections.emptySet(); + //return Collections.emptySet(); + //} + // Comment out the above, and uncomment what 's below private Set findSitesByGeoWithCapacity (GeoQuery query){ + Set results = new HashSet<>(); + Coordinate coord = query.getCoordinate(); + Double radius = query.getRadius(); + GeoUnit radiusUnit = query.getRadiusUnit(); + + try ( Jedis jedis = jedisPool.getResource() ) { + // START Challenge #5 + List radiusResponses = jedis.georadius( RedisSchema.getSiteGeoKey(), coord.getLng(), coord.getLat(), radius, radiusUnit ); + // END Challenge #5 + + Set sites = radiusResponses.stream().map( response -> jedis.hgetAll( response.getMemberByString() ) ).filter( Objects::nonNull ).map( Site::new ).collect( Collectors.toSet() ); + + // START Challenge #5 + Pipeline pipeline = jedis.pipelined(); + Map> scores = new HashMap<>( sites.size() ); + sites.forEach( site -> { + scores.put( site.getId(), pipeline.zscore( RedisSchema.getCapacityRankingKey(), String.valueOf( site.getId() ) ) ); + } ); + pipeline.sync(); + // END Challenge #5 + + for ( Site site : sites ) { + if ( scores.get( site.getId() ).get() >= capacityThreshold ) { + results.add( site ); + } + } + } + + return results; } - // Comment out the above, and uncomment what's below - // private Set findSitesByGeoWithCapacity(GeoQuery query) { - // Set results = new HashSet<>(); - // Coordinate coord = query.getCoordinate(); - // Double radius = query.getRadius(); - // GeoUnit radiusUnit = query.getRadiusUnit(); - // - // try (Jedis jedis = jedisPool.getResource()) { - // // START Challenge #5 - // // TODO: Challenge #5: Get the sites matching the geo query, store them - // // in List radiusResponses; - // // END Challenge #5 - // - // Set sites = radiusResponses.stream() - // .map(response -> jedis.hgetAll(response.getMemberByString())) - // .filter(Objects::nonNull) - // .map(Site::new).collect(Collectors.toSet()); - // - // // START Challenge #5 - // Pipeline pipeline = jedis.pipelined(); - // Map> scores = new HashMap<>(sites.size()); - // // TODO: Challenge #5: Add the code that populates the scores HashMap... - // // END Challenge #5 - // - // for (Site site : sites) { - // if (scores.get(site.getId()).get() >= capacityThreshold) { - // results.add(site); - // } - // } - // } - // - // return results; - // } private Set findSitesByGeo( GeoQuery query ) { Coordinate coord = query.getCoordinate(); diff --git a/src/test/java/com/redislabs/university/RU102J/dao/SiteGeoDaoRedisImplTest.java b/src/test/java/com/redislabs/university/RU102J/dao/SiteGeoDaoRedisImplTest.java index e23b976..d746954 100644 --- a/src/test/java/com/redislabs/university/RU102J/dao/SiteGeoDaoRedisImplTest.java +++ b/src/test/java/com/redislabs/university/RU102J/dao/SiteGeoDaoRedisImplTest.java @@ -1,193 +1,193 @@ package com.redislabs.university.RU102J.dao; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + import com.redislabs.university.RU102J.HostPort; import com.redislabs.university.RU102J.TestKeyManager; import com.redislabs.university.RU102J.api.Coordinate; import com.redislabs.university.RU102J.api.GeoQuery; import com.redislabs.university.RU102J.api.MeterReading; import com.redislabs.university.RU102J.api.Site; -import org.junit.*; -import org.junit.rules.ExpectedException; -import redis.clients.jedis.Jedis; -import redis.clients.jedis.JedisPool; -import redis.clients.jedis.JedisPoolConfig; import java.util.HashSet; import java.util.Map; import java.util.Set; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.empty; -import static org.junit.Assert.*; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import redis.clients.jedis.Jedis; +import redis.clients.jedis.JedisPool; +import redis.clients.jedis.JedisPoolConfig; public class SiteGeoDaoRedisImplTest { - private static JedisPool jedisPool; - private static Jedis jedis; - private static TestKeyManager keyManager; - private Set sites; - - @Rule - public ExpectedException thrown = ExpectedException.none(); - - @BeforeClass - public static void setUp() throws Exception { - String password = HostPort.getRedisPassword(); - - if (password.length() > 0) { - jedisPool = new JedisPool(new JedisPoolConfig(), HostPort.getRedisHost(), HostPort.getRedisPort(), 2000, password); - } else { - jedisPool = new JedisPool(HostPort.getRedisHost(), HostPort.getRedisPort()); - } - - jedis = new Jedis(HostPort.getRedisHost(), HostPort.getRedisPort()); - - if (password.length() > 0) { - jedis.auth(password); - } - - keyManager = new TestKeyManager("test"); - } - - @AfterClass - public static void tearDown() { - jedisPool.destroy(); - jedis.close(); - } - - @After - public void flush() { - keyManager.deleteKeys(jedis); - } - - @Before - public void generateData() { - sites = new HashSet<>(); - - Site site1 = new Site(1, 4.5, 3, "637 Britannia Drive", - "Vallejo", "CA", "94591" ); - site1.setCoordinate(new Coordinate("-122.193849", "38.10476999999999")); - sites.add(site1); - - Site site2 = new Site(2, 4.5, 3, "31353 Santa Elena Way", - "Union City", "CA", "94587" ); - site2.setCoordinate(new Coordinate("-122.059762", "37.593981")); - sites.add(site2); - - Site site3 = new Site(3, 4.5, 3, "1732 27th Avenue", - "Oakland", "CA", "94601" ); - site3.setCoordinate(new Coordinate("-122.228238", "37.783431")); - sites.add(site3); - } - - @Test - public void findAllWithMultipleSites() { - SiteGeoDao dao = new SiteGeoDaoRedisImpl(jedisPool); - // Insert all sites - for (Site site : sites) { - dao.insert(site); - } - - assertThat(dao.findAll(), is(sites)); - } - - @Test - public void findAllWithEmptySites() { - SiteDaoRedisImpl dao = new SiteDaoRedisImpl(jedisPool); - assertThat(dao.findAll(), is(empty())); - } - - @Test - public void findByGeo() { - // Insert sites - SiteGeoDao dao = new SiteGeoDaoRedisImpl(jedisPool); - for (Site site : sites) { - dao.insert(site); - } - - Coordinate oakland = new Coordinate("-122.272476", "37.804829"); - Set oaklandSites = dao.findByGeo(new GeoQuery(oakland, 10.0, "KM")); - assertThat(oaklandSites.size(), is(1)); - - - Coordinate vallejo = new Coordinate("-122.256637", "38.104086"); - Set vallejoSites = dao.findByGeo(new GeoQuery(vallejo, 10.0, "KM")); - assertThat(vallejoSites.size(), is(1)); - - - Coordinate unionCity = new Coordinate("-122.081630", "37.596323"); - Set unionCitySites = dao.findByGeo(new GeoQuery(unionCity, 10.0, "KM")); - assertThat(unionCitySites.size(), is(1)); - - // Expand the radius to return all 3 sites - Set californiaSites = dao.findByGeo(new GeoQuery(unionCity, 60.0, "KM")); - assertThat(californiaSites.size(), is(3)); - } - - // Challenge #5 - @Ignore - @Test - public void findByGeoWithExcessCapacity() { - SiteGeoDao siteDao = new SiteGeoDaoRedisImpl(jedisPool); - CapacityDao capacityDao = new CapacityDaoRedisImpl(jedisPool); - Site vallejo = new Site(1, 4.5, 3, "637 Britannia Drive", - "Vallejo", "CA", "94591" ); - Coordinate vallejoCoord = new Coordinate("-122.256637", "38.104086"); - vallejo.setCoordinate(vallejoCoord); - siteDao.insert(vallejo); - - // This site is returned when we're not looking for excess capacity. - Set sites = siteDao.findByGeo(new GeoQuery(vallejoCoord, 10.0, "KM")); - assertThat(sites.size(), is(1)); - assertThat(sites.contains(vallejo), is(true)); - - // Simulate changing a meter reading with no excess capacity - MeterReading reading = new MeterReading(); - reading.setSiteId(vallejo.getId()); - reading.setWhUsed(1.0); - reading.setWhGenerated(0.0); - capacityDao.update(reading); - - // In this case, no sites are returned on the excess capacity query - sites = siteDao.findByGeo(new GeoQuery(vallejoCoord, 10.0, "KM", true)); - assertThat(sites.size(), is(0)); - - // Simulate changing a meter reading indicating excess capacity - reading.setWhGenerated(2.0); - capacityDao.update(reading); - - // In this case, one site is returned on the excess capacity query - sites = siteDao.findByGeo(new GeoQuery(vallejoCoord, 10.0, "KM", true)); - assertThat(sites.size(), is(1)); - assertThat(sites.contains(vallejo), is(true)); - } - - @Test - public void insert() { - SiteGeoDao dao = new SiteGeoDaoRedisImpl(jedisPool); - Site vallejo = new Site(7, 4.5, 3, "637 Britannia Drive", - "Vallejo", "CA", "94591" ); - vallejo.setCoordinate(new Coordinate("-122.193849", "38.10476999999999")); - dao.insert(vallejo); - String key = RedisSchema.getSiteHashKey(vallejo.getId()); - Map response = jedis.hgetAll(key); - assertThat(response.get("panels"), is(vallejo.getPanels().toString())); - assertThat(response.get("capacity"), is(vallejo.getCapacity().toString())); - assertThat(response.get("address"), is(vallejo.getAddress())); - assertThat(response.get("city"), is(vallejo.getCity())); - assertThat(response.get("state"), is(vallejo.getState())); - assertThat(response.get("postalCode"), is(vallejo.getPostalCode())); - assertThat(response.get("lat"), is(vallejo.getCoordinate().getLat().toString())); - assertThat(response.get("lng"), is(vallejo.getCoordinate().getLng().toString())); - } - - @Test - public void insertFailsWithoutCoordinate() { - SiteGeoDao dao = new SiteGeoDaoRedisImpl(jedisPool); - Site vallejo = new Site(7, 4.5, 3, "637 Britannia Drive", - "Vallejo", "CA", "94591" ); - thrown.expect(IllegalArgumentException.class); - thrown.expectMessage("Coordinate required for Geo insert."); - dao.insert(vallejo); - } + private static JedisPool jedisPool; + private static Jedis jedis; + private static TestKeyManager keyManager; + private Set sites; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @BeforeClass + public static void setUp() throws Exception { + String password = HostPort.getRedisPassword(); + + if ( password.length() > 0 ) { + jedisPool = new JedisPool( new JedisPoolConfig(), HostPort.getRedisHost(), HostPort.getRedisPort(), 2000, password ); + } else { + jedisPool = new JedisPool( HostPort.getRedisHost(), HostPort.getRedisPort() ); + } + + jedis = new Jedis( HostPort.getRedisHost(), HostPort.getRedisPort() ); + + if ( password.length() > 0 ) { + jedis.auth( password ); + } + + keyManager = new TestKeyManager( "test" ); + } + + @AfterClass + public static void tearDown() { + jedisPool.destroy(); + jedis.close(); + } + + @After + public void flush() { + keyManager.deleteKeys( jedis ); + } + + @Before + public void generateData() { + sites = new HashSet<>(); + + Site site1 = new Site( 1, 4.5, 3, "637 Britannia Drive", "Vallejo", "CA", "94591" ); + site1.setCoordinate( new Coordinate( "-122.193849", "38.10476999999999" ) ); + sites.add( site1 ); + + Site site2 = new Site( 2, 4.5, 3, "31353 Santa Elena Way", "Union City", "CA", "94587" ); + site2.setCoordinate( new Coordinate( "-122.059762", "37.593981" ) ); + sites.add( site2 ); + + Site site3 = new Site( 3, 4.5, 3, "1732 27th Avenue", "Oakland", "CA", "94601" ); + site3.setCoordinate( new Coordinate( "-122.228238", "37.783431" ) ); + sites.add( site3 ); + } + + @Test + public void findAllWithMultipleSites() { + SiteGeoDao dao = new SiteGeoDaoRedisImpl( jedisPool ); + // Insert all sites + for ( Site site : sites ) { + dao.insert( site ); + } + + assertThat( dao.findAll(), is( sites ) ); + } + + @Test + public void findAllWithEmptySites() { + SiteDaoRedisImpl dao = new SiteDaoRedisImpl( jedisPool ); + assertThat( dao.findAll(), is( empty() ) ); + } + + @Test + public void findByGeo() { + // Insert sites + SiteGeoDao dao = new SiteGeoDaoRedisImpl( jedisPool ); + for ( Site site : sites ) { + dao.insert( site ); + } + + Coordinate oakland = new Coordinate( "-122.272476", "37.804829" ); + Set oaklandSites = dao.findByGeo( new GeoQuery( oakland, 10.0, "KM" ) ); + assertThat( oaklandSites.size(), is( 1 ) ); + + + Coordinate vallejo = new Coordinate( "-122.256637", "38.104086" ); + Set vallejoSites = dao.findByGeo( new GeoQuery( vallejo, 10.0, "KM" ) ); + assertThat( vallejoSites.size(), is( 1 ) ); + + + Coordinate unionCity = new Coordinate( "-122.081630", "37.596323" ); + Set unionCitySites = dao.findByGeo( new GeoQuery( unionCity, 10.0, "KM" ) ); + assertThat( unionCitySites.size(), is( 1 ) ); + + // Expand the radius to return all 3 sites + Set californiaSites = dao.findByGeo( new GeoQuery( unionCity, 60.0, "KM" ) ); + assertThat( californiaSites.size(), is( 3 ) ); + } + + // Challenge #5 + @Test + public void findByGeoWithExcessCapacity() { + SiteGeoDao siteDao = new SiteGeoDaoRedisImpl( jedisPool ); + CapacityDao capacityDao = new CapacityDaoRedisImpl( jedisPool ); + Site vallejo = new Site( 1, 4.5, 3, "637 Britannia Drive", "Vallejo", "CA", "94591" ); + Coordinate vallejoCoord = new Coordinate( "-122.256637", "38.104086" ); + vallejo.setCoordinate( vallejoCoord ); + siteDao.insert( vallejo ); + + // This site is returned when we're not looking for excess capacity. + Set sites = siteDao.findByGeo( new GeoQuery( vallejoCoord, 10.0, "KM" ) ); + assertThat( sites.size(), is( 1 ) ); + assertThat( sites.contains( vallejo ), is( true ) ); + + // Simulate changing a meter reading with no excess capacity + MeterReading reading = new MeterReading(); + reading.setSiteId( vallejo.getId() ); + reading.setWhUsed( 1.0 ); + reading.setWhGenerated( 0.0 ); + capacityDao.update( reading ); + + // In this case, no sites are returned on the excess capacity query + sites = siteDao.findByGeo( new GeoQuery( vallejoCoord, 10.0, "KM", true ) ); + assertThat( sites.size(), is( 0 ) ); + + // Simulate changing a meter reading indicating excess capacity + reading.setWhGenerated( 2.0 ); + capacityDao.update( reading ); + + // In this case, one site is returned on the excess capacity query + sites = siteDao.findByGeo( new GeoQuery( vallejoCoord, 10.0, "KM", true ) ); + assertThat( sites.size(), is( 1 ) ); + assertThat( sites.contains( vallejo ), is( true ) ); + } + + @Test + public void insert() { + SiteGeoDao dao = new SiteGeoDaoRedisImpl( jedisPool ); + Site vallejo = new Site( 7, 4.5, 3, "637 Britannia Drive", "Vallejo", "CA", "94591" ); + vallejo.setCoordinate( new Coordinate( "-122.193849", "38.10476999999999" ) ); + dao.insert( vallejo ); + String key = RedisSchema.getSiteHashKey( vallejo.getId() ); + Map response = jedis.hgetAll( key ); + assertThat( response.get( "panels" ), is( vallejo.getPanels().toString() ) ); + assertThat( response.get( "capacity" ), is( vallejo.getCapacity().toString() ) ); + assertThat( response.get( "address" ), is( vallejo.getAddress() ) ); + assertThat( response.get( "city" ), is( vallejo.getCity() ) ); + assertThat( response.get( "state" ), is( vallejo.getState() ) ); + assertThat( response.get( "postalCode" ), is( vallejo.getPostalCode() ) ); + assertThat( response.get( "lat" ), is( vallejo.getCoordinate().getLat().toString() ) ); + assertThat( response.get( "lng" ), is( vallejo.getCoordinate().getLng().toString() ) ); + } + + @Test + public void insertFailsWithoutCoordinate() { + SiteGeoDao dao = new SiteGeoDaoRedisImpl( jedisPool ); + Site vallejo = new Site( 7, 4.5, 3, "637 Britannia Drive", "Vallejo", "CA", "94591" ); + thrown.expect( IllegalArgumentException.class ); + thrown.expectMessage( "Coordinate required for Geo insert." ); + dao.insert( vallejo ); + } } \ No newline at end of file