diff options
Diffstat (limited to 'config-model/src/test')
37 files changed, 367 insertions, 95 deletions
diff --git a/config-model/src/test/cfg/application/embed/services.xml b/config-model/src/test/cfg/application/embed/services.xml index 1840063d70d..59c29aefc6a 100644 --- a/config-model/src/test/cfg/application/embed/services.xml +++ b/config-model/src/test/cfg/application/embed/services.xml @@ -19,6 +19,21 @@ <pooling-strategy>mean</pooling-strategy> </component> + <component id="splade" type="splade-embedder"> + <transformer-model model-id="e5-base-v2" url="https://my/url/model.onnx"/> + <tokenizer-model model-id="e5-base-v2-vocab" path="app/tokenizer.json"/> + <max-tokens>1024</max-tokens> + <transformer-input-ids>my_input_ids</transformer-input-ids> + <transformer-attention-mask>my_attention_mask</transformer-attention-mask> + <transformer-token-type-ids>my_token_type_ids</transformer-token-type-ids> + <transformer-output>my_output</transformer-output> + <term-score-threshold>0.2</term-score-threshold> + <onnx-execution-mode>parallel</onnx-execution-mode> + <onnx-intraop-threads>10</onnx-intraop-threads> + <onnx-interop-threads>8</onnx-interop-threads> + <onnx-gpu-device>1</onnx-gpu-device> + </component> + <component id="hf-tokenizer" type="hugging-face-tokenizer"> <model language="no" model-id="multilingual-e5-base-vocab" url="https://my/url/tokenizer.json"/> </component> diff --git a/config-model/src/test/java/com/yahoo/schema/derived/AbstractExportingTestCase.java b/config-model/src/test/java/com/yahoo/schema/derived/AbstractExportingTestCase.java index 3bb129a4c32..7686289f11c 100644 --- a/config-model/src/test/java/com/yahoo/schema/derived/AbstractExportingTestCase.java +++ b/config-model/src/test/java/com/yahoo/schema/derived/AbstractExportingTestCase.java @@ -52,7 +52,7 @@ public abstract class AbstractExportingTestCase extends AbstractSchemaTestCase { .deployLogger(logger) .rankProfileRegistry(builder.getRankProfileRegistry()) .queryProfiles(builder.getQueryProfileRegistry()) - .build()); + .build(), false); return export(dirName, builder, config); } diff --git a/config-model/src/test/java/com/yahoo/schema/derived/IndexInfoTestCase.java b/config-model/src/test/java/com/yahoo/schema/derived/IndexInfoTestCase.java new file mode 100644 index 00000000000..09450fa8023 --- /dev/null +++ b/config-model/src/test/java/com/yahoo/schema/derived/IndexInfoTestCase.java @@ -0,0 +1,55 @@ +package com.yahoo.schema.derived; + +import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.search.config.IndexInfoConfig; +import com.yahoo.vespa.model.VespaModel; +import com.yahoo.vespa.model.content.utils.ApplicationPackageBuilder; +import com.yahoo.vespa.model.content.utils.ContentClusterBuilder; +import com.yahoo.vespa.model.content.utils.DocType; +import com.yahoo.vespa.model.content.utils.SchemaBuilder; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class IndexInfoTestCase { + private static final String F = "f"; + @Test + void testThatIndexingEnablesNormalizing() { + var cmds = createIndexCmds(false); + assertEquals(8, cmds.size()); + assertEquals(1, cmds.stream().filter(c -> c.indexname().equals(F) && c.command().equals("normalize")).count()); + } + @Test + void testThatStreamingDisablesNormalizing() { + var cmds = createIndexCmds(true); + assertEquals(7, cmds.size()); + assertEquals(0, cmds.stream().filter(c -> c.indexname().equals(F) && c.command().equals("normalize")).count()); + } + + private static List<IndexInfoConfig.Indexinfo.Command> createIndexCmds(boolean isStreaming) { + final String SD = "sda"; + String documentContent = "field " + F + " type string {indexing:index | summary}"; + var cfg = createIndexInfo(SD, documentContent, isStreaming); + assertEquals(SD, cfg.indexinfo(0).name()); + return cfg.indexinfo(0).command(); + } + + private static IndexInfoConfig createIndexInfo(String schemaName, String sdContent, boolean isStreaming) { + var model = createModel(schemaName, sdContent); + var schema = model.getSearchClusters().get(0).schemas().get(schemaName); + var indexInfo = new IndexInfo(schema.fullSchema(), isStreaming); + IndexInfoConfig.Builder builder = new IndexInfoConfig.Builder(); + indexInfo.getConfig(builder); + return builder.build(); + } + + private static VespaModel createModel(String schemaName, String sdContent) { + var builder = new DeployState.Builder(); + return new ApplicationPackageBuilder() + .addCluster(new ContentClusterBuilder().name("content").docTypes(List.of(DocType.index(schemaName)))) + .addSchemas(new SchemaBuilder().name(schemaName).content(sdContent).build()) + .buildCreator().create(builder); + } +} diff --git a/config-model/src/test/java/com/yahoo/schema/derived/SchemaToDerivedConfigExporter.java b/config-model/src/test/java/com/yahoo/schema/derived/SchemaToDerivedConfigExporter.java index b219d84f108..2beab3d5ea9 100644 --- a/config-model/src/test/java/com/yahoo/schema/derived/SchemaToDerivedConfigExporter.java +++ b/config-model/src/test/java/com/yahoo/schema/derived/SchemaToDerivedConfigExporter.java @@ -46,7 +46,7 @@ public class SchemaToDerivedConfigExporter { .deployLogger(logger) .rankProfileRegistry(builder.getRankProfileRegistry()) .queryProfiles(builder.getQueryProfileRegistry()) - .build()); + .build(), false); exportConfig(dirPath, derived, builder); } } diff --git a/config-model/src/test/java/com/yahoo/schema/parser/SchemaParserTestCase.java b/config-model/src/test/java/com/yahoo/schema/parser/SchemaParserTestCase.java index c014f77d59a..5a2dc218da7 100644 --- a/config-model/src/test/java/com/yahoo/schema/parser/SchemaParserTestCase.java +++ b/config-model/src/test/java/com/yahoo/schema/parser/SchemaParserTestCase.java @@ -120,6 +120,23 @@ public class SchemaParserTestCase { assertEquals("onnx(mymodel)", rp1.getGlobalPhaseExpression().get()); } + @Test + void maxOccurrencesCanBeParsed() throws Exception { + String input = joinLines + ("schema foo {", + " document foo {", + " field bar type string {", + " indexing: summary | index", + " match { max-occurrences: 11 }", + " }", + " }", + "}"); + ParsedSchema schema = parseString(input); + var field = schema.getDocument().getFields().get(0); + assertEquals("bar", field.name()); + assertEquals(11, field.matchSettings().getMaxTermOccurrences().get()); + } + void checkFileParses(String fileName) throws Exception { var schema = parseFile(fileName); assertNotNull(schema); diff --git a/config-model/src/test/java/com/yahoo/schema/processing/IndexingScriptRewriterTestCase.java b/config-model/src/test/java/com/yahoo/schema/processing/IndexingScriptRewriterTestCase.java index 87e91acfb67..c2cc28ea6b3 100644 --- a/config-model/src/test/java/com/yahoo/schema/processing/IndexingScriptRewriterTestCase.java +++ b/config-model/src/test/java/com/yahoo/schema/processing/IndexingScriptRewriterTestCase.java @@ -147,6 +147,15 @@ public class IndexingScriptRewriterTestCase extends AbstractSchemaTestCase { createPredicateField("test", DataType.PREDICATE, "{ attribute; }", 2, OptionalLong.of(0L), OptionalLong.of(1023L))); } + @Test + void requireThatMaxTermOccurrencesIsPropagated() { + var field = new SDField("test", DataType.STRING); + field.getMatching().maxTermOccurrences(10); + field.parseIndexingScript("{ summary | index }"); + assertIndexingScript("{ input test | tokenize normalize stem:\"BEST\" max-occurrences:10 | summary test | index test; }", + field); + } + private static void assertIndexingScript(String expectedScript, SDField unprocessedField) { assertEquals(expectedScript, processField(unprocessedField).toString()); diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterExcludeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterExcludeValidatorTest.java index 25053c536da..4e88753b732 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterExcludeValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterExcludeValidatorTest.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.util.List; import java.util.Set; +import static com.yahoo.vespa.model.application.validation.ValidationTester.expect; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -56,9 +57,8 @@ public class AccessControlFilterExcludeValidatorTest { MapConfigModelRegistry.createFromList(new ModelBuilderAddingAccessControlFilter()), deployState); - IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> new AccessControlFilterExcludeValidator().validate(model, deployState)); - String expectedMessage = "Application cluster container-cluster-with-access-control excludes paths from access control, this is not allowed and should be removed."; - assertEquals(expectedMessage, exception.getMessage()); + expect(new AccessControlFilterExcludeValidator(), model, deployState, + "Application cluster container-cluster-with-access-control excludes paths from access control, this is not allowed and should be removed."); } @Test @@ -69,9 +69,8 @@ public class AccessControlFilterExcludeValidatorTest { MapConfigModelRegistry.createFromList(new ModelBuilderAddingAccessControlFilter()), deployState); - new AccessControlFilterExcludeValidator().validate(model, deployState); - String expectedMessage = "Application cluster container-cluster-with-access-control excludes paths from access control, this is not allowed and should be removed."; - assertTrue(logOutput.toString().contains(expectedMessage)); + ValidationTester.validate(new AccessControlFilterExcludeValidator(), model, deployState); + assertTrue(logOutput.toString().contains("Application cluster container-cluster-with-access-control excludes paths from access control, this is not allowed and should be removed.")); } @Test @@ -80,7 +79,7 @@ public class AccessControlFilterExcludeValidatorTest { VespaModel model = new VespaModel( MapConfigModelRegistry.createFromList(new ModelBuilderAddingAccessControlFilter()), deployState); - new AccessControlFilterExcludeValidator().validate(model, deployState); + ValidationTester.validate(new AccessControlFilterExcludeValidator(), model, deployState); } @Test @@ -90,7 +89,7 @@ public class AccessControlFilterExcludeValidatorTest { MapConfigModelRegistry.createFromList(new ModelBuilderAddingAccessControlFilter()), deployState); - new AccessControlFilterExcludeValidator().validate(model, deployState); + ValidationTester.validate(new AccessControlFilterExcludeValidator(), model, deployState); } private static DeployState createDeployState(Zone zone, StringBuffer buffer, boolean allowExcludes) { @@ -112,6 +111,6 @@ public class AccessControlFilterExcludeValidatorTest { Cloud.Builder cloudBuilder = Cloud.builder().name(cloudName); if (cloudName == CloudName.AWS) cloudBuilder.account(CloudAccount.from("123456789012")); return new Zone(cloudBuilder.build(), systemName, Environment.prod, RegionName.defaultName()); - } + } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidatorTest.java index aa42fbbf827..1bc59e118d4 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/AccessControlFilterValidatorTest.java @@ -39,7 +39,7 @@ public class AccessControlFilterValidatorTest { VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); try { - new AccessControlFilterValidator().validate(model, deployState); + ValidationTester.validate(new AccessControlFilterValidator(), model, deployState); fail(); } catch (IllegalArgumentException e) { assertEquals("The 'access-control' feature is not available in open-source Vespa.", e.getMessage()); @@ -53,7 +53,7 @@ public class AccessControlFilterValidatorTest { MapConfigModelRegistry.createFromList(new ModelBuilderAddingAccessControlFilter()), deployState); - new AccessControlFilterValidator().validate(model, deployState); + ValidationTester.validate(new AccessControlFilterValidator(), model, deployState); } private static DeployState createDeployState() { @@ -61,4 +61,5 @@ public class AccessControlFilterValidatorTest { .applicationPackage(new MockApplicationPackage.Builder().withServices(SERVICES_XML).build()) .build(); } + } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/BundleValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/BundleValidatorTest.java index f41cc266db3..1aca0c2fe47 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/BundleValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/BundleValidatorTest.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.model.application.validation; import com.yahoo.config.application.api.DeployLogger; import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.vespa.model.application.validation.AbstractBundleValidator.JarContext; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -29,7 +30,7 @@ public class BundleValidatorTest { // Valid jar file JarFile ok = createTemporaryJarFile(tempDir, "ok"); BundleValidator bundleValidator = new BundleValidator(); - bundleValidator.validateJarFile(DeployState.createTestState(), ok); + bundleValidator.validateJarFile(contextOf(DeployState.createTestState()), ok); // No manifest validateWithException("nomanifest", "Non-existing or invalid manifest in nomanifest.jar"); @@ -39,7 +40,7 @@ public class BundleValidatorTest { try { JarFile jarFile = createTemporaryJarFile(tempDir, jarName); BundleValidator bundleValidator = new BundleValidator(); - bundleValidator.validateJarFile(DeployState.createTestState(), jarFile); + bundleValidator.validateJarFile(contextOf(DeployState.createTestState()), jarFile); assert (false); } catch (IllegalArgumentException e) { assertEquals(exceptionMessage, e.getMessage()); @@ -52,7 +53,7 @@ public class BundleValidatorTest { DeployState state = createDeployState(buffer); JarFile jarFile = createTemporaryJarFile(tempDir, "snapshot_bundle"); - new BundleValidator().validateJarFile(state, jarFile); + new BundleValidator().validateJarFile(contextOf(state), jarFile); assertTrue(buffer.toString().contains("Deploying snapshot bundle")); } @@ -62,7 +63,7 @@ public class BundleValidatorTest { DeployState state = createDeployState(buffer); BundleValidator validator = new BundleValidator(); JarFile jarFile = createTemporaryJarFile(tempDir, "import-warnings"); - validator.validateJarFile(state, jarFile); + validator.validateJarFile(contextOf(state), jarFile); String output = buffer.toString(); assertTrue(output .contains("JAR file 'import-warnings.jar' imports the packages [org.json] from 'org.json:json'. \n" + @@ -123,5 +124,12 @@ public class BundleValidatorTest { List.of("org.json", "version", "[0.0.0,1)", "org.eclipse.jetty.client.api", "version", "[9.4.46,10)")); } + private static JarContext contextOf(DeployState state) { + return new JarContext() { + @Override public void illegal(String error) { throw new IllegalArgumentException(error); } + @Override public void illegal(String error, Throwable cause) { throw new IllegalArgumentException(error, cause); } + @Override public DeployState deployState() { return state; } + }; + } } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudClientsValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudClientsValidatorTest.java new file mode 100644 index 00000000000..6fbca76ccbc --- /dev/null +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudClientsValidatorTest.java @@ -0,0 +1,54 @@ +package com.yahoo.vespa.model.application.validation; + +import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.security.X509CertificateUtils; +import com.yahoo.vespa.model.test.utils.DeployLoggerStub; +import org.junit.jupiter.api.Test; + +import java.security.cert.X509Certificate; + +import static com.yahoo.yolean.Exceptions.uncheck; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author bjorncs + */ +class CloudClientsValidatorTest { + + @Test + void logs_deployment_warning_on_certificate_with_empty_sequence_of_extensions() { + // Test should fail on BouncyCastle 1.77 or later + + var logger = new DeployLoggerStub(); + var state = new DeployState.Builder().deployLogger(logger).build(); + var cert = readTestCertificate("cert-with-empty-sequence-of-extensions.pem"); + CloudClientsValidator.validateCertificate("default", "my-feed-client", cert, + (msg, cause) -> { throw new IllegalArgumentException(msg, cause); }, + state); + var expected = "Client **my-feed-client** defined for cluster **default** contains an invalid certificate: " + + "The certificate's ASN.1 structure contains an empty sequence of extensions, " + + "which is a violation of the ASN.1 specification. " + + "Please update the application package with a new certificate, " + + "e.g by generating a new one using the Vespa CLI `$ vespa auth cert`. " + + "Such certificate will no longer be accepted in near future."; + assertEquals(expected, logger.getLast().message); + } + + @Test + void accepts_valid_certificate() { + var logger = new DeployLoggerStub(); + var state = new DeployState.Builder().deployLogger(logger).build(); + var cert = readTestCertificate("valid-cert.pem"); + assertDoesNotThrow(() -> CloudClientsValidator.validateCertificate("default", "my-feed-client", cert, + (msg, cause) -> { throw new IllegalArgumentException(msg, cause); }, + state)); + assertEquals(0, logger.entries.size()); + } + + private static X509Certificate readTestCertificate(String filename) { + return X509CertificateUtils.fromPem(new String(uncheck( + () -> CloudClientsValidatorTest.class.getResourceAsStream( + "/cloud-clients-validator/%s".formatted(filename)).readAllBytes()))); + } +} diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudDataPlaneFilterValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudDataPlaneFilterValidatorTest.java index 8acbf00a5a3..80ef81ee6d7 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudDataPlaneFilterValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudDataPlaneFilterValidatorTest.java @@ -71,7 +71,7 @@ public class CloudDataPlaneFilterValidatorTest { certFile2, List.of(createCertificate("bar")))); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new CloudDataPlaneFilterValidator().validate(model, deployState); + ValidationTester.validate(new CloudDataPlaneFilterValidator(), model, deployState); } @Test @@ -100,11 +100,8 @@ public class CloudDataPlaneFilterValidatorTest { certFile2, List.of(certificate))); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - IllegalArgumentException illegalArgumentException = Assertions.assertThrows(IllegalArgumentException.class, () -> - new CloudDataPlaneFilterValidator().validate(model, deployState)); - assertEquals( - "Duplicate certificate(s) detected in files: [%s, %s]. Certificate subject of duplicates: [%s]".formatted(certFile1, certFile2, certificate.getSubjectX500Principal().getName()), - illegalArgumentException.getMessage()); + ValidationTester.expect(new CloudDataPlaneFilterValidator(), model, deployState, + "Duplicate certificate(s) detected in files: [%s, %s]. Certificate subject of duplicates: [%s]".formatted(certFile1, certFile2, certificate.getSubjectX500Principal().getName())); } @Test @@ -127,11 +124,8 @@ public class CloudDataPlaneFilterValidatorTest { Map.of(certFile1, List.of(certificate, certificate))); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - IllegalArgumentException illegalArgumentException = Assertions.assertThrows(IllegalArgumentException.class, () -> - new CloudDataPlaneFilterValidator().validate(model, deployState)); - assertEquals( - "Duplicate certificate(s) detected in files: [%s]. Certificate subject of duplicates: [%s]".formatted(certFile1, certificate.getSubjectX500Principal().getName()), - illegalArgumentException.getMessage()); + ValidationTester.expect(new CloudDataPlaneFilterValidator(), model, deployState, + "Duplicate certificate(s) detected in files: [%s]. Certificate subject of duplicates: [%s]".formatted(certFile1, certificate.getSubjectX500Principal().getName())); } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudHttpConnectorValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudHttpConnectorValidatorTest.java index 58aa0e8625e..3be1cbd44e3 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudHttpConnectorValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudHttpConnectorValidatorTest.java @@ -104,7 +104,7 @@ class CloudHttpConnectorValidatorTest { .endpoints(Set.of(new ContainerEndpoint("container", ApplicationClusterEndpoint.Scope.zone, List.of("c.example.com")))) .build(); var model = new VespaModel(new NullConfigModelRegistry(), state); - new CloudHttpConnectorValidator().validate(model, state); + ValidationTester.validate(new CloudHttpConnectorValidator(), model, state); } } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidatorTest.java index 2aa678fd34b..ac5a08b1394 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/CloudUserFilterValidatorTest.java @@ -67,7 +67,7 @@ class CloudUserFilterValidatorTest { .properties(new TestProperties().setHostedVespa(isHosted).setAllowUserFilters(false)) .build(); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new CloudUserFilterValidator().validate(model, deployState); + ValidationTester.validate(new CloudUserFilterValidator(), model, deployState); } } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ContainerInCloudValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ContainerInCloudValidatorTest.java index 43c51bea04a..b6484049eaf 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ContainerInCloudValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ContainerInCloudValidatorTest.java @@ -61,7 +61,7 @@ public class ContainerInCloudValidatorTest { } DeployState deployState = builder.build(); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new ContainerInCloudValidator().validate(model, deployState); + ValidationTester.validate(new ContainerInCloudValidator(), model, deployState); } } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/DeploymentSpecValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/DeploymentSpecValidatorTest.java index 4e388df3ef8..c9b014d9301 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/DeploymentSpecValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/DeploymentSpecValidatorTest.java @@ -63,7 +63,7 @@ public class DeploymentSpecValidatorTest { try { var deployState = builder.build(); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new DeploymentSpecValidator().validate(model, deployState); + ValidationTester.validate(new DeploymentSpecValidator(), model, deployState); fail("Did not get expected exception"); } catch (IllegalArgumentException e) { assertEquals(message, e.getMessage()); diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/EndpointCertificateSecretsValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/EndpointCertificateSecretsValidatorTest.java index 821ad1be8fa..3b6a559ce31 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/EndpointCertificateSecretsValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/EndpointCertificateSecretsValidatorTest.java @@ -48,7 +48,7 @@ public class EndpointCertificateSecretsValidatorTest { DeployState deployState = deployState(servicesXml(), deploymentXml(), Optional.of(EndpointCertificateSecrets.missing(1))); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new EndpointCertificateSecretsValidator().validate(model, deployState); + ValidationTester.validate(new EndpointCertificateSecretsValidator(), model, deployState); }); assertTrue(exception.getMessage().contains("TLS enabled, but could not yet retrieve certificate version 1 for application default:default:default")); } @@ -58,7 +58,7 @@ public class EndpointCertificateSecretsValidatorTest { DeployState deployState = deployState(servicesXml(), deploymentXml(), Optional.of(new EndpointCertificateSecrets("cert", "key"))); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new EndpointCertificateSecretsValidator().validate(model, deployState); + ValidationTester.validate(new EndpointCertificateSecretsValidator(), model, deployState); } @Test @@ -66,7 +66,7 @@ public class EndpointCertificateSecretsValidatorTest { DeployState deployState = deployState(servicesXml(), deploymentXml(), Optional.empty()); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new EndpointCertificateSecretsValidator().validate(model, deployState); + ValidationTester.validate(new EndpointCertificateSecretsValidator(), model, deployState); } private static DeployState deployState(String servicesXml, String deploymentXml, Optional<EndpointCertificateSecrets> endpointCertificateSecretsSecrets) { diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/InfrastructureDeploymentValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/InfrastructureDeploymentValidatorTest.java index bcec73432b3..190f68e6956 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/InfrastructureDeploymentValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/InfrastructureDeploymentValidatorTest.java @@ -43,6 +43,7 @@ public class InfrastructureDeploymentValidatorTest { var model = new VespaModel(new NullConfigModelRegistry(), deployState); var validator = new InfrastructureDeploymentValidator(); - validator.validate(model, deployState); + ValidationTester.validate(validator, model, deployState); } + } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java index 31e4c661151..a53ef233746 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/JvmHeapSizeValidatorTest.java @@ -13,6 +13,7 @@ import com.yahoo.config.model.deploy.TestProperties; import com.yahoo.config.model.provision.InMemoryProvisioner; import com.yahoo.config.model.test.MockApplicationPackage; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.NodeResources; import com.yahoo.text.Text; import com.yahoo.vespa.model.VespaModel; @@ -38,27 +39,25 @@ class JvmHeapSizeValidatorTest { @Test void fails_on_too_low_jvm_percentage() throws IOException, SAXException { - var deployState = createDeployState(8, 7L * 1024 * 1024 * 1024); + var deployState = createDeployState(9, 7L * 1024 * 1024 * 1024); var model = new VespaModel(new NullConfigModelRegistry(), deployState); - var e = assertThrows(IllegalArgumentException.class, () -> new JvmHeapSizeValidator().validate(model, deployState)); - String expectedMessage = "Allocated percentage of memory of JVM in cluster 'container' is too low (3% < 15%). Estimated cost of ONNX models is 7.00GB"; - assertTrue(e.getMessage().contains(expectedMessage), e.getMessage()); + ValidationTester.expect(new JvmHeapSizeValidator(), model, deployState, + "Allocated percentage of memory of JVM in cluster 'container' is too low (12% < 15%). Estimated cost of ONNX models is 7.00GB"); } @Test void fails_on_too_low_heap_size() throws IOException, SAXException { var deployState = createDeployState(2.2, 1024L * 1024 * 1024); var model = new VespaModel(new NullConfigModelRegistry(), deployState); - var e = assertThrows(IllegalArgumentException.class, () -> new JvmHeapSizeValidator().validate(model, deployState)); - String expectedMessage = "Allocated memory to JVM in cluster 'container' is too low (0.50GB < 0.60GB). Estimated cost of ONNX models is 1.00GB."; - assertTrue(e.getMessage().contains(expectedMessage), e.getMessage()); + ValidationTester.expect(new JvmHeapSizeValidator(), model, deployState, + "Allocated memory to JVM in cluster 'container' is too low (0.50GB < 0.60GB). Estimated cost of ONNX models is 1.00GB."); } @Test void accepts_adequate_heap_size() throws IOException, SAXException { var deployState = createDeployState(8, 1024L * 1024 * 1024); var model = new VespaModel(new NullConfigModelRegistry(), deployState); - assertDoesNotThrow(() -> new JvmHeapSizeValidator().validate(model, deployState)); + assertDoesNotThrow(() -> ValidationTester.validate(new JvmHeapSizeValidator(), model, deployState)); } @Test @@ -80,7 +79,7 @@ class JvmHeapSizeValidatorTest { </services>"""; var deployState = createDeployState(servicesXml, 2, 1024L * 1024 * 1024); var model = new VespaModel(new NullConfigModelRegistry(), deployState); - assertDoesNotThrow(() -> new JvmHeapSizeValidator().validate(model, deployState)); + assertDoesNotThrow(() -> ValidationTester.validate(new JvmHeapSizeValidator(), model, deployState)); } private static DeployState createDeployState(String servicesXml, double nodeGb, long modelCostBytes) { @@ -121,6 +120,7 @@ class JvmHeapSizeValidatorTest { ModelCostDummy(long modelCost) { this.modelCost = modelCost; } @Override public Calculator newCalculator(ApplicationPackage appPkg, ApplicationId applicationId) { return this; } + @Override public Calculator newCalculator(ApplicationPackage appPkg, ApplicationId applicationId, ClusterSpec.Id clusterId) { return this; } @Override public Map<String, ModelInfo> models() { return Map.of(); } @Override public void setRestartOnDeploy() {} @Override public boolean restartOnDeploy() { return false;} diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/PublicApiBundleValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/PublicApiBundleValidatorTest.java index c68599f4595..19be886d3e5 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/PublicApiBundleValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/PublicApiBundleValidatorTest.java @@ -1,6 +1,8 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.application.validation; +import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.vespa.model.application.validation.AbstractBundleValidator.JarContext; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -13,6 +15,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasSize; +import static org.junit.jupiter.api.Assertions.fail; /** * @author gjoranv @@ -29,7 +32,11 @@ public class PublicApiBundleValidatorTest { var jarFile = BundleValidatorTest.createTemporaryJarFile(tempDir, "non-public-api"); var validator = new PublicApiBundleValidator(); - validator.validateJarFile(deployState, jarFile); + validator.validateJarFile(new JarContext() { + @Override public void illegal(String error) { fail(); } + @Override public void illegal(String error, Throwable cause) { fail(); } + @Override public DeployState deployState() { return deployState; } + }, jarFile); String output = outputBuf.toString(); assertThat(output, containsString("uses non-public Vespa APIs: [")); diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/SecretStoreValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/SecretStoreValidatorTest.java index ae23b3b722d..9d53c5af61c 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/SecretStoreValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/SecretStoreValidatorTest.java @@ -48,7 +48,7 @@ public class SecretStoreValidatorTest { DeployState deployState = deployState(servicesXml(), deploymentXml(true)); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new SecretStoreValidator().validate(model, deployState); + ValidationTester.validate(new SecretStoreValidator(), model, deployState); } @Test @@ -58,7 +58,7 @@ public class SecretStoreValidatorTest { DeployState deployState = deployState(servicesXml(), deploymentXml(false)); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new SecretStoreValidator().validate(model, deployState); + ValidationTester.validate(new SecretStoreValidator(), model, deployState); }); assertTrue(exception.getMessage().contains("Container cluster 'default' uses a secret store, so an Athenz domain and" + @@ -74,7 +74,7 @@ public class SecretStoreValidatorTest { DeployState deployState = deployState(servicesXml, deploymentXml(false)); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new SecretStoreValidator().validate(model, deployState); + ValidationTester.validate(new SecretStoreValidator(), model, deployState); } private static DeployState deployState(String servicesXml, String deploymentXml) { diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/UriBindingsValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/UriBindingsValidatorTest.java index 9a2f9fadac6..92c2b5276cd 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/UriBindingsValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/UriBindingsValidatorTest.java @@ -107,7 +107,7 @@ public class UriBindingsValidatorTest { .endpoints(Set.of(new ContainerEndpoint("default", ApplicationClusterEndpoint.Scope.zone, List.of("default.example.com")))) .build(); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new UriBindingsValidator().validate(model, deployState); + ValidationTester.validate(new UriBindingsValidator(), model, deployState); } private static String createServicesXmlWithHandler(String handlerBinding) { diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/UrlConfigValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/UrlConfigValidatorTest.java index 837de946e36..d4a324901e2 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/UrlConfigValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/UrlConfigValidatorTest.java @@ -81,7 +81,7 @@ public class UrlConfigValidatorTest { .build(); DeployState deployState = createDeployState(app, systemName); VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState); - new UrlConfigValidator().validate(model, deployState); + ValidationTester.validate(new UrlConfigValidator(), model, deployState); } private static DeployState createDeployState(ApplicationPackage app, SystemName systemName) { diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ValidationTester.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ValidationTester.java index 8dc07d8857d..29279635918 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ValidationTester.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/ValidationTester.java @@ -16,12 +16,15 @@ import com.yahoo.config.provision.RegionName; import com.yahoo.config.provision.SystemName; import com.yahoo.config.provision.Zone; import com.yahoo.vespa.model.VespaModel; +import com.yahoo.vespa.model.application.validation.Validation.Execution; +import com.yahoo.vespa.model.application.validation.change.ChangeValidator; import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; @@ -30,6 +33,8 @@ import java.util.stream.Stream; import static com.yahoo.config.model.test.MockApplicationPackage.BOOK_SCHEMA; import static com.yahoo.config.model.test.MockApplicationPackage.MUSIC_SCHEMA; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author bratseth @@ -114,4 +119,27 @@ public class ValidationTester { return s.replaceAll("\\d", "-"); } + public static void expect(Validator validator, VespaModel model, DeployState deployState, String... expectedMessages) { + Execution execution = new Execution(model, deployState); + validator.validate(execution); + assertTrue( execution.errors().stream().allMatch(error -> Arrays.stream(expectedMessages).anyMatch(error::contains)) + && Arrays.stream(expectedMessages).allMatch(expected -> execution.errors().stream().anyMatch(error -> error.contains(expected))), + "Expected errors: " + Arrays.toString(expectedMessages) + "\nActual errors: " + execution.errors()); + } + + /** Runs validation, and throws on illegalities. */ + public static void validate(Validator validator, VespaModel model, DeployState deployState) { + Execution execution = new Execution(model, deployState); + validator.validate(execution); + execution.throwIfFailed(); + } + + /** Runs validation and returns the resulting config chance actions, without checking whether they're currently allowed; or throws on illegalities. */ + public static List<ConfigChangeAction> validateChanges(ChangeValidator validator, VespaModel model, DeployState deployState) { + Execution execution = new Execution(model, deployState); + validator.validate(execution); + if ( ! execution.errors().isEmpty()) execution.throwIfFailed(); + return execution.actions(); + } + } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidatorTest.java index bc36b800bfb..6b5db3b081f 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidatorTest.java @@ -41,22 +41,22 @@ public class CertificateRemovalChangeValidatorTest { CertificateRemovalChangeValidator validator = new CertificateRemovalChangeValidator(); // Adding certs -> ok - validator.validateClients("clusterId", List.of(c1, c2), List.of(c1, c2, c3), new DeployState.Builder().now(now).build()); + validator.validateClients("clusterId", List.of(c1, c2), List.of(c1, c2, c3), (id, msg) -> ValidationOverrides.empty.invalid(id, msg, now)); // Removing certs -> fails assertThrows(ValidationOverrides.ValidationException.class, () ->validator.validateClients("clusterId", List.of(c1, c2, c3), List.of(c1, c3), - new DeployState.Builder().now(now).build())); + (id, msg) -> ValidationOverrides.empty.invalid(id, msg, now))); // Removing certs with validationoverrides -> ok validator.validateClients("clusterId", List.of(c1, c2, c3), List.of(c1, c3), - new DeployState.Builder().now(now).validationOverrides(ValidationOverrides.fromXml(validationOverrides)).build()); + (id, msg) -> ValidationOverrides.fromXml(validationOverrides).invalid(id, msg, now)); // Adding and removing internal certs are ok: validator.validateClients("clusterId", List.of(c1, c2), List.of(c1, c2, internal), - new DeployState.Builder().build()); + (id, msg) -> ValidationOverrides.empty.invalid(id, msg, now)); validator.validateClients("clusterId", List.of(c1, c2, internal), List.of(c1, c2), - new DeployState.Builder().now(now).build()); + (id, msg) -> ValidationOverrides.empty.invalid(id, msg, now)); } static X509Certificate certificate(String cn) { diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigChangeTestUtils.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigChangeTestUtils.java index 081e10ecea6..c9703fc34af 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigChangeTestUtils.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigChangeTestUtils.java @@ -7,9 +7,11 @@ import com.yahoo.config.model.api.ServiceInfo; import com.yahoo.config.provision.ClusterSpec; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; +import static java.util.Comparator.comparing; import static org.junit.jupiter.api.Assertions.assertEquals; public class ConfigChangeTestUtils { @@ -60,8 +62,8 @@ public class ConfigChangeTestUtils { public static void assertEqualActions(List<ConfigChangeAction> exp, List<ConfigChangeAction> act) { var mutableExp = new ArrayList<>(exp); var mutableAct = new ArrayList<>(act); - mutableExp.sort((lhs, rhs) -> lhs.getMessage().compareTo(rhs.getMessage())); - mutableAct.sort((lhs, rhs) -> lhs.getMessage().compareTo(rhs.getMessage())); + mutableExp.sort(comparing(ConfigChangeAction::getMessage)); + mutableAct.sort(comparing(ConfigChangeAction::getMessage)); assertEquals(mutableExp, mutableAct); } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidatorTest.java index a41b538d3ca..f68a1da7dfb 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidatorTest.java @@ -1,16 +1,15 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.application.validation.change; -import com.yahoo.config.model.deploy.DeployState; -import com.yahoo.test.AnotherrestartConfig; import com.yahoo.config.ConfigInstance; -import com.yahoo.test.RestartConfig; -import com.yahoo.test.SimpletypesConfig; import com.yahoo.config.model.api.ConfigChangeAction; +import com.yahoo.config.model.producer.AbstractConfigProducerRoot; import com.yahoo.config.model.producer.AnyConfigProducer; import com.yahoo.config.model.producer.TreeConfigProducer; -import com.yahoo.config.model.producer.AbstractConfigProducerRoot; import com.yahoo.config.model.test.MockRoot; +import com.yahoo.test.AnotherrestartConfig; +import com.yahoo.test.RestartConfig; +import com.yahoo.test.SimpletypesConfig; import com.yahoo.vespa.model.AbstractService; import com.yahoo.vespa.model.Host; import com.yahoo.vespa.model.HostResource; @@ -25,7 +24,9 @@ import org.junit.jupiter.api.Test; import java.util.List; import java.util.stream.Collectors; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Testing the validator on both a stub model and a real-life Vespa model. @@ -152,11 +153,6 @@ public class ConfigValueChangeValidatorTest { assertEmptyLog(); } - private List<ConfigChangeAction> getConfigChanges(VespaModel currentModel, VespaModel nextModel) { - ConfigValueChangeValidator validator = new ConfigValueChangeValidator(); - return validator.validate(currentModel, nextModel, new DeployState.Builder().deployLogger(logger).build()); - } - private List<ConfigChangeAction> getConfigChanges(AbstractConfigProducerRoot currentModel, AbstractConfigProducerRoot nextModel) { ConfigValueChangeValidator validator = new ConfigValueChangeValidator(); @@ -245,8 +241,7 @@ public class ConfigValueChangeValidatorTest { setHostResource(new HostResource(new Host(null, "localhost"))); } - @Override - public int getPortCount() { + @Override public int getPortCount() { return 0; } @@ -262,8 +257,7 @@ public class ConfigValueChangeValidatorTest { this.value = value; } - @Override - public void getConfig(RestartConfig.Builder builder) { + @Override public void getConfig(RestartConfig.Builder builder) { builder.value(value); } @@ -283,8 +277,7 @@ public class ConfigValueChangeValidatorTest { this.anotherValue = anotherValue; } - @Override - public void getConfig(AnotherrestartConfig.Builder builder) { + @Override public void getConfig(AnotherrestartConfig.Builder builder) { builder.anothervalue(anotherValue); } } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java index ac59ca58cb5..a7485b177d3 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java @@ -5,6 +5,7 @@ import com.yahoo.config.model.api.ConfigChangeAction; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.vespa.defaults.Defaults; import com.yahoo.vespa.model.VespaModel; +import com.yahoo.vespa.model.application.validation.ValidationTester; import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg; import org.junit.jupiter.api.Test; @@ -67,7 +68,7 @@ public class ContainerRestartValidatorTest { } private static List<ConfigChangeAction> validateModel(VespaModel current, VespaModel next) { - return new ContainerRestartValidator().validate(current, next, new DeployState.Builder().build()); + return ValidationTester.validateChanges(new ContainerRestartValidator(), next, new DeployState.Builder().previousModel(current).build()); } private static VespaModel createModel(boolean restartOnDeploy, boolean alwaysRestart) { diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidatorTest.java index cdc80754194..f4123a72e1f 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidatorTest.java @@ -1,6 +1,7 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.model.application.validation.change; +import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.Environment; import com.yahoo.vespa.model.VespaModel; import com.yahoo.vespa.model.application.validation.ValidationTester; @@ -14,7 +15,7 @@ import static org.junit.jupiter.api.Assertions.*; public class GlobalDocumentChangeValidatorTest { @Test - void testChangGlobalAttribute() { + void testChangeGlobalAttribute() { testChangeGlobalAttribute(true, false, false, null); testChangeGlobalAttribute(true, true, true, null); testChangeGlobalAttribute(false, false, true, null); @@ -27,14 +28,16 @@ public class GlobalDocumentChangeValidatorTest { ValidationTester tester = new ValidationTester(); VespaModel oldModel = tester.deploy(null, getServices(oldGlobal), Environment.prod, validationOverrides, "default.indexing").getFirst(); try { - tester.deploy(oldModel, getServices(newGlobal), Environment.prod, validationOverrides, "default.indexing").getSecond(); + var actions = tester.deploy(oldModel, getServices(newGlobal), Environment.prod, validationOverrides, "default.indexing").getSecond(); assertTrue(allowed); - } catch (IllegalStateException e) { + assertEquals(validationOverrides == null ? 0 : 1, actions.size()); + if (validationOverrides != null) assertEquals(ClusterSpec.Id.from("default"), actions.get(0).clusterId()); + } catch (IllegalArgumentException e) { assertFalse(allowed); - assertEquals("Document type music in cluster default changed global from " + oldGlobal + " to " + newGlobal + ". " + - "Add validation override 'global-document-change' to force this change through. " + - "First, stop services on all content nodes. Then, deploy with validation override. Finally, start services on all content nodes.", - e.getMessage()); + assertEquals("global-document-change: Document type music in cluster default changed global from " + oldGlobal + " to " + newGlobal + ". " + + "To handle this change, first stop services on all content nodes. Then, deploy with validation override. Finally, start services on all content nodes. " + + "To allow this add <allow until='yyyy-mm-dd'>global-document-change</allow> to validation-overrides.xml, see https://docs.vespa.ai/en/reference/validation-overrides.html", + e.getMessage()); } } @@ -52,8 +55,10 @@ public class GlobalDocumentChangeValidatorTest { } private static final String globalDocumentValidationOverrides = - "<validation-overrides>\n" + - " <allow until='2000-01-14' comment='test override'>global-document-change</allow>\n" + - "</validation-overrides>\n"; + """ + <validation-overrides> + <allow until='2000-01-14' comment='test override'>global-document-change</allow> + </validation-overrides> + """; } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/IndexedSchemaClusterChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/IndexedSchemaClusterChangeValidatorTest.java index fb4e9f1a00b..3555fc21471 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/IndexedSchemaClusterChangeValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/IndexedSchemaClusterChangeValidatorTest.java @@ -7,6 +7,7 @@ import com.yahoo.config.model.api.ServiceInfo; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.vespa.model.VespaModel; +import com.yahoo.vespa.model.application.validation.ValidationTester; import com.yahoo.vespa.model.content.utils.ApplicationPackageBuilder; import com.yahoo.vespa.model.content.utils.ContentClusterBuilder; import com.yahoo.vespa.model.content.utils.SchemaBuilder; @@ -70,8 +71,7 @@ public class IndexedSchemaClusterChangeValidatorTest { } private List<ConfigChangeAction> validate() { - return normalizeServicesInActions(validator.validate(currentModel, nextModel, - new DeployState.Builder().build())); + return normalizeServicesInActions(ValidationTester.validateChanges(validator, nextModel, new DeployState.Builder().previousModel(currentModel).build())); } public void assertValidation() { diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java index afa36ac271e..b2439651cf9 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java @@ -13,6 +13,7 @@ import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.ProvisionLogger; import com.yahoo.vespa.model.VespaModel; +import com.yahoo.vespa.model.application.validation.ValidationTester; import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg; import org.junit.jupiter.api.Test; @@ -58,7 +59,7 @@ public class NodeResourceChangeValidatorTest { } private List<ConfigChangeAction> validate(VespaModel current, VespaModel next) { - return new NodeResourceChangeValidator().validate(current, next, new DeployState.Builder().build()); + return ValidationTester.validateChanges(new NodeResourceChangeValidator(), next, new DeployState.Builder().previousModel(current).build()); } private static VespaModel model(int mem1, int mem2, int mem3, int mem4) { diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidatorTest.java index 13389689de5..67e8a4d512e 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RestartOnDeployForOnnxModelChangesValidatorTest.java @@ -8,6 +8,7 @@ import com.yahoo.config.model.api.OnnxModelOptions; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.model.deploy.TestProperties; import com.yahoo.vespa.model.VespaModel; +import com.yahoo.vespa.model.application.validation.ValidationTester; import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg; import org.junit.jupiter.api.Test; @@ -71,7 +72,7 @@ public class RestartOnDeployForOnnxModelChangesValidatorTest { } private static List<ConfigChangeAction> validateModel(VespaModel current, VespaModel next) { - return new RestartOnDeployForOnnxModelChangesValidator().validate(current, next, deployStateBuilder().build()); + return ValidationTester.validateChanges(new RestartOnDeployForOnnxModelChangesValidator(), next, deployStateBuilder().previousModel(current).build()); } private static OnnxModelCost onnxModelCost() { @@ -79,7 +80,7 @@ public class RestartOnDeployForOnnxModelChangesValidatorTest { } private static OnnxModelCost onnxModelCost(long estimatedCost, long hash) { - return (appPkg, applicationId) -> new OnnxModelCost.Calculator() { + return (appPkg, applicationId, clusterId) -> new OnnxModelCost.Calculator() { private final Map<String, OnnxModelCost.ModelInfo> models = new HashMap<>(); private boolean restartOnDeploy = false; diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/StreamingSchemaClusterChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/StreamingSchemaClusterChangeValidatorTest.java index 8db9d39534d..ee64ceb6969 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/StreamingSchemaClusterChangeValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/StreamingSchemaClusterChangeValidatorTest.java @@ -7,6 +7,7 @@ import com.yahoo.config.model.api.ServiceInfo; import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.provision.ClusterSpec; import com.yahoo.vespa.model.VespaModel; +import com.yahoo.vespa.model.application.validation.ValidationTester; import com.yahoo.vespa.model.content.utils.ApplicationPackageBuilder; import com.yahoo.vespa.model.content.utils.ContentClusterBuilder; import com.yahoo.vespa.model.content.utils.DocType; @@ -69,8 +70,8 @@ public class StreamingSchemaClusterChangeValidatorTest { } public List<ConfigChangeAction> validate() { - return normalizeServicesInActions(validator.validate(currentModel, nextModel, - new DeployState.Builder().build())); + return normalizeServicesInActions(ValidationTester.validateChanges(validator, nextModel, + new DeployState.Builder().previousModel(currentModel).build())); } public void assertValidation() { diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/EmbedderTestCase.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/EmbedderTestCase.java index 138bef3ae73..2532a5be863 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/EmbedderTestCase.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/EmbedderTestCase.java @@ -12,6 +12,7 @@ import com.yahoo.config.model.deploy.DeployState; import com.yahoo.config.model.deploy.TestProperties; import com.yahoo.embedding.BertBaseEmbedderConfig; import com.yahoo.embedding.ColBertEmbedderConfig; +import com.yahoo.embedding.SpladeEmbedderConfig; import com.yahoo.embedding.huggingface.HuggingFaceEmbedderConfig; import com.yahoo.language.huggingface.config.HuggingFaceTokenizerConfig; import com.yahoo.path.Path; @@ -24,6 +25,7 @@ import com.yahoo.vespa.model.container.component.BertEmbedder; import com.yahoo.vespa.model.container.component.ColBertEmbedder; import com.yahoo.vespa.model.container.component.Component; import com.yahoo.vespa.model.container.component.HuggingFaceEmbedder; +import com.yahoo.vespa.model.container.component.SpladeEmbedder; import com.yahoo.vespa.model.container.component.HuggingFaceTokenizer; import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithFilePkg; import com.yahoo.yolean.Exceptions; @@ -101,6 +103,23 @@ public class EmbedderTestCase { assertEquals(-1, tokenizerCfg.maxLength()); } + @Test + void spladeEmbedder_selfhosted() throws Exception { + var model = loadModel(Path.fromString("src/test/cfg/application/embed/"), false); + var cluster = model.getContainerClusters().get("container"); + var embedderCfg = assertSpladeEmbedderComponentPresent(cluster); + + assertEquals("my_input_ids", embedderCfg.transformerInputIds()); + assertEquals("https://my/url/model.onnx", modelReference(embedderCfg, "transformerModel").url().orElseThrow().value()); + assertEquals(0.2, embedderCfg.termScoreThreshold()); + assertEquals(1024, embedderCfg.transformerMaxTokens()); + + var tokenizerCfg = assertHuggingfaceTokenizerComponentPresent(cluster); + assertEquals("https://my/url/tokenizer.json", modelReference(tokenizerCfg.model().get(0), "path").url().orElseThrow().value()); + assertEquals(-1, tokenizerCfg.maxLength()); + } + + @Test void colBertEmbedder_selfhosted() throws Exception { var model = loadModel(Path.fromString("src/test/cfg/application/embed/"), false); var cluster = model.getContainerClusters().get("container"); @@ -113,6 +132,7 @@ public class EmbedderTestCase { assertEquals(-1, tokenizerCfg.maxLength()); } + @Test void colBertEmbedder_hosted() throws Exception { var model = loadModel(Path.fromString("src/test/cfg/application/embed/"), true); var cluster = model.getContainerClusters().get("container"); @@ -266,13 +286,21 @@ public class EmbedderTestCase { } private static ColBertEmbedderConfig assertColBertEmbedderComponentPresent(ApplicationContainerCluster cluster) { - var colbert = (ColBertEmbedder) cluster.getComponentsMap().get(new ComponentId("colbert-embedder")); + var colbert = (ColBertEmbedder) cluster.getComponentsMap().get(new ComponentId("colbert")); assertEquals("ai.vespa.embedding.ColBertEmbedder", colbert.getClassId().getName()); var cfgBuilder = new ColBertEmbedderConfig.Builder(); colbert.getConfig(cfgBuilder); return cfgBuilder.build(); } + private static SpladeEmbedderConfig assertSpladeEmbedderComponentPresent(ApplicationContainerCluster cluster) { + var splade = (SpladeEmbedder) cluster.getComponentsMap().get(new ComponentId("splade")); + assertEquals("ai.vespa.embedding.SpladeEmbedder", splade.getClassId().getName()); + var cfgBuilder = new SpladeEmbedderConfig.Builder(); + splade.getConfig(cfgBuilder); + return cfgBuilder.build(); + } + private static BertBaseEmbedderConfig assertBertEmbedderComponentPresent(ApplicationContainerCluster cluster) { var bertEmbedder = (BertEmbedder) cluster.getComponentsMap().get(new ComponentId("bert-embedder")); assertEquals("ai.vespa.embedding.BertBaseEmbedder", bertEmbedder.getClassId().getName()); diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ModelIdResolverTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ModelIdResolverTest.java new file mode 100644 index 00000000000..409c3ac833a --- /dev/null +++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/ModelIdResolverTest.java @@ -0,0 +1,35 @@ +package com.yahoo.vespa.model.container.xml; + +import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.config.model.deploy.TestProperties; +import org.junit.jupiter.api.Test; + +import java.util.Optional; +import java.util.Set; + +import static com.yahoo.vespa.model.container.xml.ModelIdResolver.HF_TOKENIZER; +import static com.yahoo.vespa.model.container.xml.ModelIdResolver.ONNX_MODEL; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * @author bjorncs + */ +class ModelIdResolverTest { + + @Test + void throws_on_known_model_with_missing_tags() { + var state = new DeployState.Builder().properties(new TestProperties().setHostedVespa(true)).build(); + var e = assertThrows(IllegalArgumentException.class, () -> + ModelIdResolver.resolveToModelReference( + "param", Optional.of("minilm-l6-v2"), Optional.empty(), Optional.empty(), Set.of(HF_TOKENIZER), state)); + var expectedMsg = "Model 'minilm-l6-v2' on 'param' has tags [onnx-model] but are missing required tags [huggingface-tokenizer]"; + assertEquals(expectedMsg, e.getMessage()); + + assertDoesNotThrow( + () -> ModelIdResolver.resolveToModelReference( + "param", Optional.of("minilm-l6-v2"), Optional.empty(), Optional.empty(), Set.of(ONNX_MODEL), state)); + } + +}
\ No newline at end of file diff --git a/config-model/src/test/java/com/yahoo/vespa/model/content/utils/SchemaBuilder.java b/config-model/src/test/java/com/yahoo/vespa/model/content/utils/SchemaBuilder.java index 6defca17bcb..304f3dc426f 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/content/utils/SchemaBuilder.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/content/utils/SchemaBuilder.java @@ -3,7 +3,6 @@ package com.yahoo.vespa.model.content.utils; import java.util.Arrays; import java.util.List; -import java.util.stream.Collectors; import static com.yahoo.config.model.test.TestUtil.joinLines; diff --git a/config-model/src/test/resources/cloud-clients-validator/cert-with-empty-sequence-of-extensions.pem b/config-model/src/test/resources/cloud-clients-validator/cert-with-empty-sequence-of-extensions.pem new file mode 100644 index 00000000000..1942c12b28e --- /dev/null +++ b/config-model/src/test/resources/cloud-clients-validator/cert-with-empty-sequence-of-extensions.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBPDCB46ADAgECAhEAhdEB3eHnsQxTdcYcClVpkzAKBggqhkjOPQQDAjAeMRww +GgYDVQQDExNjbG91ZC52ZXNwYS5leGFtcGxlMB4XDTIyMTIyMTE4NTg0MloXDTMy +MTIxODE4NTg0MlowHjEcMBoGA1UEAxMTY2xvdWQudmVzcGEuZXhhbXBsZTBZMBMG +ByqGSM49AgEGCCqGSM49AwEHA0IABOPzpGlb+4HvgsRT5Ic6gmzYqAE2GQrgfi5z +txf8yzoi5YqgEG6utFhjleQ5bUusDhMtrfOJoBL5VZxrQccmwsCjAjAAMAoGCCqG +SM49BAMCA0gAMEUCIQCuNXMk5lsb9lF2IloYZB2wAHme/xAOyQ2arWzZf6BH2wIg +dEsmbGhel9MLlfPVQjeUwCJha/XD7xfWW6IaL+hI5TQ= +-----END CERTIFICATE----- diff --git a/config-model/src/test/resources/cloud-clients-validator/valid-cert.pem b/config-model/src/test/resources/cloud-clients-validator/valid-cert.pem new file mode 100644 index 00000000000..aebec508772 --- /dev/null +++ b/config-model/src/test/resources/cloud-clients-validator/valid-cert.pem @@ -0,0 +1,9 @@ +-----BEGIN CERTIFICATE----- +MIIBNzCB3qADAgECAhB00FXOPRoixiJghCsT2FVOMAoGCCqGSM49BAMCMB4xHDAa +BgNVBAMTE2Nsb3VkLnZlc3BhLmV4YW1wbGUwHhcNMjQwMTA0MTM0MTMwWhcNMzQw +MTAxMTM0MTMwWjAeMRwwGgYDVQQDExNjbG91ZC52ZXNwYS5leGFtcGxlMFkwEwYH +KoZIzj0CAQYIKoZIzj0DAQcDQgAEts/fYf1H+aOW4xZHtcxX2YvMWojzU4HvHw1b +9Zc+7OoUcoqv9dTZMVaYj3J8Z3A73wNn5rhjPrI4sKtI5KN6sjAKBggqhkjOPQQD +AgNIADBFAiEAqgs4QouJOf6ny48o5c6EZSTB3+iNyZr+23JXKwnYuUkCIFRtE736 +BJ5KdCPpI4jS611HgeLLlJmgF2524Gz4EpjH +-----END CERTIFICATE----- |