Skip to content

Commit

Permalink
Fix transformer fault injection
Browse files Browse the repository at this point in the history
  • Loading branch information
IMichael-ops committed Jul 7, 2023
1 parent 58bafaa commit 389b884
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import io.netty.channel.ConnectTimeoutException;
import org.json.JSONObject;

import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -331,9 +330,9 @@ public HttpResponse execute(ClientRequestContext ctx, HttpRequest req) throws Ex
logger.log(Level.INFO, logPrefix +"Issuing request!");
HttpResponse response;

// Inject transformer fault, if necessary.
if (transformerFault != null && filibusterClientInstrumentor.shouldAbort()) {
// Inject transformer fault, if necessary.
response = injectTransformerFault(filibusterClientInstrumentor, transformerFault);
response = injectTransformerFault(transformerFault);
} else {
// If there is no transformer fault, issue the request.
response = delegateWithContext(ctx, req);
Expand All @@ -343,22 +342,20 @@ public HttpResponse execute(ClientRequestContext ctx, HttpRequest req) throws Ex
// Callback that fires if the request throws an exception.
// ******************************************************************************************

if (response != null) {
response.whenComplete().handle((result, cause) -> {
// Only if this fires with an exception.
if (cause != null) {
logger.log(Level.INFO, logPrefix + "cause: " + cause);

// Notify Filibuster.
if (!(cause instanceof CancelledSubscriptionException)) {
filibusterClientInstrumentor.afterInvocationWithException(cause);
}
response.whenComplete().handle((result, cause) -> {
// Only if this fires with an exception.
if (cause != null) {
logger.log(Level.INFO, logPrefix + "cause: " + cause);

// Notify Filibuster.
if (!(cause instanceof CancelledSubscriptionException)) {
filibusterClientInstrumentor.afterInvocationWithException(cause);
}

return null;
});
}
}

return null;
});

// ******************************************************************************************
// Completion callback.
Expand Down Expand Up @@ -419,10 +416,22 @@ protected HttpObject filter(HttpObject obj) {
HashMap<String, String> returnValueProperties = new HashMap<>();
returnValueProperties.put("status_code", statusCode);

if (filibusterClientInstrumentor.getTransformerFault() == null) {
JSONObject transformerFault = filibusterClientInstrumentor.getTransformerFault();
if (transformerFault == null) {
// Only communicate a successful invocation if there was no transformer fault.
filibusterClientInstrumentor.afterInvocationComplete(className, returnValueProperties, statusCode);
} // In the case of transformer faults, we already call 'afterInvocationWithTransformerFault' in the 'injectTransformerFault' method.
} else {
// Extract the transformer fault value from the transformerFault JSONObject.
Object transformerFaultValue = transformerFault.get("value");
String sTransformerValue = transformerFaultValue.toString();

// Extract the accumulator from the transformerFault JSONObject.
Accumulator<?, ?> accumulator = new Gson().fromJson(transformerFault.get("accumulator").toString(), Accumulator.class);

logger.log(Level.INFO, logPrefix + "Notifying Filibuster of the transformer fault with value: " + transformerFaultValue);
filibusterClientInstrumentor.afterInvocationWithTransformerFault(sTransformerValue,
HttpResponse.class.toString(), accumulator);
}
}

}
Expand All @@ -433,28 +442,20 @@ protected HttpObject filter(HttpObject obj) {
};
}

