summaryrefslogtreecommitdiffstats
path: root/controller-server/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'controller-server/src/test')
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageTest.java263
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/TestPackageTest.java57
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ZipEntriesTest.java50
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java2
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationStoreMock.java15
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java13
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiCloudTest.java17
7 files changed, 298 insertions, 119 deletions
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageTest.java
index 8cf861ff963..8ac8b87ac45 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ApplicationPackageTest.java
@@ -3,18 +3,47 @@ package com.yahoo.vespa.hosted.controller.application.pkg;
import com.yahoo.config.application.api.DeploymentSpec;
import com.yahoo.config.application.api.ValidationId;
+import com.yahoo.io.LazyInputStream;
+import com.yahoo.security.KeyAlgorithm;
+import com.yahoo.security.KeyUtils;
+import com.yahoo.security.SignatureAlgorithm;
+import com.yahoo.security.X509CertificateBuilder;
import org.junit.jupiter.api.Test;
+import javax.security.auth.x500.X500Principal;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.io.SequenceInputStream;
+import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.security.KeyPair;
+import java.security.cert.X509Certificate;
import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
+import java.util.function.Predicate;
+import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import static com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage.filesZip;
+import static com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackageStream.addingCertificate;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
@@ -24,35 +53,41 @@ import static org.junit.jupiter.api.Assertions.fail;
*/
public class ApplicationPackageTest {
- static final String deploymentXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
- "<deployment version=\"1.0\">\n" +
- " <test />\n" +
- " <prod>\n" +
- " <parallel>\n" +
- " <region active=\"true\">us-central-1</region>\n" +
- " </parallel>\n" +
- " </prod>\n" +
- "</deployment>\n";
-
- static final String servicesXml = "<services version='1.0' xmlns:deploy=\"vespa\" xmlns:preprocess=\"properties\">\n" +
- " <preprocess:include file='jdisc.xml' />\n" +
- " <content version='1.0' if='foo' />\n" +
- " <content version='1.0' id='foo' deploy:environment='staging prod' deploy:region='us-east-3 us-central-1'>\n" +
- " <preprocess:include file='content/content.xml' />\n" +
- " </content>\n" +
- " <preprocess:include file='not_found.xml' required='false' />\n" +
- "</services>\n";
+ static final String deploymentXml = """
+ <?xml version="1.0" encoding="UTF-8"?>
+ <deployment version="1.0">
+ <test />
+ <prod>
+ <parallel>
+ <region active="true">us-central-1</region>
+ </parallel>
+ </prod>
+ </deployment>
+ """;
+
+ static final String servicesXml = """
+ <services version='1.0' xmlns:deploy="vespa" xmlns:preprocess="properties">
+ <preprocess:include file='jdisc.xml' />
+ <content version='1.0' if='foo' />
+ <content version='1.0' id='foo' deploy:environment='staging prod' deploy:region='us-east-3 us-central-1'>
+ <preprocess:include file='content/content.xml' />
+ </content>
+ <preprocess:include file='not_found.xml' required='false' />
+ </services>
+ """;
private static final String jdiscXml = "<container id='stateless' version='1.0' />\n";
- private static final String contentXml = "<documents>\n" +
- " <document type=\"music.sd\" mode=\"index\" />\n" +
- "</documents>\n" +
- "<preprocess:include file=\"nodes.xml\" />";
+ private static final String contentXml = """
+ <documents>
+ <document type="music.sd" mode="index" />
+ </documents>
+ <preprocess:include file="nodes.xml" />""";
- private static final String nodesXml = "<nodes>\n" +
- " <node hostalias=\"node0\" distribution-key=\"0\" />\n" +
- "</nodes>";
+ private static final String nodesXml = """
+ <nodes>
+ <node hostalias="node0" distribution-key="0" />
+ </nodes>""";
@Test
void test_createEmptyForDeploymentRemoval() {
@@ -67,22 +102,22 @@ public class ApplicationPackageTest {
@Test
void testMetaData() {
- byte[] zip = ApplicationPackage.filesZip(Map.of("services.xml", servicesXml.getBytes(UTF_8),
- "jdisc.xml", jdiscXml.getBytes(UTF_8),
- "content/content.xml", contentXml.getBytes(UTF_8),
- "content/nodes.xml", nodesXml.getBytes(UTF_8),
- "gurba", "gurba".getBytes(UTF_8)));
+ byte[] zip = filesZip(Map.of("services.xml", servicesXml.getBytes(UTF_8),
+ "jdisc.xml", jdiscXml.getBytes(UTF_8),
+ "content/content.xml", contentXml.getBytes(UTF_8),
+ "content/nodes.xml", nodesXml.getBytes(UTF_8),
+ "gurba", "gurba".getBytes(UTF_8)));
assertEquals(Map.of("services.xml", servicesXml,
- "jdisc.xml", jdiscXml,
- "content/content.xml", contentXml,
- "content/nodes.xml", nodesXml),
- unzip(new ApplicationPackage(zip, false).metaDataZip()));
+ "jdisc.xml", jdiscXml,
+ "content/content.xml", contentXml,
+ "content/nodes.xml", nodesXml),
+ unzip(new ApplicationPackage(zip, false).metaDataZip()));
}
@Test
void testMetaDataWithMissingFiles() {
- byte[] zip = ApplicationPackage.filesZip(Map.of("services.xml", servicesXml.getBytes(UTF_8)));
+ byte[] zip = filesZip(Map.of("services.xml", servicesXml.getBytes(UTF_8)));
try {
new ApplicationPackage(zip, false).metaDataZip();
@@ -132,15 +167,165 @@ public class ApplicationPackageTest {
assertEquals(originalPackage.bundleHash(), similarDeploymentXml.bundleHash());
}
- private static Map<String, String> unzip(byte[] zip) {
- return ZipEntries.from(zip, __ -> true, 1 << 10, true)
+ static Map<String, String> unzip(byte[] zip) {
+ return ZipEntries.from(zip, __ -> true, 1 << 24, true)
.asList().stream()
.collect(Collectors.toMap(ZipEntries.ZipEntryWithContent::name,
- entry -> new String(entry.contentOrThrow(), UTF_8)));
+ entry -> new String(entry.content().orElse(new byte[0]), UTF_8)));
}
- private ApplicationPackage getApplicationZip(String path) throws Exception {
+ private ApplicationPackage getApplicationZip(String path) throws IOException {
return new ApplicationPackage(Files.readAllBytes(Path.of("src/test/resources/application-packages/" + path)), true);
}
+ @Test
+ void test_replacement() throws IOException {
+ byte[] zip = zip(Map.of());
+ List<X509Certificate> certificates = IntStream.range(0, 3)
+ .mapToObj(i -> {
+ KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.EC, 256);
+ X500Principal subject = new X500Principal("CN=subject" + i);
+ return X509CertificateBuilder.fromKeypair(keyPair,
+ subject,
+ Instant.now(),
+ Instant.now().plusSeconds(1),
+ SignatureAlgorithm.SHA512_WITH_ECDSA,
+ BigInteger.valueOf(1))
+ .build();
+ }).toList();
+
+ assertEquals(List.of(), new ApplicationPackage(zip).trustedCertificates());
+ for (int i = 0; i < certificates.size(); i++) {
+ InputStream in = new ByteArrayInputStream(zip);
+ zip = new ApplicationPackageStream(() -> in, () -> __ -> false, addingCertificate(Optional.of(certificates.get(i)))).zipStream().readAllBytes();
+ assertEquals(certificates.subList(0, i + 1), new ApplicationPackage(zip).trustedCertificates());
+ }
+ }
+
+ static byte[] zip(Map<String, String> content) {
+ return filesZip(content.entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey(),
+ entry -> entry.getValue().getBytes(UTF_8))));
+ }
+
+ private static class AngryStreams {
+
+ private final byte[] content;
+ private final Map<ByteArrayInputStream, Throwable> streams = new LinkedHashMap<>();
+
+ AngryStreams(byte[] content) {
+ this.content = content;
+ }
+
+ InputStream stream() {
+ ByteArrayInputStream stream = new ByteArrayInputStream(Arrays.copyOf(content, content.length)) {
+ boolean closed = false;
+ @Override public void close() { closed = true; }
+ @Override public int read() { assertFalse(closed); return super.read(); }
+ @Override public int read(byte[] b, int off, int len) { assertFalse(closed); return super.read(b, off, len); }
+ @Override public long transferTo(OutputStream out) throws IOException { assertFalse(closed); return super.transferTo(out); }
+ @Override public byte[] readAllBytes() { assertFalse(closed); return super.readAllBytes(); }
+ };
+ streams.put(stream, new Throwable());
+ return stream;
+ }
+
+ void verifyAllRead() {
+ streams.forEach((stream, stack) -> assertEquals(0, stream.available(),
+ "unconsumed content in stream created at " +
+ new ByteArrayOutputStream() {{ stack.printStackTrace(new PrintStream(this)); }}));
+ }
+
+ }
+
+ @Test
+ void testApplicationPackageStream() throws Exception {
+ Map<String, String> content = Map.of("deployment.xml", deploymentXml,
+ "services.xml", servicesXml,
+ "jdisc.xml", jdiscXml,
+ "unused1.xml", jdiscXml,
+ "content/content.xml", contentXml,
+ "content/nodes.xml", nodesXml,
+ "gurba", "gurba");
+ byte[] zip = zip(content);
+ assertEquals(content, unzip(zip));
+ AngryStreams angry = new AngryStreams(zip);
+
+ ApplicationPackageStream identity = new ApplicationPackageStream(angry::stream);
+ InputStream lazy = new LazyInputStream(() -> new ByteArrayInputStream(identity.truncatedPackage().zippedContent()));
+ assertEquals("must completely exhaust input before reading package",
+ assertThrows(IllegalStateException.class, identity::truncatedPackage).getMessage());
+
+ // Verify no content has changed when passing through the stream.
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ try (InputStream stream = identity.zipStream()) { stream.transferTo(out); }
+ assertEquals(content, unzip(out.toByteArray()));
+ assertEquals(content, unzip(identity.truncatedPackage().zippedContent()));
+ assertEquals(content, unzip(lazy.readAllBytes()));
+ ApplicationPackage original = new ApplicationPackage(zip);
+ assertEquals(unzip(original.metaDataZip()), unzip(identity.truncatedPackage().metaDataZip()));
+ assertEquals(original.bundleHash(), identity.truncatedPackage().bundleHash());
+
+ // Change deployment.xml, remove unused1.xml and add unused2.xml
+ Map<String, UnaryOperator<InputStream>> replacements = Map.of("deployment.xml", in -> new SequenceInputStream(in, new ByteArrayInputStream("\n\n".getBytes(UTF_8))),
+ "unused1.xml", in -> null,
+ "unused2.xml", __ -> new ByteArrayInputStream(jdiscXml.getBytes(UTF_8)));
+ Predicate<String> truncation = name -> name.endsWith(".xml");
+ ApplicationPackageStream modifier = new ApplicationPackageStream(angry::stream, () -> truncation, replacements);
+ out.reset();
+
+ InputStream partiallyRead = modifier.zipStream();
+ assertEquals(15, partiallyRead.readNBytes(15).length);
+
+ try (InputStream stream = modifier.zipStream()) { stream.transferTo(out); }
+
+ assertEquals(Map.of("deployment.xml", deploymentXml + "\n\n",
+ "services.xml", servicesXml,
+ "jdisc.xml", jdiscXml,
+ "unused2.xml", jdiscXml,
+ "content/content.xml", contentXml,
+ "content/nodes.xml", nodesXml,
+ "gurba", "gurba"),
+ unzip(out.toByteArray()));
+
+ assertEquals(Map.of("deployment.xml", deploymentXml + "\n\n",
+ "services.xml", servicesXml,
+ "jdisc.xml", jdiscXml,
+ "unused2.xml", jdiscXml,
+ "content/content.xml", contentXml,
+ "content/nodes.xml", nodesXml),
+ unzip(modifier.truncatedPackage().zippedContent()));
+
+ // Compare retained metadata for an updated original package, and the truncated package of the modifier.
+ assertEquals(unzip(new ApplicationPackage(zip(Map.of("deployment.xml", deploymentXml + "\n\n", // Expected to change.
+ "services.xml", servicesXml,
+ "jdisc.xml", jdiscXml,
+ "unused1.xml", jdiscXml, // Irrelevant.
+ "content/content.xml", contentXml,
+ "content/nodes.xml", nodesXml,
+ "gurba", "gurba"))).metaDataZip()),
+ unzip(modifier.truncatedPackage().metaDataZip()));
+
+ try (InputStream stream1 = modifier.zipStream();
+ InputStream stream2 = modifier.zipStream()) {
+ assertArrayEquals(stream1.readAllBytes(),
+ stream2.readAllBytes());
+ }
+
+ ByteArrayOutputStream byteAtATime = new ByteArrayOutputStream();
+ try (InputStream stream1 = modifier.zipStream();
+ InputStream stream2 = modifier.zipStream()) {
+ for (int b; (b = stream1.read()) != -1; ) byteAtATime.write(b);
+ assertArrayEquals(stream2.readAllBytes(),
+ byteAtATime.toByteArray());
+ }
+
+ assertEquals(byteAtATime.size(),
+ 15 + partiallyRead.readAllBytes().length);
+ partiallyRead.close();
+
+ try (InputStream stream = modifier.zipStream()) { stream.readNBytes(12); }
+
+ angry.verifyAllRead();
+ }
+
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/TestPackageTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/TestPackageTest.java
index bff0ccc8ae1..6da8db1c259 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/TestPackageTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/TestPackageTest.java
@@ -1,18 +1,24 @@
package com.yahoo.vespa.hosted.controller.application.pkg;
import com.yahoo.config.application.api.DeploymentSpec;
+import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.zone.ZoneId;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
+import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId;
import com.yahoo.vespa.hosted.controller.application.pkg.TestPackage.TestSummary;
import com.yahoo.vespa.hosted.controller.config.ControllerConfig;
+import com.yahoo.vespa.hosted.controller.config.ControllerConfig.Steprunner.Testerapp;
import org.junit.jupiter.api.Test;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
@@ -20,9 +26,11 @@ import static com.yahoo.vespa.hosted.controller.api.integration.deployment.Teste
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterCloud.Suite.staging;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterCloud.Suite.staging_setup;
import static com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterCloud.Suite.system;
+import static com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackageTest.unzip;
import static com.yahoo.vespa.hosted.controller.application.pkg.TestPackage.validateTests;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* @author jonmv
@@ -77,15 +85,15 @@ public class TestPackageTest {
@Test
void testBundleValidation() throws IOException {
byte[] testZip = ApplicationPackage.filesZip(Map.of("components/foo-tests.jar", testsJar("SystemTest", "StagingSetup", "ProductionTest"),
- "artifacts/key", new byte[0]));
+ "artifacts/key", new byte[0]));
TestSummary summary = validateTests(List.of(system), testZip);
assertEquals(List.of(system, staging_setup, production), summary.suites());
assertEquals(List.of("test package contains 'artifacts/key'; this conflicts with credentials used to run tests in Vespa Cloud",
- "test package has staging setup, so it should also include staging tests",
- "test package has production tests, but no production tests are declared in deployment.xml",
- "see https://docs.vespa.ai/en/testing.html for details on how to write system tests for Vespa"),
- summary.problems());
+ "test package has staging setup, so it should also include staging tests",
+ "test package has production tests, but no production tests are declared in deployment.xml",
+ "see https://docs.vespa.ai/en/testing.html for details on how to write system tests for Vespa"),
+ summary.problems());
}
@Test
@@ -95,20 +103,47 @@ public class TestPackageTest {
assertEquals(List.of(staging, production), summary.suites());
assertEquals(List.of("test package has staging tests, so it should also include staging setup",
- "see https://docs.vespa.ai/en/testing.html for details on how to write system tests for Vespa"),
- summary.problems());
+ "see https://docs.vespa.ai/en/testing.html for details on how to write system tests for Vespa"),
+ summary.problems());
}
@Test
void testBasicTestsValidation() {
byte[] testZip = ApplicationPackage.filesZip(Map.of("tests/staging-test/foo.json", new byte[0],
- "tests/staging-setup/foo.json", new byte[0]));
+ "tests/staging-setup/foo.json", new byte[0]));
TestSummary summary = validateTests(List.of(system, production), testZip);
assertEquals(List.of(staging_setup, staging), summary.suites());
assertEquals(List.of("test package has no system tests, but <test /> is declared in deployment.xml",
- "test package has no production tests, but production tests are declared in deployment.xml",
- "see https://docs.vespa.ai/en/testing.html for details on how to write system tests for Vespa"),
- summary.problems());
+ "test package has no production tests, but production tests are declared in deployment.xml",
+ "see https://docs.vespa.ai/en/testing.html for details on how to write system tests for Vespa"),
+ summary.problems());
+ }
+
+ @Test
+ void testTestPacakgeAssembly() throws IOException {
+ byte[] bundleZip = ApplicationPackage.filesZip(Map.of("components/foo-tests.jar", testsJar("SystemTest", "ProductionTest"),
+ "artifacts/key", new byte[0]));
+ TestPackage bundleTests = new TestPackage(() -> new ByteArrayInputStream(bundleZip),
+ false,
+ new RunId(ApplicationId.defaultId(), JobType.dev("abc"), 123),
+ new Testerapp.Builder().tenantCdBundle("foo").runtimeProviderClass("bar").build(),
+ DeploymentSpec.fromXml("""
+ <deployment>
+ <test />
+ </deployment>
+ """),
+ null,
+ null);
+
+ Map<String, String> bundlePackage = unzip(bundleTests.asApplicationPackage().zipStream().readAllBytes());
+ bundlePackage.keySet().removeIf(name -> name.startsWith("tests/.ignore") || name.startsWith("artifacts/.ignore"));
+ assertEquals(Set.of("deployment.xml",
+ "services.xml",
+ "components/foo-tests.jar",
+ "artifacts/key"),
+ bundlePackage.keySet());
+ assertEquals(Map.of(),
+ unzip(bundleTests.asApplicationPackage().truncatedPackage().zippedContent()));
}
@Test
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ZipEntriesTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ZipEntriesTest.java
deleted file mode 100644
index 37062e1002b..00000000000
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/application/pkg/ZipEntriesTest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.hosted.controller.application.pkg;
-
-import com.yahoo.security.KeyAlgorithm;
-import com.yahoo.security.KeyUtils;
-import com.yahoo.security.SignatureAlgorithm;
-import com.yahoo.security.X509CertificateBuilder;
-import org.junit.jupiter.api.Test;
-
-import javax.security.auth.x500.X500Principal;
-import java.math.BigInteger;
-import java.security.KeyPair;
-import java.security.cert.X509Certificate;
-import java.time.Instant;
-import java.util.List;
-import java.util.stream.Collectors;
-import java.util.stream.IntStream;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
-/**
- * @author mpolden
- */
-public class ZipEntriesTest {
-
- @Test
- void test_replacement() {
- ApplicationPackage applicationPackage = new ApplicationPackage(new byte[0]);
- List<X509Certificate> certificates = IntStream.range(0, 3)
- .mapToObj(i -> {
- KeyPair keyPair = KeyUtils.generateKeypair(KeyAlgorithm.EC, 256);
- X500Principal subject = new X500Principal("CN=subject" + i);
- return X509CertificateBuilder.fromKeypair(keyPair,
- subject,
- Instant.now(),
- Instant.now().plusSeconds(1),
- SignatureAlgorithm.SHA512_WITH_ECDSA,
- BigInteger.valueOf(1))
- .build();
- })
- .collect(Collectors.toUnmodifiableList());
-
- assertEquals(List.of(), applicationPackage.trustedCertificates());
- for (int i = 0; i < certificates.size(); i++) {
- applicationPackage = applicationPackage.withTrustedCertificate(certificates.get(i));
- assertEquals(certificates.subList(0, i + 1), applicationPackage.trustedCertificates());
- }
- }
-
-}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
index 9bf762d2f99..2f245ab9736 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunnerTest.java
@@ -516,7 +516,7 @@ public class InternalStepRunnerTest {
assertEquals(oldTrusted, tester.configServer().application(app.instanceId(), id.type().zone()).get().applicationPackage().trustedCertificates());
tester.configServer().throwOnNextPrepare(null);
- tester.clock().advance(Duration.ofSeconds(300));
+ tester.clock().advance(Duration.ofSeconds(450));
tester.runner().run();
assertEquals(succeeded, tester.jobs().run(id).stepStatuses().get(Step.deployTester));
assertEquals(succeeded, tester.jobs().run(id).stepStatuses().get(Step.deployReal));
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationStoreMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationStoreMock.java
index 8ed38761c95..e025a3bea4f 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationStoreMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ApplicationStoreMock.java
@@ -12,6 +12,8 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.RevisionId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterId;
import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.time.Instant;
import java.util.Map;
import java.util.NavigableMap;
@@ -46,15 +48,14 @@ public class ApplicationStoreMock implements ApplicationStore {
}
@Override
- public byte[] get(DeploymentId deploymentId, RevisionId revisionId) {
+ public InputStream stream(DeploymentId deploymentId, RevisionId revisionId) {
if ( ! revisionId.isProduction())
- return requireNonNull(devStore.get(deploymentId));
+ return new ByteArrayInputStream(devStore.get(deploymentId));
TenantAndApplicationId tenantAndApplicationId = TenantAndApplicationId.from(deploymentId.applicationId());
byte[] bytes = store.get(appId(tenantAndApplicationId.tenant(), tenantAndApplicationId.application())).get(revisionId);
- if (bytes == null)
- throw new NotExistsException("No " + revisionId + " found for " + tenantAndApplicationId);
- return bytes;
+ if (bytes == null) throw new NotExistsException("No " + revisionId + " found for " + tenantAndApplicationId);
+ return new ByteArrayInputStream(bytes);
}
@Override
@@ -96,8 +97,8 @@ public class ApplicationStoreMock implements ApplicationStore {
}
@Override
- public byte[] getTester(TenantName tenant, ApplicationName application, RevisionId revision) {
- return requireNonNull(store.get(testerId(tenant, application)).get(revision));
+ public InputStream streamTester(TenantName tenant, ApplicationName application, RevisionId revision) {
+ return new ByteArrayInputStream(store.get(testerId(tenant, application)).get(revision));
}
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
index 07d9efdf8fc..eaa178c9727 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java
@@ -42,9 +42,12 @@ import com.yahoo.vespa.hosted.controller.api.integration.noderepository.RestartF
import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretStore;
import com.yahoo.vespa.hosted.controller.application.SystemApplication;
import com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage;
+import wiremock.org.checkerframework.checker.units.qual.A;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.InputStream;
+import java.io.UncheckedIOException;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
@@ -376,6 +379,13 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer
@Override
public PreparedApplication deploy(DeploymentData deployment) {
+ ApplicationPackage appPackage;
+ try (InputStream in = deployment.applicationPackage()) {
+ appPackage = new ApplicationPackage(in.readAllBytes());
+ }
+ catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
lastPrepareVersion = deployment.platform();
if (prepareException != null)
prepareException.accept(ApplicationId.from(deployment.instance().tenant(),
@@ -383,8 +393,9 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer
deployment.instance().instance()));
DeploymentId id = new DeploymentId(deployment.instance(), deployment.zone());
- applications.put(id, new Application(id.applicationId(), lastPrepareVersion, new ApplicationPackage(deployment.applicationPackage())));
+ applications.put(id, new Application(id.applicationId(), lastPrepareVersion, appPackage));
ClusterSpec.Id cluster = ClusterSpec.Id.from("default");
+ deployment.endpointCertificateMetadata(); // Supplier with side effects >_<
if (nodeRepository().list(id.zoneId(), NodeFilter.all().applications(id.applicationId())).isEmpty())
provision(id.zoneId(), id.applicationId(), cluster);
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 3b5a09e4a74..a1e70b77948 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
@@ -384,20 +384,17 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
tester.assertResponse(request("/application/v4/tenant/scoober", GET).roles(Role.reader(tenantName)),
(response) -> assertFalse(response.getBodyAsString().contains("archiveAccessRole")),
200);
- tester.assertResponse(request("/application/v4/tenant/scoober/archive-access", PUT)
- .data("{\"role\":\"dummy\"}").roles(Role.administrator(tenantName)),
- "{\"error-code\":\"BAD_REQUEST\",\"message\":\"Invalid archive access role 'dummy': Must match expected pattern: 'arn:aws:iam::\\\\d{12}:.+'\"}", 400);
tester.assertResponse(request("/application/v4/tenant/scoober/archive-access/aws", PUT)
.data("{\"role\":\"arn:aws:iam::123456789012:role/my-role\"}").roles(Role.administrator(tenantName)),
"{\"message\":\"AWS archive access role set to 'arn:aws:iam::123456789012:role/my-role' for tenant scoober.\"}", 200);
tester.assertResponse(request("/application/v4/tenant/scoober", GET).roles(Role.reader(tenantName)),
- (response) -> assertTrue(response.getBodyAsString().contains("\"archiveAccessRole\":\"arn:aws:iam::123456789012:role/my-role\"")),
+ (response) -> assertTrue(response.getBodyAsString().contains("\"awsRole\":\"arn:aws:iam::123456789012:role/my-role\"")),
200);
tester.assertResponse(request("/application/v4/tenant/scoober/archive-access/aws", DELETE).roles(Role.administrator(tenantName)),
"{\"message\":\"AWS archive access role removed for tenant scoober.\"}", 200);
tester.assertResponse(request("/application/v4/tenant/scoober", GET).roles(Role.reader(tenantName)),
- (response) -> assertFalse(response.getBodyAsString().contains("\"archiveAccessRole\":\"arn:aws:iam::123456789012:role/my-role\"")),
+ (response) -> assertFalse(response.getBodyAsString().contains("\"awsRole\":\"arn:aws:iam::123456789012:role/my-role\"")),
200);
tester.assertResponse(request("/application/v4/tenant/scoober/archive-access/gcp", PUT)
@@ -412,25 +409,25 @@ public class ApplicationApiCloudTest extends ControllerContainerCloudTest {
(response) -> assertFalse(response.getBodyAsString().contains("\"gcpMember\":\"user:test@example.com\"")),
200);
- tester.assertResponse(request("/application/v4/tenant/scoober/archive-access", PUT)
+ tester.assertResponse(request("/application/v4/tenant/scoober/archive-access/aws", PUT)
.data("{\"role\":\"arn:aws:iam::123456789012:role/my-role\"}").roles(Role.administrator(tenantName)),
"{\"message\":\"AWS archive access role set to 'arn:aws:iam::123456789012:role/my-role' for tenant scoober.\"}", 200);
tester.assertResponse(request("/application/v4/tenant/scoober", GET).roles(Role.reader(tenantName)),
- (response) -> assertTrue(response.getBodyAsString().contains("\"archiveAccessRole\":\"arn:aws:iam::123456789012:role/my-role\"")),
+ (response) -> assertTrue(response.getBodyAsString().contains("\"awsRole\":\"arn:aws:iam::123456789012:role/my-role\"")),
200);
- tester.assertResponse(request("/application/v4/tenant/scoober/archive-access", PUT)
+ tester.assertResponse(request("/application/v4/tenant/scoober/archive-access/aws", PUT)
.data("{\"role\":\"arn:aws:iam::123456789012:role/my-role\"}").roles(Role.administrator(tenantName)),
"{\"message\":\"AWS archive access role set to 'arn:aws:iam::123456789012:role/my-role' for tenant scoober.\"}", 200);
tester.assertResponse(request("/application/v4/tenant/scoober", GET).roles(Role.reader(tenantName)),
- (response) -> assertTrue(response.getBodyAsString().contains("\"archiveAccessRole\":\"arn:aws:iam::123456789012:role/my-role\"")),
+ (response) -> assertTrue(response.getBodyAsString().contains("\"awsRole\":\"arn:aws:iam::123456789012:role/my-role\"")),
200);
tester.assertResponse(request("/application/v4/tenant/scoober/application/albums/environment/prod/region/aws-us-east-1c/instance/default", GET)
.roles(Role.reader(tenantName)),
new File("deployment-cloud.json"));
- tester.assertResponse(request("/application/v4/tenant/scoober/archive-access", DELETE).roles(Role.administrator(tenantName)),
+ tester.assertResponse(request("/application/v4/tenant/scoober/archive-access/aws", DELETE).roles(Role.administrator(tenantName)),
"{\"message\":\"AWS archive access role removed for tenant scoober.\"}", 200);
tester.assertResponse(request("/application/v4/tenant/scoober", GET).roles(Role.reader(tenantName)),
(response) -> assertFalse(response.getBodyAsString().contains("archiveAccessRole")),