diff --git a/extensions/common/vault/vault-hashicorp/src/main/java/org/eclipse/edc/vault/hashicorp/client/HashicorpVaultClient.java b/extensions/common/vault/vault-hashicorp/src/main/java/org/eclipse/edc/vault/hashicorp/client/HashicorpVaultClient.java index 01301b1c902..fe935571034 100644 --- a/extensions/common/vault/vault-hashicorp/src/main/java/org/eclipse/edc/vault/hashicorp/client/HashicorpVaultClient.java +++ b/extensions/common/vault/vault-hashicorp/src/main/java/org/eclipse/edc/vault/hashicorp/client/HashicorpVaultClient.java @@ -121,7 +121,7 @@ public Result doHealthCheck() { public Result isTokenRenewable() { var uri = settings.url() .newBuilder() - .addPathSegment(TOKEN_LOOK_UP_SELF_PATH) + .addPathSegments(TOKEN_LOOK_UP_SELF_PATH) .build(); var request = httpGet(uri); diff --git a/extensions/common/vault/vault-hashicorp/src/test/java/org/eclipse/edc/vault/hashicorp/client/HashicorpVaultClientIntegrationTest.java b/extensions/common/vault/vault-hashicorp/src/test/java/org/eclipse/edc/vault/hashicorp/client/HashicorpVaultClientIntegrationTest.java index 6000e33b2e3..bb02af0ca88 100644 --- a/extensions/common/vault/vault-hashicorp/src/test/java/org/eclipse/edc/vault/hashicorp/client/HashicorpVaultClientIntegrationTest.java +++ b/extensions/common/vault/vault-hashicorp/src/test/java/org/eclipse/edc/vault/hashicorp/client/HashicorpVaultClientIntegrationTest.java @@ -19,6 +19,7 @@ import org.eclipse.edc.junit.annotations.ComponentTest; import org.eclipse.edc.spi.monitor.ConsoleMonitor; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -35,98 +36,158 @@ import static org.eclipse.edc.junit.assertions.AbstractResultAssert.assertThat; import static org.testcontainers.shaded.org.awaitility.Awaitility.await; -@ComponentTest -@Testcontainers -class HashicorpVaultClientIntegrationTest { - @Container - static final VaultContainer VAULT_CONTAINER = new VaultContainer<>("vault:1.9.6") - .withVaultToken(UUID.randomUUID().toString()); - - private static final String HTTP_URL_FORMAT = "http://%s:%s"; - private static final String HEALTH_CHECK_PATH = "/health/path"; - private static final String CLIENT_TOKEN_KEY = "client_token"; - private static final String AUTH_KEY = "auth"; - private static final long CREATION_TTL = 6L; - private static final long TTL = 5L; - private static final long RENEW_BUFFER = 4L; - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - private static final ConsoleMonitor MONITOR = new ConsoleMonitor(); - - private static HashicorpVaultClient client; - - @BeforeEach - void beforeEach() throws IOException, InterruptedException { - assertThat(CREATION_TTL).isGreaterThan(TTL); - client = new HashicorpVaultClient( - testHttpClient(), - OBJECT_MAPPER, - MONITOR, - getSettings() - ); - } - - @Test - void lookUpToken_whenTokenNotExpired_shouldSucceed() { - var tokenLookUpResult = client.isTokenRenewable(); - - assertThat(tokenLookUpResult).isSucceeded().isEqualTo(true); - } - - @Test - void lookUpToken_whenTokenExpired_shouldFail() { - await() - .pollDelay(CREATION_TTL, TimeUnit.SECONDS) - .atMost(CREATION_TTL + 1, TimeUnit.SECONDS) - .untilAsserted(() -> { - var tokenLookUpResult = client.isTokenRenewable(); - assertThat(tokenLookUpResult).isFailed(); - assertThat(tokenLookUpResult.getFailureDetail()).isEqualTo("Token look up failed with status 403"); - }); - } - @Test - void renewToken_whenTokenNotExpired_shouldSucceed() { - var tokenRenewResult = client.renewToken(); +class HashicorpVaultClientIntegrationTest { - assertThat(tokenRenewResult).isSucceeded().satisfies(ttl -> assertThat(ttl).isEqualTo(TTL)); + @ComponentTest + @Testcontainers + @Nested + abstract static class Tests { + + protected static final String HTTP_URL_FORMAT = "http://%s:%s"; + protected static final String HEALTH_CHECK_PATH = "/health/path"; + protected static final String CLIENT_TOKEN_KEY = "client_token"; + protected static final String AUTH_KEY = "auth"; + protected static final long CREATION_TTL = 6L; + protected static final long TTL = 5L; + protected static final long RENEW_BUFFER = 4L; + protected HashicorpVaultClient client; + protected final ObjectMapper mapper = new ObjectMapper(); + protected final ConsoleMonitor monitor = new ConsoleMonitor(); + + @BeforeEach + void beforeEach() throws IOException, InterruptedException { + assertThat(CREATION_TTL).isGreaterThan(TTL); + } + + @Test + void lookUpToken_whenTokenNotExpired_shouldSucceed() { + var tokenLookUpResult = client.isTokenRenewable(); + + assertThat(tokenLookUpResult).isSucceeded().isEqualTo(true); + } + + @Test + void lookUpToken_whenTokenExpired_shouldFail() { + await() + .pollDelay(CREATION_TTL, TimeUnit.SECONDS) + .atMost(CREATION_TTL + 1, TimeUnit.SECONDS) + .untilAsserted(() -> { + var tokenLookUpResult = client.isTokenRenewable(); + assertThat(tokenLookUpResult).isFailed(); + assertThat(tokenLookUpResult.getFailureDetail()).isEqualTo("Token look up failed with status 403"); + }); + } + + @Test + void renewToken_whenTokenNotExpired_shouldSucceed() { + var tokenRenewResult = client.renewToken(); + + assertThat(tokenRenewResult).isSucceeded().satisfies(ttl -> assertThat(ttl).isEqualTo(TTL)); + } + + @Test + void renewToken_whenTokenExpired_shouldFail() { + await() + .pollDelay(CREATION_TTL, TimeUnit.SECONDS) + .atMost(CREATION_TTL + 1, TimeUnit.SECONDS) + .untilAsserted(() -> { + var tokenRenewResult = client.renewToken(); + assertThat(tokenRenewResult).isFailed(); + assertThat(tokenRenewResult.getFailureDetail()).isEqualTo("Token renew failed with status: 403"); + }); + } } - @Test - void renewToken_whenTokenExpired_shouldFail() { - await() - .pollDelay(CREATION_TTL, TimeUnit.SECONDS) - .atMost(CREATION_TTL + 1, TimeUnit.SECONDS) - .untilAsserted(() -> { - var tokenRenewResult = client.renewToken(); - assertThat(tokenRenewResult).isFailed(); - assertThat(tokenRenewResult.getFailureDetail()).isEqualTo("Token renew failed with status: 403"); - }); + @ComponentTest + @Testcontainers + @Nested + class LastKnownFoss extends Tests { + @Container + static final VaultContainer VAULT_CONTAINER = new VaultContainer<>("vault:1.9.6") + .withVaultToken(UUID.randomUUID().toString()); + + public static HashicorpVaultSettings getSettings() throws IOException, InterruptedException { + var execResult = VAULT_CONTAINER.execInContainer( + "vault", + "token", + "create", + "-policy=root", + "-ttl=%d".formatted(CREATION_TTL), + "-format=json"); + + var jsonParser = Json.createParser(new StringReader(execResult.getStdout())); + jsonParser.next(); + var auth = jsonParser.getObjectStream().filter(e -> e.getKey().equals(AUTH_KEY)) + .map(Map.Entry::getValue) + .findFirst() + .orElseThrow() + .asJsonObject(); + var clientToken = auth.getString(CLIENT_TOKEN_KEY); + + return HashicorpVaultSettings.Builder.newInstance() + .url(HTTP_URL_FORMAT.formatted(VAULT_CONTAINER.getHost(), VAULT_CONTAINER.getFirstMappedPort())) + .healthCheckPath(HEALTH_CHECK_PATH) + .token(clientToken) + .ttl(TTL) + .renewBuffer(RENEW_BUFFER) + .build(); + } + + @BeforeEach + void beforeEach() throws IOException, InterruptedException { + client = new HashicorpVaultClient( + testHttpClient(), + mapper, + monitor, + getSettings() + ); + } } - public static HashicorpVaultSettings getSettings() throws IOException, InterruptedException { - var execResult = VAULT_CONTAINER.execInContainer( - "vault", - "token", - "create", - "-policy=root", - "-ttl=%d".formatted(CREATION_TTL), - "-format=json"); - - var jsonParser = Json.createParser(new StringReader(execResult.getStdout())); - jsonParser.next(); - var auth = jsonParser.getObjectStream().filter(e -> e.getKey().equals(AUTH_KEY)) - .map(Map.Entry::getValue) - .findFirst() - .orElseThrow() - .asJsonObject(); - var clientToken = auth.getString(CLIENT_TOKEN_KEY); - - return HashicorpVaultSettings.Builder.newInstance() - .url(HTTP_URL_FORMAT.formatted(VAULT_CONTAINER.getHost(), VAULT_CONTAINER.getFirstMappedPort())) - .healthCheckPath(HEALTH_CHECK_PATH) - .token(clientToken) - .ttl(TTL) - .renewBuffer(RENEW_BUFFER) - .build(); + @ComponentTest + @Testcontainers + @Nested + class Latest extends Tests { + @Container + static final VaultContainer VAULT_CONTAINER = new VaultContainer<>("hashicorp/vault:1.17.3") + .withVaultToken(UUID.randomUUID().toString()); + + public static HashicorpVaultSettings getSettings() throws IOException, InterruptedException { + var execResult = VAULT_CONTAINER.execInContainer( + "vault", + "token", + "create", + "-policy=root", + "-ttl=%d".formatted(CREATION_TTL), + "-format=json"); + + var jsonParser = Json.createParser(new StringReader(execResult.getStdout())); + jsonParser.next(); + var auth = jsonParser.getObjectStream().filter(e -> e.getKey().equals(AUTH_KEY)) + .map(Map.Entry::getValue) + .findFirst() + .orElseThrow() + .asJsonObject(); + var clientToken = auth.getString(CLIENT_TOKEN_KEY); + + return HashicorpVaultSettings.Builder.newInstance() + .url(HTTP_URL_FORMAT.formatted(VAULT_CONTAINER.getHost(), VAULT_CONTAINER.getFirstMappedPort())) + .healthCheckPath(HEALTH_CHECK_PATH) + .token(clientToken) + .ttl(TTL) + .renewBuffer(RENEW_BUFFER) + .build(); + } + + @BeforeEach + void beforeEach() throws IOException, InterruptedException { + client = new HashicorpVaultClient( + testHttpClient(), + mapper, + monitor, + getSettings() + ); + } } -} +} \ No newline at end of file