YAML model repository: supports only version 1 with elements as map (#4807)

* YAML model repository: supports only version 1 with elements as map

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo
2025-05-18 20:44:31 +02:00
committed by GitHub
parent 6ecd6c3891
commit 53ddb0c29c
24 changed files with 105 additions and 534 deletions
@@ -29,7 +29,6 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -61,7 +60,6 @@ import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
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.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
@@ -75,7 +73,7 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLParser;
*
* @author Laurent Garnier - Initial contribution
* @author Jan N. Klug - Refactored for multiple types per file and add modifying possibility
* @author Laurent Garnier - Introduce version 2 using map instead of table
* @author Laurent Garnier - Map used instead of table
* @author Laurent Garnier - Added basic version management
* @author Laurent Garnier - Added method generateSyntaxFromElements + new parameters
* for method isValid
@@ -83,7 +81,7 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLParser;
@NonNullByDefault
@Component(immediate = true)
public class YamlModelRepositoryImpl implements WatchService.WatchEventListener, YamlModelRepository {
private static final int DEFAULT_MODEL_VERSION = 2;
private static final int DEFAULT_MODEL_VERSION = 1;
private static final String VERSION = "version";
private static final String READ_ONLY = "readOnly";
private static final Set<String> KNOWN_ELEMENTS = Set.of( //
@@ -208,27 +206,19 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
newElementNames.add(elementName);
JsonNode node = element.getValue();
List<JsonNode> newNodeV1Elements = new ArrayList<>();
JsonNode newNodeElements = null;
if (modelVersion == 1) {
if (!node.isArray()) {
// all processable sub-elements are arrays
logger.trace("Element {} in model {} is not an array, ignoring it", elementName, modelName);
continue;
}
node.elements().forEachRemaining(newNodeV1Elements::add);
} else {
if (!node.isContainerNode() || node.isArray()) {
// all processable sub-elements are container nodes (not array)
logger.trace("Element {} in model {} is not a container object, ignoring it", elementName,
if (!node.isContainerNode() || node.isArray()) {
// all processable sub-elements are container nodes (not array)
logger.trace("Element {} in model {} is not a container object, ignoring it", elementName,
modelName);
if (getElementName(YamlSemanticTagDTO.class).equals(elementName) && node.isArray()) {
logger.warn(
"Your YAML model {} contains custom tags with an old and now unsupported syntax. An upgrade of this model is required to upgrade to the new syntax. This can be done by running the upgrade tool.",
modelName);
continue;
}
newNodeElements = node;
continue;
}
JsonNode newNodeElements = node;
List<JsonNode> oldNodeV1Elements = model.getNodesV1().getOrDefault(elementName, List.of());
JsonNode oldNodeElements = model.getNodes().get(elementName);
for (YamlModelListener<?> elementListener : getElementListeners(elementName, modelVersion)) {
@@ -238,9 +228,9 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
List<String> warnings = new ArrayList<>();
Map<String, ? extends YamlElement> oldElements = listToMap(
parseJsonNodes(oldNodeV1Elements, oldNodeElements, elementClass, null, null));
parseJsonMapNode(oldNodeElements, elementClass, null, null));
Map<String, ? extends YamlElement> newElements = listToMap(
parseJsonNodes(newNodeV1Elements, newNodeElements, elementClass, errors, warnings));
parseJsonMapNode(newNodeElements, elementClass, errors, warnings));
errors.forEach(error -> {
logger.warn("YAML model {}: {}", modelName, error);
@@ -276,47 +266,23 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
}
// replace cache
if (modelVersion == 1) {
model.getNodesV1().put(elementName, newNodeV1Elements);
} else {
model.getNodes().put(elementName, newNodeElements);
}
model.getNodes().put(elementName, newNodeElements);
}
// remove removed elements
if (modelVersion == 1) {
model.getNodesV1().entrySet().removeIf(e -> {
String elementName = e.getKey();
if (newElementNames.contains(elementName)) {
return false;
}
model.getNodes().entrySet().removeIf(e -> {
String elementName = e.getKey();
if (newElementNames.contains(elementName)) {
return false;
}
List<JsonNode> removedNodes = e.getValue();
if (removedNodes != null) {
getElementListeners(elementName, modelVersion).forEach(listener -> {
List removedElements = parseJsonNodesV1(removedNodes, listener.getElementClass(), null,
null);
listener.removedModel(modelName, removedElements);
});
}
return true;
JsonNode removedNode = e.getValue();
getElementListeners(elementName, modelVersion).forEach(listener -> {
List removedElements = parseJsonMapNode(removedNode, listener.getElementClass(), null, null);
listener.removedModel(modelName, removedElements);
});
} else {
model.getNodes().entrySet().removeIf(e -> {
String elementName = e.getKey();
if (newElementNames.contains(elementName)) {
return false;
}
JsonNode removedNode = e.getValue();
getElementListeners(elementName, modelVersion).forEach(listener -> {
List removedElements = parseJsonMapNode(removedNode, listener.getElementClass(), null,
null);
listener.removedModel(modelName, removedElements);
});
return true;
});
}
return true;
});
checkElementNames(modelName, model);
} else {
@@ -335,16 +301,6 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
}
logger.info("Removing YAML model {}", modelName);
int version = removedModel.getVersion();
for (Map.Entry<String, List<JsonNode>> modelEntry : removedModel.getNodesV1().entrySet()) {
String elementName = modelEntry.getKey();
List<JsonNode> removedNodes = modelEntry.getValue();
if (!removedNodes.isEmpty()) {
getElementListeners(elementName, version).forEach(listener -> {
List removedElements = parseJsonNodesV1(removedNodes, listener.getElementClass(), null, null);
listener.removedModel(modelName, removedElements);
});
}
}
for (Map.Entry<String, @Nullable JsonNode> modelEntry : removedModel.getNodes().entrySet()) {
String elementName = modelEntry.getKey();
JsonNode removedMapNode = modelEntry.getValue();
@@ -376,14 +332,13 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
"Element {} in model {} version {} is still supported but deprecated, please consider migrating your model to a more recent version",
elementName, modelName, modelVersion);
}
List<JsonNode> modelNodes = model.getNodesV1().getOrDefault(elementName, List.of());
JsonNode modelMapNode = model.getNodes().get(elementName);
if (modelNodes.isEmpty() && modelMapNode == null) {
if (modelMapNode == null) {
return;
}
List<String> errors = new ArrayList<>();
List<String> warnings = new ArrayList<>();
List modelElements = parseJsonNodes(modelNodes, modelMapNode, elementClass, errors, warnings);
List modelElements = parseJsonMapNode(modelMapNode, elementClass, errors, warnings);
errors.forEach(error -> {
logger.warn("YAML model {}: {}", modelName, error);
});
@@ -406,8 +361,7 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
private void checkElementNames(String modelName, YamlModelWrapper model) {
Set<String> elementListenerNames = elementListeners.keySet();
if (elementListenerNames.containsAll(KNOWN_ELEMENTS)) {
Set<String> modelElementNames = model.getVersion() == 1 ? model.getNodesV1().keySet()
: model.getNodes().keySet();
Set<String> modelElementNames = model.getNodes().keySet();
modelElementNames.stream().filter(e -> !KNOWN_ELEMENTS.contains(e)).forEach(unknownElement -> {
logger.warn("Element '{}' in model {} is unknown.", unknownElement, modelName);
});
@@ -435,29 +389,19 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
return;
}
List<JsonNode> addedNodes = new ArrayList<>();
JsonNode mapAddedNode = null;
if (model.getVersion() == 1) {
List<JsonNode> modelNodes = Objects
.requireNonNull(model.getNodesV1().computeIfAbsent(elementName, k -> new CopyOnWriteArrayList<>()));
JsonNode newNode = objectMapper.convertValue(element, JsonNode.class);
modelNodes.add(newNode);
addedNodes.add(newNode);
JsonNode mapAddedNode = objectMapper.valueToTree(Map.of(id, element.cloneWithoutId()));
JsonNode modelMapNode = model.getNodes().get(elementName);
if (modelMapNode == null) {
model.getNodes().put(elementName, mapAddedNode);
} else {
mapAddedNode = objectMapper.valueToTree(Map.of(id, element.cloneWithoutId()));
JsonNode modelMapNode = model.getNodes().get(elementName);
if (modelMapNode == null) {
model.getNodes().put(elementName, mapAddedNode);
} else {
JsonNode newNode = objectMapper.convertValue(element.cloneWithoutId(), JsonNode.class);
((ObjectNode) modelMapNode).set(id, newNode);
}
JsonNode newNode = objectMapper.convertValue(element.cloneWithoutId(), JsonNode.class);
((ObjectNode) modelMapNode).set(id, newNode);
}
// notify listeners
for (YamlModelListener<?> l : getElementListeners(elementName, model.getVersion())) {
List<String> errors = new ArrayList<>();
List<String> warnings = new ArrayList<>();
List newElements = parseJsonNodes(addedNodes, mapAddedNode, l.getElementClass(), errors, warnings);
List newElements = parseJsonMapNode(mapAddedNode, l.getElementClass(), errors, warnings);
errors.forEach(error -> {
logger.warn("YAML model {}: {}", modelName, error);
});
@@ -487,31 +431,21 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
return;
}
List<JsonNode> modelNodes = model.getNodesV1().get(elementName);
JsonNode modelMapNode = model.getNodes().get(elementName);
if (modelNodes == null && modelMapNode == null) {
if (modelMapNode == null) {
logger.warn("Failed to remove {} from model {} because type {} is not known in the model.", element,
modelName, elementName);
return;
}
JsonNode toRemove = modelNodes == null ? null : findNodeById(modelNodes, element.getClass(), id);
boolean found = modelMapNode == null ? false : modelMapNode.has(id);
if (toRemove == null && !found) {
if (!modelMapNode.has(id)) {
logger.warn("Failed to remove {} from model {} because element is not in model.", element, modelName);
return;
}
List<JsonNode> removedNodes = new ArrayList<>();
JsonNode mapRemovedNode = null;
if (toRemove != null) {
modelNodes.remove(toRemove);
removedNodes.add(toRemove);
} else if (found) {
((ObjectNode) modelMapNode).remove(id);
mapRemovedNode = objectMapper.valueToTree(Map.of(id, element.cloneWithoutId()));
}
((ObjectNode) modelMapNode).remove(id);
JsonNode mapRemovedNode = objectMapper.valueToTree(Map.of(id, element.cloneWithoutId()));
// notify listeners
for (YamlModelListener<?> l : getElementListeners(elementName, model.getVersion())) {
List oldElements = parseJsonNodes(removedNodes, mapRemovedNode, l.getElementClass(), null, null);
List oldElements = parseJsonMapNode(mapRemovedNode, l.getElementClass(), null, null);
if (!oldElements.isEmpty()) {
l.removedModel(modelName, oldElements);
}
@@ -535,35 +469,24 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
return;
}
List<JsonNode> modelNodes = model.getNodesV1().get(elementName);
JsonNode modelMapNode = model.getNodes().get(elementName);
if (modelNodes == null && modelMapNode == null) {
if (modelMapNode == null) {
logger.warn("Failed to update {} in model {} because type {} is not known in the model.", element,
modelName, elementName);
return;
}
JsonNode oldElement = modelNodes == null ? null : findNodeById(modelNodes, element.getClass(), id);
boolean found = modelMapNode == null ? false : modelMapNode.has(id);
if (oldElement == null && !found) {
if (!modelMapNode.has(id)) {
logger.warn("Failed to update {} in model {} because element is not in model.", element, modelName);
return;
}
List<JsonNode> updatedNodes = new ArrayList<>();
JsonNode mapUpdatedNode = null;
if (oldElement != null) {
JsonNode newNode = objectMapper.convertValue(element, JsonNode.class);
modelNodes.set(modelNodes.indexOf(oldElement), newNode);
updatedNodes.add(newNode);
} else if (found) {
JsonNode newNode = objectMapper.convertValue(element.cloneWithoutId(), JsonNode.class);
((ObjectNode) modelMapNode).set(id, newNode);
mapUpdatedNode = objectMapper.valueToTree(Map.of(id, element.cloneWithoutId()));
}
JsonNode newNode = objectMapper.convertValue(element.cloneWithoutId(), JsonNode.class);
((ObjectNode) modelMapNode).set(id, newNode);
JsonNode mapUpdatedNode = objectMapper.valueToTree(Map.of(id, element.cloneWithoutId()));
// notify listeners
for (YamlModelListener<?> l : getElementListeners(elementName, model.getVersion())) {
List<String> errors = new ArrayList<>();
List<String> warnings = new ArrayList<>();
List newElements = parseJsonNodes(updatedNodes, mapUpdatedNode, l.getElementClass(), errors, warnings);
List newElements = parseJsonMapNode(mapUpdatedNode, l.getElementClass(), errors, warnings);
errors.forEach(error -> {
logger.warn("YAML model {}: {}", modelName, error);
});
@@ -596,17 +519,9 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
rootNode.put(VERSION, model.getVersion());
rootNode.put(READ_ONLY, model.isReadOnly());
if (model.getVersion() == 1) {
for (Map.Entry<String, List<JsonNode>> elementNodes : model.getNodesV1().entrySet()) {
ArrayNode arrayNode = nodeFactory.arrayNode();
elementNodes.getValue().forEach(arrayNode::add);
rootNode.set(elementNodes.getKey(), arrayNode);
}
} else {
for (Map.Entry<String, @Nullable JsonNode> elementNodes : model.getNodes().entrySet()) {
if (elementNodes.getValue() != null) {
rootNode.set(elementNodes.getKey(), elementNodes.getValue());
}
for (Map.Entry<String, @Nullable JsonNode> elementNodes : model.getNodes().entrySet()) {
if (elementNodes.getValue() != null) {
rootNode.set(elementNodes.getKey(), elementNodes.getValue());
}
}
@@ -668,42 +583,10 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
return getElementListeners(elementName).stream().filter(l -> l.isVersionSupported(version)).toList();
}
// To be used only for version 1
private <T extends YamlElement> @Nullable JsonNode findNodeById(List<JsonNode> nodes, Class<T> elementClass,
String id) {
return nodes.stream().filter(node -> {
Optional<T> parsedNode = parseJsonNode(node, elementClass, null, null);
return parsedNode.filter(yamlDTO -> id.equals(yamlDTO.getId())).isPresent();
}).findAny().orElse(null);
}
private Map<String, ? extends YamlElement> listToMap(List<? extends YamlElement> elements) {
return elements.stream().collect(Collectors.toMap(YamlElement::getId, e -> e));
}
// To be used only for version 1
private <T extends YamlElement> List<T> parseJsonNodesV1(List<JsonNode> nodes, Class<T> elementClass,
@Nullable List<String> errors, @Nullable List<String> warnings) {
return nodes.stream().map(nE -> parseJsonNode(nE, elementClass, errors, warnings)).flatMap(Optional::stream)
.filter(elt -> elt.isValid(errors, warnings)).toList();
}
// To be used only for version 1
private <T extends YamlElement> Optional<T> parseJsonNode(JsonNode node, Class<T> elementClass,
@Nullable List<String> errors, @Nullable List<String> warnings) {
try {
return Optional.of(objectMapper.treeToValue(node, elementClass));
} catch (JsonProcessingException e) {
if (errors != null) {
String msg = e.getMessage();
errors.add("Could not parse element %s to %s: %s".formatted(node.toPrettyString(),
elementClass.getSimpleName(), msg == null ? "" : msg.replace(UNWANTED_EXCEPTION_TEXT, "")));
}
return Optional.empty();
}
}
// To be not used for version 1
private <T extends YamlElement> List<T> parseJsonMapNode(@Nullable JsonNode mapNode, Class<T> elementClass,
@Nullable List<String> errors, @Nullable List<String> warnings) {
List<T> elements = new ArrayList<>();
@@ -744,13 +627,4 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
}
return elements;
}
// Usable whatever the format version
private <T extends YamlElement> List<T> parseJsonNodes(List<JsonNode> nodes, @Nullable JsonNode mapNode,
Class<T> elementClass, @Nullable List<String> errors, @Nullable List<String> warnings) {
List<T> elements = new ArrayList<>();
elements.addAll(parseJsonNodesV1(nodes, elementClass, errors, warnings));
elements.addAll(parseJsonMapNode(mapNode, elementClass, errors, warnings));
return elements;
}
}
@@ -12,7 +12,6 @@
*/
package org.openhab.core.model.yaml.internal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -25,19 +24,12 @@ import com.fasterxml.jackson.databind.JsonNode;
* The {@link YamlModelWrapper} is used to store the information read from a model in the model cache.
*
* @author Jan N. Klug - Initial contribution
* @author Laurent Garnier - Introduce version 2 using map instead of table
* @author Laurent Garnier - Map used instead of table
*/
@NonNullByDefault
public class YamlModelWrapper {
private final int version;
private final boolean readOnly;
/**
* Nodes as a list in version 1
*/
private final Map<String, List<JsonNode>> nodesV1 = new ConcurrentHashMap<>();
/**
* Nodes as a map in version >= 2
*/
private final Map<String, @Nullable JsonNode> nodes = new ConcurrentHashMap<>();
public YamlModelWrapper(int version, boolean readOnly) {
@@ -53,20 +45,6 @@ public class YamlModelWrapper {
return readOnly;
}
/**
* Get the nodes for version 1
*
* @return the nodes
*/
public Map<String, List<JsonNode>> getNodesV1() {
return nodesV1;
}
/**
* Get the nodes for version >= 2
*
* @return the nodes
*/
public Map<String, @Nullable JsonNode> getNodes() {
return nodes;
}
@@ -157,7 +157,7 @@ public class YamlThingProvider extends AbstractProvider<Thing>
@Override
public boolean isVersionSupported(int version) {
return version >= 2;
return version >= 1;
}
@Override
@@ -60,13 +60,10 @@ public class YamlModelRepositoryImplTest {
private static final Path SOURCE_PATH = Path.of("src/test/resources/model");
private static final String MODEL_NAME = "model.yaml";
private static final Path MODEL_PATH = Path.of(MODEL_NAME);
private static final String MODEL2_NAME = "model2.yaml";
private static final Path MODEL2_PATH = Path.of(MODEL2_NAME);
private @Mock @NonNullByDefault({}) WatchService watchServiceMock;
private @TempDir @NonNullByDefault({}) Path watchPath;
private @NonNullByDefault({}) Path fullModelPath;
private @NonNullByDefault({}) Path fullModel2Path;
private @Mock @NonNullByDefault({}) YamlModelListener<@NonNull FirstTypeDTO> firstTypeListener;
private @Mock @NonNullByDefault({}) YamlModelListener<@NonNull SecondTypeDTO> secondTypeListener1;
@@ -79,7 +76,6 @@ public class YamlModelRepositoryImplTest {
@BeforeEach
public void setup() {
fullModelPath = watchPath.resolve(MODEL_PATH);
fullModel2Path = watchPath.resolve(MODEL2_PATH);
when(watchServiceMock.getWatchPath()).thenReturn(watchPath);
when(firstTypeListener.getElementClass()).thenReturn(FirstTypeDTO.class);
@@ -96,7 +92,6 @@ public class YamlModelRepositoryImplTest {
@Test
public void testFileAddedAfterListeners() throws IOException {
Files.copy(SOURCE_PATH.resolve("modelFileAddedOrRemoved.yaml"), fullModelPath);
Files.copy(SOURCE_PATH.resolve("modelV2FileAddedOrRemoved.yaml"), fullModel2Path);
YamlModelRepositoryImpl modelRepository = new YamlModelRepositoryImpl(watchServiceMock);
modelRepository.addYamlModelListener(firstTypeListener);
@@ -104,27 +99,23 @@ public class YamlModelRepositoryImplTest {
modelRepository.addYamlModelListener(secondTypeListener2);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModelPath);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModel2Path);
verify(firstTypeListener).addedModel(eq(MODEL_NAME), firstTypeCaptor.capture());
verify(firstTypeListener).addedModel(eq(MODEL2_NAME), firstTypeCaptor.capture());
verify(firstTypeListener, never()).updatedModel(any(), any());
verify(firstTypeListener, never()).removedModel(any(), any());
verify(secondTypeListener1).addedModel(eq(MODEL_NAME), secondTypeCaptor1.capture());
verify(secondTypeListener1).addedModel(eq(MODEL2_NAME), secondTypeCaptor1.capture());
verify(secondTypeListener1, never()).updatedModel(any(), any());
verify(secondTypeListener1, never()).removedModel(any(), any());
verify(secondTypeListener2).addedModel(eq(MODEL_NAME), secondTypeCaptor2.capture());
verify(secondTypeListener2).addedModel(eq(MODEL2_NAME), secondTypeCaptor2.capture());
verify(secondTypeListener2, never()).updatedModel(any(), any());
verify(secondTypeListener2, never()).removedModel(any(), any());
List<Collection<FirstTypeDTO>> firstTypeCaptorValues = firstTypeCaptor.getAllValues();
assertThat(firstTypeCaptorValues, hasSize(2));
assertThat(firstTypeCaptorValues, hasSize(1));
List<Collection<SecondTypeDTO>> secondTypeCaptor1Values = secondTypeCaptor1.getAllValues();
assertThat(secondTypeCaptor1Values, hasSize(2));
assertThat(secondTypeCaptor1Values, hasSize(1));
List<Collection<SecondTypeDTO>> secondTypeCaptor2Values = secondTypeCaptor2.getAllValues();
assertThat(secondTypeCaptor2Values, hasSize(2));
assertThat(secondTypeCaptor2Values, hasSize(1));
Collection<FirstTypeDTO> firstTypeElements = firstTypeCaptorValues.getFirst();
Collection<SecondTypeDTO> secondTypeElements1 = secondTypeCaptor1Values.getFirst();
@@ -137,53 +128,36 @@ public class YamlModelRepositoryImplTest {
assertThat(secondTypeElements1, contains(new SecondTypeDTO("Second1", "Label1")));
assertThat(secondTypeElements2, hasSize(1));
assertThat(secondTypeElements2, contains(new SecondTypeDTO("Second1", "Label1")));
firstTypeElements = firstTypeCaptorValues.get(1);
secondTypeElements1 = secondTypeCaptor1Values.get(1);
secondTypeElements2 = secondTypeCaptor2Values.get(1);
assertThat(firstTypeElements, hasSize(2));
assertThat(firstTypeElements,
containsInAnyOrder(new FirstTypeDTO("First1", "Description1"), new FirstTypeDTO("First2", null)));
assertThat(secondTypeElements1, hasSize(1));
assertThat(secondTypeElements1, contains(new SecondTypeDTO("Second1", "Label1")));
assertThat(secondTypeElements2, hasSize(1));
assertThat(secondTypeElements2, contains(new SecondTypeDTO("Second1", "Label1")));
}
@Test
public void testFileAddedBeforeListeners() throws IOException {
Files.copy(SOURCE_PATH.resolve("modelFileAddedOrRemoved.yaml"), fullModelPath);
Files.copy(SOURCE_PATH.resolve("modelV2FileAddedOrRemoved.yaml"), fullModel2Path);
YamlModelRepositoryImpl modelRepository = new YamlModelRepositoryImpl(watchServiceMock);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModelPath);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModel2Path);
modelRepository.addYamlModelListener(firstTypeListener);
modelRepository.addYamlModelListener(secondTypeListener1);
modelRepository.addYamlModelListener(secondTypeListener2);
verify(firstTypeListener).addedModel(eq(MODEL_NAME), firstTypeCaptor.capture());
verify(firstTypeListener).addedModel(eq(MODEL2_NAME), firstTypeCaptor.capture());
verify(firstTypeListener, never()).updatedModel(any(), any());
verify(firstTypeListener, never()).removedModel(any(), any());
verify(secondTypeListener1).addedModel(eq(MODEL_NAME), secondTypeCaptor1.capture());
verify(secondTypeListener1).addedModel(eq(MODEL2_NAME), secondTypeCaptor1.capture());
verify(secondTypeListener1, never()).updatedModel(any(), any());
verify(secondTypeListener1, never()).removedModel(any(), any());
verify(secondTypeListener2).addedModel(eq(MODEL_NAME), secondTypeCaptor2.capture());
verify(secondTypeListener2).addedModel(eq(MODEL2_NAME), secondTypeCaptor2.capture());
verify(secondTypeListener2, never()).updatedModel(any(), any());
verify(secondTypeListener2, never()).removedModel(any(), any());
List<Collection<FirstTypeDTO>> firstTypeCaptorValues = firstTypeCaptor.getAllValues();
assertThat(firstTypeCaptorValues, hasSize(2));
assertThat(firstTypeCaptorValues, hasSize(1));
List<Collection<SecondTypeDTO>> secondTypeCaptor1Values = secondTypeCaptor1.getAllValues();
assertThat(secondTypeCaptor1Values, hasSize(2));
assertThat(secondTypeCaptor1Values, hasSize(1));
List<Collection<SecondTypeDTO>> secondTypeCaptor2Values = secondTypeCaptor2.getAllValues();
assertThat(secondTypeCaptor2Values, hasSize(2));
assertThat(secondTypeCaptor2Values, hasSize(1));
Collection<FirstTypeDTO> firstTypeElements = firstTypeCaptorValues.getFirst();
Collection<SecondTypeDTO> secondTypeElements1 = secondTypeCaptor1Values.getFirst();
@@ -196,18 +170,6 @@ public class YamlModelRepositoryImplTest {
assertThat(secondTypeElements1, contains(new SecondTypeDTO("Second1", "Label1")));
assertThat(secondTypeElements2, hasSize(1));
assertThat(secondTypeElements2, contains(new SecondTypeDTO("Second1", "Label1")));
firstTypeElements = firstTypeCaptorValues.get(1);
secondTypeElements1 = secondTypeCaptor1Values.get(1);
secondTypeElements2 = secondTypeCaptor2Values.get(1);
assertThat(firstTypeElements, hasSize(2));
assertThat(firstTypeElements,
containsInAnyOrder(new FirstTypeDTO("First1", "Description1"), new FirstTypeDTO("First2", null)));
assertThat(secondTypeElements1, hasSize(1));
assertThat(secondTypeElements1, contains(new SecondTypeDTO("Second1", "Label1")));
assertThat(secondTypeElements2, hasSize(1));
assertThat(secondTypeElements2, contains(new SecondTypeDTO("Second1", "Label1")));
}
@Test
@@ -215,7 +177,6 @@ public class YamlModelRepositoryImplTest {
YamlModelRepositoryImpl modelRepository = new YamlModelRepositoryImpl(watchServiceMock);
modelRepository.addYamlModelListener(firstTypeListener);
// File in v1 format
Files.copy(SOURCE_PATH.resolve("modelFileUpdatePost.yaml"), fullModelPath);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModelPath);
verify(firstTypeListener).addedModel(eq(MODEL_NAME), any());
@@ -226,88 +187,43 @@ public class YamlModelRepositoryImplTest {
verify(firstTypeListener).updatedModel(eq(MODEL_NAME), firstTypeCaptor.capture());
verify(firstTypeListener).removedModel(eq(MODEL_NAME), firstTypeCaptor.capture());
// File in v2 format
Files.copy(SOURCE_PATH.resolve("modelV2FileUpdatePost.yaml"), fullModel2Path);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModel2Path);
verify(firstTypeListener).addedModel(eq(MODEL2_NAME), any());
Files.copy(SOURCE_PATH.resolve("modelV2FileUpdatePre.yaml"), fullModel2Path,
StandardCopyOption.REPLACE_EXISTING);
modelRepository.processWatchEvent(WatchService.Kind.MODIFY, fullModel2Path);
verify(firstTypeListener, times(2)).addedModel(eq(MODEL2_NAME), firstTypeCaptor.capture());
verify(firstTypeListener).updatedModel(eq(MODEL2_NAME), firstTypeCaptor.capture());
verify(firstTypeListener).removedModel(eq(MODEL2_NAME), firstTypeCaptor.capture());
List<Collection<FirstTypeDTO>> firstTypeCaptorValues = firstTypeCaptor.getAllValues();
assertThat(firstTypeCaptorValues, hasSize(8));
assertThat(firstTypeCaptorValues, hasSize(4));
// added originally - first file
// added originally
assertThat(firstTypeCaptorValues.getFirst(), hasSize(3));
assertThat(firstTypeCaptorValues.getFirst(), containsInAnyOrder(new FirstTypeDTO("First", "First original"),
new FirstTypeDTO("Second", "Second original"), new FirstTypeDTO("Third", "Third original")));
// added by update - first file
// added by update
assertThat(firstTypeCaptorValues.get(1), hasSize(1));
assertThat(firstTypeCaptorValues.get(1), contains(new FirstTypeDTO("Fourth", "Fourth original")));
// updated by update - first file
// updated by update
assertThat(firstTypeCaptorValues.get(2), hasSize(1));
assertThat(firstTypeCaptorValues.get(2), contains(new FirstTypeDTO("Second", "Second modified")));
// removed by update - first file
// removed by update
assertThat(firstTypeCaptorValues.get(3), hasSize(1));
assertThat(firstTypeCaptorValues.get(3), contains(new FirstTypeDTO("Third", "Third original")));
// added originally -second file
assertThat(firstTypeCaptorValues.get(4), hasSize(3));
assertThat(firstTypeCaptorValues.get(4), containsInAnyOrder(new FirstTypeDTO("First", "First original"),
new FirstTypeDTO("Second", "Second original"), new FirstTypeDTO("Third", "Third original")));
// added by update -second file
assertThat(firstTypeCaptorValues.get(5), hasSize(1));
assertThat(firstTypeCaptorValues.get(5), contains(new FirstTypeDTO("Fourth", "Fourth original")));
// updated by update -second file
assertThat(firstTypeCaptorValues.get(6), hasSize(1));
assertThat(firstTypeCaptorValues.get(6), contains(new FirstTypeDTO("Second", "Second modified")));
// removed by update -second file
assertThat(firstTypeCaptorValues.get(7), hasSize(1));
assertThat(firstTypeCaptorValues.get(7), contains(new FirstTypeDTO("Third", "Third original")));
}
@ParameterizedTest
@CsvSource({ //
"modelFileUpdateRemovedElements.yaml,modelV2FileUpdateRemovedElements.yaml",
"modelFileUpdateRenamedElements.yaml,modelV2FileUpdateRenamedElements.yaml",
"modelFileUpdateRemovedVersion.yaml,modelV2FileUpdateRemovedVersion.yaml" //
"modelFileUpdateRemovedElements.yaml", "modelFileUpdateRenamedElements.yaml",
"modelFileUpdateRemovedVersion.yaml" //
})
public void testFileRemovedElements(String v1File, String v2File) throws IOException {
public void testFileRemovedElements(String file) throws IOException {
YamlModelRepositoryImpl modelRepository = new YamlModelRepositoryImpl(watchServiceMock);
modelRepository.addYamlModelListener(firstTypeListener);
// File in v1 format
Files.copy(SOURCE_PATH.resolve("modelFileUpdatePost.yaml"), fullModelPath);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModelPath);
verify(firstTypeListener).addedModel(eq(MODEL_NAME), any());
Files.copy(SOURCE_PATH.resolve(v1File), fullModelPath, StandardCopyOption.REPLACE_EXISTING);
Files.copy(SOURCE_PATH.resolve(file), fullModelPath, StandardCopyOption.REPLACE_EXISTING);
modelRepository.processWatchEvent(WatchService.Kind.MODIFY, fullModelPath);
verify(firstTypeListener).removedModel(eq(MODEL_NAME), firstTypeCaptor.capture());
Collection<FirstTypeDTO> firstTypeElements = firstTypeCaptor.getAllValues().getFirst();
// Check that the elements were removed
assertThat(firstTypeElements, hasSize(3));
assertThat(firstTypeElements, containsInAnyOrder(new FirstTypeDTO("First", "First original"),
new FirstTypeDTO("Second", "Second original"), new FirstTypeDTO("Third", "Third original")));
// File in v2 format
Files.copy(SOURCE_PATH.resolve("modelV2FileUpdatePost.yaml"), fullModel2Path);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModel2Path);
verify(firstTypeListener).addedModel(eq(MODEL2_NAME), any());
Files.copy(SOURCE_PATH.resolve(v2File), fullModel2Path, StandardCopyOption.REPLACE_EXISTING);
modelRepository.processWatchEvent(WatchService.Kind.MODIFY, fullModel2Path);
verify(firstTypeListener).removedModel(eq(MODEL2_NAME), firstTypeCaptor.capture());
assertThat(firstTypeCaptor.getAllValues(), hasSize(2));
firstTypeElements = firstTypeCaptor.getAllValues().getLast();
// Check that the elements were removed
assertThat(firstTypeElements, hasSize(3));
assertThat(firstTypeElements, containsInAnyOrder(new FirstTypeDTO("First", "First original"),
@@ -320,7 +236,6 @@ public class YamlModelRepositoryImplTest {
modelRepository.addYamlModelListener(firstTypeListener);
// File in v1 format
Files.copy(SOURCE_PATH.resolve("modelFileUpdatePost.yaml"), fullModelPath);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModelPath);
modelRepository.processWatchEvent(WatchService.Kind.DELETE, fullModelPath);
@@ -329,35 +244,17 @@ public class YamlModelRepositoryImplTest {
verify(firstTypeListener, never()).updatedModel(any(), any());
verify(firstTypeListener).removedModel(eq(MODEL_NAME), firstTypeCaptor.capture());
// File in v2 format
Files.copy(SOURCE_PATH.resolve("modelV2FileUpdatePost.yaml"), fullModel2Path);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModel2Path);
modelRepository.processWatchEvent(WatchService.Kind.DELETE, fullModel2Path);
verify(firstTypeListener).addedModel(eq(MODEL2_NAME), firstTypeCaptor.capture());
verify(firstTypeListener, never()).updatedModel(any(), any());
verify(firstTypeListener).removedModel(eq(MODEL2_NAME), firstTypeCaptor.capture());
List<Collection<FirstTypeDTO>> firstTypeCaptorValues = firstTypeCaptor.getAllValues();
assertThat(firstTypeCaptorValues, hasSize(4));
assertThat(firstTypeCaptorValues, hasSize(2));
// all are added - first file
// all are added
assertThat(firstTypeCaptorValues.getFirst(), hasSize(3));
assertThat(firstTypeCaptorValues.getFirst(), containsInAnyOrder(new FirstTypeDTO("First", "First original"),
new FirstTypeDTO("Second", "Second original"), new FirstTypeDTO("Third", "Third original")));
// all are removed - first file
// all are removed
assertThat(firstTypeCaptorValues.get(1), hasSize(3));
assertThat(firstTypeCaptorValues.get(1), containsInAnyOrder(new FirstTypeDTO("First", "First original"),
new FirstTypeDTO("Second", "Second original"), new FirstTypeDTO("Third", "Third original")));
// all are added - second file
assertThat(firstTypeCaptorValues.get(2), hasSize(3));
assertThat(firstTypeCaptorValues.get(2), containsInAnyOrder(new FirstTypeDTO("First", "First original"),
new FirstTypeDTO("Second", "Second original"), new FirstTypeDTO("Third", "Third original")));
// all are removed - second file
assertThat(firstTypeCaptorValues.get(3), hasSize(3));
assertThat(firstTypeCaptorValues.get(3), containsInAnyOrder(new FirstTypeDTO("First", "First original"),
new FirstTypeDTO("Second", "Second original"), new FirstTypeDTO("Third", "Third original")));
}
@Test
@@ -387,35 +284,15 @@ public class YamlModelRepositoryImplTest {
assertThat(yaml.load(actualFileContent), equalTo(yaml.load(expectedFileContent)));
Files.copy(SOURCE_PATH.resolve("modifyModelV2InitialContent.yaml"), fullModel2Path);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModel2Path);
modelRepository.addElementToModel(MODEL2_NAME, added);
modelRepository.addElementToModel(MODEL2_NAME, added2);
verify(firstTypeListener, times(2)).addedModel(eq(MODEL2_NAME), firstTypeCaptor.capture());
verify(firstTypeListener, never()).updatedModel(any(), any());
verify(firstTypeListener, never()).removedModel(any(), any());
verify(secondTypeListener1).addedModel(eq(MODEL2_NAME), secondTypeCaptor1.capture());
verify(secondTypeListener1, never()).updatedModel(any(), any());
verify(secondTypeListener1, never()).removedModel(any(), any());
actualFileContent = Files.readString(fullModel2Path);
expectedFileContent = Files.readString(SOURCE_PATH.resolve("addToModelV2ExpectedContent.yaml"));
assertThat(yaml.load(actualFileContent), equalTo(yaml.load(expectedFileContent)));
List<Collection<FirstTypeDTO>> firstTypeCaptorValues = firstTypeCaptor.getAllValues();
assertThat(firstTypeCaptorValues, hasSize(4));
assertThat(firstTypeCaptorValues, hasSize(2));
assertThat(firstTypeCaptorValues.get(1), hasSize(1));
assertThat(firstTypeCaptorValues.get(1), contains(new FirstTypeDTO("element3", "description3")));
assertThat(firstTypeCaptorValues.get(3), hasSize(1));
assertThat(firstTypeCaptorValues.get(3), contains(new FirstTypeDTO("element3", "description3")));
List<Collection<SecondTypeDTO>> secondTypeCaptor1Values = secondTypeCaptor1.getAllValues();
assertThat(secondTypeCaptor1Values, hasSize(2));
assertThat(secondTypeCaptor1Values, hasSize(1));
assertThat(secondTypeCaptor1Values.getFirst(), hasSize(1));
assertThat(secondTypeCaptor1Values.getFirst(), contains(new SecondTypeDTO("elt1", "My label")));
assertThat(secondTypeCaptor1Values.get(1), hasSize(1));
assertThat(secondTypeCaptor1Values.get(1), contains(new SecondTypeDTO("elt1", "My label")));
}
@Test
@@ -439,24 +316,10 @@ public class YamlModelRepositoryImplTest {
assertThat(yaml.load(actualFileContent), equalTo(yaml.load(expectedFileContent)));
Files.copy(SOURCE_PATH.resolve("modifyModelV2InitialContent.yaml"), fullModel2Path);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModel2Path);
modelRepository.updateElementInModel(MODEL2_NAME, updated);
verify(firstTypeListener).addedModel(eq(MODEL2_NAME), any());
verify(firstTypeListener).updatedModel(eq(MODEL2_NAME), firstTypeCaptor.capture());
verify(firstTypeListener, never()).removedModel(any(), any());
actualFileContent = Files.readString(fullModel2Path);
expectedFileContent = Files.readString(SOURCE_PATH.resolve("updateInModelV2ExpectedContent.yaml"));
assertThat(yaml.load(actualFileContent), equalTo(yaml.load(expectedFileContent)));
List<Collection<FirstTypeDTO>> firstTypeCaptorValues = firstTypeCaptor.getAllValues();
assertThat(firstTypeCaptorValues, hasSize(2));
assertThat(firstTypeCaptorValues, hasSize(1));
assertThat(firstTypeCaptorValues.getFirst(), hasSize(1));
assertThat(firstTypeCaptorValues.getFirst(), contains(new FirstTypeDTO("element1", "newDescription1")));
assertThat(firstTypeCaptorValues.get(1), hasSize(1));
assertThat(firstTypeCaptorValues.get(1), contains(new FirstTypeDTO("element1", "newDescription1")));
}
@Test
@@ -480,24 +343,10 @@ public class YamlModelRepositoryImplTest {
assertThat(yaml.load(actualFileContent), equalTo(yaml.load(expectedFileContent)));
Files.copy(SOURCE_PATH.resolve("modifyModelV2InitialContent.yaml"), fullModel2Path);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModel2Path);
modelRepository.removeElementFromModel(MODEL2_NAME, removed);
verify(firstTypeListener).addedModel(eq(MODEL2_NAME), any());
verify(firstTypeListener, never()).updatedModel(any(), any());
verify(firstTypeListener).removedModel(eq(MODEL2_NAME), firstTypeCaptor.capture());
actualFileContent = Files.readString(fullModel2Path);
expectedFileContent = Files.readString(SOURCE_PATH.resolve("removeFromModelV2ExpectedContent.yaml"));
assertThat(yaml.load(actualFileContent), equalTo(yaml.load(expectedFileContent)));
List<Collection<FirstTypeDTO>> firstTypeCaptorValues = firstTypeCaptor.getAllValues();
assertThat(firstTypeCaptorValues, hasSize(2));
assertThat(firstTypeCaptorValues, hasSize(1));
assertThat(firstTypeCaptorValues.getFirst(), hasSize(1));
assertThat(firstTypeCaptorValues.getFirst(), contains(new FirstTypeDTO("element1", "description1")));
assertThat(firstTypeCaptorValues.get(1), hasSize(1));
assertThat(firstTypeCaptorValues.get(1), contains(new FirstTypeDTO("element1", "description1")));
}
@Test
@@ -521,24 +370,12 @@ public class YamlModelRepositoryImplTest {
Yaml yaml = new Yaml();
assertThat(yaml.load(actualFileContent), equalTo(yaml.load(expectedFileContent)));
Files.copy(SOURCE_PATH.resolve("modelV2FileAddedOrRemoved.yaml"), fullModel2Path);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModel2Path);
modelRepository.addElementToModel(MODEL2_NAME, added);
modelRepository.removeElementFromModel(MODEL2_NAME, removed);
modelRepository.updateElementInModel(MODEL2_NAME, updated);
actualFileContent = Files.readString(fullModel2Path);
expectedFileContent = Files.readString(SOURCE_PATH.resolve("modelV2FileAddedOrRemoved.yaml"));
assertThat(yaml.load(actualFileContent), equalTo(yaml.load(expectedFileContent)));
}
@Test
public void testExistingProviderForVersion() throws IOException {
// Provider supporting only version 1
// Provider supports version 1
when(firstTypeListener.isVersionSupported(eq(1))).thenReturn(true);
when(firstTypeListener.isVersionSupported(eq(2))).thenReturn(false);
when(firstTypeListener.isDeprecated()).thenReturn(false);
Files.copy(SOURCE_PATH.resolve("modelFileAddedOrRemoved.yaml"), fullModelPath);
@@ -560,9 +397,8 @@ public class YamlModelRepositoryImplTest {
@Test
public void testExistingDeprecatedProviderForVersion() throws IOException {
// Provider supporting only version 1 and deprecated
// Provider supports version 1 as deprecated
when(firstTypeListener.isVersionSupported(eq(1))).thenReturn(true);
when(firstTypeListener.isVersionSupported(eq(2))).thenReturn(false);
when(firstTypeListener.isDeprecated()).thenReturn(true);
Files.copy(SOURCE_PATH.resolve("modelFileAddedOrRemoved.yaml"), fullModelPath);
@@ -584,9 +420,8 @@ public class YamlModelRepositoryImplTest {
@Test
public void testNoProviderForVersion() throws IOException {
// Provider supporting only version 2
// Provider does not support version 1
when(firstTypeListener.isVersionSupported(eq(1))).thenReturn(false);
when(firstTypeListener.isVersionSupported(eq(2))).thenReturn(true);
when(firstTypeListener.isDeprecated()).thenReturn(false);
Files.copy(SOURCE_PATH.resolve("modelFileAddedOrRemoved.yaml"), fullModelPath);
@@ -603,40 +438,31 @@ public class YamlModelRepositoryImplTest {
@Test
public void testDifferentProvidersDependingOnVersion() throws IOException {
// secondTypeListener1 supports version 1 only
// secondTypeListener1 supports version 1
when(secondTypeListener1.isVersionSupported(eq(1))).thenReturn(true);
when(secondTypeListener1.isVersionSupported(eq(2))).thenReturn(false);
when(secondTypeListener1.isDeprecated()).thenReturn(false);
// secondTypeListener2 supports version 2 only
// secondTypeListener2 does not supports version 1
when(secondTypeListener2.isVersionSupported(eq(1))).thenReturn(false);
when(secondTypeListener2.isVersionSupported(eq(2))).thenReturn(true);
when(secondTypeListener2.isDeprecated()).thenReturn(false);
Files.copy(SOURCE_PATH.resolve("modelFileAddedOrRemoved.yaml"), fullModelPath);
Files.copy(SOURCE_PATH.resolve("modelV2FileAddedOrRemoved.yaml"), fullModel2Path);
YamlModelRepositoryImpl modelRepository = new YamlModelRepositoryImpl(watchServiceMock);
modelRepository.addYamlModelListener(secondTypeListener1);
modelRepository.addYamlModelListener(secondTypeListener2);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModelPath);
modelRepository.processWatchEvent(WatchService.Kind.CREATE, fullModel2Path);
verify(secondTypeListener1).addedModel(eq(MODEL_NAME), secondTypeCaptor1.capture());
verify(secondTypeListener1, never()).addedModel(eq(MODEL2_NAME), any());
verify(secondTypeListener1, never()).updatedModel(any(), any());
verify(secondTypeListener1, never()).removedModel(any(), any());
verify(secondTypeListener2).addedModel(eq(MODEL2_NAME), secondTypeCaptor2.capture());
verify(secondTypeListener2, never()).addedModel(eq(MODEL_NAME), any());
verify(secondTypeListener2, never()).addedModel(any(), any());
verify(secondTypeListener2, never()).updatedModel(any(), any());
verify(secondTypeListener2, never()).removedModel(any(), any());
Collection<SecondTypeDTO> secondTypeElements = secondTypeCaptor1.getValue();
assertThat(secondTypeElements, hasSize(1));
assertThat(secondTypeElements, contains(new SecondTypeDTO("Second1", "Label1")));
secondTypeElements = secondTypeCaptor2.getValue();
assertThat(secondTypeElements, hasSize(1));
assertThat(secondTypeElements, contains(new SecondTypeDTO("Second1", "Label1")));
}
}
@@ -1,12 +1,12 @@
version: 1
readOnly: false
firstType:
- uid: element1
element1:
description: description1
- uid: element2
element2:
description: description2
- uid: element3
element3:
description: description3
secondType:
- id: elt1
elt1:
label: My label
@@ -1,12 +0,0 @@
version: 2
readOnly: false
firstType:
element1:
description: description1
element2:
description: description2
element3:
description: description3
secondType:
elt1:
label: My label
@@ -6,23 +6,20 @@ version: 1
# known first type
firstType:
# a valid element with uid and description
- uid: First1
First1:
description: Description1
# a valid element with uid only
- uid: First2
# an invalid element (missing uid)
- description: Description3
First2:
# known second type
secondType:
# a valid element with id and label
- id: Second1
Second1:
label: Label1
# unknown third type
thirdType:
- foo: Bar
Foobar:
nonArrayElement: Test
@@ -3,9 +3,9 @@
version: 1
firstType:
- uid: First
First:
description: First original
- uid: Second
Second:
description: Second original
- uid: Third
Third:
description: Third original
@@ -3,9 +3,9 @@
version: 1
firstType:
- uid: First
First:
description: First original
- uid: Second
Second:
description: Second modified
- uid: Fourth
Fourth:
description: Fourth original
@@ -1,4 +1,3 @@
# A YAML test file for updating the model
version: 1
@@ -3,9 +3,9 @@
# version: 1 => removed in this update
firstType:
- uid: First
First:
description: First original
- uid: Second
Second:
description: Second original
- uid: Third
Third:
description: Third original
@@ -3,9 +3,9 @@
version: 1
firstTypeRenamed:
- uid: First
First:
description: First original
- uid: Second
Second:
description: Second original
- uid: Third
Third:
description: Third original
@@ -1,25 +0,0 @@
# A YAML test file in version 2 with different types
# The structure is valid but also contains invalid elements
version: 2
# known first type
firstType:
# a valid element with uid and description
First1:
description: Description1
# a valid element with uid only
First2:
# known second type
secondType:
# a valid element with id and label
Second1:
label: Label1
# unknown third type
thirdType:
Foobar:
nonArrayElement: Test
@@ -1,11 +0,0 @@
# A YAML test file in version 2 for updating the model
version: 2
firstType:
First:
description: First original
Second:
description: Second original
Third:
description: Third original
@@ -1,11 +0,0 @@
# A YAML test file in version 2 for updating the model
version: 2
firstType:
First:
description: First original
Second:
description: Second modified
Fourth:
description: Fourth original
@@ -1,3 +0,0 @@
# A YAML test file for updating the model
version: 2
@@ -1,11 +0,0 @@
# A YAML test file in version 2 for updating the model
# version: 2 => removed
firstType:
First:
description: First original
Second:
description: Second original
Third:
description: Third original
@@ -1,11 +0,0 @@
# A YAML test file for updating the model
version: 2
firstTypeRenamed:
First:
description: First original
Second:
description: Second original
Third:
description: Third original
@@ -1,7 +1,7 @@
version: 1
readOnly: false
firstType:
- uid: element1
element1:
description: description1
- uid: element2
element2:
description: description2
@@ -1,7 +0,0 @@
version: 2
readOnly: false
firstType:
element1:
description: description1
element2:
description: description2
@@ -1,5 +1,5 @@
version: 1
readOnly: false
firstType:
- uid: element2
element2:
description: description2
@@ -1,5 +0,0 @@
version: 2
readOnly: false
firstType:
element2:
description: description2
@@ -1,7 +1,7 @@
version: 1
readOnly: false
firstType:
- uid: element1
element1:
description: newDescription1
- uid: element2
element2:
description: description2
@@ -1,7 +0,0 @@
version: 2
readOnly: false
firstType:
element1:
description: newDescription1
element2:
description: description2