Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions gateway-service/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ bootRun {
systemProperties = System.properties
}

test {
useJUnitPlatform()
jvmArgs '--add-opens=jdk.httpserver/sun.net.httpserver=ALL-UNNAMED'
}

publishing {
publications {
mavenJavaFat(MavenPublication) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,50 @@
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.springframework.test.context.TestPropertySource;
import org.zowe.apiml.gateway.MockService;
import org.zowe.apiml.gateway.acceptance.common.AcceptanceTestWithMockServices;
import org.zowe.apiml.gateway.acceptance.common.MicroservicesAcceptanceTest;

import static io.restassured.RestAssured.given;
import static org.apache.http.HttpStatus.SC_SERVICE_UNAVAILABLE;
import static org.apache.http.HttpStatus.SC_UNAUTHORIZED;
import static org.apache.http.HttpStatus.*;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;

@MicroservicesAcceptanceTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestPropertySource(properties = {
"apiml.gateway.servicesToDisableRetry=no-retry-service,no-RETRY-Service-2"
})
class RetryPerServiceTest extends AcceptanceTestWithMockServices {
class RetryPerServiceTest {

private static final String HEADER_X_FORWARD_TO = "X-Forward-To";

private MockService mockService;
private MockService mockNoRetryService;
private MockService mockNoRetryService2;

@BeforeAll
void startMockService() {
mockService = mockService("serviceid1").scope(MockService.Scope.CLASS)
@Nested
@MicroservicesAcceptanceTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@TestPropertySource(properties = {
"apiml.gateway.servicesToDisableRetry=no-retry-service,no-RETRY-Service-2"
})
class GivenRetryOnAllOperationsIsDisabled extends AcceptanceTestWithMockServices {

private MockService mockService;
private MockService mockNoRetryService;
private MockService mockNoRetryService2;

@BeforeAll
void startMockService() {
mockService = mockService("serviceid1").scope(MockService.Scope.CLASS)
.addEndpoint("/503").responseCode(503)
.and()
.and()
.addEndpoint("/401").responseCode(401)
.and().start();
.and().start();

mockNoRetryService = mockService("no-retry-service").scope(MockService.Scope.CLASS)
.addEndpoint("/503").responseCode(503)
.and().start();

mockNoRetryService2 = mockService("No-Retry-Service-2").scope(MockService.Scope.CLASS)
.addEndpoint("/503").responseCode(503)
.and().start();
}
mockNoRetryService = mockService("no-retry-service").scope(MockService.Scope.CLASS)
.addEndpoint("/503").responseCode(503)
.and().start();

@Nested
class GivenRetryOnAllOperationsIsDisabled {
//Only default GET method remains active
mockNoRetryService2 = mockService("No-Retry-Service-2").scope(MockService.Scope.CLASS)
.addEndpoint("/503").responseCode(503)
.and().start();
}

@Test
void whenGetReturnsUnavailable_thenRetry() {
Expand Down Expand Up @@ -119,4 +119,54 @@ void whenRetryForServiceIsDisabled_andGetReturnsUnavailable_onMixedCaseServiceId

}

@Nested
@MicroservicesAcceptanceTest
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class ConnectionReset extends AcceptanceTestWithMockServices {

private MockService mockService;

@BeforeAll
void startMockService() {
mockService = mockService("serviceid1").scope(MockService.Scope.CLASS)
.addEndpoint("/200").responseCode(200)
.and().start();
}

@ParameterizedTest(name = "givenConnectionInPool_whenServerWasRestarted_thenRetry({0}, {1})")
@CsvSource({
"GET,CLOSE,200",
"GET,CLOSE_CHANNEL,200",
"GET,KILL_CHANNEL,200",
"GET,MARK_CHANNEL_AS_CLOSED,200",
"POST,CLOSE,200",
"POST,CLOSE_CHANNEL,200",
"POST,KILL_CHANNEL,500",
"POST,MARK_CHANNEL_AS_CLOSED,500"
})
void givenConnectionInPool_whenServerWasRestarted_thenRetry(String method, MockService.ConnectionCleanupType cleanupType, int responseStatus) {
var port = mockService.getPort();

given()
.header(HEADER_X_FORWARD_TO, "serviceid1")
.when()
.get(basePath + "/200")
.then()
.statusCode(is(SC_OK));

mockService.cleanConnections(cleanupType);

var port2 = mockService.getPort();
assertEquals(port, port2);

given()
.header(HEADER_X_FORWARD_TO, "serviceid1")
.when()
.request(method, basePath + "/200")
.then()
.statusCode(is(responseStatus));
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,14 @@
import org.assertj.core.error.MultipleAssertionsError;
import org.springframework.cloud.netflix.eureka.EurekaServiceInstance;
import org.springframework.http.MediaType;
import org.springframework.test.util.ReflectionTestUtils;
import org.zowe.apiml.auth.AuthenticationScheme;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
Expand Down Expand Up @@ -223,6 +221,38 @@ public void stop() {
setStatus(Status.STOPPED);
}


/**
* To close and clean all open connection on the server
* @throws IOException in case of error during closing a connection
*/
public void cleanConnections(ConnectionCleanupType cleanupType) {
Object serverImpl = ReflectionTestUtils.getField(server, "server");
Set<Object> allConnections = (Set<Object>) ReflectionTestUtils.getField(serverImpl, "allConnections");
Set<Object> idleConnections = (Set<Object>) ReflectionTestUtils.getField(serverImpl, "idleConnections");
synchronized (allConnections) {
for (Object connection : allConnections) {
var channel = ReflectionTestUtils.invokeMethod(connection, "getChannel");
switch (cleanupType) {
case CLOSE:
ReflectionTestUtils.invokeMethod(connection, "close");
break;
case CLOSE_CHANNEL:
ReflectionTestUtils.invokeMethod(channel, "close");
break;
case KILL_CHANNEL:
ReflectionTestUtils.invokeMethod(channel, "kill");
break;
case MARK_CHANNEL_AS_CLOSED:
ReflectionTestUtils.setField(channel, "closed", false);
break;
}
}
}
allConnections.clear();
idleConnections.clear();
}

/**
* To stop service without any notification (to be still in the registry). In the case service is down, just notify
* to be in the registry.
Expand Down Expand Up @@ -541,4 +571,13 @@ public boolean isUp() {

}

public enum ConnectionCleanupType {

CLOSE,
CLOSE_CHANNEL,
KILL_CHANNEL,
MARK_CHANNEL_AS_CLOSED

}

}
Loading