summaryrefslogtreecommitdiffstats
path: root/controller-server/src/test
diff options
context:
space:
mode:
authorMorten Tokle <mortent@yahooinc.com>2023-06-12 22:45:43 +0200
committerMorten Tokle <mortent@yahooinc.com>2023-06-12 22:45:43 +0200
commit362ddb0749608a5ace2be1caa5507ca9d3895eaf (patch)
treeeff7d386e26d0d293f123a16139d10b19e84ebd7 /controller-server/src/test
parent5f25e0ba346c04ccc27c60cc410c0ed2fdb6b06b (diff)
API to generate/list/delete dataplane tokens
Diffstat (limited to 'controller-server/src/test')
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java36
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenServiceTest.java82
2 files changed, 118 insertions, 0 deletions
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
index 6012b491fe7..841e46ad881 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java
@@ -28,6 +28,7 @@ import com.yahoo.vespa.hosted.controller.security.Auth0Credentials;
import com.yahoo.vespa.hosted.controller.security.CloudTenantSpec;
import com.yahoo.vespa.hosted.controller.security.Credentials;
import com.yahoo.vespa.hosted.controller.tenant.CloudTenant;
+import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -35,12 +36,14 @@ import java.io.File;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;
+import java.util.regex.Pattern;
import static com.yahoo.application.container.handler.Request.Method.DELETE;
import static com.yahoo.application.container.handler.Request.Method.GET;
import static com.yahoo.application.container.handler.Request.Method.POST;
import static com.yahoo.application.container.handler.Request.Method.PUT;
import static com.yahoo.vespa.hosted.controller.restapi.application.ApplicationApiTest.createApplicationSubmissionData;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -462,6 +465,39 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
assertTrue(tester.controller().applications().getApplication(TenantAndApplicationId.from(tenantName, application)).isPresent());
}
+ @Test
+ void dataplane_token_test() {
+ tester.assertResponse(request("/application/v4/tenant/scoober/token", GET)
+ .roles(Role.developer(tenantName)),
+ "{\"tokens\":[]}", 200);
+
+ String regexGenerateToken = "\\{\"id\":\"myTokenId\",\"token\":\"vespa_cloud_.*\",\"fingerprint\":\".*\"}";
+ tester.assertResponse(request("/application/v4/tenant/scoober/token/myTokenId", POST).roles(Role.developer(tenantName)),
+ (response) -> Assertions.assertThat(new String(response.getBody(), UTF_8)).matches(Pattern.compile(regexGenerateToken)),
+ 200);
+
+ String regexListTokens = "\\{\"tokens\":\\[\\{\"id\":\"myTokenId\",\"fingerprints\":\\[\\{\"value\":\".*\",\"created-at\":\".*\",\"author\":\"user@test\"}]}]}";
+ tester.assertResponse(request("/application/v4/tenant/scoober/token", GET)
+ .roles(Role.developer(tenantName)),
+ (response) -> Assertions.assertThat(new String(response.getBody(), UTF_8)).matches(Pattern.compile(regexListTokens)),
+ 200);
+
+ // Rejects invalid tokenIds on create
+ tester.assertResponse(request("/application/v4/tenant/scoober/token/foo+bar", POST).roles(Role.developer(tenantName)),
+ "{\"error-code\":\"BAD_REQUEST\",\"message\":\"tokenId must match '[A-Za-z][A-Za-z0-9_-]{0,59}', but got: 'foo bar'\"}",
+ 400);
+
+ // Rejects invalid tokenIds on delete
+ tester.assertResponse(request("/application/v4/tenant/scoober/token/foo+bar?fingerprint=ab:cd", DELETE).roles(Role.developer(tenantName)),
+ "{\"error-code\":\"BAD_REQUEST\",\"message\":\"tokenId must match '[A-Za-z][A-Za-z0-9_-]{0,59}', but got: 'foo bar'\"}",
+ 400);
+
+ // Rejects invalid fingerprints on delete
+ tester.assertResponse(request("/application/v4/tenant/scoober/token/tokenid?fingerprint=ab:cdef", DELETE).roles(Role.developer(tenantName)),
+ "{\"error-code\":\"BAD_REQUEST\",\"message\":\"fingerPrint must match '([a-f0-9]{2}:)+[a-f0-9]{2}', but got: 'ab:cdef'\"}",
+ 400);
+ }
+
private ApplicationPackageBuilder prodBuilder() {
return new ApplicationPackageBuilder()
.withoutAthenzIdentity()
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenServiceTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenServiceTest.java
new file mode 100644
index 00000000000..066eecc2c95
--- /dev/null
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/dataplanetoken/DataplaneTokenServiceTest.java
@@ -0,0 +1,82 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.controller.restapi.dataplanetoken;
+
+import com.yahoo.config.provision.SystemName;
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.vespa.hosted.controller.ControllerTester;
+import com.yahoo.vespa.hosted.controller.api.integration.dataplanetoken.DataplaneToken;
+import com.yahoo.vespa.hosted.controller.api.integration.dataplanetoken.DataplaneTokenVersions;
+import com.yahoo.vespa.hosted.controller.api.integration.dataplanetoken.FingerPrint;
+import com.yahoo.vespa.hosted.controller.api.integration.dataplanetoken.TokenId;
+import com.yahoo.vespa.hosted.controller.api.role.SimplePrincipal;
+import org.junit.jupiter.api.Test;
+
+import java.security.Principal;
+import java.util.Collection;
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class DataplaneTokenServiceTest {
+ private final ControllerTester tester = new ControllerTester(SystemName.Public);
+ private final DataplaneTokenService dataplaneTokenService = new DataplaneTokenService(tester.controller());
+ private final TenantName tenantName = TenantName.from("tenant");
+ Principal principal = new SimplePrincipal("user");
+ private final TokenId tokenId = TokenId.of("myTokenId");
+
+ @Test
+ void generates_and_persists_token() {
+ DataplaneToken dataplaneToken = dataplaneTokenService.generateToken(tenantName, tokenId, principal);
+ List<DataplaneTokenVersions> dataplaneTokenVersions = dataplaneTokenService.listTokens(tenantName);
+ assertEquals(dataplaneToken.fingerPrint(), dataplaneTokenVersions.get(0).tokenVersions().get(0).fingerPrint());
+ }
+
+ @Test
+ void generating_new_token_appends() {
+ DataplaneToken dataplaneToken1 = dataplaneTokenService.generateToken(tenantName, tokenId, principal);
+ DataplaneToken dataplaneToken2 = dataplaneTokenService.generateToken(tenantName, tokenId, principal);
+ assertNotEquals(dataplaneToken1.fingerPrint(), dataplaneToken2.fingerPrint());
+
+ List<DataplaneTokenVersions> dataplaneTokenVersions = dataplaneTokenService.listTokens(tenantName);
+ List<FingerPrint> tokenFingerprints = dataplaneTokenVersions.stream()
+ .filter(token -> token.tokenId().equals(tokenId))
+ .map(DataplaneTokenVersions::tokenVersions)
+ .flatMap(Collection::stream)
+ .map(DataplaneTokenVersions.Version::fingerPrint)
+ .toList();
+ assertThat(tokenFingerprints).containsExactlyInAnyOrder(dataplaneToken1.fingerPrint(), dataplaneToken2.fingerPrint());
+ }
+
+ @Test
+ void delete_last_fingerprint_deletes_token() {
+ DataplaneToken dataplaneToken1 = dataplaneTokenService.generateToken(tenantName, tokenId, principal);
+ DataplaneToken dataplaneToken2 = dataplaneTokenService.generateToken(tenantName, tokenId, principal);
+ dataplaneTokenService.deleteToken(tenantName, tokenId, dataplaneToken1.fingerPrint());
+ dataplaneTokenService.deleteToken(tenantName, tokenId, dataplaneToken2.fingerPrint());
+ assertEquals(List.of(), dataplaneTokenService.listTokens(tenantName));
+ }
+
+ @Test
+ void deleting_nonexistent_fingerprint_throws() {
+ DataplaneToken dataplaneToken = dataplaneTokenService.generateToken(tenantName, tokenId, principal);
+ DataplaneToken dataplaneToken2 = dataplaneTokenService.generateToken(tenantName, tokenId, principal);
+ dataplaneTokenService.deleteToken(tenantName, tokenId, dataplaneToken.fingerPrint());
+
+ // Token currently contains value of "dataplaneToken2"
+ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> dataplaneTokenService.deleteToken(tenantName, tokenId, dataplaneToken.fingerPrint()));
+ assertEquals("Fingerprint does not exist: " + dataplaneToken.fingerPrint(), exception.getMessage());
+ }
+
+ @Test
+ void deleting_nonexistent_token_throws() {
+ DataplaneToken dataplaneToken = dataplaneTokenService.generateToken(tenantName, tokenId, principal);
+ dataplaneTokenService.deleteToken(tenantName, tokenId, dataplaneToken.fingerPrint());
+
+ // Token is created and deleted above, no longer exists
+ IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> dataplaneTokenService.deleteToken(tenantName, tokenId, dataplaneToken.fingerPrint()));
+ assertEquals("Token does not exist: " + tokenId, exception.getMessage());
+ }
+}