Remove legacy type endpoints in favor of catalogs
This commit is contained in:
parent
41c2f844be
commit
f729c8a460
|
|
@ -38,9 +38,7 @@ public class SecurityConfig {
|
|||
.requestMatchers("/v3/api-docs/**").permitAll()
|
||||
.requestMatchers("/actuator/**").permitAll()
|
||||
.requestMatchers("/error").permitAll()
|
||||
.requestMatchers("/blocks/types").permitAll()
|
||||
.requestMatchers("/blocks/types/**").permitAll()
|
||||
.requestMatchers("/containers/types").permitAll()
|
||||
.requestMatchers("/containers/types/**").permitAll()
|
||||
.requestMatchers("/retriever/**").permitAll()
|
||||
.anyRequest().authenticated())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,184 @@
|
|||
package it.cnr.isti.workflow.manager.blocks.configurations;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
@Component
|
||||
public class JsonSchemaCatalogBundler {
|
||||
|
||||
private static final String DEFINITIONS_FIELD = "definitions";
|
||||
private static final String DEFS_FIELD = "$defs";
|
||||
private static final String SHARED_DEFINITIONS_FIELD = "sharedDefinitions";
|
||||
private static final String DEFINITIONS_REF_PREFIX = "#/definitions/";
|
||||
private static final String DEFS_REF_PREFIX = "#/$defs/";
|
||||
private static final String SHARED_DEFINITIONS_REF_PREFIX = "#/" + SHARED_DEFINITIONS_FIELD + "/";
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public JsonSchemaCatalogBundler(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
public record SchemaBundle(ObjectNode sharedDefinitions, List<JsonNode> schemas) {
|
||||
}
|
||||
|
||||
public SchemaBundle bundle(List<? extends JsonNode> sourceSchemas) {
|
||||
List<JsonNode> schemas = new ArrayList<>(sourceSchemas.size());
|
||||
for (JsonNode schema : sourceSchemas) {
|
||||
schemas.add(schema == null ? null : schema.deepCopy());
|
||||
}
|
||||
|
||||
Map<String, JsonNode> sharedDefinitions = collectSharedDefinitions(schemas);
|
||||
if (sharedDefinitions.isEmpty()) {
|
||||
return new SchemaBundle(objectMapper.createObjectNode(), schemas);
|
||||
}
|
||||
|
||||
Set<String> sharedNames = sharedDefinitions.keySet();
|
||||
ObjectNode sharedDefinitionsNode = objectMapper.createObjectNode();
|
||||
for (Entry<String, JsonNode> entry : sharedDefinitions.entrySet()) {
|
||||
JsonNode definition = entry.getValue().deepCopy();
|
||||
rewriteSharedRefs(definition, sharedNames);
|
||||
sharedDefinitionsNode.set(entry.getKey(), definition);
|
||||
}
|
||||
|
||||
for (JsonNode schema : schemas) {
|
||||
if (!(schema instanceof ObjectNode root)) {
|
||||
continue;
|
||||
}
|
||||
rewriteSharedRefs(root, sharedNames);
|
||||
removeSharedDefinitions(root, sharedNames);
|
||||
}
|
||||
|
||||
return new SchemaBundle(sharedDefinitionsNode, schemas);
|
||||
}
|
||||
|
||||
private Map<String, JsonNode> collectSharedDefinitions(List<JsonNode> schemas) {
|
||||
Map<String, DefinitionStats> definitionsByName = new LinkedHashMap<>();
|
||||
for (JsonNode schema : schemas) {
|
||||
ObjectNode definitions = definitionsNode(schema);
|
||||
if (definitions == null) {
|
||||
continue;
|
||||
}
|
||||
for (Entry<String, JsonNode> entry : iterable(definitions.fields())) {
|
||||
definitionsByName
|
||||
.computeIfAbsent(entry.getKey(), ignored -> new DefinitionStats())
|
||||
.register(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, JsonNode> sharedDefinitions = new LinkedHashMap<>();
|
||||
for (Entry<String, DefinitionStats> entry : definitionsByName.entrySet()) {
|
||||
if (entry.getValue().isShareable()) {
|
||||
sharedDefinitions.put(entry.getKey(), entry.getValue().sample());
|
||||
}
|
||||
}
|
||||
return sharedDefinitions;
|
||||
}
|
||||
|
||||
private void rewriteSharedRefs(JsonNode node, Set<String> sharedNames) {
|
||||
if (node instanceof ObjectNode objectNode) {
|
||||
JsonNode refNode = objectNode.get("$ref");
|
||||
if (refNode != null && refNode.isTextual()) {
|
||||
String rewritten = rewriteSharedRef(refNode.asText(), sharedNames);
|
||||
if (!rewritten.equals(refNode.asText())) {
|
||||
objectNode.put("$ref", rewritten);
|
||||
}
|
||||
}
|
||||
for (JsonNode child : iterable(objectNode.elements())) {
|
||||
rewriteSharedRefs(child, sharedNames);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (node instanceof ArrayNode arrayNode) {
|
||||
for (JsonNode child : arrayNode) {
|
||||
rewriteSharedRefs(child, sharedNames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String rewriteSharedRef(String ref, Set<String> sharedNames) {
|
||||
if (ref.startsWith(DEFINITIONS_REF_PREFIX)) {
|
||||
String definitionName = ref.substring(DEFINITIONS_REF_PREFIX.length());
|
||||
if (sharedNames.contains(definitionName)) {
|
||||
return SHARED_DEFINITIONS_REF_PREFIX + definitionName;
|
||||
}
|
||||
}
|
||||
if (ref.startsWith(DEFS_REF_PREFIX)) {
|
||||
String definitionName = ref.substring(DEFS_REF_PREFIX.length());
|
||||
if (sharedNames.contains(definitionName)) {
|
||||
return SHARED_DEFINITIONS_REF_PREFIX + definitionName;
|
||||
}
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
private void removeSharedDefinitions(ObjectNode root, Set<String> sharedNames) {
|
||||
ObjectNode definitions = definitionsNode(root);
|
||||
if (definitions == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
sharedNames.forEach(definitions::remove);
|
||||
if (definitions.isEmpty()) {
|
||||
if (root.has(DEFINITIONS_FIELD)) {
|
||||
root.remove(DEFINITIONS_FIELD);
|
||||
}
|
||||
if (root.has(DEFS_FIELD)) {
|
||||
root.remove(DEFS_FIELD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ObjectNode definitionsNode(JsonNode schema) {
|
||||
if (!(schema instanceof ObjectNode root)) {
|
||||
return null;
|
||||
}
|
||||
JsonNode definitions = root.get(DEFINITIONS_FIELD);
|
||||
if (definitions instanceof ObjectNode objectNode) {
|
||||
return objectNode;
|
||||
}
|
||||
JsonNode defs = root.get(DEFS_FIELD);
|
||||
if (defs instanceof ObjectNode objectNode) {
|
||||
return objectNode;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static <T> Iterable<T> iterable(java.util.Iterator<T> iterator) {
|
||||
return () -> iterator;
|
||||
}
|
||||
|
||||
private static final class DefinitionStats {
|
||||
private int occurrences;
|
||||
private final Set<String> fingerprints = new LinkedHashSet<>();
|
||||
private JsonNode sample;
|
||||
|
||||
void register(JsonNode definition) {
|
||||
occurrences++;
|
||||
fingerprints.add(definition.toString());
|
||||
if (sample == null) {
|
||||
sample = definition.deepCopy();
|
||||
}
|
||||
}
|
||||
|
||||
boolean isShareable() {
|
||||
return occurrences >= 2 && fingerprints.size() == 1;
|
||||
}
|
||||
|
||||
JsonNode sample() {
|
||||
return sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
import it.cnr.isti.workflow.manager.app.ObjectMapperHolder;
|
||||
import it.cnr.isti.workflow.manager.blocks.Block;
|
||||
import it.cnr.isti.workflow.manager.blocks.configurations.BlockConfiguration;
|
||||
import it.cnr.isti.workflow.manager.blocks.configurations.JsonSchemaCatalogBundler;
|
||||
import it.cnr.isti.workflow.manager.blocks.configurations.JsonSchemaProducer;
|
||||
import it.cnr.isti.workflow.manager.blocks.factories.BlockFactory;
|
||||
import it.cnr.isti.workflow.manager.blocks.types.BlockType;
|
||||
|
|
@ -13,6 +14,7 @@ import it.cnr.isti.workflow.manager.executions.design.FlowSharedVariableCatalogS
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.IntStream;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
|
@ -24,6 +26,7 @@ import org.eclipse.microprofile.openapi.annotations.Operation;
|
|||
import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
|
||||
import org.springframework.web.server.ResponseStatusException;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
@RestController
|
||||
|
|
@ -42,6 +45,9 @@ public class BlocksController {
|
|||
@Autowired
|
||||
JsonSchemaProducer schemaProducer;
|
||||
|
||||
@Autowired
|
||||
JsonSchemaCatalogBundler schemaCatalogBundler;
|
||||
|
||||
@Autowired
|
||||
FlowSharedVariableCatalogService flowSharedVariableCatalogService;
|
||||
|
||||
|
|
@ -57,6 +63,11 @@ public class BlocksController {
|
|||
Object schema) {
|
||||
}
|
||||
|
||||
public record BlockConfigurationCatalog(
|
||||
JsonNode sharedDefinitions,
|
||||
List<BlockConfigurationDescriptor> descriptors) {
|
||||
}
|
||||
|
||||
public record InteractionContractDescriptor(
|
||||
String kind,
|
||||
String messageField,
|
||||
|
|
@ -66,19 +77,38 @@ public class BlocksController {
|
|||
boolean supportsPartialResult) {
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("types")
|
||||
@Operation(summary = "Get block types", description = "Returns all block types with their configuration descriptor and JSON schema.")
|
||||
public List<BlockConfigurationDescriptor> getTypes() {
|
||||
return blockTypes.values().stream().map(this::toDescriptor).toList();
|
||||
}
|
||||
|
||||
@GetMapping("/types/catalog")
|
||||
@Operation(summary = "Get compact block type catalog", description = "Returns all block types with JSON schemas compacted through shared schema definitions.")
|
||||
public BlockConfigurationCatalog getTypeCatalog() {
|
||||
List<BlockConfigurationDescriptor> descriptors = getTypes();
|
||||
JsonSchemaCatalogBundler.SchemaBundle bundle = schemaCatalogBundler.bundle(descriptors.stream()
|
||||
.map(BlockConfigurationDescriptor::schema)
|
||||
.map(schema -> schema instanceof JsonNode jsonNode ? jsonNode : null)
|
||||
.toList());
|
||||
|
||||
List<BlockConfigurationDescriptor> compactDescriptors = IntStream.range(0, descriptors.size())
|
||||
.mapToObj(index -> withSchema(descriptors.get(index), bundle.schemas().get(index)))
|
||||
.toList();
|
||||
|
||||
return new BlockConfigurationCatalog(bundle.sharedDefinitions(), compactDescriptors);
|
||||
}
|
||||
|
||||
@GetMapping("/types/configurations/descriptors")
|
||||
@Operation(summary = "Get block configuration descriptors", description = "Alias of /blocks/types. Returns one descriptor for each block type, including JSON schema.")
|
||||
@Operation(summary = "Get block configuration descriptors", description = "Returns one descriptor for each block type, including JSON schema.")
|
||||
public List<BlockConfigurationDescriptor> getConfigurationDescriptors() {
|
||||
return getTypes();
|
||||
}
|
||||
|
||||
@GetMapping("/types/configurations/catalog")
|
||||
@Operation(summary = "Get compact block configuration descriptors", description = "Alias of /blocks/types/catalog. Returns one compact descriptor for each block type, with shared schema definitions lifted to the response root.")
|
||||
public BlockConfigurationCatalog getConfigurationCatalog() {
|
||||
return getTypeCatalog();
|
||||
}
|
||||
|
||||
@GetMapping("/types/{type}/configuration/descriptor")
|
||||
@Operation(summary = "Get block configuration descriptor by type", description = "Returns the descriptor and JSON schema for the requested block type.")
|
||||
public BlockConfigurationDescriptor getConfigurationDescriptorForType(@PathVariable String type) {
|
||||
|
|
@ -139,6 +169,19 @@ public class BlocksController {
|
|||
return "/blocks/types/" + blockType.getName() + "/example";
|
||||
}
|
||||
|
||||
private BlockConfigurationDescriptor withSchema(BlockConfigurationDescriptor descriptor, JsonNode schema) {
|
||||
return new BlockConfigurationDescriptor(
|
||||
descriptor.type(),
|
||||
descriptor.description(),
|
||||
descriptor.userInteractive(),
|
||||
descriptor.interactionContract(),
|
||||
descriptor.hasExampleBlock(),
|
||||
descriptor.exampleBlockEndpoint(),
|
||||
descriptor.configurationType(),
|
||||
descriptor.configurationClass(),
|
||||
schema);
|
||||
}
|
||||
|
||||
private InteractionContractDescriptor resolveInteractionContract(BlockType blockType) {
|
||||
if ("ChatInteraction".equals(blockType.getName()) || "MCPAgentChat".equals(blockType.getName())) {
|
||||
return new InteractionContractDescriptor(
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package it.cnr.isti.workflow.manager.controllers;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.eclipse.microprofile.openapi.annotations.Operation;
|
||||
import org.eclipse.microprofile.openapi.annotations.security.SecurityRequirement;
|
||||
|
|
@ -21,9 +22,11 @@ import it.cnr.isti.workflow.manager.containers.factories.ContainerFactory;
|
|||
import it.cnr.isti.workflow.manager.containers.iresolvers.ContainerFlowInterfaceResolver;
|
||||
import it.cnr.isti.workflow.manager.containers.types.ContainerType;
|
||||
import it.cnr.isti.workflow.manager.blocks.configurations.JsonSchemaProducer;
|
||||
import it.cnr.isti.workflow.manager.blocks.configurations.JsonSchemaCatalogBundler;
|
||||
import it.cnr.isti.workflow.manager.flows.model.FlowData;
|
||||
import it.cnr.isti.workflow.manager.flows.validation.ValidationError;
|
||||
import it.cnr.isti.workflow.manager.ios.IODescriptor;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/containers")
|
||||
|
|
@ -35,16 +38,20 @@ public class ContainersController {
|
|||
|
||||
JsonSchemaProducer schemaProducer;
|
||||
|
||||
private final JsonSchemaCatalogBundler schemaCatalogBundler;
|
||||
|
||||
private final ContainerSubFlowValidator containerSubFlowValidator;
|
||||
|
||||
public ContainersController(
|
||||
Map<String, ContainerType> containerTypes,
|
||||
List<ContainerFactory<?, ?>> containerFactories,
|
||||
JsonSchemaProducer schemaProducer,
|
||||
JsonSchemaCatalogBundler schemaCatalogBundler,
|
||||
ContainerSubFlowValidator containerSubFlowValidator) {
|
||||
this.containerTypes = containerTypes;
|
||||
this.containerFactories = containerFactories;
|
||||
this.schemaProducer = schemaProducer;
|
||||
this.schemaCatalogBundler = schemaCatalogBundler;
|
||||
this.containerSubFlowValidator = containerSubFlowValidator;
|
||||
}
|
||||
|
||||
|
|
@ -59,6 +66,11 @@ public class ContainersController {
|
|||
Object schema) {
|
||||
}
|
||||
|
||||
public record ContainerConfigurationCatalog(
|
||||
JsonNode sharedDefinitions,
|
||||
List<ContainerConfigurationDescriptor> descriptors) {
|
||||
}
|
||||
|
||||
public static class ContainerSubFlowValidationRequest {
|
||||
private FlowData subFlow;
|
||||
|
||||
|
|
@ -88,12 +100,26 @@ public class ContainersController {
|
|||
List<ContainerHandleDescriptor> openOutputs) {
|
||||
}
|
||||
|
||||
@GetMapping("types")
|
||||
@Operation(summary = "Get container types", description = "Returns all container types with their configuration descriptor and JSON schema.")
|
||||
public List<ContainerConfigurationDescriptor> getTypes() {
|
||||
return containerTypes.values().stream().map(this::toDescriptor).toList();
|
||||
}
|
||||
|
||||
@GetMapping("types/catalog")
|
||||
@Operation(summary = "Get compact container type catalog", description = "Returns all container types with JSON schemas compacted through shared schema definitions.")
|
||||
public ContainerConfigurationCatalog getTypeCatalog() {
|
||||
List<ContainerConfigurationDescriptor> descriptors = getTypes();
|
||||
JsonSchemaCatalogBundler.SchemaBundle bundle = schemaCatalogBundler.bundle(descriptors.stream()
|
||||
.map(ContainerConfigurationDescriptor::schema)
|
||||
.map(schema -> schema instanceof JsonNode jsonNode ? jsonNode : null)
|
||||
.toList());
|
||||
|
||||
List<ContainerConfigurationDescriptor> compactDescriptors = IntStream.range(0, descriptors.size())
|
||||
.mapToObj(index -> withSchema(descriptors.get(index), bundle.schemas().get(index)))
|
||||
.toList();
|
||||
|
||||
return new ContainerConfigurationCatalog(bundle.sharedDefinitions(), compactDescriptors);
|
||||
}
|
||||
|
||||
@GetMapping("/types/{type}/example")
|
||||
@Operation(summary = "Get container example by type", description = "Returns an empty example container for the requested container type.")
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
@ -139,6 +165,7 @@ public class ContainersController {
|
|||
private ContainerHandleDescriptor toHandle(ContainerFlowInterfaceResolver.OpenHandle handle) {
|
||||
return new ContainerHandleDescriptor(handle.blockId(), handle.blockName(), handle.io());
|
||||
}
|
||||
|
||||
private ContainerConfigurationDescriptor toDescriptor(ContainerType containerType) {
|
||||
Class<? extends ContainerConfiguration<?>> configurationClass = containerType.getContainerConfigurationClass();
|
||||
return new ContainerConfigurationDescriptor(
|
||||
|
|
@ -151,4 +178,16 @@ public class ContainersController {
|
|||
configurationClass == null ? null : configurationClass.getName(),
|
||||
configurationClass == null ? null : schemaProducer.generateSchemaNode(configurationClass));
|
||||
}
|
||||
|
||||
private ContainerConfigurationDescriptor withSchema(ContainerConfigurationDescriptor descriptor, JsonNode schema) {
|
||||
return new ContainerConfigurationDescriptor(
|
||||
descriptor.type(),
|
||||
descriptor.description(),
|
||||
descriptor.userInteractive(),
|
||||
descriptor.hasExampleContainer(),
|
||||
descriptor.exampleContainerEndpoint(),
|
||||
descriptor.configurationType(),
|
||||
descriptor.configurationClass(),
|
||||
schema);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
|
|
@ -59,6 +60,9 @@ public class BlocksControllerTest {
|
|||
@Autowired
|
||||
private ExecutionVariablesFieldRetriever executionVariablesFieldRetriever;
|
||||
|
||||
@Autowired
|
||||
private RequestMappingHandlerMapping requestMappingHandlerMapping;
|
||||
|
||||
private LLMDescriptor simulatorDescriptor() {
|
||||
return LLMDescriptor.builder()
|
||||
.provider("testProvider")
|
||||
|
|
@ -78,6 +82,35 @@ public class BlocksControllerTest {
|
|||
System.out.println("Type: " + type.type());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTypeCatalogExtractsSharedBlockDefinitions() {
|
||||
BlocksController.BlockConfigurationCatalog catalog = blocksController.getTypeCatalog();
|
||||
|
||||
assertNotNull(catalog);
|
||||
assertNotNull(catalog.sharedDefinitions());
|
||||
assertTrue(catalog.sharedDefinitions().has("LLMDescriptor"));
|
||||
assertEquals(blocksController.getTypes().size(), catalog.descriptors().size());
|
||||
|
||||
JsonNode llmSchema = (JsonNode) catalog.descriptors().stream()
|
||||
.filter(type -> LLMBlockType.TYPE.equals(type.type()))
|
||||
.findFirst()
|
||||
.orElseThrow()
|
||||
.schema();
|
||||
|
||||
assertEquals("#/sharedDefinitions/LLMDescriptor",
|
||||
llmSchema.path("properties").path("llmDescriptor").path("$ref").asText());
|
||||
assertFalse(llmSchema.path("definitions").has("LLMDescriptor"));
|
||||
assertEquals("/retriever/LLM/providers",
|
||||
catalog.sharedDefinitions().path("LLMDescriptor").path("properties").path("provider").path("x-retriever-url").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void blockTypesListEndpointIsNotRegistered() {
|
||||
assertFalse(requestMappingHandlerMapping.getHandlerMethods().keySet().stream()
|
||||
.flatMap(info -> info.getPatternValues().stream())
|
||||
.anyMatch("/blocks/types"::equals));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void create(){
|
||||
LLMBlockConfiguration config = LLMBlockConfiguration.builder()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import org.junit.jupiter.api.Test;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
|
||||
|
|
@ -39,6 +40,9 @@ public class ContainersControllerTest {
|
|||
@Autowired
|
||||
private BlocksController blocksController;
|
||||
|
||||
@Autowired
|
||||
private RequestMappingHandlerMapping requestMappingHandlerMapping;
|
||||
|
||||
@Test
|
||||
public void getTypes() {
|
||||
List<ContainersController.ContainerConfigurationDescriptor> types = containersController.getTypes();
|
||||
|
|
@ -51,6 +55,44 @@ public class ContainersControllerTest {
|
|||
assertTrue(types.stream().allMatch(type -> type.exampleContainerEndpoint().equals("/containers/types/" + type.type() + "/example")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTypeCatalogExtractsSharedContainerDefinitions() {
|
||||
ContainersController.ContainerConfigurationCatalog catalog = containersController.getTypeCatalog();
|
||||
|
||||
assertNotNull(catalog);
|
||||
assertNotNull(catalog.sharedDefinitions());
|
||||
assertTrue(catalog.sharedDefinitions().has("FlowData"));
|
||||
assertTrue(catalog.sharedDefinitions().has("Position"));
|
||||
assertEquals(containersController.getTypes().size(), catalog.descriptors().size());
|
||||
|
||||
JsonNode genericSchema = (JsonNode) catalog.descriptors().stream()
|
||||
.filter(type -> GenericContainerType.TYPE.equals(type.type()))
|
||||
.findFirst()
|
||||
.orElseThrow()
|
||||
.schema();
|
||||
|
||||
assertEquals("#/sharedDefinitions/FlowData", genericSchema.path("properties").path("subFlow").path("$ref").asText());
|
||||
assertFalse(genericSchema.path("definitions").has("FlowData"));
|
||||
|
||||
JsonNode loopSchema = (JsonNode) catalog.descriptors().stream()
|
||||
.filter(type -> LoopContainerType.TYPE.equals(type.type()))
|
||||
.findFirst()
|
||||
.orElseThrow()
|
||||
.schema();
|
||||
|
||||
assertFalse(loopSchema.path("definitions").has("FlowData"));
|
||||
assertTrue(loopSchema.path("definitions").has("LLMDescriptor"));
|
||||
assertEquals("#/sharedDefinitions/IODescriptor",
|
||||
catalog.sharedDefinitions().path("FlowData").path("properties").path("globalInputs").path("items").path("$ref").asText());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void containerTypesListEndpointIsNotRegistered() {
|
||||
assertFalse(requestMappingHandlerMapping.getHandlerMethods().keySet().stream()
|
||||
.flatMap(info -> info.getPatternValues().stream())
|
||||
.anyMatch("/containers/types"::equals));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getGenericContainerExampleForType() {
|
||||
Container<GenericContainerType> container = containersController.getExampleForType(GenericContainerType.TYPE);
|
||||
|
|
|
|||
Loading…
Reference in New Issue