You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by el...@apache.org on 2018/06/14 17:31:29 UTC

[trafficcontrol] 02/05: Implement Traffic Router unit tests for geo-steering

This is an automated email from the ASF dual-hosted git repository.

elsloo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git

commit ea97ee6202d9d02ee51d87dbbbb5475c6f4b8a5e
Author: Rawlin Peters <ra...@comcast.com>
AuthorDate: Tue Mar 20 16:52:00 2018 -0600

    Implement Traffic Router unit tests for geo-steering
---
 .../core/ds/SteeringGeolocationComparator.java     |   4 +-
 .../traffic_router/core/ds/SteeringRegistry.java   |   1 +
 .../traffic_router/core/ds/SteeringTarget.java     |   4 +
 .../traffic_router/core/router/TrafficRouter.java  |   8 +-
 .../core/ds/SteeringGeolocationComparatorTest.java | 151 +++++++++++++++++++++
 .../core/router/GeoSortSteeringResultsTest.java    | 134 ++++++++++++++++++
 6 files changed, 296 insertions(+), 6 deletions(-)

diff --git a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringGeolocationComparator.java b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringGeolocationComparator.java
index 5436dae..2dbe8d1 100644
--- a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringGeolocationComparator.java
+++ b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringGeolocationComparator.java
@@ -19,7 +19,6 @@ import java.util.Comparator;
 
 import com.comcast.cdn.traffic_control.traffic_router.geolocation.Geolocation;
 
-// TODO: add unit tests for this class
 public class SteeringGeolocationComparator implements Comparator<SteeringResult> {
 
     private final Geolocation clientLocation;
@@ -29,6 +28,7 @@ public class SteeringGeolocationComparator implements Comparator<SteeringResult>
     }
 
     @Override