@Nullable
private static HttpResponse injectTransformerFault(FilibusterClientInstrumentor filibusterClientInstrumentor, JSONObject transformerFault) {
private static HttpResponse injectTransformerFault(JSONObject transformerFault) {
try {
if (transformerFault.has("value") && transformerFault.has("accumulator")) {

// Extract the transformer fault value from the transformerFault JSONObject.
Object transformerFaultValue = transformerFault.get("value");
String sTransformerValue = transformerFaultValue.toString();
logger.log(Level.INFO, logPrefix + "Injecting the transformed fault value: " + sTransformerValue);

// Extract the accumulator from the transformerFault JSONObject.
Accumulator<?, ?> accumulator = new Gson().fromJson(transformerFault.get("accumulator").toString(), Accumulator.class);

// Notify Filibuster.
filibusterClientInstrumentor.afterInvocationWithTransformerFault(sTransformerValue,
HttpResponse.class.toString(), accumulator);
logger.log(Level.INFO, logPrefix + "Injecting the transformed fault value: " + transformerFaultValue);

// Return the transformer fault value.
if (transformerFaultValue == JSONObject.NULL) {
return null;
transformerFaultValue = null;
}
return (HttpResponse) transformerFaultValue;
return HttpResponse.of(HttpStatus.OK, MediaType.PLAIN_TEXT, String.valueOf(transformerFaultValue));

} else {
String missingKey;
if (transformerFault.has("value")) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,16 @@
import org.junit.jupiter.api.TestMethodOrder;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.Random;

import static cloud.filibuster.integration.instrumentation.TestHelper.startHelloServerAndWaitUntilAvailable;
import static cloud.filibuster.integration.instrumentation.TestHelper.startWorldServerAndWaitUntilAvailable;
import static cloud.filibuster.junit.Assertions.wasFaultInjected;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class JUnitFilibusterTransformerHTTPTest {
private final static Set<String> testErrorCodesReceived = new HashSet<>();

private static int numberOfTestsExecuted = 0;

@BeforeAll
Expand All @@ -40,24 +36,28 @@ public static void startHelloService() throws IOException, InterruptedException
startWorldServerAndWaitUntilAvailable();
}

@DisplayName("Test world route with Filibuster.")
@DisplayName("Test injecting 'null' as HTTP response using transformers.")
@TestWithFilibuster(analysisConfigurationFile = FilibusterHTTPNullTransformerAnalysisConfigurationFile.class)
@Order(1)
public void testHelloAndWorldServiceWithFilibuster() {
public void testInjectNullInHTTP() {
numberOfTestsExecuted++;
String cookie = String.valueOf(new Random(0).nextInt());

try {
String baseURI = "http://" + Networking.getHost("hello") + ":" + Networking.getPort("hello") + "/";
WebClient webClient = TestHelper.getTestWebClient(baseURI);
RequestHeaders getHeaders = RequestHeaders.of(HttpMethod.GET, "/world", HttpHeaderNames.ACCEPT, "application/json");
WebClient webClient = TestHelper.getTestWebClient(baseURI, "test");
RequestHeaders getHeaders = RequestHeaders.of(HttpMethod.GET, "/echo-cookie", HttpHeaderNames.ACCEPT, "application/json");
getHeaders = getHeaders.toBuilder().add("cookie", cookie).build();
AggregatedHttpResponse response = webClient.execute(getHeaders).aggregate().join();
ResponseHeaders headers = response.headers();
String statusCode = headers.get(HttpHeaderNames.STATUS);

assertEquals("200", statusCode);

if (wasFaultInjected()) {
testErrorCodesReceived.add(statusCode);
assertEquals("null", response.content().toStringAscii());
} else {
assertEquals("200", statusCode);
assertEquals(cookie, response.content().toStringAscii());
}
} catch (Throwable t) {
fail(t);
Expand All @@ -72,14 +72,4 @@ public void testNumExecutions() {
assertEquals(2, numberOfTestsExecuted);
}

@DisplayName("Verify correct faults number and status code.")
@Test
@Order(3)
public void testFaultsNumAndStatusCode() {
// 1 fault for the transformer value 'null'
assertEquals(1, testErrorCodesReceived.size());

// Injecting the transformer value 'null' leads to an error code of '503'
assertTrue(testErrorCodesReceived.contains("503"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,20 @@ public void run() {
}
});

sb.service("/echo-cookie", new AbstractHttpService() {
// Return the cookie of the received request
@Override
protected @NotNull HttpResponse doGet(@NotNull ServiceRequestContext ctx, @NotNull HttpRequest req) {
setupLocalFixtures();

if(req.headers().get("cookie") != null) {
return HttpResponse.of(req.headers().get("cookie"));
} else {
return HttpResponse.of(HttpStatus.NOT_FOUND);
}
}
}.decorate(delegate -> new FilibusterDecoratingHttpService(delegate, serviceName)));

sb.service("/world", new AbstractHttpService() {
@Override
protected @NotNull HttpResponse doGet(@NotNull ServiceRequestContext ctx, @NotNull HttpRequest req) {
Expand Down

0 comments on commit 389b884

Please sign in to comment.