package com.netflix.ribbon.transport.netty.http;
import com.netflix.loadbalancer.reactive.ExecutionContext;
import com.netflix.loadbalancer.reactive.ExecutionInfo;
import com.netflix.loadbalancer.reactive.ExecutionListener;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.Server;
import io.netty.buffer.ByteBuf;
import io.reactivex.netty.protocol.http.client.HttpClientRequest;
import io.reactivex.netty.protocol.http.client.HttpClientResponse;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
/**
* @author Allen Wang
*/
public class TestExecutionListener<I, O> implements ExecutionListener<HttpClientRequest<I>, HttpClientResponse<O>> {
public AtomicInteger executionStartCounter = new AtomicInteger(0);
public AtomicInteger startWithServerCounter = new AtomicInteger(0);
public AtomicInteger exceptionWithServerCounter = new AtomicInteger(0);
public AtomicInteger executionFailedCounter = new AtomicInteger(0);
public AtomicInteger executionSuccessCounter = new AtomicInteger(0);
private HttpClientRequest<ByteBuf> expectedRequest;
private IClientConfig requestConfig;
private volatile boolean checkContext = true;
private volatile boolean checkExecutionInfo = true;
private volatile Throwable finalThrowable;
private HttpClientResponse<O> response;
private List<Throwable> errors = new CopyOnWriteArrayList<Throwable>();
private AtomicInteger numAttemptsOnServer = new AtomicInteger();
private AtomicInteger numServers = new AtomicInteger();
private volatile Server lastServer;
private static final Integer MY_OBJECT = Integer.valueOf(9);
private volatile ExecutionContext<HttpClientRequest<I>> context;
public TestExecutionListener(HttpClientRequest<ByteBuf> expectedRequest, IClientConfig requestConfig) {
this.expectedRequest = expectedRequest;
this.requestConfig = requestConfig;
}
private void checkContext(ExecutionContext<HttpClientRequest<I>> context) {
try {
assertSame(requestConfig, context.getRequestConfig());
assertSame(expectedRequest, context.getRequest());
assertEquals(MY_OBJECT, context.get("MyObject"));
if (this.context == null) {
this.context = context;
} else {
assertSame(this.context, context);
}
} catch (Throwable e) {
e.printStackTrace();
checkContext = false;
}
}
private void checkExecutionInfo(ExecutionInfo info) {
try {
assertEquals(numAttemptsOnServer.get(), info.getNumberOfPastAttemptsOnServer());
assertEquals(numServers.get(), info.getNumberOfPastServersAttempted());
} catch (Throwable e) {
e.printStackTrace();
checkExecutionInfo = false;
}
}
@Override
public void onExecutionStart(ExecutionContext<HttpClientRequest<I>> context) {
context.put("MyObject", MY_OBJECT);
checkContext(context);
executionStartCounter.incrementAndGet();
}
@Override
public void onStartWithServer(ExecutionContext<HttpClientRequest<I>> context, ExecutionInfo info) {
checkContext(context);
if (lastServer == null) {
lastServer = info.getServer();
} else if (!lastServer.equals(info.getServer())) {
lastServer = info.getServer();
numAttemptsOnServer.set(0);
numServers.incrementAndGet();
}
checkExecutionInfo(info);
startWithServerCounter.incrementAndGet();
}
@Override
public void onExceptionWithServer(ExecutionContext<HttpClientRequest<I>> context, Throwable exception, ExecutionInfo info) {
checkContext(context);
checkExecutionInfo(info);
numAttemptsOnServer.incrementAndGet();
errors.add(exception);
exceptionWithServerCounter.incrementAndGet();
}
@Override
public void onExecutionSuccess(ExecutionContext<HttpClientRequest<I>> context, HttpClientResponse<O> response, ExecutionInfo info) {
checkContext(context);
checkExecutionInfo(info);
this.response = response;
executionSuccessCounter.incrementAndGet();
}
@Override
public void onExecutionFailed(ExecutionContext<HttpClientRequest<I>> context, Throwable finalException, ExecutionInfo info) {
checkContext(context);
checkExecutionInfo(info);
executionFailedCounter.incrementAndGet();
finalThrowable = finalException;
}
public boolean isContextChecked() {
return checkContext;
}
public boolean isCheckExecutionInfo() {
return checkExecutionInfo;
}
public Throwable getFinalThrowable() {
return finalThrowable;
}
public HttpClientResponse<O> getResponse() {
return response;
}
public ExecutionContext<HttpClientRequest<I>> getContext() {
return this.context;
}
}