/*
Copyright (c) 2016 LinkedIn Corp.
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.
*/
/* $Id$ */
package com.linkedin.d2.balancer.clients;
import com.linkedin.d2.balancer.KeyMapper;
import com.linkedin.d2.balancer.LoadBalancerState;
import com.linkedin.d2.balancer.PartitionedLoadBalancerTestState;
import com.linkedin.d2.balancer.properties.PartitionData;
import com.linkedin.d2.balancer.simple.SimpleLoadBalancer;
import com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerStrategyConfig;
import com.linkedin.d2.balancer.strategies.degrader.DegraderLoadBalancerStrategyV3;
import com.linkedin.d2.balancer.util.partitions.PartitionAccessException;
import com.linkedin.d2.balancer.util.partitions.PartitionAccessor;
import com.linkedin.r2.message.RequestContext;
import com.linkedin.r2.message.rest.RestRequest;
import com.linkedin.r2.message.rest.RestRequestBuilder;
import com.linkedin.r2.message.rest.RestResponse;
import java.util.Arrays;
import org.testng.annotations.Test;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertNull;
import static org.testng.Assert.assertTrue;
/**
* Created by xzhu on 8/27/14.
*/
public class RetryClientTest
{
@Test
public void testRetry() throws Exception
{
SimpleLoadBalancer balancer = prepareLoadBalancer(Arrays.asList("http://test.linkedin.com/retry1", "http://test.linkedin.com/good"));
DynamicClient dynamicClient = new DynamicClient(balancer, null);
RetryClient client = new RetryClient(dynamicClient, 3);
URI uri = URI.create("d2://retryService?arg1arg2");
RestRequest restRequest = new RestRequestBuilder(uri).build();
TrackerClientTest.TestCallback<RestResponse> restCallback = new TrackerClientTest.TestCallback<RestResponse>();
client.restRequest(restRequest, restCallback);
assertNull(restCallback.e);
assertNotNull(restCallback.t);
}
@Test
public void testRestException() throws Exception
{
SimpleLoadBalancer balancer = prepareLoadBalancer(Arrays.asList("http://test.linkedin.com/retry1", "http://test.linkedin.com/bad"));
DynamicClient dynamicClient = new DynamicClient(balancer, null);
RetryClient client = new RetryClient(dynamicClient, 3);
URI uri = URI.create("d2://retryService?arg1=empty&arg2=empty");
RestRequest restRequest = new RestRequestBuilder(uri).build();
TrackerClientTest.TestCallback<RestResponse> restCallback = new TrackerClientTest.TestCallback<RestResponse>();
RequestContext context = new RequestContext();
KeyMapper.TargetHostHints.setRequestContextTargetHost(context, URI.create("http://test.linkedin.com/bad"));
client.restRequest(restRequest, context, restCallback);
assertNull(restCallback.t);
assertNotNull(restCallback.e);
assertTrue(restCallback.e.getMessage().contains("exception happens"));
}
@Test
public void testRetryOverLimit() throws Exception
{
SimpleLoadBalancer balancer = prepareLoadBalancer(Arrays.asList("http://test.linkedin.com/retry1", "http://test.linkedin.com/retry2"));
DynamicClient dynamicClient = new DynamicClient(balancer, null);
RetryClient client = new RetryClient(dynamicClient, 1);
URI uri = URI.create("d2://retryService?arg1=empty&arg2=empty");
RestRequest restRequest = new RestRequestBuilder(uri).build();
TrackerClientTest.TestCallback<RestResponse> restCallback = new TrackerClientTest.TestCallback<RestResponse>();
client.restRequest(restRequest, restCallback);
assertNull(restCallback.t);
assertNotNull(restCallback.e);
assertTrue(restCallback.e.getMessage().contains("Data not available"));
}
@Test
public void testRetryNoAvailableHosts() throws Exception
{
SimpleLoadBalancer balancer = prepareLoadBalancer(Arrays.asList("http://test.linkedin.com/retry1", "http://test.linkedin.com/retry2"));
DynamicClient dynamicClient = new DynamicClient(balancer, null);
RetryClient client = new RetryClient(dynamicClient, 3);
URI uri = URI.create("d2://retryService?arg1=empty&arg2=empty");
RestRequest restRequest = new RestRequestBuilder(uri).build();
TrackerClientTest.TestCallback<RestResponse> restCallback = new TrackerClientTest.TestCallback<RestResponse>();
client.restRequest(restRequest, restCallback);
assertNull(restCallback.t);
assertNotNull(restCallback.e);
assertTrue(restCallback.e.toString().contains("retryService is in a bad state"));
}
public SimpleLoadBalancer prepareLoadBalancer(List<String> uris) throws URISyntaxException
{
String serviceName = "retryService";
String clusterName = "cluster";
String path = "";
String strategyName = "degrader";
// setup partition
Map<URI,Map<Integer, PartitionData>> partitionDescriptions = new HashMap<URI, Map<Integer, PartitionData>>();
for (String uri : uris)
{
final URI foo = URI.create(uri);
Map<Integer, PartitionData> foo1Data = new HashMap<Integer, PartitionData>();
foo1Data.put(0, new PartitionData(1.0));
partitionDescriptions.put(foo, foo1Data);
}
DegraderLoadBalancerStrategyV3 strategy = new DegraderLoadBalancerStrategyV3(new DegraderLoadBalancerStrategyConfig(5000), serviceName, null);
List<LoadBalancerState.SchemeStrategyPair> orderedStrategies = new ArrayList<LoadBalancerState.SchemeStrategyPair>();
orderedStrategies.add(new LoadBalancerState.SchemeStrategyPair("http", strategy));
PartitionAccessor accessor = new TestRetryPartitionAccessor();
SimpleLoadBalancer balancer = new SimpleLoadBalancer(new PartitionedLoadBalancerTestState(
clusterName, serviceName, path, strategyName, partitionDescriptions, orderedStrategies,
accessor
));
return balancer;
}
private class TestRetryPartitionAccessor implements PartitionAccessor
{
@Override
public int getPartitionId(URI uri)
throws PartitionAccessException
{
return 0;
}
@Override
public int getPartitionId(String key)
throws PartitionAccessException
{
return 0;
}
@Override
public int getMaxPartitionId()
{
return 0;
}
}
}