From 898a2f9af7fe4b0db6dee48f562b30cb004bbfb1 Mon Sep 17 00:00:00 2001 From: Tobia De Koninck Date: Thu, 12 Oct 2023 10:48:42 +0200 Subject: [PATCH] Fix #31542: improve and refactor tests --- .../containerproxy/api/ProxyController.java | 22 +- .../containerproxy/service/ProxyService.java | 11 +- .../leader/memory/MemoryLeaderService.java | 11 +- .../containerproxy/util/Retrying.java | 12 + .../test/auth/LDAPAuthenticationTest.java | 64 +- .../test/auth/NoAuthenticationTest.java | 55 +- .../test/auth/SimpleAuthenticationTest.java | 99 +- .../e2e/app_recovery/TestAppRecovery.java | 543 +++----- .../containerproxy/test/e2e/ecs/TestEcs.java | 81 -- .../test/helpers/ContainerSetup.java | 144 ++ .../test/helpers/KubernetesTestBase.java | 105 -- .../helpers/NotInternalOnlyTestStrategy.java | 58 + .../PropertyOverrideContextInitializer.java | 14 +- .../test/helpers/ShinyProxyClient.java | 192 ++- .../test/helpers/ShinyProxyInstance.java | 111 +- .../test/helpers/TestHelperException.java | 33 + .../containerproxy/test/helpers/TestUtil.java | 33 + .../test/proxy/MockedUserService.java | 77 -- .../test/proxy/TestIntegrationOnEcs.java | 54 + .../test/proxy/TestIntegrationOnKube.java | 1153 +++++++---------- .../test/proxy/TestIntegrationOnSwarm.java | 150 +-- .../proxy/TestIntegrationPortAllocator.java | 49 +- .../test/proxy/TestProxyService.java | 95 -- .../test/unit/RetryingTest.java | 5 +- .../test/unit/TestComputeTargetPath.java | 5 +- .../test/unit/TestOpenIdParseClaimRoles.java | 5 +- .../TestParameterServiceAccessControl.java | 8 +- .../unit/TestParameterValidationService.java | 5 +- .../test/unit/TestParametersService.java | 7 +- .../application-app-recovery_ecs.yml | 39 - .../application-redis-integration.yml | 2 + src/test/resources/application-test-ecs.yml | 43 + .../resources/application-test-ldap-auth.yml | 2 - src/test/resources/application-test.yml | 5 +- 34 files changed, 1485 insertions(+), 1807 deletions(-) delete mode 100644 src/test/java/eu/openanalytics/containerproxy/test/e2e/ecs/TestEcs.java create mode 100644 src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java delete mode 100644 src/test/java/eu/openanalytics/containerproxy/test/helpers/KubernetesTestBase.java create mode 100644 src/test/java/eu/openanalytics/containerproxy/test/helpers/NotInternalOnlyTestStrategy.java rename src/test/java/eu/openanalytics/containerproxy/test/{proxy => helpers}/PropertyOverrideContextInitializer.java (69%) create mode 100644 src/test/java/eu/openanalytics/containerproxy/test/helpers/TestHelperException.java create mode 100644 src/test/java/eu/openanalytics/containerproxy/test/helpers/TestUtil.java delete mode 100644 src/test/java/eu/openanalytics/containerproxy/test/proxy/MockedUserService.java create mode 100644 src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnEcs.java delete mode 100644 src/test/java/eu/openanalytics/containerproxy/test/proxy/TestProxyService.java delete mode 100644 src/test/resources/application-app-recovery_ecs.yml create mode 100644 src/test/resources/application-test-ecs.yml diff --git a/src/main/java/eu/openanalytics/containerproxy/api/ProxyController.java b/src/main/java/eu/openanalytics/containerproxy/api/ProxyController.java index 23c8acc9..8a35f97e 100644 --- a/src/main/java/eu/openanalytics/containerproxy/api/ProxyController.java +++ b/src/main/java/eu/openanalytics/containerproxy/api/ProxyController.java @@ -37,12 +37,14 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.converter.json.MappingJacksonValue; import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import javax.inject.Inject; import java.util.List; +import java.util.Map; @RestController @@ -239,18 +241,34 @@ public ResponseEntity> getProxy(@PathVariable String proxyId) }) @JsonView(Views.UserApi.class) @RequestMapping(value="/api/proxy/{proxySpecId}", method=RequestMethod.POST, produces=MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity> startProxy(@PathVariable String proxySpecId) throws InvalidParametersException { + public ResponseEntity> startProxy(@PathVariable String proxySpecId, @RequestBody(required = false) ParametersBody parametersBody) throws InvalidParametersException { ProxySpec baseSpec = proxyService.findProxySpec(s -> s.getId().equals(proxySpecId), false); if (baseSpec == null) { return ApiResponse.failForbidden(); } try { - Proxy proxy = proxyService.startProxy(baseSpec); + Proxy proxy = proxyService.startProxy(baseSpec, (parametersBody != null) ? parametersBody.getParameters() : null); return ApiResponse.created(proxy); + } catch (InvalidParametersException ex) { + return ApiResponse.fail(ex.getMessage()); } catch (Throwable t ) { return ApiResponse.error("Failed to start proxy"); } } + public static class ParametersBody { + private Map parameters; + + @Schema(description = "Map of parameters for the app.", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + public Map getParameters() { + return parameters; + } + + public void setParameters(Map parameters) { + this.parameters = parameters; + } + + } + } diff --git a/src/main/java/eu/openanalytics/containerproxy/service/ProxyService.java b/src/main/java/eu/openanalytics/containerproxy/service/ProxyService.java index 4700ca7d..83e3ca47 100644 --- a/src/main/java/eu/openanalytics/containerproxy/service/ProxyService.java +++ b/src/main/java/eu/openanalytics/containerproxy/service/ProxyService.java @@ -243,7 +243,14 @@ public Proxy startProxy(ProxySpec spec) { return getProxy(id); } - /** + public Proxy startProxy(ProxySpec spec, Map parameters) { + String id = UUID.randomUUID().toString(); + startProxy(userService.getCurrentAuth(), spec, null, id, parameters).run(); + return getProxy(id); + } + + + /** * Launch a new proxy using the given ProxySpec. * * @param spec The ProxySpec to base the new proxy on. @@ -607,7 +614,7 @@ private Command action(String proxyId, BlockingAction blocking, AsyncAction asyn } } - public interface Command extends Runnable { + public interface Command extends Runnable { } @FunctionalInterface diff --git a/src/main/java/eu/openanalytics/containerproxy/service/leader/memory/MemoryLeaderService.java b/src/main/java/eu/openanalytics/containerproxy/service/leader/memory/MemoryLeaderService.java index f219ba88..ac7026ff 100644 --- a/src/main/java/eu/openanalytics/containerproxy/service/leader/memory/MemoryLeaderService.java +++ b/src/main/java/eu/openanalytics/containerproxy/service/leader/memory/MemoryLeaderService.java @@ -22,11 +22,20 @@ import eu.openanalytics.containerproxy.service.leader.ILeaderService; +import javax.annotation.PreDestroy; + public class MemoryLeaderService implements ILeaderService { + private volatile boolean leader = true; + @Override public boolean isLeader() { - return true; + return leader; + } + + @PreDestroy + public void preDestroy() { + leader = false; } } diff --git a/src/main/java/eu/openanalytics/containerproxy/util/Retrying.java b/src/main/java/eu/openanalytics/containerproxy/util/Retrying.java index 65f6c5a1..839d7f58 100644 --- a/src/main/java/eu/openanalytics/containerproxy/util/Retrying.java +++ b/src/main/java/eu/openanalytics/containerproxy/util/Retrying.java @@ -20,8 +20,13 @@ */ package eu.openanalytics.containerproxy.util; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class Retrying { + private static final Logger log = LoggerFactory.getLogger(Retrying.class); + @FunctionalInterface public interface Attempt { boolean attempt(int currentAttempt, int maxAttempts); @@ -32,6 +37,10 @@ public static boolean retry(Attempt job, int maxDelay) { } public static boolean retry(Attempt job, int maxDelay, boolean retryOnException) { + return retry(job, maxDelay, null, -1, retryOnException); + } + + public static boolean retry(Attempt job, int maxDelay, String logMessage, int logAfterAttmepts, boolean retryOnException) { boolean retVal = false; RuntimeException exception = null; int maxAttempts = numberOfAttempts(maxDelay); @@ -47,6 +56,9 @@ public static boolean retry(Attempt job, int maxDelay, boolean retryOnException) if (retryOnException) exception = e; else throw e; } + if (currentAttempt > logAfterAttmepts && logMessage != null) { + log.info(String.format("Retry: %s (%d/%d)", logMessage, currentAttempt, maxAttempts)); + } } if (exception == null) return retVal; else throw exception; diff --git a/src/test/java/eu/openanalytics/containerproxy/test/auth/LDAPAuthenticationTest.java b/src/test/java/eu/openanalytics/containerproxy/test/auth/LDAPAuthenticationTest.java index 86a5a101..995d9eee 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/auth/LDAPAuthenticationTest.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/auth/LDAPAuthenticationTest.java @@ -20,43 +20,41 @@ */ package eu.openanalytics.containerproxy.test.auth; -import eu.openanalytics.containerproxy.test.proxy.PropertyOverrideContextInitializer; +import eu.openanalytics.containerproxy.test.helpers.BasicAuthInterceptor; +import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.core.env.Environment; -import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; - -import javax.inject.Inject; - -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@SpringBootTest -@ExtendWith(SpringExtension.class) -@AutoConfigureMockMvc -@ActiveProfiles("test-ldap-auth") -@ContextConfiguration(initializers = PropertyOverrideContextInitializer.class) -public class LDAPAuthenticationTest { - @Inject - private MockMvc mvc; +import java.time.Duration; + +public class LDAPAuthenticationTest { - @Inject - private Environment environment; - @Test public void authenticateUser() throws Exception { - String userName = environment.getProperty("proxy.test-username"); - String password = environment.getProperty("proxy.test-password"); - mvc - .perform(get("/api/proxy").with(httpBasic(userName, password)).accept(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(status().isOk()); + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-ldap-auth.yml")) { + String username = "tesla"; + String password = "password"; + + String baseUrl = "http://localhost:7583"; + OkHttpClient client = new OkHttpClient.Builder() + .addInterceptor(new BasicAuthInterceptor(username, password)) + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxy/") + .build(); + + try (Response response = client.newCall(request).execute()) { + Assertions.assertEquals(200, response.code()); + Assertions.assertFalse(response.isRedirect()); + } + } } } diff --git a/src/test/java/eu/openanalytics/containerproxy/test/auth/NoAuthenticationTest.java b/src/test/java/eu/openanalytics/containerproxy/test/auth/NoAuthenticationTest.java index 201a3e4b..4b8af691 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/auth/NoAuthenticationTest.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/auth/NoAuthenticationTest.java @@ -20,38 +20,37 @@ */ package eu.openanalytics.containerproxy.test.auth; -import eu.openanalytics.containerproxy.test.proxy.PropertyOverrideContextInitializer; +import eu.openanalytics.containerproxy.test.helpers.BasicAuthInterceptor; +import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; -import javax.inject.Inject; +import java.time.Duration; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@SpringBootTest -@ExtendWith(SpringExtension.class) -@AutoConfigureMockMvc -@ActiveProfiles("test-no-auth") -@ContextConfiguration(initializers = PropertyOverrideContextInitializer.class) public class NoAuthenticationTest { - @Inject - private MockMvc mvc; + @Test + public void authenticateUser() throws Exception { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-no-auth.yml")) { + String baseUrl = "http://localhost:7583"; + OkHttpClient client = new OkHttpClient.Builder() + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxyspec") + .build(); + + try (Response response = client.newCall(request).execute()) { + Assertions.assertEquals(200, response.code()); + Assertions.assertFalse(response.isRedirect()); + } + } + } - @Test - public void authenticateUser() throws Exception { - mvc - .perform(get("/api/proxyspec").accept(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(status().isOk()) - .andExpect(jsonPath("$").isNotEmpty()); - } } diff --git a/src/test/java/eu/openanalytics/containerproxy/test/auth/SimpleAuthenticationTest.java b/src/test/java/eu/openanalytics/containerproxy/test/auth/SimpleAuthenticationTest.java index cb918f62..ab90adf8 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/auth/SimpleAuthenticationTest.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/auth/SimpleAuthenticationTest.java @@ -20,43 +20,70 @@ */ package eu.openanalytics.containerproxy.test.auth; -import eu.openanalytics.containerproxy.test.proxy.PropertyOverrideContextInitializer; +import eu.openanalytics.containerproxy.test.helpers.BasicAuthInterceptor; +import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.core.env.Environment; -import org.springframework.http.MediaType; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.web.servlet.MockMvc; - -import javax.inject.Inject; - -import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -@SpringBootTest -@ExtendWith(SpringExtension.class) -@AutoConfigureMockMvc -@ActiveProfiles("test-simple-auth") -@ContextConfiguration(initializers = PropertyOverrideContextInitializer.class) + +import java.time.Duration; + public class SimpleAuthenticationTest { - @Inject - private MockMvc mvc; - - @Inject - private Environment environment; - - @Test - public void authenticateUser() throws Exception { - String userName = environment.getProperty("proxy.users[0].name"); - String password = environment.getProperty("proxy.users[0].password"); - mvc - .perform(get("/api/proxy").with(httpBasic(userName, password)).accept(MediaType.APPLICATION_JSON_VALUE)) - .andExpect(status().isOk()); - } + @Test + public void authenticateUser() throws Exception { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-simple-auth.yml")) { + String username = "demo"; + String password = "demo"; + + String baseUrl = "http://localhost:7583"; + OkHttpClient client = new OkHttpClient.Builder() + .addInterceptor(new BasicAuthInterceptor(username, password)) + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxy/") + .build(); + + try (Response response = client.newCall(request).execute()) { + Assertions.assertEquals(200, response.code()); + Assertions.assertFalse(response.isRedirect()); + } + } + } + + @Test + public void invalidUser() throws Exception { + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-test-simple-auth.yml")) { + String username = "not"; + String password = "correct"; + + String baseUrl = "http://localhost:7583"; + OkHttpClient client = new OkHttpClient.Builder() + .addInterceptor(new BasicAuthInterceptor(username, password)) + .callTimeout(Duration.ofSeconds(120)) + .readTimeout(Duration.ofSeconds(120)) + .followRedirects(false) + .build(); + + + Request request = new Request.Builder() + .url(baseUrl + "/api/proxy/") + .header("Accept", "application/json") + .build(); + + try (Response response = client.newCall(request).execute()) { + Assertions.assertEquals(302, response.code()); + Assertions.assertTrue(response.isRedirect()); + } + } + } + + + } diff --git a/src/test/java/eu/openanalytics/containerproxy/test/e2e/app_recovery/TestAppRecovery.java b/src/test/java/eu/openanalytics/containerproxy/test/e2e/app_recovery/TestAppRecovery.java index cabcd7d2..f8a6fa7a 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/e2e/app_recovery/TestAppRecovery.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/e2e/app_recovery/TestAppRecovery.java @@ -20,430 +20,309 @@ */ package eu.openanalytics.containerproxy.test.e2e.app_recovery; -import com.spotify.docker.client.DefaultDockerClient; -import com.spotify.docker.client.exceptions.DockerCertificateException; -import com.spotify.docker.client.exceptions.DockerException; -import eu.openanalytics.containerproxy.test.helpers.KubernetesTestBase; +import eu.openanalytics.containerproxy.test.helpers.ContainerSetup; import eu.openanalytics.containerproxy.test.helpers.ShinyProxyClient; import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; -import io.fabric8.kubernetes.api.model.Pod; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import javax.json.JsonObject; -import java.io.IOException; -import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; -import java.util.List; +import java.util.Map; import java.util.stream.Stream; -public class TestAppRecovery extends KubernetesTestBase { - private static Stream provideStringsForIsBlank() { +public class TestAppRecovery { + + private static Stream backends() { return Stream.of( - Arguments.of("docker", ""), - Arguments.of("docker", "--proxy.docker.internal-networking=true"), - Arguments.of("docker-swarm", ""), - Arguments.of("docker-swarm", "--proxy.docker.internal-networking=true"), - Arguments.of("kubernetes", ""), - Arguments.of("kubernetes", "--proxy.docker.internal-networking=true") + Arguments.of("docker", new HashMap()), + Arguments.of("docker", new HashMap() {{ + put("proxy.docker.internal-networking", "true"); + }}), + Arguments.of("docker-swarm", new HashMap()), + Arguments.of("docker-swarm", new HashMap() {{ + put("proxy.docker.internal-networking", "true"); + }}), + Arguments.of("kubernetes", new HashMap() {{ + put("proxy.kubernetes.namespace", "itest"); + }}), + Arguments.of("kubernetes", new HashMap() {{ + put("proxy.kubernetes.namespace", "itest"); + put("proxy.kubernetes.internal-networking", "true"); + }}) ); } - private void assertEverythingCleanedUp() throws DockerCertificateException, DockerException, InterruptedException { - // Docker - DefaultDockerClient dockerClient = DefaultDockerClient.fromEnv().build(); - Assertions.assertEquals(0, dockerClient.listContainers().stream() - .filter(it -> it.labels() != null && it.labels().containsKey("openanalytics.eu/sp-proxied-app")) - .count()); - - // Docker swarm - Assertions.assertEquals(0, dockerClient.listServices().size()); - - // k8s - List pods = client.pods().inNamespace(namespace).list().getItems(); - Assertions.assertEquals(0, pods.size()); - pods = client.pods().inNamespace(overriddenNamespace).list().getItems(); - Assertions.assertEquals(0, pods.size()); - pods = client.pods().inNamespace("default").list().getItems(); - Assertions.assertEquals(0, pods.size()); - } - - @AfterEach - public void waitForCleanup() throws InterruptedException, DockerException, DockerCertificateException { - Thread.sleep(20_000); - assertEverythingCleanedUp(); - } - - @BeforeEach - public void beforeEach() throws DockerCertificateException, DockerException, InterruptedException { - assertEverythingCleanedUp(); - } - @ParameterizedTest - @MethodSource("provideStringsForIsBlank") - public void simple_recover_single_app_after_shutdown(String backend, String extraArgs) throws IOException, InterruptedException { - ShinyProxyClient shinyProxyClient = new ShinyProxyClient("demo", "demo"); - List instances = new ArrayList<>(); - try { - // 1. create the instance - ShinyProxyInstance instance1 = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), extraArgs); - instances.add(instance1); - Assertions.assertTrue(instance1.start()); - - // 2. create a proxy - String id = shinyProxyClient.startProxy("01_hello"); - Assertions.assertNotNull(id); - - // 3. get defined proxies - HashSet originalProxies = shinyProxyClient.getProxies(); - Assertions.assertNotNull(originalProxies); - Assertions.assertEquals(1, originalProxies.size()); + @MethodSource("backends") + public void simple_recover_single_app_after_shutdown(String backend, Map properties) { + try (ContainerSetup k8s = new ContainerSetup(backend)) { + HashSet originalProxies; + String id; - // 4. stop the instance - instance1.stop(); - - // 5. start the instance again - ShinyProxyInstance instance2 = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), extraArgs); - instances.add(instance2); - Assertions.assertTrue(instance2.start()); - - // 6. get defined proxies - HashSet newProxies = shinyProxyClient.getProxies(); - Assertions.assertNotNull(newProxies); - - // 7. assert that the responses are equal - Assertions.assertEquals(originalProxies, newProxies); - - // 8. stop the proxy - Assertions.assertTrue(shinyProxyClient.stopProxy(id)); + // 1. create the instance + try (ShinyProxyInstance inst = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), properties)) { + // 2. create a proxy + id = inst.client.startProxy("01_hello"); + // 3. get defined proxies + originalProxies = inst.client.getProxies(); + Assertions.assertNotNull(originalProxies); + Assertions.assertEquals(1, originalProxies.size()); + } - // 9. stop the instance - instance2.stop(); - } finally { - instances.forEach(ShinyProxyInstance::stop); + // 4. start the instance again + try (ShinyProxyInstance inst = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), properties)) { + // 5. get defined proxies + HashSet newProxies = inst.client.getProxies(); + // 6. assert that the responses are equal + Assertions.assertNotNull(newProxies); + Assertions.assertEquals(originalProxies, newProxies); + // 7. stop the proxy + inst.client.stopProxy(id); + } } } private static Stream new_app_should_work_after_recovery_src() { return Stream.of( - Arguments.of("docker", ""), - Arguments.of("docker-swarm", ""), - Arguments.of("kubernetes", ""), - Arguments.of("kubernetes", "--proxy.docker.internal-networking=true") + Arguments.of("docker", new HashMap()), + Arguments.of("docker-swarm", new HashMap()), + Arguments.of("kubernetes", new HashMap()) ); } // note: this test only works with minikube running on the same local machine, because it uses the NodePort services @ParameterizedTest @MethodSource("new_app_should_work_after_recovery_src") - public void new_app_should_work_after_recovery(String backend, String extraArgs) throws IOException, InterruptedException { - ShinyProxyClient shinyProxyClient = new ShinyProxyClient("demo", "demo"); - List instances = new ArrayList<>(); - try { + public void new_app_should_work_after_recovery(String backend, Map properties) { + try (ContainerSetup k8s = new ContainerSetup(backend)) { + HashSet originalProxies; + String id1; // 1. create the instance - ShinyProxyInstance instance1 = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), extraArgs); - instances.add(instance1); - Assertions.assertTrue(instance1.start()); + try (ShinyProxyInstance inst = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), properties, true)) { + // 2. create a proxy + id1 = inst.client.startProxy("01_hello"); + Assertions.assertNotNull(id1); + inst.client.testProxyReachable(id1); + // 3. get defined proxies + originalProxies = inst.client.getProxies(); + Assertions.assertNotNull(originalProxies); + Assertions.assertEquals(1, originalProxies.size()); + } - // 2. create a proxy - String id1 = shinyProxyClient.startProxy("01_hello"); - Assertions.assertNotNull(id1); - Thread.sleep(10000); // give the app some time to get ready (we are not using ShinyProxyTestStrategy, so status is not reliable) - Assertions.assertTrue(shinyProxyClient.getProxyRequest(id1)); + // 5. start the instance again + try (ShinyProxyInstance inst = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), properties, true)) { + // 6. get defined proxies + HashSet newProxies = inst.client.getProxies(); + Assertions.assertNotNull(newProxies); + // 7. assert that the responses are equal + Assertions.assertEquals(originalProxies, newProxies); - // 3. get defined proxies - HashSet originalProxies = shinyProxyClient.getProxies(); - Assertions.assertNotNull(originalProxies); + // 8. create a proxy + String id2 = inst.client.startProxy("02_hello"); + Assertions.assertNotNull(id2); - // 4. stop the instance - instance1.stop(); + // 9. test if both proxies are still + inst.client.testProxyReachable(id1); + inst.client.testProxyReachable(id2); - // 5. start the instance again - ShinyProxyInstance instance2 = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), extraArgs); - instances.add(instance2); - Assertions.assertTrue(instance2.start()); - - // 6. get defined proxies - HashSet newProxies = shinyProxyClient.getProxies(); - Assertions.assertNotNull(newProxies); - - // 7. assert that the responses are equal - Assertions.assertEquals(originalProxies, newProxies); - - // 8. create a proxy - String id2 = shinyProxyClient.startProxy("02_hello"); - Assertions.assertNotNull(id2); - Thread.sleep(10000); // give the app some time to get ready (we are not using ShinyProxyTestStrategy, so status is not reliable) - - // 9. test if both proxies are still reachable - Assertions.assertTrue(shinyProxyClient.getProxyRequest(id1)); - Assertions.assertTrue(shinyProxyClient.getProxyRequest(id2)); - - // 8. stop both proxy - Assertions.assertTrue(shinyProxyClient.stopProxy(id1)); - Assertions.assertTrue(shinyProxyClient.stopProxy(id2)); - - // 9. stop the instance - instance2.stop(); - } finally { - instances.forEach(ShinyProxyInstance::stop); + // 10. stop both proxies + inst.client.stopProxy(id1); + inst.client.stopProxy(id2); + } } } @ParameterizedTest - @MethodSource("provideStringsForIsBlank") - public void complex_recover_multiple_apps_after_shutdown(String backend, String extraArgs) throws IOException, InterruptedException { - ShinyProxyClient shinyProxyClient1 = new ShinyProxyClient("demo", "demo"); - ShinyProxyClient shinyProxyClient2 = new ShinyProxyClient("demo2", "demo2"); - ShinyProxyClient shinyProxyClient3 = new ShinyProxyClient("demo3", "demo3"); - - List instances = new ArrayList<>(); - try { - // 1. create the instance - ShinyProxyInstance instance1 = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), extraArgs); - instances.add(instance1); - Assertions.assertTrue(instance1.start()); - - - // 2. create two proxies for user demo - String id1 = shinyProxyClient1.startProxy("01_hello"); - Assertions.assertNotNull(id1); - - String id2 = shinyProxyClient1.startProxy("02_hello"); - Assertions.assertNotNull(id2); - - // 3. get defined proxies - HashSet originalProxies1 = shinyProxyClient1.getProxies(); - Assertions.assertNotNull(originalProxies1); - Assertions.assertEquals(2, originalProxies1.size()); - - - // 4. create two proxies for user demo - String id3 = shinyProxyClient2.startProxy("01_hello"); - Assertions.assertNotNull(id3); - - String id4 = shinyProxyClient2.startProxy("02_hello"); - Assertions.assertNotNull(id4); - - // 5. get defined proxies - HashSet originalProxies2 = shinyProxyClient2.getProxies(); - Assertions.assertNotNull(originalProxies2); + @MethodSource("backends") + public void complex_recover_multiple_apps_after_shutdown(String backend, Map properties) { + try (ContainerSetup k8s = new ContainerSetup(backend)) { + String id1, id2, id3, id4, id5, id6; + HashSet originalProxies1, originalProxies2, originalProxies3; + // 1. create the instance + try (ShinyProxyInstance inst = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), properties)) { + ShinyProxyClient clientDemo2 = inst.getClient("demo2"); + ShinyProxyClient clientDemo3 = inst.getClient("demo3"); - // 6. create two proxies for user demo - String id5 = shinyProxyClient3.startProxy("01_hello"); - Assertions.assertNotNull(id5); + // 2. create two proxies for user demo + id1 = inst.client.startProxy("01_hello"); + Assertions.assertNotNull(id1); - String id6 = shinyProxyClient3.startProxy("02_hello"); - Assertions.assertNotNull(id6); + id2 = inst.client.startProxy("02_hello"); + Assertions.assertNotNull(id2); - // 7. get defined proxies - HashSet originalProxies3 = shinyProxyClient3.getProxies(); - Assertions.assertNotNull(originalProxies3); + // 3. get defined proxies + originalProxies1 = inst.client.getProxies(); + Assertions.assertNotNull(originalProxies1); + Assertions.assertEquals(2, originalProxies1.size()); + // 4. create two proxies for user demo2 + id3 = clientDemo2.startProxy("01_hello"); + Assertions.assertNotNull(id3); - // 8. stop the instance - instance1.stop(); + id4 = clientDemo2.startProxy("02_hello"); + Assertions.assertNotNull(id4); - // 9. start the instance again - ShinyProxyInstance instance2 = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), extraArgs); - instances.add(instance2); - Assertions.assertTrue(instance2.start()); + // 5. get defined proxies + originalProxies2 = clientDemo2.getProxies(); + Assertions.assertNotNull(originalProxies2); - // 10. get defined proxies for user demo - HashSet newProxies1 = shinyProxyClient1.getProxies(); - Assertions.assertNotNull(newProxies1); + // 6. create two proxies for user demo333 + id5 = clientDemo3.startProxy("01_hello"); + Assertions.assertNotNull(id5); - // 11. assert that the responses are equal - Assertions.assertEquals(originalProxies1, newProxies1); + id6 = clientDemo3.startProxy("02_hello"); + Assertions.assertNotNull(id6); + // 7. get defined proxies + originalProxies3 = clientDemo3.getProxies(); + Assertions.assertNotNull(originalProxies3); + } - // 12. get defined proxies for user demo2 - HashSet newProxies2 = shinyProxyClient2.getProxies(); - Assertions.assertNotNull(newProxies2); + // 8. start the instance again + try (ShinyProxyInstance inst = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), properties)) { + ShinyProxyClient clientDemo2 = inst.getClient("demo2"); + ShinyProxyClient clientDemo3 = inst.getClient("demo3"); - // 13. assert that the responses are equal - Assertions.assertEquals(originalProxies2, newProxies2); + // 9. get defined proxies for user demo + HashSet newProxies1 = inst.client.getProxies(); + Assertions.assertNotNull(newProxies1); + // 10. assert that the responses are equal + Assertions.assertEquals(originalProxies1, newProxies1); - // 14. get defined proxies for user demo3 - HashSet newProxies3 = shinyProxyClient3.getProxies(); - Assertions.assertNotNull(newProxies3); + // 11. get defined proxies for user demo2 + HashSet newProxies2 = clientDemo2.getProxies(); + Assertions.assertNotNull(newProxies2); - // 15. assert that the responses are equal - Assertions.assertEquals(originalProxies3, newProxies3); + // 12. assert that the responses are equal + Assertions.assertEquals(originalProxies2, newProxies2); + // 13. get defined proxies for user demo3 + HashSet newProxies3 = clientDemo3.getProxies(); + Assertions.assertNotNull(newProxies3); - // 16. stop the proxies - Assertions.assertTrue(shinyProxyClient1.stopProxy(id1)); - Assertions.assertTrue(shinyProxyClient1.stopProxy(id2)); - Assertions.assertTrue(shinyProxyClient2.stopProxy(id3)); - Assertions.assertTrue(shinyProxyClient2.stopProxy(id4)); - Assertions.assertTrue(shinyProxyClient3.stopProxy(id5)); - Assertions.assertTrue(shinyProxyClient3.stopProxy(id6)); + // 14. assert that the responses are equal + Assertions.assertEquals(originalProxies3, newProxies3); - // 17. stop the instance - instance2.stop(); - } finally { - instances.forEach(ShinyProxyInstance::stop); + // 15. stop the proxies + inst.client.stopProxy(id1); + inst.client.stopProxy(id2); + clientDemo2.stopProxy(id3); + clientDemo2.stopProxy(id4); + clientDemo3.stopProxy(id5); + clientDemo3.stopProxy(id6); + } } } @ParameterizedTest - @MethodSource("provideStringsForIsBlank") - public void simple_recover_multiple_instances(String backend, String extraArgs) throws IOException, InterruptedException { - ShinyProxyClient shinyProxyClient1 = new ShinyProxyClient("demo", "demo", 7583); - ShinyProxyClient shinyProxyClient2 = new ShinyProxyClient("demo", "demo", 7584); - List instances = new ArrayList<>(); - try { + @MethodSource("backends") + public void simple_recover_multiple_instances(String backend, Map properties) { + try (ContainerSetup k8s = new ContainerSetup(backend)) { + String id1, id2; + HashSet originalProxies1, originalProxies2; // 1. create the first instance - ShinyProxyInstance instance1 = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), 7583, extraArgs); - instances.add(instance1); - Assertions.assertTrue(instance1.start()); - - // 1. create the second instance - ShinyProxyInstance instance2 = new ShinyProxyInstance(String.format("application-app-recovery_%s_2.yml", backend), 7584, extraArgs); - instances.add(instance2); - Assertions.assertTrue(instance2.start()); - - // 2. create a proxy on both instances - String id1 = shinyProxyClient1.startProxy("01_hello"); - Assertions.assertNotNull(id1); - - String id2 = shinyProxyClient2.startProxy("01_hello"); - Assertions.assertNotNull(id2); - - // 3. get defined proxies - HashSet originalProxies1 = shinyProxyClient1.getProxies(); - Assertions.assertNotNull(originalProxies1); - Assertions.assertEquals(1, originalProxies1.size()); - - HashSet originalProxies2 = shinyProxyClient2.getProxies(); - Assertions.assertNotNull(originalProxies2); - Assertions.assertEquals(1, originalProxies2.size()); - - // 4. stop both instances - instance1.stop(); - instance2.stop(); + try (ShinyProxyInstance inst1 = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), 7583, "demo", properties, false)) { + // 2. create the second instance + try (ShinyProxyInstance inst2 = new ShinyProxyInstance(String.format("application-app-recovery_%s_2.yml", backend), 7584, "demo", properties, false)) { + + // 3. create a proxy on both instances + id1 = inst1.client.startProxy("01_hello"); + Assertions.assertNotNull(id1); + + id2 = inst2.client.startProxy("01_hello"); + Assertions.assertNotNull(id2); + + // 4. get defined proxies + originalProxies1 = inst1.client.getProxies(); + Assertions.assertNotNull(originalProxies1); + Assertions.assertEquals(1, originalProxies1.size()); + + originalProxies2 = inst2.client.getProxies(); + Assertions.assertNotNull(originalProxies2); + Assertions.assertEquals(1, originalProxies2.size()); + } + } // 5. start both instances again - ShinyProxyInstance instance3 = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), 7583, extraArgs); - instances.add(instance3); - Assertions.assertTrue(instance3.start()); - - ShinyProxyInstance instance4 = new ShinyProxyInstance(String.format("application-app-recovery_%s_2.yml", backend), 7584, extraArgs); - instances.add(instance4); - Assertions.assertTrue(instance4.start()); - - // 6. get defined proxies - HashSet newProxies1 = shinyProxyClient1.getProxies(); - Assertions.assertNotNull(newProxies1); - - HashSet newProxies2 = shinyProxyClient2.getProxies(); - Assertions.assertNotNull(newProxies2); - - // 7. assert that the responses are equal - Assertions.assertEquals(originalProxies1, newProxies1); - Assertions.assertEquals(originalProxies2, newProxies2); - - // 8. stop the proxy - Assertions.assertTrue(shinyProxyClient1.stopProxy(id1)); - Assertions.assertTrue(shinyProxyClient2.stopProxy(id2)); - - // 9. stop the instance - instance3.stop(); - instance4.stop(); - } finally { - instances.forEach(ShinyProxyInstance::stop); + try (ShinyProxyInstance inst1 = new ShinyProxyInstance(String.format("application-app-recovery_%s.yml", backend), 7583, "demo", properties, false)) { + try (ShinyProxyInstance inst2 = new ShinyProxyInstance(String.format("application-app-recovery_%s_2.yml", backend), 7584, "demo", properties, false)) { + // 6. get defined proxies + HashSet newProxies1 = inst1.client.getProxies(); + Assertions.assertNotNull(newProxies1); + + HashSet newProxies2 = inst2.client.getProxies(); + Assertions.assertNotNull(newProxies2); + + // 7. assert that the responses are equal + Assertions.assertEquals(originalProxies1, newProxies1); + Assertions.assertEquals(originalProxies2, newProxies2); + + // 8. stop the proxies + inst1.client.stopProxy(id1); + inst2.client.stopProxy(id2); + } + } } } @Test public void kubernetes_multiple_namespaces() { - setup((client, namespace, overriddenNamespace) -> { - ShinyProxyClient shinyProxyClient = new ShinyProxyClient("demo", "demo"); - List instances = new ArrayList<>(); - try { - // 1. create the instance - ShinyProxyInstance instance1 = new ShinyProxyInstance("application-app-recovery_kubernetes_multi_ns.yml"); - instances.add(instance1); - Assertions.assertTrue(instance1.start()); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id1, id2; + HashSet originalProxies; + // 1. create the instance + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-app-recovery_kubernetes_multi_ns.yml")) { // 2. create a proxy - String id1 = shinyProxyClient.startProxy("01_hello"); + id1 = inst.client.startProxy("01_hello"); Assertions.assertNotNull(id1); - String id2 = shinyProxyClient.startProxy("02_hello"); + id2 = inst.client.startProxy("02_hello"); Assertions.assertNotNull(id2); // 3. get defined proxies - HashSet originalProxies = shinyProxyClient.getProxies(); + originalProxies = inst.client.getProxies(); Assertions.assertNotNull(originalProxies); + } - // 4. stop the instance - instance1.stop(); - - // 5. start the instance again - ShinyProxyInstance instance2 = new ShinyProxyInstance("application-app-recovery_kubernetes_multi_ns.yml"); - instances.add(instance2); - Assertions.assertTrue(instance2.start()); - - // 6. get defined proxies - HashSet newProxies = shinyProxyClient.getProxies(); + // 4. start the instances again + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-app-recovery_kubernetes_multi_ns.yml")) { + // 5. get defined proxies + HashSet newProxies = inst.client.getProxies(); Assertions.assertNotNull(newProxies); - // 7. assert that the responses are equal + // 6. assert that the responses are equal Assertions.assertEquals(originalProxies, newProxies); - // 8. stop the proxy - Assertions.assertTrue(shinyProxyClient.stopProxy(id1)); - Assertions.assertTrue(shinyProxyClient.stopProxy(id2)); - - // 9. stop the instance - instance2.stop(); - } finally { - instances.forEach(ShinyProxyInstance::stop); + // 7. stop the proxies + inst.client.stopProxy(id1); + inst.client.stopProxy(id2); } - }); - + } } @Test public void shutdown_should_cleanup_by_default() { - setup((client, namespace, overriddenNamespace) -> { - ShinyProxyClient shinyProxyClient = new ShinyProxyClient("demo", "demo"); - List instances = new ArrayList<>(); - try { - // 1. create the instance - ShinyProxyInstance instance1 = new ShinyProxyInstance("application-app-recovery_kubernetes_normal_shutdown.yml"); - instances.add(instance1); - Assertions.assertTrue(instance1.start()); - + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + // 1. create the instance + try (ShinyProxyInstance inst = new ShinyProxyInstance("application-app-recovery_kubernetes_normal_shutdown.yml")) { // 2. create a proxy - String id = shinyProxyClient.startProxy("01_hello"); + String id = inst.client.startProxy("01_hello"); Assertions.assertNotNull(id); - - // 3. stop the instance - instance1.stop(); - - // 4. wait for cleanup - Thread.sleep(5000); - - // 4. check if pod is cleanup correctly - List pods = client.pods().inNamespace(overriddenNamespace).list().getItems(); - Assertions.assertEquals(0, pods.size()); - - } finally { - instances.forEach(ShinyProxyInstance::stop); } - }); + + // 3. check if pod is cleanup correctly + Assertions.assertTrue(k8s.checkDockerIsClean()); + } } } diff --git a/src/test/java/eu/openanalytics/containerproxy/test/e2e/ecs/TestEcs.java b/src/test/java/eu/openanalytics/containerproxy/test/e2e/ecs/TestEcs.java deleted file mode 100644 index 7567e5f3..00000000 --- a/src/test/java/eu/openanalytics/containerproxy/test/e2e/ecs/TestEcs.java +++ /dev/null @@ -1,81 +0,0 @@ -/** - * ContainerProxy - * - * Copyright (C) 2016-2023 Open Analytics - * - * =========================================================================== - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Apache License as published by - * The Apache Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Apache License for more details. - * - * You should have received a copy of the Apache License - * along with this program. If not, see - */ -package eu.openanalytics.containerproxy.test.e2e.ecs; - -import eu.openanalytics.containerproxy.test.helpers.ShinyProxyClient; -import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -import javax.json.JsonObject; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; - -public class TestEcs { - - - @AfterEach - public void waitForCleanup() throws InterruptedException { - Thread.sleep(20_000); - } - - @Test - public void ecs_test() { - ShinyProxyClient shinyProxyClient = new ShinyProxyClient("demo", "demo"); - List instances = new ArrayList<>(); - try { - // 1. create the instance - System.out.println("Starting instance"); - ShinyProxyInstance instance1 = new ShinyProxyInstance("1", "application-app-recovery_ecs.yml"); - instances.add(instance1); - Assertions.assertTrue(instance1.start()); - System.out.println("Instance started"); - - // 2. create a proxy - String id = shinyProxyClient.startProxy("01_hello"); - Assertions.assertNotNull(id); - - // 3. stop the instance - instance1.stop(); - - // 4. start the instance again - ShinyProxyInstance instance2 = new ShinyProxyInstance("2", "application-app-recovery_ecs.yml"); - instances.add(instance2); - Assertions.assertTrue(instance2.start()); - - // 5. get defined proxies - HashSet newProxies = shinyProxyClient.getProxies(); - Assertions.assertNotNull(newProxies); - - // 6. stop the proxy - Assertions.assertTrue(shinyProxyClient.stopProxy(id)); - - // 7. stop the instance - instance2.stop(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - instances.forEach(ShinyProxyInstance::stop); - } - } -} diff --git a/src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java b/src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java new file mode 100644 index 00000000..da971166 --- /dev/null +++ b/src/test/java/eu/openanalytics/containerproxy/test/helpers/ContainerSetup.java @@ -0,0 +1,144 @@ +/** + * ContainerProxy + * + * Copyright (C) 2016-2023 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.test.helpers; + +import com.spotify.docker.client.DefaultDockerClient; +import com.spotify.docker.client.exceptions.DockerCertificateException; +import com.spotify.docker.client.exceptions.DockerException; +import eu.openanalytics.containerproxy.util.Retrying; +import io.fabric8.kubernetes.api.model.Namespace; +import io.fabric8.kubernetes.api.model.NamespaceBuilder; +import io.fabric8.kubernetes.api.model.Pod; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.client.DefaultKubernetesClient; +import io.fabric8.kubernetes.client.NamespacedKubernetesClient; +import org.junit.jupiter.api.Assertions; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class ContainerSetup implements AutoCloseable { + + public final String namespace = "itest"; + public final String overriddenNamespace = "itest-overridden"; + private final List managedNamespaces = Arrays.asList(namespace, overriddenNamespace); + public final DefaultKubernetesClient client = new DefaultKubernetesClient(); + public final NamespacedKubernetesClient namespacedClient; + private final String backend; + + public ContainerSetup(String backend) { + this.backend = backend; + try { + if (backend.equals("kubernetes")) { + // set up Kubernetes + deleteNamespaces(); + createNamespaces(); + + TestUtil.sleep(1000); // wait for namespaces and tokens to become ready + namespacedClient = client.inNamespace(namespace); + } else { + namespacedClient = null; + } + + // check docker + if (!checkDockerIsClean()) { + throw new TestHelperException("Docker not clean before starting test"); + } + } catch (Throwable t) { + throw new TestHelperException("Error while setting up kubernetes", t); + } + } + + private void deleteNamespaces() { + if (!backend.equals("kubernetes")) { + return; + } + try { + for (String namespace : managedNamespaces) { + Namespace ns = client.namespaces().withName(namespace).get(); + if (ns == null) { + continue; + } + client.namespaces().withName(namespace).delete(); + } + for (String namespace : managedNamespaces) { + Retrying.retry((c, m) -> client.namespaces().withName(namespace).get() == null, 60_000, "namespace deletion: " + namespace, 1, true); + } + } catch (Throwable t) { + throw new TestHelperException("Error while cleaning kubernetes", t); + } + } + + private void createNamespaces() { + for (String namespace : managedNamespaces) { + client.namespaces().create(new NamespaceBuilder() + .withNewMetadata() + .withName(namespace) + .endMetadata() + .build()); + } + } + + public List getSecrets(String namespace) { + return client.secrets().inNamespace(namespace).list().getItems().stream().filter(it -> !it.getMetadata().getName().startsWith("default-token")).collect(Collectors.toList()); + } + + public Secret getSingleSecret(String namespace) { + List secrets = getSecrets(namespace); + Assertions.assertEquals(1, secrets.size()); + return secrets.get(0); + } + + public boolean checkDockerIsClean() { + return Retrying.retry((c, m) -> { + try { + if (backend.equals("docker")) { + DefaultDockerClient dockerClient = DefaultDockerClient.fromEnv().build(); + long count = dockerClient.listContainers().stream() + .filter(it -> it.labels() != null && it.labels().containsKey("openanalytics.eu/sp-proxied-app")) + .count(); + return count <= 0; + } else if (backend.equals("docker-swarm")) { + DefaultDockerClient dockerClient = DefaultDockerClient.fromEnv().build(); + return dockerClient.listServices().isEmpty(); + } else if (backend.equals("kubernetes")) { + List pods1 = client.pods().inNamespace(namespace).list().getItems(); + List pods2 = client.pods().inNamespace(overriddenNamespace).list().getItems(); + return pods1.isEmpty() && pods2.isEmpty(); + } + return true; + } catch (DockerException | InterruptedException | DockerCertificateException e) { + throw new TestHelperException("Error while checking if Docker is clean", e); + } + }, 60_000, "docker/swarm/k8s is clean", 1, true); + } + + + @Override + public void close() { + deleteNamespaces(); + if (!checkDockerIsClean()) { + throw new TestHelperException("Docker not clean after executing test"); + } + } + +} diff --git a/src/test/java/eu/openanalytics/containerproxy/test/helpers/KubernetesTestBase.java b/src/test/java/eu/openanalytics/containerproxy/test/helpers/KubernetesTestBase.java deleted file mode 100644 index 635307aa..00000000 --- a/src/test/java/eu/openanalytics/containerproxy/test/helpers/KubernetesTestBase.java +++ /dev/null @@ -1,105 +0,0 @@ -/** - * ContainerProxy - * - * Copyright (C) 2016-2023 Open Analytics - * - * =========================================================================== - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Apache License as published by - * The Apache Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Apache License for more details. - * - * You should have received a copy of the Apache License - * along with this program. If not, see - */ -package eu.openanalytics.containerproxy.test.helpers; - -import io.fabric8.kubernetes.api.model.Namespace; -import io.fabric8.kubernetes.api.model.NamespaceBuilder; -import io.fabric8.kubernetes.api.model.Secret; -import io.fabric8.kubernetes.client.DefaultKubernetesClient; -import io.fabric8.kubernetes.client.NamespacedKubernetesClient; -import org.junit.jupiter.api.Assertions; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -public abstract class KubernetesTestBase { - - public static interface TestBody { - public void run(NamespacedKubernetesClient client, String namespace, String overriddenNamespace) throws Exception; - } - - public static final String namespace = "itest"; - public static final String overriddenNamespace = "itest-overridden"; - private final List managedNamespaces = Arrays.asList(namespace, overriddenNamespace); - - static protected final DefaultKubernetesClient client = new DefaultKubernetesClient(); - - protected void setup(TestBody test) { - Runtime.getRuntime().addShutdownHook(new Thread(this::deleteNamespaces)); - - deleteNamespaces(); - createNamespaces(); - - try { - Thread.sleep(1000); // wait for namespaces and tokens to become ready - - NamespacedKubernetesClient namespacedKubernetesClient = client.inNamespace(namespace); - - test.run(namespacedKubernetesClient, namespace, overriddenNamespace); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException(e); - } finally { - deleteNamespaces(); - } - } - - private void deleteNamespaces() { - try { - for (String namespace : managedNamespaces) { - Namespace ns = client.namespaces().withName(namespace).get(); - if (ns == null) { - continue; - } - - client.namespaces().delete(ns); - - while (client.namespaces().withName(namespace).get() != null) { - Thread.sleep(1000); - } - } - } catch (InterruptedException e) { - } - } - - private void createNamespaces() { - for (String namespace : managedNamespaces) { - client.namespaces().create(new NamespaceBuilder() - .withNewMetadata() - .withName(namespace) - .endMetadata() - .build()); - } - } - - - protected List getSecrets(String namespace) { - return client.secrets().inNamespace(namespace).list().getItems().stream().filter(it -> !it.getMetadata().getName().startsWith("default-token")).collect(Collectors.toList()); - } - - protected Secret getSingleSecret(String namespace) { - List secrets = getSecrets(namespace); - Assertions.assertEquals(1, secrets.size()); - return secrets.get(0); - } - -} diff --git a/src/test/java/eu/openanalytics/containerproxy/test/helpers/NotInternalOnlyTestStrategy.java b/src/test/java/eu/openanalytics/containerproxy/test/helpers/NotInternalOnlyTestStrategy.java new file mode 100644 index 00000000..55298c55 --- /dev/null +++ b/src/test/java/eu/openanalytics/containerproxy/test/helpers/NotInternalOnlyTestStrategy.java @@ -0,0 +1,58 @@ +/** + * ContainerProxy + * + * Copyright (C) 2016-2023 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.test.helpers; + +import eu.openanalytics.containerproxy.backend.strategy.IProxyTestStrategy; +import eu.openanalytics.containerproxy.model.runtime.Proxy; +import eu.openanalytics.containerproxy.util.Retrying; + +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.util.Arrays; + +public class NotInternalOnlyTestStrategy implements IProxyTestStrategy { + + @Override + public boolean testProxy(Proxy proxy) { + URI targetURI = proxy.getContainers().get(0).getTargets().get(proxy.getId()); + + return Retrying.retry((currentAttempt, maxAttempts) -> { + try { + if (proxy.getStatus().isUnavailable()) { + // proxy got stopped while loading -> no need to try to connect it since the container will already be deleted + return true; + } + URL testURL = new URL(targetURI.toString() + "/"); + HttpURLConnection connection = ((HttpURLConnection) testURL.openConnection()); + connection.setInstanceFollowRedirects(false); + int responseCode = connection.getResponseCode(); + if (Arrays.asList(200, 301, 302, 303, 307, 308).contains(responseCode)) { + return true; + } + } catch (Exception e) { + return false; + } + return false; + }, 60_000); + } + +} diff --git a/src/test/java/eu/openanalytics/containerproxy/test/proxy/PropertyOverrideContextInitializer.java b/src/test/java/eu/openanalytics/containerproxy/test/helpers/PropertyOverrideContextInitializer.java similarity index 69% rename from src/test/java/eu/openanalytics/containerproxy/test/proxy/PropertyOverrideContextInitializer.java rename to src/test/java/eu/openanalytics/containerproxy/test/helpers/PropertyOverrideContextInitializer.java index 65bfb381..1e4a568e 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/proxy/PropertyOverrideContextInitializer.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/helpers/PropertyOverrideContextInitializer.java @@ -18,30 +18,21 @@ * You should have received a copy of the Apache License * along with this program. If not, see */ -package eu.openanalytics.containerproxy.test.proxy; +package eu.openanalytics.containerproxy.test.helpers; -import eu.openanalytics.containerproxy.ContainerProxyApplication; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.env.MutablePropertySources; -import org.springframework.core.env.PropertiesPropertySource; import org.springframework.core.env.PropertySource; -import org.springframework.test.context.support.TestPropertySourceUtils; import javax.annotation.Nonnull; import java.util.stream.Collectors; -public class PropertyOverrideContextInitializer - implements ApplicationContextInitializer { +public class PropertyOverrideContextInitializer implements ApplicationContextInitializer { @Override public void initialize(@Nonnull ConfigurableApplicationContext configurableApplicationContext) { - TestPropertySourceUtils.addInlinedPropertiesToEnvironment(configurableApplicationContext, - "proxy.kubernetes.namespace=" + TestIntegrationOnKube.namespace); - MutablePropertySources propertySources = configurableApplicationContext.getEnvironment().getPropertySources(); - PropertiesPropertySource defaultProperties = new PropertiesPropertySource("shinyProxyDefaultProperties", ContainerProxyApplication.getDefaultProperties()); - propertySources.addFirst(defaultProperties); // remove any external, file-based property source // we don't want any application.yml or application.properties to be loaded during the tests @@ -51,6 +42,5 @@ public void initialize(@Nonnull ConfigurableApplicationContext configurableAppli .filter(p -> p.contains("Config resource 'file ") && p.contains("via location 'optional:file:./'")) .collect(Collectors.toList()) .forEach(propertySources::remove); - } } diff --git a/src/test/java/eu/openanalytics/containerproxy/test/helpers/ShinyProxyClient.java b/src/test/java/eu/openanalytics/containerproxy/test/helpers/ShinyProxyClient.java index 2853344a..7d571ef2 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/helpers/ShinyProxyClient.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/helpers/ShinyProxyClient.java @@ -20,12 +20,24 @@ */ package eu.openanalytics.containerproxy.test.helpers; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.datatype.jsr353.JSR353Module; -import okhttp3.*; - -import javax.json.*; +import eu.openanalytics.containerproxy.model.runtime.ProxyStatus; +import eu.openanalytics.containerproxy.util.Retrying; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.json.Json; +import javax.json.JsonObject; +import javax.json.JsonObjectBuilder; +import javax.json.JsonReader; import java.time.Duration; +import java.util.HashMap; import java.util.HashSet; public class ShinyProxyClient { @@ -34,57 +46,106 @@ public class ShinyProxyClient { private final String baseUrl; public static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); - private ObjectMapper objectMapper = new ObjectMapper(); - public ShinyProxyClient(String username, String password, int port) { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + public ShinyProxyClient(String usernameAndPassword, int port) { this.baseUrl = "http://localhost:" + port; client = new OkHttpClient.Builder() - .addInterceptor(new BasicAuthInterceptor(username, password)) + .addInterceptor(new BasicAuthInterceptor(usernameAndPassword, usernameAndPassword)) .callTimeout(Duration.ofSeconds(120)) .readTimeout(Duration.ofSeconds(120)) .build(); - objectMapper.registerModule(new JSR353Module()); } - public ShinyProxyClient(String username, String password) { - this(username, password, 7583); + public String startProxy(String specId) { + return startProxy(specId, null); } - public String startProxy(String specId) { + public String startProxy(String specId, HashMap parameters) { + RequestBody body = RequestBody.create("", null); + if (parameters != null) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + body = RequestBody.create( + objectMapper.writeValueAsString(new HashMap() {{ + put("parameters", parameters); + }}), MediaType.get("application/json")); + } catch (JsonProcessingException e) { + throw new TestHelperException("JSON error", e); + } + } Request request = new Request.Builder() - .post(RequestBody.create(null, new byte[0])) + .post(body) .url(baseUrl + "/api/proxy/" + specId) .build(); + JsonObject response = call(request, 201); + String id = response.getJsonObject("data").getString("id"); + ProxyStatus proxyStatus = waitForProxyStatus(id); + if (proxyStatus != ProxyStatus.Up) { + throw new TestHelperException(String.format("Proxy with id %s failed to reach Up status", id)); + } + return id; + } + + public JsonObject startProxyError(String specId, HashMap parameters) { + RequestBody body = RequestBody.create("", null); + if (parameters != null) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + body = RequestBody.create( + objectMapper.writeValueAsString(new HashMap() {{ + put("parameters", parameters); + }}), MediaType.get("application/json")); + } catch (JsonProcessingException e) { + throw new TestHelperException("JSON error", e); + } + } + Request request = new Request.Builder() + .post(body) + .url(baseUrl + "/api/proxy/" + specId) + .build(); + try (Response response = client.newCall(request).execute()) { - if (response.code() == 201) { - JsonReader jsonReader = Json.createReader(response.body().byteStream()); - JsonObject object = jsonReader.readObject(); - jsonReader.close(); - return object.getJsonObject("data").getString("id"); - } else { - System.out.println("BODY: " + response.body().string()); - System.out.println("CODE: " + response.code()); + if (response.body() == null) { return null; } - } catch (Exception e) { - e.printStackTrace(); - return null; + JsonReader jsonReader = Json.createReader(response.body().byteStream()); + JsonObject object = jsonReader.readObject(); + jsonReader.close(); + return object; + } catch (Throwable t) { + throw new TestHelperException("Error during http request", t); } } - public boolean stopProxy(String proxyId) { + private ProxyStatus waitForProxyStatus(String proxyId) { + for (int i = 0; i < 3; i++) { + Request request = new Request.Builder() + .get() + .url(baseUrl + "/api/" + proxyId + "/status?watch=true&timeout=60") + .build(); + + JsonObject response = call(request, 200); + ProxyStatus proxyStatus = ProxyStatus.valueOf(response.getJsonObject("data").getString("status")); + if (proxyStatus.equals(ProxyStatus.Up) || proxyStatus.equals(ProxyStatus.Stopped) || proxyStatus.equals(ProxyStatus.Paused)) { + return proxyStatus; + } + } + throw new TestHelperException(String.format("Proxy with id %s failed to reach status", proxyId)); + } + + public void stopProxy(String proxyId) { Request request = new Request.Builder() .put(RequestBody.create("{\"desiredState\":\"Stopping\"}", JSON)) .url(baseUrl + "/api/" + proxyId + "/status") .build(); - try (Response response = client.newCall(request).execute()) { - Thread.sleep(2_000); - return response.code() == 200; - } catch (Exception e) { - e.printStackTrace(); - return false; + call(request, 200); + ProxyStatus status = waitForProxyStatus(proxyId); + if (status != ProxyStatus.Stopped) { + throw new TestHelperException(String.format("Failed to stop proxy: %s, status: %s", proxyId, status)); } } @@ -94,36 +155,61 @@ public HashSet getProxies() { .url(baseUrl + "/api/proxy/") .build(); - try (Response response = client.newCall(request).execute()) { - JsonObject resp = objectMapper.readValue(response.body().byteStream(), JsonObject.class); + JsonObject response = call(request, 200); + HashSet result = new HashSet<>(); - HashSet result = new HashSet<>(); + for (JsonObject proxy : response.getJsonArray("data").getValuesAs(JsonObject.class)) { + JsonObjectBuilder builder = Json.createObjectBuilder(); + proxy.forEach(builder::add); + // remove startupTimestamp since it is different after app recovery + builder.add("startupTimestamp", "null"); + result.add(builder.build()); + } - for (JsonObject proxy : resp.getJsonArray("data").getValuesAs(JsonObject.class)) { - JsonObjectBuilder builder = Json.createObjectBuilder(); - proxy.forEach(builder::add); - // remove startupTimestamp since it is different after app recovery - builder.add("startupTimestamp", "null"); - result.add(builder.build()); - } + return result; + } - return result; - } catch (Exception e) { - return null; + public void testProxyReachable(String id) { + boolean res = Retrying.retry((c, m) -> { + try { + Request request = new Request.Builder() + .get() + .url(baseUrl + "/api/route/" + id + "/") + .build(); + + try (Response response = client.newCall(request).execute()) { + if (response.code() == 200) { + return true; + } + } + return false; + } catch (Throwable t) { + throw new TestHelperException("Error during http request", t); + } + }, 60_000, "proxy is reachable", 1, true); + if (!res) { + throw new TestHelperException("Proxy not reachable"); } } - public boolean getProxyRequest(String id) { - Request request = new Request.Builder() - .get() - .url(baseUrl + "/api/route/" + id + "/") - .build(); - + private JsonObject call(Request request, int expectedStatusCode) { try (Response response = client.newCall(request).execute()) { - return response.code() == 200; - } catch (Exception e) { - e.printStackTrace(); - return false; + if (response.code() == expectedStatusCode) { + if (response.body() == null) { + throw new TestHelperException("Response null during http request"); + } + JsonReader jsonReader = Json.createReader(response.body().byteStream()); + JsonObject object = jsonReader.readObject(); + jsonReader.close(); + return object; + } else { + if (response.body() != null) { + logger.info("Response body: " + response.body().string()); + } + throw new TestHelperException(String.format("Unexpected status code %s (expected %s) during http request", response.code(), expectedStatusCode)); + } + } catch (Throwable t) { + throw new TestHelperException("Error during http request", t); } } diff --git a/src/test/java/eu/openanalytics/containerproxy/test/helpers/ShinyProxyInstance.java b/src/test/java/eu/openanalytics/containerproxy/test/helpers/ShinyProxyInstance.java index dcac36b9..d1123a27 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/helpers/ShinyProxyInstance.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/helpers/ShinyProxyInstance.java @@ -20,64 +20,90 @@ */ package eu.openanalytics.containerproxy.test.helpers; +import eu.openanalytics.containerproxy.ContainerProxyApplication; +import eu.openanalytics.containerproxy.service.ProxyService; +import eu.openanalytics.containerproxy.util.Retrying; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; -import java.io.File; -import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; -public class ShinyProxyInstance { +public class ShinyProxyInstance implements AutoCloseable { - private ProcessBuilder processBuilder; - private Process process; - private int port; + private final int port; private final Logger logger = LoggerFactory.getLogger(getClass()); - public ShinyProxyInstance(String configFileName, int port, String extraArgs) { - this.port = port; + private ConfigurableApplicationContext app; + private final Thread thread; - int mgmtPort = port % 1000 + 9000; + public final ShinyProxyClient client; + public final ProxyService proxyService; - String uuid = java.util.UUID.randomUUID().toString(); - - logger.info("Starting ShinyProxy server, with output in {}", uuid); - - processBuilder = new ProcessBuilder("java", "-jar", - "target/containerproxy-app-recovery.jar", - "--spring.config.location=src/test/resources/" + configFileName, - "--server.port=" + port, - "--management.server.port=" + mgmtPort, - extraArgs) - .redirectOutput(new File(String.format("shinyproxy_recovery_%s_stdout.log", uuid))) - .redirectError(new File(String.format("shinyproxy_recovery_%s_stderr.log", uuid))); + public ShinyProxyInstance(String configFileName, Map properties) { + this(configFileName, 7583, "demo", properties, false); } - public ShinyProxyInstance(String configFileName, String extraArgs) { - this(configFileName, 7583, extraArgs); + public ShinyProxyInstance(String configFileName, Map properties, boolean useNotInternalOnlyTestStrategyConfiguration) { + this(configFileName, 7583, "demo", properties, useNotInternalOnlyTestStrategyConfiguration); } public ShinyProxyInstance(String configFileName) { - this(configFileName, 7583, ""); + this(configFileName, 7583, "demo", new HashMap<>(), false); } - public boolean start() throws IOException, InterruptedException { - process = processBuilder.start(); + public ShinyProxyInstance(String configFileName, int port, String usernameAndPassword, Map properties, boolean useNotInternalOnlyTestStrategyConfiguration) { + try { + this.port = port; + int mgmtPort = port % 1000 + 9000; - for (int i = 0; i < 20; i++) { - Thread.sleep(2_000); - if (checkAlive()) { - return true; + SpringApplication application = new SpringApplication(ContainerProxyApplication.class); + if (useNotInternalOnlyTestStrategyConfiguration) { + // only works if networking is NOT internal! + application.addPrimarySources(Collections.singletonList(NotInternalOnlyTestStrategyConfiguration.class)); } + Properties allProperties = ContainerProxyApplication.getDefaultProperties(); + allProperties.put("spring.config.location", "src/test/resources/" + configFileName); + allProperties.put("server.port", port); + allProperties.put("management.server.port", mgmtPort); + allProperties.put("proxy.kubernetes.namespace", "itest"); + allProperties.putAll(properties); + application.setDefaultProperties(allProperties); + + client = new ShinyProxyClient(usernameAndPassword, port); + + thread = new Thread(() -> { + app = application.run(); + }); + thread.start(); + + Retrying.retry((c, m) -> checkAlive(), 60_000, "ShinyProxyInstance available", 1, true); + proxyService = app.getBean("proxyService", ProxyService.class); + } catch (Throwable t) { + throw new TestHelperException("Error during startup of ShinyProxy", t); } + } - return false; + public ShinyProxyClient getClient(String usernameAndPassword) { + return new ShinyProxyClient(usernameAndPassword, port); } - public boolean checkAlive() { + public T getBean(String name, Class requiredType) throws BeansException { + return app.getBean(name, requiredType); + } + + private boolean checkAlive() { OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() @@ -93,8 +119,25 @@ public boolean checkAlive() { } - public void stop() { - process.destroy(); + @Override + public void close() { + app.stop(); + app.close(); + try { + thread.join(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + public static class NotInternalOnlyTestStrategyConfiguration { + + @Primary + @Bean + public NotInternalOnlyTestStrategy notInternalOnlyTestStrategy() { + return new NotInternalOnlyTestStrategy(); + } + } } diff --git a/src/test/java/eu/openanalytics/containerproxy/test/helpers/TestHelperException.java b/src/test/java/eu/openanalytics/containerproxy/test/helpers/TestHelperException.java new file mode 100644 index 00000000..e0d06b7a --- /dev/null +++ b/src/test/java/eu/openanalytics/containerproxy/test/helpers/TestHelperException.java @@ -0,0 +1,33 @@ +/** + * ContainerProxy + * + * Copyright (C) 2016-2023 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.test.helpers; + +public class TestHelperException extends RuntimeException { + + public TestHelperException(String message) { + super(message); + } + + public TestHelperException(String message, Throwable t) { + super(message, t); + } + +} diff --git a/src/test/java/eu/openanalytics/containerproxy/test/helpers/TestUtil.java b/src/test/java/eu/openanalytics/containerproxy/test/helpers/TestUtil.java new file mode 100644 index 00000000..59530a93 --- /dev/null +++ b/src/test/java/eu/openanalytics/containerproxy/test/helpers/TestUtil.java @@ -0,0 +1,33 @@ +/** + * ContainerProxy + * + * Copyright (C) 2016-2023 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.test.helpers; + +public class TestUtil { + + public static void sleep(int ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + throw new TestHelperException("Error while sleeping", e); + } + } + +} diff --git a/src/test/java/eu/openanalytics/containerproxy/test/proxy/MockedUserService.java b/src/test/java/eu/openanalytics/containerproxy/test/proxy/MockedUserService.java deleted file mode 100644 index a74d8ee6..00000000 --- a/src/test/java/eu/openanalytics/containerproxy/test/proxy/MockedUserService.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * ContainerProxy - * - * Copyright (C) 2016-2023 Open Analytics - * - * =========================================================================== - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Apache License as published by - * The Apache Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Apache License for more details. - * - * You should have received a copy of the Apache License - * along with this program. If not, see - */ -package eu.openanalytics.containerproxy.test.proxy; - -import eu.openanalytics.containerproxy.service.UserService; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -public class MockedUserService extends UserService { - - public String getCurrentUserId() { - return "jack"; - } - - public Authentication getCurrentAuth() { - return new Authentication() { - @Override - public Collection getAuthorities() { - return Arrays.asList(new SimpleGrantedAuthority("ROLE_GROUP1"), new SimpleGrantedAuthority("ROLE_GROUP2")); - } - - @Override - public Object getCredentials() { - return "N/A"; - } - - @Override - public Object getDetails() { - return "N/A"; - } - - @Override - public Object getPrincipal() { - return "N/A"; - } - - @Override - public boolean isAuthenticated() { - return true; - } - - @Override - public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { - // no-op - } - - @Override - public String getName() { - return "jack"; - } - }; - } - -} diff --git a/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnEcs.java b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnEcs.java new file mode 100644 index 00000000..5ae250b8 --- /dev/null +++ b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnEcs.java @@ -0,0 +1,54 @@ +/** + * ContainerProxy + * + * Copyright (C) 2016-2023 Open Analytics + * + * =========================================================================== + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Apache License as published by + * The Apache Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Apache License for more details. + * + * You should have received a copy of the Apache License + * along with this program. If not, see + */ +package eu.openanalytics.containerproxy.test.proxy; + +import com.spotify.docker.client.DefaultDockerClient; +import com.spotify.docker.client.exceptions.DockerCertificateException; +import com.spotify.docker.client.exceptions.DockerException; +import com.spotify.docker.client.messages.swarm.Service; +import eu.openanalytics.containerproxy.model.runtime.Proxy; +import eu.openanalytics.containerproxy.service.InvalidParametersException; +import eu.openanalytics.containerproxy.test.helpers.ContainerSetup; +import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.List; + +public class TestIntegrationOnEcs { + + private static final ShinyProxyInstance inst = new ShinyProxyInstance("application-test-ecs.yml", new HashMap<>()); + + @AfterAll + public static void afterAll() { + inst.close(); + } + + @Test + public void launchProxy() { + try (ContainerSetup containerSetup = new ContainerSetup("ecs")) { + String id = inst.client.startProxy("01_hello"); + } + } + +} diff --git a/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnKube.java b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnKube.java index 1786475a..4a87c29d 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnKube.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnKube.java @@ -20,19 +20,15 @@ */ package eu.openanalytics.containerproxy.test.proxy; -import eu.openanalytics.containerproxy.ContainerProxyApplication; import eu.openanalytics.containerproxy.ContainerProxyException; -import eu.openanalytics.containerproxy.backend.IContainerBackend; -import eu.openanalytics.containerproxy.backend.kubernetes.KubernetesBackend; import eu.openanalytics.containerproxy.model.runtime.Proxy; import eu.openanalytics.containerproxy.model.runtime.runtimevalues.BackendContainerNameKey; import eu.openanalytics.containerproxy.model.spec.ProxySpec; -import eu.openanalytics.containerproxy.service.ProxyService; -import eu.openanalytics.containerproxy.service.UserService; import eu.openanalytics.containerproxy.spec.expression.SpelException; -import eu.openanalytics.containerproxy.test.helpers.KubernetesTestBase; -import eu.openanalytics.containerproxy.test.proxy.TestIntegrationOnKube.TestConfiguration; -import eu.openanalytics.containerproxy.util.ProxyMappingManager; +import eu.openanalytics.containerproxy.test.helpers.ContainerSetup; +import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; +import eu.openanalytics.containerproxy.test.helpers.TestUtil; +import eu.openanalytics.containerproxy.util.Retrying; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ContainerStatus; import io.fabric8.kubernetes.api.model.EnvVar; @@ -49,22 +45,16 @@ import io.fabric8.kubernetes.api.model.ServiceList; import io.fabric8.kubernetes.api.model.Volume; import io.fabric8.kubernetes.api.model.VolumeMount; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.AbstractFactoryBean; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; -import org.springframework.core.env.Environment; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; - -import javax.inject.Inject; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.SimpleGrantedAuthority; + +import javax.json.JsonObject; import java.io.ByteArrayInputStream; -import java.net.URI; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -72,35 +62,14 @@ import java.util.UUID; import java.util.stream.Collectors; +public class TestIntegrationOnKube { -/** - * Test which tests various setups against a Kubernetes Backend. - * Things which are not yet tested: - * - internal networking - * - node selector - * - image pull policy + secret - * - * How to run these tests: - * 1. Install minikube on your system - * 2. run minikube start - * 3. run tests: - * - using Eclipse or mvn test - * - Arquillian will find you Kube config automatically - * 4. Done. All used resources should be gone in minikube. - */ -@SpringBootTest(classes = {TestConfiguration.class, ContainerProxyApplication.class}) -@ContextConfiguration(initializers = PropertyOverrideContextInitializer.class) -@ActiveProfiles("test") -public class TestIntegrationOnKube extends KubernetesTestBase { - - @Inject - private Environment environment; + private static final ShinyProxyInstance inst = new ShinyProxyInstance("application-test.yml", new HashMap<>()); - @Inject - private ProxyService proxyService; - - @Inject - private UserService userService; + @AfterAll + public static void afterAll() { + inst.close(); + } /** * This test starts a Proxy with a very simple Spec and checks whether @@ -108,18 +77,16 @@ public class TestIntegrationOnKube extends KubernetesTestBase { */ @Test public void launchProxy() { - setup((client, namespace, overriddenNamespace) -> { - String specId = environment.getProperty("proxy.specs[0].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -127,48 +94,41 @@ public void launchProxy() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); Assertions.assertFalse(pod.getSpec().getContainers().get(0).getSecurityContext().getPrivileged()); - ServiceList serviceList = client.services().inNamespace(namespace).list(); + ServiceList serviceList = k8s.client.services().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, serviceList.getItems().size()); Service service = serviceList.getItems().get(0); - Assertions.assertEquals(namespace, service.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, service.getMetadata().getNamespace()); Assertions.assertEquals("sp-service-" + containerId, service.getMetadata().getName()); Assertions.assertEquals(containerId, service.getSpec().getSelector().get("app")); Assertions.assertEquals(1, service.getSpec().getPorts().size()); Assertions.assertEquals(Integer.valueOf(3838), service.getSpec().getPorts().get(0).getTargetPort().getIntVal()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // all services should be deleted - serviceList = client.services().inNamespace(namespace).list(); + serviceList = k8s.client.services().inNamespace(k8s.namespace).list(); Assertions.assertEquals(0, serviceList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + } } /** * This test starts a Proxy with a Spec containing two volumes. */ @Test - public void launchProxyWithVolumes() throws Exception { - setup((client, namespace, overriddenNamespace) -> { - String specId = environment.getProperty("proxy.specs[1].id"); + public void launchProxyWithVolumes() { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_volume"); + Proxy proxy = inst.proxyService.getProxy(id); - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -192,36 +152,28 @@ public void launchProxyWithVolumes() throws Exception { Assertions.assertEquals("shinyproxy-volume-1", volumeMounts.get(1).getName()); Assertions.assertEquals("/srv/myvolume2", volumeMounts.get(1).getMountPath()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + assertNoPods(k8s); + } } /** * This test starts a Proxy with a Spec containing env variables. */ @Test - public void launchProxyWithEnv() throws Exception { - setup((client, namespace, overriddenNamespace) -> { - String specId = environment.getProperty("proxy.specs[2].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + public void launchProxyWithEnv() { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_env"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -232,7 +184,7 @@ public void launchProxyWithEnv() throws Exception { List envList = pod.getSpec().getContainers().get(0).getEnv(); Map env = envList.stream().collect(Collectors.toMap(EnvVar::getName, e -> e)); Assertions.assertTrue(env.containsKey("SHINYPROXY_USERNAME")); - Assertions.assertEquals("jack", env.get("SHINYPROXY_USERNAME").getValue()); // value is a String "null" + Assertions.assertEquals("demo", env.get("SHINYPROXY_USERNAME").getValue()); // value is a String "null" Assertions.assertTrue(env.containsKey("SHINYPROXY_USERGROUPS")); Assertions.assertEquals("GROUP1,GROUP2", env.get("SHINYPROXY_USERGROUPS").getValue()); Assertions.assertTrue(env.containsKey("VAR1")); @@ -242,42 +194,29 @@ public void launchProxyWithEnv() throws Exception { Assertions.assertTrue(env.containsKey("VAR3")); Assertions.assertEquals("VALUE3", env.get("VAR3").getValue()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + assertNoPods(k8s); + } } @Test - public void launchProxyWithSecretRef() throws Exception { - setup((client, namespace, overriddenNamespace) -> { + public void launchProxyWithSecretRef() { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { // first create the required secret - client.secrets().inNamespace(namespace).create( - new SecretBuilder() - .withNewMetadata() - .withName("mysecret") - .endMetadata() - .addToData("username", "YWRtaW4=") - .build()); - - String specId = environment.getProperty("proxy.specs[3].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + k8s.client.secrets().inNamespace(k8s.namespace).create( + new SecretBuilder().withNewMetadata().withName("mysecret").endMetadata().addToData("username", "YWRtaW4=").build()); + + String id = inst.client.startProxy("01_hello_secret"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -291,33 +230,25 @@ public void launchProxyWithSecretRef() throws Exception { Assertions.assertEquals("username", env.get("MY_SECRET").getValueFrom().getSecretKeyRef().getKey()); Assertions.assertEquals("mysecret", env.get("MY_SECRET").getValueFrom().getSecretKeyRef().getName()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + assertNoPods(k8s); + } } @Test - public void launchProxyWithResources() throws Exception { - setup((client, namespace, overriddenNamespace) -> { - String specId = environment.getProperty("proxy.specs[4].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + public void launchProxyWithResources() { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_limits"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -331,33 +262,26 @@ public void launchProxyWithResources() throws Exception { Assertions.assertEquals(new Quantity("2"), req.getLimits().get("cpu")); Assertions.assertEquals(new Quantity("2Gi"), req.getLimits().get("memory")); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + assertNoPods(k8s); + } } @Test - public void launchProxyWithPrivileged() throws Exception { - setup((client, namespace, overriddenNamespace) -> { - String specId = environment.getProperty("proxy.specs[5].id"); + public void launchProxyWithPrivileged() { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_priv"); + Proxy proxy = inst.proxyService.getProxy(id); - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -366,55 +290,45 @@ public void launchProxyWithPrivileged() throws Exception { Assertions.assertTrue(pod.getSpec().getContainers().get(0).getSecurityContext().getPrivileged()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + assertNoPods(k8s); + } } @Test public void launchProxyWithPodPatches() { - setup((client, namespace, overriddenNamespace) -> { - final String serviceAccountName = "sp-ittest-b9fa0a24-account"; + final String serviceAccountName = "sp-ittest-b9fa0a24-account"; + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { try { - client.serviceAccounts().inNamespace(overriddenNamespace).create(new ServiceAccountBuilder() + k8s.client.serviceAccounts().inNamespace(k8s.overriddenNamespace).create(new ServiceAccountBuilder() .withNewMetadata() - .withName(serviceAccountName) - .withNamespace(overriddenNamespace) + .withName(serviceAccountName).withNamespace(k8s.overriddenNamespace) .endMetadata() .build()); // Give Kube time to setup ServiceAccount - Thread.sleep(2000); - - String specId = environment.getProperty("proxy.specs[6].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + TestUtil.sleep(2000); + String id = inst.client.startProxy("01_hello_patches1"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); // Check whether the effectively used namespace is correct - Assertions.assertEquals(overriddenNamespace, proxy.getContainers().get(0).getRuntimeValue(BackendContainerNameKey.inst).split("/")[0]); + Assertions.assertEquals(k8s.overriddenNamespace, proxy.getContainers().get(0).getRuntimeValue(BackendContainerNameKey.inst).split("/")[0]); // no pods should exist in the default namespace - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(0, podList.getItems().size()); // no services should exist in the default namespace - ServiceList serviceList = client.services().inNamespace(namespace).list(); + ServiceList serviceList = k8s.client.services().inNamespace(k8s.namespace).list(); Assertions.assertEquals(0, serviceList.getItems().size()); - podList = client.pods().inNamespace(overriddenNamespace).list(); + podList = k8s.client.pods().inNamespace(k8s.overriddenNamespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(overriddenNamespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.overriddenNamespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); Assertions.assertEquals(serviceAccountName, pod.getSpec().getServiceAccount()); @@ -422,53 +336,45 @@ public void launchProxyWithPodPatches() { Assertions.assertEquals(true, container.getReady()); Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); - serviceList = client.services().inNamespace(overriddenNamespace).list(); + serviceList = k8s.client.services().inNamespace(k8s.overriddenNamespace).list(); Assertions.assertEquals(1, serviceList.getItems().size()); Service service = serviceList.getItems().get(0); - Assertions.assertEquals(overriddenNamespace, service.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.overriddenNamespace, service.getMetadata().getNamespace()); Assertions.assertEquals("sp-service-" + containerId, service.getMetadata().getName()); Assertions.assertEquals(containerId, service.getSpec().getSelector().get("app")); Assertions.assertEquals(1, service.getSpec().getPorts().size()); Assertions.assertEquals(Integer.valueOf(3838), service.getSpec().getPorts().get(0).getTargetPort().getIntVal()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(overriddenNamespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // all services should be deleted - serviceList = client.services().inNamespace(overriddenNamespace).list(); + serviceList = k8s.client.services().inNamespace(k8s.overriddenNamespace).list(); Assertions.assertEquals(0, serviceList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - } finally { - client.serviceAccounts().withName(serviceAccountName).delete(); + k8s.client.serviceAccounts().withName(serviceAccountName).delete(); } - }); + } } /** * Test whether the merging of properties works properly */ @Test - public void launchProxyWithPatchesWithMerging() throws Exception { - setup((client, namespace, overriddenNamespace) -> { - String specId = environment.getProperty("proxy.specs[7].id"); + public void launchProxyWithPatchesWithMerging() { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_patches2"); + Proxy proxy = inst.proxyService.getProxy(id); - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -491,17 +397,11 @@ public void launchProxyWithPatchesWithMerging() throws Exception { Assertions.assertTrue(env.containsKey("ADDED_VAR")); Assertions.assertEquals("VALUE", env.get("ADDED_VAR").getValue()); // value is a String "null" - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + assertNoPods(k8s); + } } /** @@ -511,47 +411,42 @@ public void launchProxyWithPatchesWithMerging() throws Exception { */ @Test public void launchProxyWithAdditionalManifests() { - setup((client, namespace, overriddenNamespace) -> { - ProxySpec spec = proxyService.getProxySpec("01_hello_manifests"); - Proxy proxy = proxyService.startProxy(spec); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_manifests"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(overriddenNamespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.overriddenNamespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(overriddenNamespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.overriddenNamespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); Assertions.assertEquals(true, container.getReady()); Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); - PersistentVolumeClaimList claimList = client.persistentVolumeClaims().inNamespace(overriddenNamespace).list(); + PersistentVolumeClaimList claimList = k8s.client.persistentVolumeClaims().inNamespace(k8s.overriddenNamespace).list(); Assertions.assertEquals(1, claimList.getItems().size()); PersistentVolumeClaim claim = claimList.getItems().get(0); - Assertions.assertEquals(overriddenNamespace, claim.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.overriddenNamespace, claim.getMetadata().getNamespace()); Assertions.assertEquals("manifests-pvc", claim.getMetadata().getName()); // secret has no namespace defined -> should be created in the namespace defined by the pod patches - Secret secret = getSingleSecret(overriddenNamespace); - Assertions.assertEquals(overriddenNamespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.overriddenNamespace); + Assertions.assertEquals(k8s.overriddenNamespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - // all additional manifests should be deleted - Assertions.assertEquals(0, getSecrets(overriddenNamespace).size()); - Assertions.assertEquals(0, client.persistentVolumeClaims().inNamespace(overriddenNamespace).list().getItems().size()); + assertNoPods(k8s); - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + // all additional manifests should be deleted + Assertions.assertEquals(0, k8s.getSecrets(k8s.overriddenNamespace).size()); + Assertions.assertEquals(0, k8s.client.persistentVolumeClaims().inNamespace(k8s.overriddenNamespace).list().getItems().size()); + } } /** @@ -562,67 +457,66 @@ public void launchProxyWithAdditionalManifests() { * This is exactly the same test as the previous one, except that the PVC already exists (and should not be re-created). */ @Test - public void launchProxyWithAdditionalManifestsOfWhichOneAlreadyExists() throws Exception { - setup((client, namespace, overriddenNamespace) -> { + public void launchProxyWithAdditionalManifestsOfWhichOneAlreadyExists() { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { // create the PVC String pvcSpec = "apiVersion: v1\n" + - "kind: PersistentVolumeClaim\n" + - "metadata:\n" + - " name: manifests-pvc\n" + - " namespace: itest-overridden\n" + - "spec:\n" + - " storageClassName: standard\n" + - " accessModes:\n" + - " - ReadWriteOnce\n" + - " resources:\n" + - " requests:\n" + - " storage: 5Gi"; - - client.load(new ByteArrayInputStream(pvcSpec.getBytes())).createOrReplace(); - - String specId = environment.getProperty("proxy.specs[8].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + "kind: PersistentVolumeClaim\n" + + "metadata:\n" + + " name: manifests-pvc\n" + + " namespace: itest-overridden\n" + + "spec:\n" + + " storageClassName: standard\n" + + " accessModes:\n" + + " - ReadWriteOnce\n" + + " resources:\n" + + " requests:\n" + + " storage: 5Gi"; + + + k8s.client.inNamespace(k8s.overriddenNamespace).load(new ByteArrayInputStream(pvcSpec.getBytes())).createOrReplace(); + + String id = inst.client.startProxy("01_hello_manifests"); + Proxy proxy = inst.proxyService.getProxy(id); + String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(overriddenNamespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.overriddenNamespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(overriddenNamespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.overriddenNamespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); Assertions.assertEquals(true, container.getReady()); Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); - PersistentVolumeClaimList claimList = client.persistentVolumeClaims().inNamespace(overriddenNamespace).list(); + PersistentVolumeClaimList claimList = k8s.client.persistentVolumeClaims().inNamespace(k8s.overriddenNamespace).list(); Assertions.assertEquals(1, claimList.getItems().size()); PersistentVolumeClaim claim = claimList.getItems().get(0); - Assertions.assertEquals(overriddenNamespace, claim.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.overriddenNamespace, claim.getMetadata().getNamespace()); Assertions.assertEquals("manifests-pvc", claim.getMetadata().getName()); + // IMPORTANT: PVC should not have any labels, since it is the already existing resource and not created by shinyproxy + Assertions.assertEquals(0, claim.getMetadata().getLabels().size()); // secret has no namespace defined -> should be created in the namespace defined by the pod patches - Secret secret = getSingleSecret(overriddenNamespace); - Assertions.assertEquals(overriddenNamespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.overriddenNamespace); + Assertions.assertEquals(k8s.overriddenNamespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - // all additional manifests should be deleted - Assertions.assertEquals(0, getSecrets(overriddenNamespace).size()); - Assertions.assertEquals(0, client.persistentVolumeClaims().inNamespace(overriddenNamespace).list().getItems().size()); + assertNoPods(k8s); - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + // the secret additional manifests should be deleted + Assertions.assertEquals(0, k8s.getSecrets(k8s.overriddenNamespace).size()); + // the pvc should still exist, shinyproxy does not delete it because it was not created by shinyproxy + // using sp-additional-manifest-policy: Patch it will be patched and deleted, see test launchProxyWithManifestPolicyPatch case 2 + Assertions.assertEquals(1, k8s.client.persistentVolumeClaims().inNamespace(k8s.overriddenNamespace).list().getItems().size()); + } } @@ -630,19 +524,17 @@ public void launchProxyWithAdditionalManifestsOfWhichOneAlreadyExists() throws E * Tests the use of Spring Expression in kubernetes patches and additional manifests. */ @Test - public void launchProxyWithExpressionInPatchAndManifests() throws Exception { - setup((client, namespace, overriddenNamespace) -> { - String specId = environment.getProperty("proxy.specs[9].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + public void launchProxyWithExpressionInPatchAndManifests() { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_manifests_espression"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -655,33 +547,28 @@ public void launchProxyWithExpressionInPatchAndManifests() throws Exception { Map env = envList.stream().collect(Collectors.toMap(EnvVar::getName, e -> e)); Assertions.assertTrue(env.containsKey("CUSTOM_USERNAME")); Assertions.assertTrue(env.containsKey("PROXY_ID")); - Assertions.assertEquals("jack", env.get("CUSTOM_USERNAME").getValue()); + Assertions.assertEquals("demo", env.get("CUSTOM_USERNAME").getValue()); Assertions.assertEquals(proxy.getId(), env.get("PROXY_ID").getValue()); - PersistentVolumeClaimList claimList = client.persistentVolumeClaims().inNamespace(namespace).list(); + PersistentVolumeClaimList claimList = k8s.client.persistentVolumeClaims().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, claimList.getItems().size()); PersistentVolumeClaim claim = claimList.getItems().get(0); - Assertions.assertEquals(namespace, claim.getMetadata().getNamespace()); - Assertions.assertEquals("home-dir-pvc-jack", claim.getMetadata().getName()); + Assertions.assertEquals(k8s.namespace, claim.getMetadata().getNamespace()); + Assertions.assertEquals("home-dir-pvc-demo", claim.getMetadata().getName()); // check volume mount Volume volume = pod.getSpec().getVolumes().get(0); - Assertions.assertEquals("home-dir-pvc-jack", volume.getName()); - Assertions.assertEquals("home-dir-pvc-jack", volume.getPersistentVolumeClaim().getClaimName()); - - proxyService.stopProxy(null, proxy, true).run(); + Assertions.assertEquals("home-dir-pvc-demo", volume.getName()); + Assertions.assertEquals("home-dir-pvc-demo", volume.getPersistentVolumeClaim().getClaimName()); - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - // all additional manifests should be deleted - Assertions.assertEquals(0, client.persistentVolumeClaims().inNamespace(namespace).list().getItems().size()); + assertNoPods(k8s); - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + // all additional manifests should be deleted + Assertions.assertEquals(0, k8s.client.persistentVolumeClaims().inNamespace(k8s.namespace).list().getItems().size()); + } } /** @@ -691,68 +578,60 @@ public void launchProxyWithExpressionInPatchAndManifests() throws Exception { * It is a PVC which should be persistent. */ @Test - public void launchProxyWithAdditionalPersistentManifests() throws Exception { - setup((client, namespace, overriddenNamespace) -> { - String specId = environment.getProperty("proxy.specs[11].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + public void launchProxyWithAdditionalPersistentManifests() { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_manifests_persistent"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(overriddenNamespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.overriddenNamespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(overriddenNamespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.overriddenNamespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); Assertions.assertEquals(true, container.getReady()); Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); - PersistentVolumeClaimList claimList = client.persistentVolumeClaims().inNamespace(overriddenNamespace).list(); + PersistentVolumeClaimList claimList = k8s.client.persistentVolumeClaims().inNamespace(k8s.overriddenNamespace).list(); Assertions.assertEquals(1, claimList.getItems().size()); PersistentVolumeClaim claim = claimList.getItems().get(0); - Assertions.assertEquals(overriddenNamespace, claim.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.overriddenNamespace, claim.getMetadata().getNamespace()); Assertions.assertEquals("manifests-pvc", claim.getMetadata().getName()); // secret has no namespace defined -> should be created in the namespace defined by the pod patches - Secret secret = getSingleSecret(overriddenNamespace); - Assertions.assertEquals(overriddenNamespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.overriddenNamespace); + Assertions.assertEquals(k8s.overriddenNamespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // the secret should be deleted - Assertions.assertEquals(0, getSecrets(overriddenNamespace).size()); + Assertions.assertEquals(0, k8s.getSecrets(k8s.overriddenNamespace).size()); // the PVC should not be deleted - Assertions.assertEquals(1, client.persistentVolumeClaims().inNamespace(overriddenNamespace).list().getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + Assertions.assertEquals(1, k8s.client.persistentVolumeClaims().inNamespace(k8s.overriddenNamespace).list().getItems().size()); + } } @Test public void launchProxyWithManifestPolicyCreateOnce() { // case 1: secret does not exist yet - setup((client, namespace, overriddenNamespace) -> { - ProxySpec spec = proxyService.getProxySpec("01_hello_manifests_policy_create_once"); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_manifests_policy_create_once"); + Proxy proxy = inst.proxyService.getProxy(id); - Proxy proxy = proxyService.startProxy(spec); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -760,47 +639,43 @@ public void launchProxyWithManifestPolicyCreateOnce() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); // secret has no namespace defined -> should be created in the default namespace - Secret secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); // secret should have the value from the application.yml Assertions.assertEquals("cGFzc3dvcmQ=", secret.getData().get("password")); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // the secret should be deleted - Assertions.assertEquals(0, getSecrets(overriddenNamespace).size()); - }); + Assertions.assertEquals(0, k8s.getSecrets(k8s.overriddenNamespace).size()); + } // case 2: secret does already exist, check that it does not get overridden - setup((client, namespace, overriddenNamespace) -> { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { // first create secret - client.secrets().inNamespace(namespace).create(new SecretBuilder() + k8s.client.secrets().inNamespace(k8s.namespace).create(new SecretBuilder() .withNewMetadata() .withName("manifests-secret") .withLabels(new HashMap() {{ put("openanalytics.eu/sp-additional-manifest", "true"); put("openanalytics.eu/sp-persistent-manifest", "false"); - put("openanalytics.eu/sp-manifest-id", "4d1d0a831959477994c28330254195c1623c17fb"); + put("openanalytics.eu/sp-manifest-id", "994e40ac66b4bc9329b97d776146b66679afb2b9"); }}) .endMetadata() .withData(Collections.singletonMap("password", "b2xkX3Bhc3N3b3Jk")) .build()); - ProxySpec spec = proxyService.getProxySpec("01_hello_manifests_policy_create_once"); - Proxy proxy = proxyService.startProxy(spec); + String id = inst.client.startProxy("01_hello_manifests_policy_create_once"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -808,40 +683,34 @@ public void launchProxyWithManifestPolicyCreateOnce() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); // secret has no namespace defined -> should be created in the default namespace - Secret secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); // secret should have the value from the secret we created above not from the application.yml Assertions.assertEquals("b2xkX3Bhc3N3b3Jk", secret.getData().get("password")); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // the secret should be deleted - Assertions.assertEquals(0, getSecrets(namespace).size()); - }); + Assertions.assertEquals(0, k8s.getSecrets(k8s.namespace).size()); + } } @Test public void launchProxyWithManifestPolicyPatch() { // case 1: secret does not exist yet - setup((client, namespace, overriddenNamespace) -> { - String specId = environment.getProperty("proxy.specs[14].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_manifests_policy_patch"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -849,28 +718,24 @@ public void launchProxyWithManifestPolicyPatch() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); // secret has no namespace defined -> should be created in the default namespace - Secret secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); // secret should have the value from the application.yml Assertions.assertEquals("cGFzc3dvcmQ=", secret.getData().get("password")); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // the secret should be deleted - Assertions.assertEquals(0, getSecrets(namespace).size()); - }); + Assertions.assertEquals(0, k8s.getSecrets(k8s.namespace).size()); + } // case 2: secret does already exist, check that it gets overridden - setup((client, namespace, overriddenNamespace) -> { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { // first create secret - Secret originalSecret = client.secrets().inNamespace(namespace).create(new SecretBuilder() + Secret originalSecret = k8s.client.secrets().inNamespace(k8s.namespace).create(new SecretBuilder() .withNewMetadata() .withName("manifests-secret") .endMetadata() @@ -880,19 +745,16 @@ public void launchProxyWithManifestPolicyPatch() { String originalCreationTimestamp = originalSecret.getMetadata().getCreationTimestamp(); // let the secret live for some seconds, so that the timestamp will be different - Thread.sleep(2000); - - String specId = environment.getProperty("proxy.specs[14].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + TestUtil.sleep(2000); + String id = inst.client.startProxy("01_hello_manifests_policy_patch"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -900,50 +762,45 @@ public void launchProxyWithManifestPolicyPatch() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); // secret has no namespace defined -> should be created in the default namespace - Secret secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); // secret should have the value from the application.yml not from the secret we created above Assertions.assertEquals("cGFzc3dvcmQ=", secret.getData().get("password")); // since the secret should not have been replaced, the creation timestamp must be equal Assertions.assertEquals(originalCreationTimestamp, secret.getMetadata().getCreationTimestamp()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // the secret should be deleted - Assertions.assertEquals(0, getSecrets(overriddenNamespace).size()); - }); + Assertions.assertEquals(0, k8s.getSecrets(k8s.overriddenNamespace).size()); + } } @Test public void launchProxyWithManifestPolicyDelete() { // case 1: secret does already exist, check that it gets deleted - setup((client, namespace, overriddenNamespace) -> { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { // first create secret - client.secrets().inNamespace(namespace).create(new SecretBuilder() + k8s.client.secrets().inNamespace(k8s.namespace).create(new SecretBuilder() .withNewMetadata() .withName("manifests-secret") .endMetadata() .withData(Collections.singletonMap("password", "b2xkX3Bhc3N3b3Jk")) .build()); - String specId = environment.getProperty("proxy.specs[15].id"); + String id = inst.client.startProxy("01_hello_manifests_policy_delete"); + Proxy proxy = inst.proxyService.getProxy(id); - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -951,34 +808,28 @@ public void launchProxyWithManifestPolicyDelete() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); // the secret should be deleted - Assertions.assertEquals(0, getSecrets(overriddenNamespace).size()); + Assertions.assertEquals(0, k8s.getSecrets(k8s.overriddenNamespace).size()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - }); + assertNoPods(k8s); + } } @Test public void launchProxyWithManifestPolicyReplace() { // case 1: secret does not exist yet - setup((client, namespace, overriddenNamespace) -> { - String specId = environment.getProperty("proxy.specs[16].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_manifests_policy_replace"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -986,28 +837,24 @@ public void launchProxyWithManifestPolicyReplace() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); // secret has no namespace defined -> should be created in the default namespace - Secret secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); // secret should have the value from the application.yml Assertions.assertEquals("cGFzc3dvcmQ=", secret.getData().get("password")); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // the secret should be deleted - Assertions.assertEquals(0, getSecrets(overriddenNamespace).size()); - }); + Assertions.assertEquals(0, k8s.getSecrets(k8s.overriddenNamespace).size()); + } // case 2: secret does already exist, check that it gets overridden - setup((client, namespace, overriddenNamespace) -> { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { // first create secret - Secret originalSecret = client.secrets().inNamespace(namespace).create(new SecretBuilder() + Secret originalSecret = k8s.client.secrets().inNamespace(k8s.namespace).create(new SecretBuilder() .withNewMetadata() .withName("manifests-secret") .endMetadata() @@ -1017,19 +864,18 @@ public void launchProxyWithManifestPolicyReplace() { String originalCreationTimestamp = originalSecret.getMetadata().getCreationTimestamp(); // let the secret live for some seconds, so that the timestamp will be different - Thread.sleep(2000); + TestUtil.sleep(2000); - String specId = environment.getProperty("proxy.specs[16].id"); + String id = inst.client.startProxy("01_hello_manifests_policy_replace"); + Proxy proxy = inst.proxyService.getProxy(id); - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -1037,40 +883,36 @@ public void launchProxyWithManifestPolicyReplace() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); // secret has no namespace defined -> should be created in the default namespace - Secret secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); // secret should have the value from the application.yml not from the secret we created above Assertions.assertEquals("cGFzc3dvcmQ=", secret.getData().get("password")); // since the secret was replaced, the creation timestamp must be different Assertions.assertNotEquals(originalCreationTimestamp, secret.getMetadata().getCreationTimestamp()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // the secret should be deleted - Assertions.assertEquals(0, getSecrets(overriddenNamespace).size()); - }); + Assertions.assertEquals(0, k8s.getSecrets(k8s.overriddenNamespace).size()); + } } @Test public void launchProxyWithPersistentManifestPolicyCreateOnce() { // case 1: secret does not exist yet - setup((client, namespace, overriddenNamespace) -> { - ProxySpec spec = proxyService.getProxySpec("01_hello_persistent_manifests_policy_create_once"); - Proxy proxy = proxyService.startProxy(spec); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_persistent_manifests_policy_create_once"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -1078,64 +920,56 @@ public void launchProxyWithPersistentManifestPolicyCreateOnce() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); // secret has no namespace defined -> should be created in the default namespace - Secret secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); Assertions.assertEquals("cGFzc3dvcmQ=", secret.getData().get("password")); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); + // the secret should not be deleted - Assertions.assertEquals(1, getSecrets(namespace).size()); + Assertions.assertEquals(1, k8s.getSecrets(k8s.namespace).size()); - String originalCreationTimestamp = client.secrets().inNamespace(namespace) + String originalCreationTimestamp = k8s.client.secrets().inNamespace(k8s.namespace) .withName("manifests-secret").get().getMetadata().getCreationTimestamp(); // step 2: secret does already exist, check that it gets overridden - proxy = proxyService.startProxy(spec); + id = inst.client.startProxy("01_hello_persistent_manifests_policy_create_once"); + proxy = inst.proxyService.getProxy(id); // secret has no namespace defined -> should be created in the default namespace - secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); Assertions.assertEquals("cGFzc3dvcmQ=", secret.getData().get("password")); // secret should have not been modified -> check timestamp Assertions.assertEquals(originalCreationTimestamp, secret.getMetadata().getCreationTimestamp()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // the secret should not be deleted - Assertions.assertEquals(1, getSecrets(namespace).size()); - }); + Assertions.assertEquals(1, k8s.getSecrets(k8s.namespace).size()); + } } @Test public void launchProxyWithPersistentManifestPolicyPatch() { // case 1: secret does not exist yet - setup((client, namespace, overriddenNamespace) -> { - String specId = environment.getProperty("proxy.specs[18].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_persistent_manifests_policy_patch"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -1143,75 +977,65 @@ public void launchProxyWithPersistentManifestPolicyPatch() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); // secret has no namespace defined -> should be created in the default namespace - Secret secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); Assertions.assertEquals("cGFzc3dvcmQ=", secret.getData().get("password")); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); + // the secret should not be deleted - Assertions.assertEquals(1, getSecrets(namespace).size()); + Assertions.assertEquals(1, k8s.getSecrets(k8s.namespace).size()); - String originalCreationTimestamp = client.secrets().inNamespace(namespace) + String originalCreationTimestamp = k8s.client.secrets().inNamespace(k8s.namespace) .withName("manifests-secret").get().getMetadata().getCreationTimestamp(); // same spec, different value - String specId2 = environment.getProperty("proxy.specs[19].id"); - spec = proxyService.findProxySpec(s -> s.getId().equals(specId2), true); - proxy = proxyService.startProxy(spec); + id = inst.client.startProxy("01_hello_persistent_manifests_policy_patch2"); + proxy = inst.proxyService.getProxy(id); // secret has no namespace defined -> should be created in the default namespace - secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); // secret should have the value from the second spec Assertions.assertEquals("b2xkX3Bhc3N3b3Jk", secret.getData().get("password")); // since the secret should not have been replaced, the creation timestamp must be equal Assertions.assertEquals(originalCreationTimestamp, secret.getMetadata().getCreationTimestamp()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // the secret should not be deleted - Assertions.assertEquals(1, getSecrets(namespace).size()); - }); + Assertions.assertEquals(1, k8s.getSecrets(k8s.namespace).size()); + } } @Test public void launchProxyWithPersistentManifestPolicyDelete() { // case 1: secret does already exist, check that it gets deleted - setup((client, namespace, overriddenNamespace) -> { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { // first create secret - client.secrets().inNamespace(namespace).create(new SecretBuilder() + k8s.client.secrets().inNamespace(k8s.namespace).create(new SecretBuilder() .withNewMetadata() .withName("manifests-secret") .endMetadata() .withData(Collections.singletonMap("password", "b2xkX3Bhc3N3b3Jk")) .build()); - String specId = environment.getProperty("proxy.specs[20].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + String id = inst.client.startProxy("01_hello_persistent_manifests_policy_delete"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -1219,32 +1043,28 @@ public void launchProxyWithPersistentManifestPolicyDelete() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); // the secret should be deleted - Assertions.assertEquals(0, getSecrets(overriddenNamespace).size()); - - proxyService.stopProxy(null, proxy, true).run(); + Assertions.assertEquals(0, k8s.getSecrets(k8s.overriddenNamespace).size()); - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - }); + assertNoPods(k8s); + } } @Test public void launchProxyWithPersistentManifestPolicyReplace() { // case 1: secret does not exist yet - setup((client, namespace, overriddenNamespace) -> { - ProxySpec spec = proxyService.getProxySpec("01_hello_persistent_manifests_policy_replace"); - Proxy proxy = proxyService.startProxy(spec); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_persistent_manifests_policy_replace"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -1252,48 +1072,41 @@ public void launchProxyWithPersistentManifestPolicyReplace() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); // secret has no namespace defined -> should be created in the default namespace - Secret secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + Secret secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); Assertions.assertEquals("cGFzc3dvcmQ=", secret.getData().get("password")); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); + // the secret should not be deleted - Assertions.assertEquals(1, getSecrets(namespace).size()); + Assertions.assertEquals(1, k8s.getSecrets(k8s.namespace).size()); - String originalCreationTimestamp = client.secrets().inNamespace(namespace) + String originalCreationTimestamp = k8s.client.secrets().inNamespace(k8s.namespace) .withName("manifests-secret").get().getMetadata().getCreationTimestamp(); // same spec, different value - spec = proxyService.getProxySpec("01_hello_persistent_manifests_policy_replace2"); - proxy = proxyService.startProxy(spec); + id = inst.client.startProxy("01_hello_persistent_manifests_policy_replace2"); + proxy = inst.proxyService.getProxy(id); // secret has no namespace defined -> should be created in the default namespace - secret = getSingleSecret(namespace); - Assertions.assertEquals(namespace, secret.getMetadata().getNamespace()); + secret = k8s.getSingleSecret(k8s.namespace); + Assertions.assertEquals(k8s.namespace, secret.getMetadata().getNamespace()); Assertions.assertEquals("manifests-secret", secret.getMetadata().getName()); Assertions.assertEquals("b2xkX3Bhc3N3b3Jk", secret.getData().get("password")); // since the secret should have been replaced, the creation timestamp must be different Assertions.assertNotEquals(originalCreationTimestamp, secret.getMetadata().getCreationTimestamp()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // the secret should not be deleted - Assertions.assertEquals(1, getSecrets(namespace).size()); - }); + Assertions.assertEquals(1, k8s.getSecrets(k8s.namespace).size()); + } } @@ -1302,16 +1115,16 @@ public void launchProxyWithPersistentManifestPolicyReplace() { */ @Test public void advancedRuntimeLabels() { - setup((client, namespace, overriddenNamespace) -> { - ProxySpec spec = proxyService.getProxySpec("01_hello_advanced_runtime_labels"); - Proxy proxy = proxyService.startProxy(spec); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_advanced_runtime_labels"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(namespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(namespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -1319,10 +1132,10 @@ public void advancedRuntimeLabels() { Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); Assertions.assertFalse(pod.getSpec().getContainers().get(0).getSecurityContext().getPrivileged()); - ServiceList serviceList = client.services().inNamespace(namespace).list(); + ServiceList serviceList = k8s.client.services().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, serviceList.getItems().size()); Service service = serviceList.getItems().get(0); - Assertions.assertEquals(namespace, service.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.namespace, service.getMetadata().getNamespace()); Assertions.assertEquals("sp-service-" + containerId, service.getMetadata().getName()); Assertions.assertEquals(containerId, service.getSpec().getSelector().get("app")); Assertions.assertEquals(1, service.getSpec().getPorts().size()); @@ -1355,41 +1168,29 @@ public void advancedRuntimeLabels() { Assertions.assertEquals(proxy.getRuntimeValue("SHINYPROXY_INSTANCE"), labels.get("custom_label_patch_instance")); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); + // all services should be deleted - serviceList = client.services().inNamespace(namespace).list(); + serviceList = k8s.client.services().inNamespace(k8s.namespace).list(); Assertions.assertEquals(0, serviceList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + } } @Test public void launchProxyWithParameters() { - setup((client, namespace, overriddenNamespace) -> { - ProxySpec spec = proxyService.getProxySpec("parameters"); - String proxyId = UUID.randomUUID().toString(); - proxyService.startProxy( - userService.getCurrentAuth(), - spec, - null, - proxyId, - new HashMap() {{ - put("environment", "base_r"); - put("version", "4.0.5"); - put("memory", "2G"); - }}) - .run(); - Proxy proxy = proxyService.getProxy(proxyId); - - PodList podList = client.pods().inNamespace(namespace).list(); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("parameters", + new HashMap() {{ + put("environment", "base_r"); + put("version", "4.0.5"); + put("memory", "2G"); + }}); + Proxy proxy = inst.proxyService.getProxy(id); + + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -1409,38 +1210,25 @@ public void launchProxyWithParameters() { Assertions.assertTrue(env.containsKey("VALUESET_NAME")); Assertions.assertEquals("the-first-value-set", env.get("VALUESET_NAME").getValue()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + assertNoPods(k8s); + } } @Test public void launchProxyWithParametersWithNullValueSetName() { - setup((client, namespace, overriddenNamespace) -> { - ProxySpec spec = proxyService.getProxySpec("parameters-null"); - String proxyId = UUID.randomUUID().toString(); - proxyService.startProxy( - userService.getCurrentAuth(), - spec, - null, - proxyId, - new HashMap() {{ - put("environment", "base_r"); - put("version", "4.0.5"); - put("memory", "2G"); - }}) - .run(); - Proxy proxy = proxyService.getProxy(proxyId); - - PodList podList = client.pods().inNamespace(namespace).list(); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("parameters-null", + new HashMap() {{ + put("environment", "base_r"); + put("version", "4.0.5"); + put("memory", "2G"); + }}); + Proxy proxy = inst.proxyService.getProxy(id); + + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -1452,75 +1240,68 @@ public void launchProxyWithParametersWithNullValueSetName() { Map env = envList.stream().collect(Collectors.toMap(EnvVar::getName, e -> e)); Assertions.assertTrue(env.containsKey("VALUESET_NAME")); - Assertions.assertNull( env.get("VALUESET_NAME").getValue()); + Assertions.assertNull(env.get("VALUESET_NAME").getValue()); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + assertNoPods(k8s); + } } @Test public void launchProxyWithParametersWithError() { - setup((client, namespace, overriddenNamespace) -> { - ProxySpec spec = proxyService.getProxySpec("parameters-error"); - + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + // case 1: test using API + JsonObject resp = inst.client.startProxyError("parameters-error", + new HashMap() {{ + put("environment", "base_r"); + put("version", "4.0.5"); + put("memory", "2G"); + }}); + Assertions.assertEquals(resp.getString("status"), "error"); + Assertions.assertEquals(resp.getString("data"), "Failed to start proxy"); + + // case 2: test using ProxyService + Authentication auth = UsernamePasswordAuthenticationToken.authenticated("demo", null, Arrays.asList(new SimpleGrantedAuthority("ROLE_GROUP1"))); + ProxySpec spec = inst.proxyService.getProxySpec("parameters-error"); ContainerProxyException ex = Assertions.assertThrows(ContainerProxyException.class, () -> { - proxyService.startProxy(userService.getCurrentAuth(), spec, null, + inst.proxyService.startProxy(auth, spec, null, UUID.randomUUID().toString(), new HashMap() {{ put("environment", "base_r"); put("version", "4.0.5"); put("memory", "2G"); }}) - .run(); + .run(); }, "The parameter with id \"non-existing-parameter\" does not exist"); Assertions.assertEquals("Container failed to start", ex.getMessage()); Assertions.assertEquals(SpelException.class, ex.getCause().getClass()); Assertions.assertEquals("Error while resolving expression: \"- op: add\n" + - " path: /spec/containers/0/env/-\n" + - " value:\n" + - " name: ERROR\n" + - " value: \"#{proxy.getRuntimeObject('SHINYPROXY_PARAMETERS').getValue('non-existing-parameter')}\"\n" + - "\", error: The parameter with id \"non-existing-parameter\" does not exist!", ex.getCause().getMessage()); - - Thread.sleep(2000); - - // all pods should be deleted - PodList podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + " path: /spec/containers/0/env/-\n" + + " value:\n" + + " name: ERROR\n" + + " value: \"#{proxy.getRuntimeObject('SHINYPROXY_PARAMETERS').getValue('non-existing-parameter')}\"\n" + + "\", error: The parameter with id \"non-existing-parameter\" does not exist!", ex.getCause().getMessage()); + + // no pods created + assertNoPods(k8s); + } } @Test public void launchProxyWithParametersFinalResolve() { - setup((client, namespace, overriddenNamespace) -> { - ProxySpec spec = proxyService.getProxySpec("parameters-final-resolve"); - String proxyId = UUID.randomUUID().toString(); - proxyService.startProxy( - userService.getCurrentAuth(), - spec, - null, - proxyId, - new HashMap() {{ - put("environment", "base_r"); - put("version", "4.0.5"); - put("memory", "2G"); - }}) - .run(); - Proxy proxy = proxyService.getProxy(proxyId); - - PodList podList = client.pods().inNamespace(namespace).list(); + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("parameters-final-resolve", + new HashMap() {{ + put("environment", "base_r"); + put("version", "4.0.5"); + put("memory", "2G"); + }}); + Proxy proxy = inst.proxyService.getProxy(id); + + PodList podList = k8s.client.pods().inNamespace(k8s.namespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); @@ -1555,124 +1336,66 @@ public void launchProxyWithParametersFinalResolve() { Assertions.assertTrue(labels.containsKey("HEARTBEAT_TIMEOUT")); Assertions.assertEquals("70", labels.get("HEARTBEAT_TIMEOUT")); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); + assertNoPods(k8s); + } } + /** * Tests the creation and deleting of additional manifests (both persistent and non-persistent) using auth objects inside. * See #26789 */ @Test - public void launchProxyWithAdditionalPersistentManifestsUsingAuthObjects() throws Exception { - setup((client, namespace, overriddenNamespace) -> { - ProxySpec spec = proxyService.getProxySpec("01_hello_manifests_persistent_using_auth"); - Proxy proxy = proxyService.startProxy(spec); + public void launchProxyWithAdditionalPersistentManifestsUsingAuthObjects() { + try (ContainerSetup k8s = new ContainerSetup("kubernetes")) { + String id = inst.client.startProxy("01_hello_manifests_persistent_using_auth"); + Proxy proxy = inst.proxyService.getProxy(id); String containerId = proxy.getContainers().get(0).getId(); - PodList podList = client.pods().inNamespace(overriddenNamespace).list(); + PodList podList = k8s.client.pods().inNamespace(k8s.overriddenNamespace).list(); Assertions.assertEquals(1, podList.getItems().size()); Pod pod = podList.getItems().get(0); Assertions.assertEquals("Running", pod.getStatus().getPhase()); - Assertions.assertEquals(overriddenNamespace, pod.getMetadata().getNamespace()); + Assertions.assertEquals(k8s.overriddenNamespace, pod.getMetadata().getNamespace()); Assertions.assertEquals("sp-pod-" + containerId, pod.getMetadata().getName()); Assertions.assertEquals(1, pod.getStatus().getContainerStatuses().size()); ContainerStatus container = pod.getStatus().getContainerStatuses().get(0); Assertions.assertEquals(true, container.getReady()); Assertions.assertTrue(container.getImage().endsWith("openanalytics/shinyproxy-demo:latest")); - ConfigMap configMap1 = client.configMaps().inNamespace(overriddenNamespace).withName("configmap1").get(); + ConfigMap configMap1 = k8s.client.configMaps().inNamespace(k8s.overriddenNamespace).withName("configmap1").get(); Assertions.assertTrue(configMap1.getData().containsKey("test.txt")); Assertions.assertEquals("GROUP1,GROUP2\n", configMap1.getData().get("test.txt")); - ConfigMap configMap2 = client.configMaps().inNamespace(overriddenNamespace).withName("configmap2").get(); + ConfigMap configMap2 = k8s.client.configMaps().inNamespace(k8s.overriddenNamespace).withName("configmap2").get(); Assertions.assertTrue(configMap2.getData().containsKey("test.txt")); Assertions.assertEquals("GROUP1,GROUP2\n", configMap2.getData().get("test.txt")); - proxyService.stopProxy(null, proxy, true).run(); - - // Give Kube the time to clean - Thread.sleep(2000); + inst.proxyService.stopProxy(null, proxy, true).run(); // all pods should be deleted - podList = client.pods().inNamespace(namespace).list(); - Assertions.assertEquals(0, podList.getItems().size()); + assertNoPods(k8s); // configmap 1 should have been deleted - configMap1 = client.configMaps().inNamespace(overriddenNamespace).withName("configmap1").get(); + configMap1 = k8s.client.configMaps().inNamespace(k8s.overriddenNamespace).withName("configmap1").get(); Assertions.assertNull(configMap1); // configmap 2 should not have been deleted - configMap2 = client.configMaps().inNamespace(overriddenNamespace).withName("configmap2").get(); + configMap2 = k8s.client.configMaps().inNamespace(k8s.overriddenNamespace).withName("configmap2").get(); Assertions.assertTrue(configMap2.getData().containsKey("test.txt")); - - Assertions.assertEquals(0, proxyService.getProxies(null, true).size()); - }); - } - - public static class TestConfiguration { - @Bean - @Primary - public ProxyMappingManager mappingManager() { - return new NoopMappingManager(); } - - @Bean - @Primary - public AbstractFactoryBean backendFactory() { - return new TestContainerBackendFactory(); - } - - @Bean - @Primary - public UserService mockedUserService() { - return new MockedUserService(); - } - } - public static class TestContainerBackendFactory extends AbstractFactoryBean - implements ApplicationContextAware { - - private ApplicationContext applicationContext; - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - this.applicationContext = applicationContext; - } - - @Override - public Class getObjectType() { - return IContainerBackend.class; - } - - @Override - protected IContainerBackend createInstance() { - KubernetesBackend backend = new KubernetesBackend(); - applicationContext.getAutowireCapableBeanFactory().autowireBean(backend); - backend.initialize(client); - return backend; - } - } - - public static class NoopMappingManager extends ProxyMappingManager { - @Override - public synchronized void addMapping(String proxyId, String path, URI target) { - // No-op - } - - @Override - public synchronized void removeMapping(String path) { - // No-ops - } + private void assertNoPods(ContainerSetup k8s) { + boolean cleanedUp = Retrying.retry((c, m) -> { + List pods1 = k8s.client.pods().inNamespace(k8s.namespace).list().getItems(); + List pods2 = k8s.client.pods().inNamespace(k8s.overriddenNamespace).list().getItems(); + return pods1.isEmpty() && pods2.isEmpty(); + }, 5_000, "assert no pods", 1, true); + Assertions.assertTrue(cleanedUp); + Assertions.assertEquals(0, inst.proxyService.getProxies(null, true).size()); } } diff --git a/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnSwarm.java b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnSwarm.java index 3b46e4c2..6f9ef987 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnSwarm.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationOnSwarm.java @@ -26,146 +26,90 @@ import com.spotify.docker.client.messages.swarm.SecretBind; import com.spotify.docker.client.messages.swarm.SecretSpec; import com.spotify.docker.client.messages.swarm.Service; -import eu.openanalytics.containerproxy.ContainerProxyApplication; import eu.openanalytics.containerproxy.model.runtime.Proxy; -import eu.openanalytics.containerproxy.model.spec.ProxySpec; import eu.openanalytics.containerproxy.service.InvalidParametersException; -import eu.openanalytics.containerproxy.service.ProxyService; -import eu.openanalytics.containerproxy.service.UserService; -import eu.openanalytics.containerproxy.util.ProxyMappingManager; -import org.junit.jupiter.api.AfterEach; +import eu.openanalytics.containerproxy.test.helpers.ContainerSetup; +import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; -import org.springframework.core.env.Environment; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; - -import javax.inject.Inject; + import java.nio.charset.StandardCharsets; import java.util.Base64; +import java.util.HashMap; import java.util.List; -@SpringBootTest(classes = {TestIntegrationOnSwarm.TestConfiguration.class, ContainerProxyApplication.class}) -@ContextConfiguration(initializers = PropertyOverrideContextInitializer.class) -@ActiveProfiles("test-swarm") public class TestIntegrationOnSwarm { - @Inject - private Environment environment; - - @Inject - private ProxyService proxyService; - - private boolean checkEverythingCleanedUp() throws DockerCertificateException, DockerException, InterruptedException { - try (DefaultDockerClient dockerClient = DefaultDockerClient.fromEnv().build()) { + private static final ShinyProxyInstance inst = new ShinyProxyInstance("application-test-swarm.yml", new HashMap<>()); - return dockerClient.listContainers().stream() - .filter(it -> it.labels() != null && it.labels().containsKey("openanalytics.eu/sp-proxied-app")) - .count() == 0 - && dockerClient.listServices().size() == 0; - } - } - - @AfterEach - public void waitForCleanup() throws InterruptedException, DockerException, DockerCertificateException { - Thread.sleep(3_000); // wait before checking - for (int i = 0; i < 120; i++) { - if (checkEverythingCleanedUp()) { - break; - } - Thread.sleep(1_000); - } - Assertions.assertTrue(checkEverythingCleanedUp()); - } - - @BeforeEach - public void beforeEach() throws DockerCertificateException, DockerException, InterruptedException { - Assertions.assertTrue(checkEverythingCleanedUp()); + @AfterAll + public static void afterAll() { + inst.close(); } @Test public void launchProxy() throws DockerCertificateException, DockerException, InterruptedException, InvalidParametersException { - try (DefaultDockerClient dockerClient = DefaultDockerClient.fromEnv().build()) { - String specId = environment.getProperty("proxy.specs[0].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); + try (ContainerSetup containerSetup = new ContainerSetup("docker-swarm")) { + try (DefaultDockerClient dockerClient = DefaultDockerClient.fromEnv().build()) { + String id = inst.client.startProxy("01_hello"); + Proxy proxy = inst.proxyService.getProxy(id); - List services = dockerClient.listServices(); - Assertions.assertEquals(1, services.size()); - Service service = services.get(0); - Assertions.assertEquals("openanalytics/shinyproxy-demo", service.spec().taskTemplate().containerSpec().image()); + List services = dockerClient.listServices(); + Assertions.assertEquals(1, services.size()); + Service service = services.get(0); + Assertions.assertEquals("openanalytics/shinyproxy-demo", service.spec().taskTemplate().containerSpec().image()); - proxyService.stopProxy(null, proxy, true).run(); + inst.proxyService.stopProxy(null, proxy, true).run(); + } } } @Test public void launchProxyWithSecret() throws DockerCertificateException, DockerException, InterruptedException, InvalidParametersException { - try (DefaultDockerClient dockerClient = DefaultDockerClient.fromEnv().build()) { - String secret1Id = dockerClient.createSecret(SecretSpec.builder() + try (ContainerSetup containerSetup = new ContainerSetup("docker-swarm")) { + try (DefaultDockerClient dockerClient = DefaultDockerClient.fromEnv().build()) { + String secret1Id = dockerClient.createSecret(SecretSpec.builder() .data(Base64.getEncoder().encodeToString("MySecret1".getBytes(StandardCharsets.UTF_8))) .name("my_secret") .build()).id(); - String secret2Id = dockerClient.createSecret(SecretSpec.builder() + String secret2Id = dockerClient.createSecret(SecretSpec.builder() .data(Base64.getEncoder().encodeToString("MySecret2".getBytes(StandardCharsets.UTF_8))) .name("my_secret_2") .build()).id(); - String specId = environment.getProperty("proxy.specs[1].id"); - - ProxySpec spec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - Proxy proxy = proxyService.startProxy(spec); - - List services = dockerClient.listServices(); - Assertions.assertEquals(1, services.size()); - Service service = services.get(0); - Assertions.assertEquals("openanalytics/shinyproxy-demo", service.spec().taskTemplate().containerSpec().image()); + String id = inst.client.startProxy("01_hello_secret"); + Proxy proxy = inst.proxyService.getProxy(id); - SecretBind secret1 = service.spec().taskTemplate().containerSpec().secrets().get(0); + List services = dockerClient.listServices(); + Assertions.assertEquals(1, services.size()); + Service service = services.get(0); + Assertions.assertEquals("openanalytics/shinyproxy-demo", service.spec().taskTemplate().containerSpec().image()); - Assertions.assertEquals(secret1Id, secret1.secretId()); - Assertions.assertEquals("my_secret", secret1.secretName()); - Assertions.assertEquals("my_secret", secret1.file().name()); - Assertions.assertEquals("0", secret1.file().gid()); - Assertions.assertEquals("0", secret1.file().uid()); - Assertions.assertEquals(292, secret1.file().mode()); // 0444 in decimal + SecretBind secret1 = service.spec().taskTemplate().containerSpec().secrets().get(0); - SecretBind secret2 = service.spec().taskTemplate().containerSpec().secrets().get(1); + Assertions.assertEquals(secret1Id, secret1.secretId()); + Assertions.assertEquals("my_secret", secret1.secretName()); + Assertions.assertEquals("my_secret", secret1.file().name()); + Assertions.assertEquals("0", secret1.file().gid()); + Assertions.assertEquals("0", secret1.file().uid()); + Assertions.assertEquals(292, secret1.file().mode()); // 0444 in decimal - Assertions.assertEquals(secret2Id, secret2.secretId()); - Assertions.assertEquals("my_secret_2", secret2.secretName()); - Assertions.assertEquals("/var/pass", secret2.file().name()); - Assertions.assertEquals("1000", secret2.file().gid()); - Assertions.assertEquals("1000", secret2.file().uid()); - Assertions.assertEquals(384, secret2.file().mode()); // 0444 in decimal - - proxyService.stopProxy(null, proxy, true).run(); - dockerClient.deleteSecret(secret1Id); - dockerClient.deleteSecret(secret2Id); - } - } + SecretBind secret2 = service.spec().taskTemplate().containerSpec().secrets().get(1); + Assertions.assertEquals(secret2Id, secret2.secretId()); + Assertions.assertEquals("my_secret_2", secret2.secretName()); + Assertions.assertEquals("/var/pass", secret2.file().name()); + Assertions.assertEquals("1000", secret2.file().gid()); + Assertions.assertEquals("1000", secret2.file().uid()); + Assertions.assertEquals(384, secret2.file().mode()); // 0444 in decimal - public static class TestConfiguration { - - @Bean - @Primary - public ProxyMappingManager mappingManager() { - return new TestIntegrationOnKube.NoopMappingManager(); - } - - @Bean - @Primary - public UserService mockedUserService() { - return new MockedUserService(); + inst.proxyService.stopProxy(null, proxy, true).run(); + dockerClient.deleteSecret(secret1Id); + dockerClient.deleteSecret(secret2Id); + } } - } } diff --git a/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationPortAllocator.java b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationPortAllocator.java index 223cf98f..69b091fa 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationPortAllocator.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestIntegrationPortAllocator.java @@ -20,55 +20,45 @@ */ package eu.openanalytics.containerproxy.test.proxy; -import eu.openanalytics.containerproxy.ContainerProxyApplication; import eu.openanalytics.containerproxy.ContainerProxyException; import eu.openanalytics.containerproxy.service.IdentifierService; import eu.openanalytics.containerproxy.service.portallocator.IPortAllocator; import eu.openanalytics.containerproxy.service.portallocator.memory.MemoryPortAllocator; import eu.openanalytics.containerproxy.service.portallocator.redis.RedisPortAllocator; +import eu.openanalytics.containerproxy.test.helpers.ShinyProxyInstance; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.support.TestPropertySourceUtils; -import javax.annotation.Nonnull; -import javax.inject.Inject; +import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; -import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; - - /** * These tests require redis to be running... */ -@SpringBootTest(classes = {ContainerProxyApplication.class}) -@ContextConfiguration(initializers = TestIntegrationPortAllocator.PropertyOverride.class) -@ActiveProfiles("redis-integration") -@TestInstance(PER_CLASS) public class TestIntegrationPortAllocator { - @Inject - private RedisTemplate portTemplate; + private static final ShinyProxyInstance inst = new ShinyProxyInstance("application-redis-integration.yml", new HashMap<>()); + private static final RedisTemplate portTemplate = inst.getBean("porRedisTemplate", RedisTemplate.class); + private static final IdentifierService identifierService = inst.getBean("identifierService", IdentifierService.class); + private static final RedisPortAllocator redisPortAllocator = inst.getBean("portAllocator", RedisPortAllocator.class); - @Inject - private IdentifierService identifierService; + @AfterAll + public static void afterAll() { + inst.close(); + } - private Stream parameters() { + private static Stream parameters() { return Stream.of( - Arguments.of(new RedisPortAllocator(portTemplate, identifierService)), + Arguments.of(redisPortAllocator), Arguments.of(new MemoryPortAllocator()) ); } @@ -224,17 +214,4 @@ public void testNoPortAvailable(IPortAllocator portAllocator) { }, "Cannot create container: all allocated ports are currently in use. Please try again later or contact an administrator."); } - public static class PropertyOverride extends PropertyOverrideContextInitializer { - - @Override - public void initialize(@Nonnull ConfigurableApplicationContext configurableApplicationContext) { - super.initialize(configurableApplicationContext); - - TestPropertySourceUtils.addInlinedPropertiesToEnvironment(configurableApplicationContext, - "proxy.realm-id=" + UUID.randomUUID()); - - } - - } - } diff --git a/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestProxyService.java b/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestProxyService.java deleted file mode 100644 index 6f6be91b..00000000 --- a/src/test/java/eu/openanalytics/containerproxy/test/proxy/TestProxyService.java +++ /dev/null @@ -1,95 +0,0 @@ -/** - * ContainerProxy - * - * Copyright (C) 2016-2023 Open Analytics - * - * =========================================================================== - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Apache License as published by - * The Apache Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Apache License for more details. - * - * You should have received a copy of the Apache License - * along with this program. If not, see - */ -package eu.openanalytics.containerproxy.test.proxy; - -import java.net.URI; - -import javax.inject.Inject; - -import eu.openanalytics.containerproxy.service.InvalidParametersException; -import eu.openanalytics.containerproxy.service.UserService; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Primary; -import org.springframework.core.env.Environment; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import eu.openanalytics.containerproxy.ContainerProxyApplication; -import eu.openanalytics.containerproxy.model.runtime.Proxy; -import eu.openanalytics.containerproxy.model.spec.ProxySpec; -import eu.openanalytics.containerproxy.service.ProxyService; -import eu.openanalytics.containerproxy.test.proxy.TestProxyService.TestConfiguration; -import eu.openanalytics.containerproxy.util.ProxyMappingManager; - -@SpringBootTest(classes= {TestConfiguration.class, ContainerProxyApplication.class}) -@ExtendWith(SpringExtension.class) -@ActiveProfiles("test") -@ContextConfiguration(initializers = PropertyOverrideContextInitializer.class) -public class TestProxyService { - - @Inject - private Environment environment; - - @Inject - private ProxyService proxyService; - - @Test - public void launchProxy() throws InvalidParametersException { - String specId = environment.getProperty("proxy.specs[0].id"); - - ProxySpec baseSpec = proxyService.findProxySpec(s -> s.getId().equals(specId), true); - - Proxy proxy = proxyService.startProxy(baseSpec); - proxyService.stopProxy(null, proxy, true).run(); - } - - public static class TestConfiguration { - @Bean - @Primary - public ProxyMappingManager mappingManager() { - return new NoopMappingManager(); - } - - @Bean - @Primary - public UserService mockedUserService() { - return new MockedUserService(); - } - } - - public static class NoopMappingManager extends ProxyMappingManager { - @Override - public synchronized void addMapping(String proxyId, String path, URI target) { - // No-op - System.out.println("NOOP"); - } - - @Override - public synchronized void removeMapping(String path) { - // No-ops - } - } - -} diff --git a/src/test/java/eu/openanalytics/containerproxy/test/unit/RetryingTest.java b/src/test/java/eu/openanalytics/containerproxy/test/unit/RetryingTest.java index 01e740a0..e80209b0 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/unit/RetryingTest.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/unit/RetryingTest.java @@ -21,8 +21,7 @@ package eu.openanalytics.containerproxy.test.unit; import eu.openanalytics.containerproxy.ContainerProxyApplication; -import eu.openanalytics.containerproxy.test.proxy.PropertyOverrideContextInitializer; -import eu.openanalytics.containerproxy.test.proxy.TestProxyService; +import eu.openanalytics.containerproxy.test.helpers.PropertyOverrideContextInitializer; import eu.openanalytics.containerproxy.util.Retrying; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -36,7 +35,7 @@ import java.time.Instant; import java.util.concurrent.atomic.AtomicInteger; -@SpringBootTest(classes = {TestProxyService.TestConfiguration.class, ContainerProxyApplication.class}) +@SpringBootTest(classes = {ContainerProxyApplication.class}) @ExtendWith(SpringExtension.class) @ActiveProfiles("test") @ContextConfiguration(initializers = PropertyOverrideContextInitializer.class) diff --git a/src/test/java/eu/openanalytics/containerproxy/test/unit/TestComputeTargetPath.java b/src/test/java/eu/openanalytics/containerproxy/test/unit/TestComputeTargetPath.java index e282976a..d706c431 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/unit/TestComputeTargetPath.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/unit/TestComputeTargetPath.java @@ -22,8 +22,7 @@ import eu.openanalytics.containerproxy.ContainerProxyApplication; import eu.openanalytics.containerproxy.backend.AbstractContainerBackend; -import eu.openanalytics.containerproxy.test.proxy.PropertyOverrideContextInitializer; -import eu.openanalytics.containerproxy.test.proxy.TestProxyService.TestConfiguration; +import eu.openanalytics.containerproxy.test.helpers.PropertyOverrideContextInitializer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -33,7 +32,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; -@SpringBootTest(classes= {TestConfiguration.class, ContainerProxyApplication.class}) +@SpringBootTest(classes= {ContainerProxyApplication.class}) @ExtendWith(SpringExtension.class) @ActiveProfiles("test") @ContextConfiguration(initializers = PropertyOverrideContextInitializer.class) diff --git a/src/test/java/eu/openanalytics/containerproxy/test/unit/TestOpenIdParseClaimRoles.java b/src/test/java/eu/openanalytics/containerproxy/test/unit/TestOpenIdParseClaimRoles.java index 358f43e8..fd798495 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/unit/TestOpenIdParseClaimRoles.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/unit/TestOpenIdParseClaimRoles.java @@ -22,8 +22,7 @@ import eu.openanalytics.containerproxy.ContainerProxyApplication; import eu.openanalytics.containerproxy.auth.impl.OpenIDAuthenticationBackend; -import eu.openanalytics.containerproxy.test.proxy.PropertyOverrideContextInitializer; -import eu.openanalytics.containerproxy.test.proxy.TestProxyService; +import eu.openanalytics.containerproxy.test.helpers.PropertyOverrideContextInitializer; import net.minidev.json.JSONArray; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -40,7 +39,7 @@ import java.util.List; -@SpringBootTest(classes = {TestProxyService.TestConfiguration.class, ContainerProxyApplication.class}) +@SpringBootTest(classes = {ContainerProxyApplication.class}) @ExtendWith(SpringExtension.class) @ActiveProfiles("test") @ContextConfiguration(initializers = PropertyOverrideContextInitializer.class) diff --git a/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParameterServiceAccessControl.java b/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParameterServiceAccessControl.java index cabe8c07..9a2d840a 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParameterServiceAccessControl.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParameterServiceAccessControl.java @@ -32,16 +32,17 @@ import eu.openanalytics.containerproxy.service.UserService; import eu.openanalytics.containerproxy.spec.IProxySpecProvider; import eu.openanalytics.containerproxy.spec.expression.SpecExpressionResolver; -import eu.openanalytics.containerproxy.test.proxy.PropertyOverrideContextInitializer; -import eu.openanalytics.containerproxy.test.proxy.TestIntegrationOnKube; +import eu.openanalytics.containerproxy.test.helpers.PropertyOverrideContextInitializer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.support.GenericApplicationContext; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; import javax.annotation.PostConstruct; import javax.inject.Inject; @@ -54,8 +55,9 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@SpringBootTest(classes = {TestIntegrationOnKube.TestConfiguration.class, ContainerProxyApplication.class}) +@SpringBootTest(classes = {ContainerProxyApplication.class}) @ContextConfiguration(initializers = PropertyOverrideContextInitializer.class) +@ExtendWith(SpringExtension.class) @ActiveProfiles("parameters") public class TestParameterServiceAccessControl { diff --git a/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParameterValidationService.java b/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParameterValidationService.java index 52d7c68c..c4e3dc14 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParameterValidationService.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParameterValidationService.java @@ -21,8 +21,6 @@ package eu.openanalytics.containerproxy.test.unit; import eu.openanalytics.containerproxy.ContainerProxyApplication; -import eu.openanalytics.containerproxy.test.proxy.PropertyOverrideContextInitializer; -import eu.openanalytics.containerproxy.test.proxy.TestIntegrationOnKube; import org.junit.jupiter.api.Test; import org.springframework.boot.env.YamlPropertySourceLoader; import org.springframework.boot.test.context.runner.WebApplicationContextRunner; @@ -43,9 +41,8 @@ public class TestParameterValidationService { private void test(String resource, String expectedError) { this.contextRunner - .withInitializer(new PropertyOverrideContextInitializer()) .withInitializer(new TestPropertyLoader(resource)) - .withUserConfiguration(TestIntegrationOnKube.TestConfiguration.class, ContainerProxyApplication.class) + .withUserConfiguration(ContainerProxyApplication.class) .run(context -> { assertThat(context) .hasFailed(); diff --git a/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParametersService.java b/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParametersService.java index 3fceb4ed..a32058f1 100644 --- a/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParametersService.java +++ b/src/test/java/eu/openanalytics/containerproxy/test/unit/TestParametersService.java @@ -28,8 +28,7 @@ import eu.openanalytics.containerproxy.service.InvalidParametersException; import eu.openanalytics.containerproxy.service.ParametersService; import eu.openanalytics.containerproxy.service.ProxyService; -import eu.openanalytics.containerproxy.test.proxy.PropertyOverrideContextInitializer; -import eu.openanalytics.containerproxy.test.proxy.TestIntegrationOnKube; +import eu.openanalytics.containerproxy.test.helpers.PropertyOverrideContextInitializer; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; @@ -48,7 +47,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -@SpringBootTest(classes = {TestIntegrationOnKube.TestConfiguration.class, ContainerProxyApplication.class}) +@SpringBootTest(classes = {ContainerProxyApplication.class}) @ContextConfiguration(initializers = PropertyOverrideContextInitializer.class) @ActiveProfiles("parameters") public class TestParametersService { @@ -59,7 +58,7 @@ public class TestParametersService { @Inject private ParametersService parametersService; - private Authentication auth = mock(Authentication.class); + private final Authentication auth = mock(Authentication.class); @Test public void testBigParameters() { diff --git a/src/test/resources/application-app-recovery_ecs.yml b/src/test/resources/application-app-recovery_ecs.yml deleted file mode 100644 index 31b8fcf8..00000000 --- a/src/test/resources/application-app-recovery_ecs.yml +++ /dev/null @@ -1,39 +0,0 @@ -proxy: - recover-running-proxies: true - stop-proxies-on-shutdown: false - - authentication: simple - container-backend: ecs - - users: - - name: demo - password: demo - - name: demo2 - password: demo2 - - name: demo3 - password: demo3 - - ecs: - name: "shinyproxy" - region: "ap-southeast-2" - - specs: - - id: 01_hello - container-specs: - - image: "openanalytics/shinyproxy-demo" - cmd: ["R", "-e", "shinyproxy::run_01_hello()"] - port-mapping: - default: 3838 - - id: 02_hello - container-specs: - - image: "openanalytics/shinyproxy-demo" - cmd: ["R", "-e", "shinyproxy::run_01_hello()"] - port-mapping: - default: 3838 - - id: 03_hello - container-specs: - - task-definition: "shinyproxy:1" - cmd: ["R", "-e", "shinyproxy::run_01_hello()"] - port-mapping: - default: 3838 - capacity-provider: FARGATE_SPOT diff --git a/src/test/resources/application-redis-integration.yml b/src/test/resources/application-redis-integration.yml index c8174945..ce5e5098 100644 --- a/src/test/resources/application-redis-integration.yml +++ b/src/test/resources/application-redis-integration.yml @@ -5,6 +5,8 @@ proxy: store-mode: Redis authentication: simple container-backend: docker + realm-id: my-realm + users: [] diff --git a/src/test/resources/application-test-ecs.yml b/src/test/resources/application-test-ecs.yml new file mode 100644 index 00000000..3845cc65 --- /dev/null +++ b/src/test/resources/application-test-ecs.yml @@ -0,0 +1,43 @@ +spring: + session: + store-type: none + data: + redis: + repositories: + enabled: false +proxy: + authentication: simple + container-backend: docker-swarm + + + users: + - name: demo + password: demo + - name: demo2 + password: demo2 + + docker: + url: http://localhost:2375 + + specs: + - id: 01_hello + container-specs: + - image: "openanalytics/shinyproxy-demo" + cmd: ["R", "-e", "shinyproxy::run_01_hello()"] + port-mapping: + - name: default + port: 3838 + - id: 01_hello_secret + container-specs: + - image: "openanalytics/shinyproxy-demo" + cmd: ["R", "-e", "shinyproxy::run_01_hello()"] + port-mapping: + - name: default + port: 3838 + docker-swarm-secrets: + - name: my_secret + - name: my_secret_2 + target: /var/pass + gid: 1000 + uid: 1000 + mode: 600 diff --git a/src/test/resources/application-test-ldap-auth.yml b/src/test/resources/application-test-ldap-auth.yml index e00efe70..dda9c6fc 100644 --- a/src/test/resources/application-test-ldap-auth.yml +++ b/src/test/resources/application-test-ldap-auth.yml @@ -13,5 +13,3 @@ proxy: group-search-filter: (uniqueMember={0}) manager-dn: cn=read-only-admin,dc=example,dc=com manager-password: password - test-username: tesla - test-password: password \ No newline at end of file diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml index c176e5d9..34681e5a 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -7,12 +7,15 @@ spring: enabled: false proxy: authentication: simple - container-backend: docker + container-backend: kubernetes users: - name: demo password: demo + groups: + - group1 + - group2 - name: demo2 password: demo2