+    @SuppressWarnings({"PMD.CyclomaticComplexity"})
     public int compare(final SteeringResult result1, final SteeringResult result2) {
         final Geolocation originGeo1 = result1.getSteeringTarget().getGeolocation();
         final Geolocation originGeo2 = result2.getSteeringTarget().getGeolocation();
@@ -63,7 +63,7 @@ public class SteeringGeolocationComparator implements Comparator<SteeringResult>
 
         // different cache and origin locations, prefer shortest total distance
         if (totalDistance1 != totalDistance2) {
-            // TODO: if the difference is smaller than a certain threshold, still prefer the closer edge even though distance is greater?
+            // TODO: if the difference is smaller than a certain threshold/ratio, still prefer the closer edge even though distance is greater?
             return Double.compare(totalDistance1, totalDistance2);
         }
 
diff --git a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringRegistry.java b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringRegistry.java
index 2bf197b..0b9437a 100644
--- a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringRegistry.java
+++ b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringRegistry.java
@@ -33,6 +33,7 @@ public class SteeringRegistry {
 	private final Map<String, Steering> registry = new HashMap<String, Steering>();
 	private final ObjectMapper objectMapper = new ObjectMapper(new JsonFactory());
 
+	@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.AvoidDuplicateLiterals"})
 	public void update(final String json) {
 		Map<String, List<Steering>> m;
 		try {
diff --git a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringTarget.java b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringTarget.java
index d1a38df..c054ccd 100644
--- a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringTarget.java
+++ b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringTarget.java
@@ -102,6 +102,10 @@ public class SteeringTarget extends DefaultHashable {
 		return geolocation;
 	}
 
+	public void setGeolocation(final Geolocation geolocation) {
+		this.geolocation = geolocation;
+	}
+
 	@Override
 	@SuppressWarnings("PMD")
 	public boolean equals(Object o) {
diff --git a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java
index 5f49865..c67455c 100644
--- a/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java
+++ b/traffic_router/core/src/main/java/com/comcast/cdn/traffic_control/traffic_router/core/router/TrafficRouter.java
@@ -617,6 +617,7 @@ public class TrafficRouter {
 		return routeResult;
 	}
 
+	@SuppressWarnings({"PMD.NPathComplexity"})
 	private List<SteeringResult> getSteeringResults(final HTTPRequest request, final Track track, final DeliveryService entryDeliveryService) {
 
 		if (isTlsMismatch(request, entryDeliveryService)) {
@@ -633,7 +634,7 @@ public class TrafficRouter {
 			return null;
 		}
 
-		List<SteeringResult> toBeRemoved = new ArrayList<>();
+		final List<SteeringResult> toBeRemoved = new ArrayList<>();
 		for (final SteeringResult steeringResult : steeringResults) {
 			final DeliveryService ds = steeringResult.getDeliveryService();
 			if (isTlsMismatch(request, ds)) {
@@ -851,7 +852,7 @@ public class TrafficRouter {
 		return steeringRegistry.get(deliveryService.getId()).isClientSteering();
 	}
 
-	private Geolocation getClientLocationByCoverageZoneOrGeo(final String clientIP, final DeliveryService deliveryService) {
+	protected Geolocation getClientLocationByCoverageZoneOrGeo(final String clientIP, final DeliveryService deliveryService) {
 		Geolocation clientLocation;
 		final NetworkNode networkNode = getNetworkNode(clientIP);
 		if (networkNode != null && networkNode.getGeolocation() != null) {
@@ -866,8 +867,7 @@ public class TrafficRouter {
 		return deliveryService.supportLocation(clientLocation);
 	}
 
-	// TODO: add unit test for this method
-	private void geoSortSteeringResults(final List<SteeringResult> steeringResults, final String clientIP, final DeliveryService deliveryService) {
+	protected void geoSortSteeringResults(final List<SteeringResult> steeringResults, final String clientIP, final DeliveryService deliveryService) {
 		if (clientIP == null || clientIP.isEmpty()
 				|| steeringResults.stream().allMatch(t -> t.getSteeringTarget().getGeolocation() == null)) {
 			return;
diff --git a/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringGeolocationComparatorTest.java b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringGeolocationComparatorTest.java
new file mode 100644
index 0000000..ed72081
--- /dev/null
+++ b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/ds/SteeringGeolocationComparatorTest.java
@@ -0,0 +1,151 @@
+/*
+ *
+ * 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 com.comcast.cdn.traffic_control.traffic_router.core.ds;
+
+import com.comcast.cdn.traffic_control.traffic_router.core.cache.Cache;
+import com.comcast.cdn.traffic_control.traffic_router.geolocation.Geolocation;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class SteeringGeolocationComparatorTest {
+    /*
+    This test class assumes some knowledge of United States geography. For reference,
+    here are the rough distances looking at a map from left to right:
+
+    Seattle <--- 1300 mi ---> Denver <--- 2000 mi ---> Boston
+
+    */
+
+    private Geolocation seattleGeolocation;
+    private Geolocation denverGeolocation;
+    private Geolocation bostonGeolocation;
+
+    private Cache seattleCache;
+    private Cache denverCache;
+    private Cache bostonCache;
+
+    private SteeringTarget seattleTarget;
+    private SteeringTarget seattleTarget2;
+    private SteeringTarget denverTarget;
+    private SteeringTarget bostonTarget;
+
+    private SteeringResult seattleResult;
+    private SteeringResult seattleResult2;
+    private SteeringResult denverResult;
+    private SteeringResult bostonResult;
+
+    private SteeringGeolocationComparator seattleComparator;
+    private SteeringGeolocationComparator denverComparator;
+    private SteeringGeolocationComparator bostonComparator;
+
+    @Before
+    public void before() {
+        seattleGeolocation = new Geolocation(47.0, -122.0);
+        denverGeolocation = new Geolocation(39.0, -104.0);
+        bostonGeolocation = new Geolocation(42.0, -71.0);
+
+        seattleCache = new Cache("seattle-id", "seattle-hash-id", 1, seattleGeolocation);
+        denverCache = new Cache("denver-id", "denver-hash-id", 1, denverGeolocation);
+        bostonCache = new Cache("boston-id", "boston-hash-id", 1, bostonGeolocation);
+
+        seattleTarget = new SteeringTarget();
+        seattleTarget.setGeolocation(seattleGeolocation);
+        seattleResult = new SteeringResult(seattleTarget, null);
+        seattleResult.setCache(seattleCache);
+
+        seattleTarget2 = new SteeringTarget();
+        seattleTarget2.setGeolocation(seattleGeolocation);
+        seattleResult2 = new SteeringResult(seattleTarget2, null);
+        seattleResult2.setCache(seattleCache);
+
+        denverTarget = new SteeringTarget();
+        denverTarget.setGeolocation(denverGeolocation);
+        denverResult = new SteeringResult(denverTarget, null);
+        denverResult.setCache(denverCache);
+
+        bostonTarget = new SteeringTarget();
+        bostonTarget.setGeolocation(bostonGeolocation);
+        bostonResult = new SteeringResult(bostonTarget, null);
+        bostonResult.setCache(bostonCache);
+
+        seattleComparator = new SteeringGeolocationComparator(seattleGeolocation);
+        denverComparator = new SteeringGeolocationComparator(denverGeolocation);
+        bostonComparator = new SteeringGeolocationComparator(bostonGeolocation);
+
+    }
+
+    @Test
+    public void testLeftNullOriginGeo() {
+        seattleResult.getSteeringTarget().setGeolocation(null);
+        assertEquals(1, seattleComparator.compare(seattleResult, bostonResult));
+    }
+
+    @Test
+    public void testRightNullOriginGeo() {
+        denverResult.getSteeringTarget().setGeolocation(null);
+        assertEquals(-1, seattleComparator.compare(seattleResult, denverResult));
+    }
+
+    @Test
+    public void testBothNullOriginGeo() {
+        seattleResult.getSteeringTarget().setGeolocation(null);
+        denverResult.getSteeringTarget().setGeolocation(null);
+        assertEquals(0, seattleComparator.compare(seattleResult, denverResult));
+    }
+
+    @Test
+    public void testSameCacheAndOriginGeo() {
+        assertEquals(0, seattleComparator.compare(seattleResult, seattleResult));
+    }
+
+    @Test
+    public void testSameCacheAndOriginGeoWithGeoOrder() {
+        seattleTarget.setGeoOrder(1);
+        seattleTarget2.setGeoOrder(2);
+        assertEquals(-1, seattleComparator.compare(seattleResult, seattleResult2));
+        assertEquals(1, seattleComparator.compare(seattleResult2, seattleResult));
+        seattleTarget.setGeoOrder(2);
+        assertEquals(0, seattleComparator.compare(seattleResult, seattleResult2));
+    }
+
+    @Test
+    public void testDifferentCacheAndOriginGeo() {
+        assertEquals(-1, seattleComparator.compare(seattleResult, denverResult));
+        assertEquals(-1, seattleComparator.compare(denverResult, bostonResult));
+        assertEquals(1, seattleComparator.compare(bostonResult, seattleResult));
+    }
+
+    @Test
+    public void testCacheGeoDifferentFromOriginGeo() {
+        seattleResult.setCache(denverCache);
+        // seattle -> denver -> seattle || seattle -> denver
+        assertEquals(1, seattleComparator.compare(seattleResult, denverResult));
+        // denver -> seattle || denver
+        assertEquals(1, denverComparator.compare(seattleResult, denverResult));
+        // boston -> denver -> seattle || boston -> denver
+        assertEquals(1, bostonComparator.compare(seattleResult, denverResult));
+        // seattle -> denver -> seattle || seattle -> boston
+        assertEquals(-1, seattleComparator.compare(seattleResult, bostonResult));
+        seattleResult.setCache(bostonCache);
+        bostonResult.setCache(denverCache);
+        // seattle -> boston -> seattle || seattle -> denver -> boston
+        assertEquals(1, seattleComparator.compare(seattleResult, bostonResult));
+    }
+
+}
diff --git a/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/router/GeoSortSteeringResultsTest.java b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/router/GeoSortSteeringResultsTest.java
new file mode 100644
index 0000000..81d3ed0
--- /dev/null
+++ b/traffic_router/core/src/test/java/com/comcast/cdn/traffic_control/traffic_router/core/router/GeoSortSteeringResultsTest.java
@@ -0,0 +1,134 @@
+/*
+ *
+ * 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 com.comcast.cdn.traffic_control.traffic_router.core.router;
+
+import com.comcast.cdn.traffic_control.traffic_router.core.cache.Cache;
+import com.comcast.cdn.traffic_control.traffic_router.core.ds.DeliveryService;
+import com.comcast.cdn.traffic_control.traffic_router.core.ds.SteeringResult;
+import com.comcast.cdn.traffic_control.traffic_router.core.ds.SteeringTarget;
+import com.comcast.cdn.traffic_control.traffic_router.geolocation.Geolocation;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({Collections.class})
+public class GeoSortSteeringResultsTest {
+
+    private TrafficRouter trafficRouter;
+    private List<SteeringResult> steeringResults;
+    private Geolocation clientLocation;
+    private DeliveryService deliveryService;
+
+    @Before
+    public void before() {
+        trafficRouter = mock(TrafficRouter.class);
+        steeringResults = new ArrayList<>();
+        clientLocation = new Geolocation(47.0, -122.0);
+        deliveryService = mock(DeliveryService.class);
+        doCallRealMethod().when(trafficRouter).geoSortSteeringResults(anyListOf(SteeringResult.class), anyString(), any(DeliveryService.class));
+        when(trafficRouter.getClientLocationByCoverageZoneOrGeo(anyString(), any(DeliveryService.class))).thenReturn(clientLocation);
+    }
+
+    @Test
+    public void testNullClientIP() {
+        trafficRouter.geoSortSteeringResults(steeringResults, null, deliveryService);
+        verify(trafficRouter, never()).getClientLocationByCoverageZoneOrGeo(null, deliveryService);
+    }
+
+    @Test
+    public void testEmptyClientIP() {
+        trafficRouter.geoSortSteeringResults(steeringResults, "", deliveryService);
+        verify(trafficRouter, never()).getClientLocationByCoverageZoneOrGeo("", deliveryService);
+    }
+
+    @Test
+    public void testNoSteeringTargetsHaveGeolocations() {
+        steeringResults.add(new SteeringResult(new SteeringTarget(), deliveryService));
+        trafficRouter.geoSortSteeringResults(steeringResults, "::1", deliveryService);
+        verify(trafficRouter, never()).getClientLocationByCoverageZoneOrGeo("::1", deliveryService);
+    }
+
+    @Test
+    public void testClientGeolocationIsNull() {
+        SteeringTarget steeringTarget = new SteeringTarget();
+        steeringTarget.setGeolocation(clientLocation);
+        steeringResults.add(new SteeringResult(steeringTarget, deliveryService));
+        clientLocation = null;
+        PowerMockito.mockStatic(Collections.class);
+
+        trafficRouter.geoSortSteeringResults(steeringResults, "::1", deliveryService);
+
+        PowerMockito.verifyStatic(never());
+    }
+
+    @Test
+    public void testGeoSortingMixedWithNonGeoTargets() {
+        Cache cache = new Cache("fake-id", "fake-hash-id",1, clientLocation);
+        SteeringTarget target;
+
+        target = new SteeringTarget();
+        target.setOrder(-1);
+        SteeringResult resultNoGeoNegativeOrder = new SteeringResult(target, deliveryService);
+        resultNoGeoNegativeOrder.setCache(cache);
+        steeringResults.add(resultNoGeoNegativeOrder);
+
+        target = new SteeringTarget();
+        target.setOrder(1);
+        SteeringResult resultNoGeoPositiveOrder = new SteeringResult(target, deliveryService);
+        resultNoGeoPositiveOrder.setCache(cache);
+        steeringResults.add(resultNoGeoPositiveOrder);
+
+        target = new SteeringTarget();
+        target.setOrder(0);
+        SteeringResult resultNoGeoZeroOrder = new SteeringResult(target, deliveryService);
+        resultNoGeoZeroOrder.setCache(cache);
+        steeringResults.add(resultNoGeoZeroOrder);
+
+        target = new SteeringTarget();
+        target.setGeolocation(clientLocation);
+        target.setOrder(0);
+        SteeringResult resultGeo = new SteeringResult(target, deliveryService);
+        resultGeo.setCache(cache);
+        steeringResults.add(resultGeo);
+
+        trafficRouter.geoSortSteeringResults(steeringResults, "::1", deliveryService);
+
+        assertEquals(resultNoGeoNegativeOrder, steeringResults.get(0));
+        assertEquals(resultGeo, steeringResults.get(1));
+        assertEquals(resultNoGeoZeroOrder, steeringResults.get(2));
+        assertEquals(resultNoGeoPositiveOrder, steeringResults.get(3));
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
elsloo@apache.org.