/*
* Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.restconf.nb.rfc8040.databind;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import org.junit.Test;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
public class XmlPatchBodyTest extends AbstractPatchBodyTest {
public XmlPatchBodyTest() {
super(XmlPatchBody::new);
}
@Test
public final void moduleDataTest() throws Exception {
checkPatchContext(parse(mountPrefix() + "instance-identifier-patch-module:patch-cont/my-list1=leaf1", """
test-patch
this is test patch
edit1
create
/my-list2=my-leaf20
my-leaf20
I am leaf21-0
I am leaf22-0
edit2
create
/my-list2=my-leaf21
my-leaf21
I am leaf21-1
I am leaf22-1
"""));
}
/**
* Test trying to use Patch create operation which requires value without value. Error code 400 should be returned.
*/
@Test
public final void moduleDataValueMissingNegativeTest() throws Exception {
final var ex = assertThrows(RestconfDocumentedException.class,
() -> parse(mountPrefix() + "instance-identifier-patch-module:patch-cont/my-list1=leaf1", """
test-patch
Test patch with missing value node for create operation
edit1
create
/my-list2
"""));
assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
}
/**
* Test trying to use value with Patch delete operation which does not support value. Error code 400 should be
* returned.
*/
@Test
public final void moduleDataNotValueNotSupportedNegativeTest() throws Exception {
final var ex = assertThrows(RestconfDocumentedException.class,
() -> parse(mountPrefix() + "instance-identifier-patch-module:patch-cont/my-list1=leaf1", """
test-patch
Test patch with not allowed value node for delete operation
edit1
delete
/my-list2/my-leaf21
my-leaf20
I am leaf21-0
I am leaf22-0
"""));
assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
}
/**
* Test of YANG Patch with absolute target path.
*/
@Test
public final void moduleDataAbsoluteTargetPathTest() throws Exception {
checkPatchContext(parse(mountPrefix(), """
test-patch
Test patch with absolute target path
edit1
create
/instance-identifier-patch-module:patch-cont/my-list1=leaf1/my-list2=my-leaf20
my-leaf20
I am leaf21-0
I am leaf22-0
edit2
create
/instance-identifier-patch-module:patch-cont/my-list1=leaf1/my-list2=my-leaf21
my-leaf21
I am leaf21-1
I am leaf22-1
"""));
}
/**
* Test using Patch when target is completely specified in request URI and thus target leaf contains only '/' sign.
*/
@Test
public final void modulePatchCompleteTargetInURITest() throws Exception {
checkPatchContext(parse(mountPrefix() + "instance-identifier-patch-module:patch-cont", """
test-patch
Test to create and replace data in container directly using / sign as a target
edit1
create
/
my-list1 - A
I am leaf11-0
I am leaf12-1
my-list1 - B
I am leaf11-0
I am leaf12-1
edit2
replace
/
my-list1 - Replacing
I am leaf11-0
I am leaf12-1
"""));
}
/**
* Test of Yang Patch merge operation on list. Test consists of two edit operations - replace and merge.
*/
@Test
public final void moduleDataMergeOperationOnListTest() throws Exception {
checkPatchContext(parse(mountPrefix() + "instance-identifier-patch-module:patch-cont/my-list1=leaf1", """
Test merge operation
This is test patch for merge operation on list
edit1
replace
/my-list2=my-leaf20
my-leaf20
I am leaf21-0
I am leaf22-0
edit2
merge
/my-list2=my-leaf21
my-leaf21
I am leaf21-1
I am leaf22-1
"""));
}
/**
* Test of Yang Patch merge operation on container. Test consists of two edit operations - create and merge.
*/
@Test
public final void moduleDataMergeOperationOnContainerTest() throws Exception {
checkPatchContext(parse(mountPrefix() + "instance-identifier-patch-module:patch-cont", """
Test merge operation
This is test patch for merge operation on container
edit1
create
/
my-list1 - A
I am leaf11-0
I am leaf12-1
my-list1 - B
I am leaf11-0
I am leaf12-1
edit2
merge
/
my-list1 - Merged
I am leaf11-0
I am leaf12-1
"""));
}
/**
* Test of Yang Patch on the top-level container with empty URI for data root.
*/
@Test
public final void modulePatchTargetTopLevelContainerWithEmptyURITest() throws Exception {
checkPatchContext(parse(mountPrefix(), """
test-patch
Test patch applied to the top-level container with empty URI
edit1
replace
/instance-identifier-patch-module:patch-cont
my-leaf10
"""));
}
/**
* Test of YANG Patch on the top-level container with the full path in the URI and "/" in 'target'.
*/
@Test
public final void modulePatchTargetTopLevelContainerWithFullPathURITest() throws Exception {
final var returnValue = parse(mountPrefix() + "instance-identifier-patch-module:patch-cont", """
test-patch
Test patch applied to the top-level container with '/' in target
edit1
replace
/
my-leaf-set
leaf-a
leaf-b
""");
checkPatchContext(returnValue);
assertEquals(Builders.containerBuilder()
.withNodeIdentifier(new NodeIdentifier(PATCH_CONT_QNAME))
.withChild(Builders.mapBuilder()
.withNodeIdentifier(new NodeIdentifier(MY_LIST1_QNAME))
.withChild(Builders.mapEntryBuilder()
.withNodeIdentifier(NodeIdentifierWithPredicates.of(MY_LIST1_QNAME, LEAF_NAME_QNAME, "my-leaf-set"))
.withChild(ImmutableNodes.leafNode(LEAF_NAME_QNAME, "my-leaf-set"))
.withChild(ImmutableNodes.leafNode(MY_LEAF11_QNAME, "leaf-a"))
.withChild(ImmutableNodes.leafNode(MY_LEAF12_QNAME, "leaf-b"))
.build())
.build())
.build(), returnValue.getData().get(0).getNode());
}
/**
* Test of YANG Patch on the second-level list with the full path in the URI and "/" in 'target'.
*/
@Test
public final void modulePatchTargetSecondLevelListWithFullPathURITest() throws Exception {
final var returnValue = parse(
mountPrefix() + "instance-identifier-patch-module:patch-cont/my-list1=my-leaf-set",
"""
test-patch
Test patch applied to the second-level list with '/' in target
edit1
replace
/
my-leaf-set
leaf-a
leaf-b
""");
checkPatchContext(returnValue);
assertEquals(Builders.mapBuilder()
.withNodeIdentifier(new NodeIdentifier(MY_LIST1_QNAME))
.withChild(Builders.mapEntryBuilder()
.withNodeIdentifier(NodeIdentifierWithPredicates.of(MY_LIST1_QNAME, LEAF_NAME_QNAME, "my-leaf-set"))
.withChild(ImmutableNodes.leafNode(LEAF_NAME_QNAME, "my-leaf-set"))
.withChild(ImmutableNodes.leafNode(MY_LEAF11_QNAME, "leaf-a"))
.withChild(ImmutableNodes.leafNode(MY_LEAF12_QNAME, "leaf-b"))
.build())
.build(), returnValue.getData().get(0).getNode());
}
/**
* Test of Yang Patch on the top augmented element.
*/
@Test
public final void moduleTargetTopLevelAugmentedContainerTest() throws Exception {
final var returnValue = parse(mountPrefix(), """
test-patch
This test patch for augmented element
edit1
replace
/test-m:container-root/test-m:container-lvl1/test-m-aug:container-aug
data
""");
checkPatchContext(returnValue);
assertEquals(Builders.containerBuilder()
.withNodeIdentifier(new NodeIdentifier(CONT_AUG_QNAME))
.withChild(ImmutableNodes.leafNode(LEAF_AUG_QNAME, "data"))
.build(), returnValue.getData().get(0).getNode());
}
/**
* Test of YANG Patch on the top system map node element.
*/
@Test
public final void moduleTargetMapNodeTest() throws Exception {
final var returnValue = parse(mountPrefix(), """
map-patch
YANG patch comment
edit1
replace
/map-model:cont-root/map-model:cont1/map-model:my-map=key
key
data
""");
checkPatchContext(returnValue);
assertEquals(Builders.mapBuilder()
.withNodeIdentifier(new NodeIdentifier(MAP_CONT_QNAME))
.withChild(Builders.mapEntryBuilder()
.withNodeIdentifier(NodeIdentifierWithPredicates.of(MAP_CONT_QNAME, KEY_LEAF_QNAME, "key"))
.withChild(ImmutableNodes.leafNode(KEY_LEAF_QNAME, "key"))
.withChild(ImmutableNodes.leafNode(DATA_LEAF_QNAME, "data"))
.build())
.build(), returnValue.getData().get(0).getNode());
}
/**
* Test of YANG Patch on the leaf set node element.
*/
@Test
public final void modulePatchTargetLeafSetNodeTest() throws Exception {
final var returnValue = parse(mountPrefix(), """
set-patch
YANG patch comment
edit1
replace
/set-model:cont-root/set-model:cont1/set-model:my-set="data1"
data1
""");
checkPatchContext(returnValue);
assertEquals(Builders.leafSetBuilder()
.withNodeIdentifier(new NodeIdentifier(LEAF_SET_QNAME))
.withChild(Builders.leafSetEntryBuilder()
.withNodeIdentifier(new NodeWithValue<>(LEAF_SET_QNAME, "data1"))
.withValue("data1")
.build())
.build(), returnValue.getData().get(0).getNode());
}
/**
* Test of Yang Patch on the top unkeyed list element.
*/
@Test
public final void moduleTargetUnkeyedListNodeTest() throws Exception {
final var returnValue = parse(mountPrefix(), """
list-patch
YANG patch comment
edit1
replace
/list-model:cont-root/list-model:cont1/list-model:unkeyed-list
data1
data2
""");
checkPatchContext(returnValue);
assertEquals(Builders.unkeyedListBuilder()
.withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
.withChild(Builders.unkeyedListEntryBuilder()
.withNodeIdentifier(new NodeIdentifier(LIST_QNAME))
.withChild(ImmutableNodes.leafNode(LIST_LEAF1_QNAME, "data1"))
.withChild(ImmutableNodes.leafNode(LIST_LEAF2_QNAME, "data2"))
.build())
.build(), returnValue.getData().get(0).getNode());
}
/**
* Test of Yang Patch on the top case node element.
*/
@Test
public final void moduleTargetCaseNodeTest() throws Exception {
final var returnValue = parse(mountPrefix(), """
choice-patch
YANG patch comment
edit1
replace
/choice-model:cont-root/choice-model:cont1/choice-model:case-cont1
data
""");
checkPatchContext(returnValue);
assertEquals(Builders.containerBuilder()
.withNodeIdentifier(new NodeIdentifier(CHOICE_CONT_QNAME))
.withChild(ImmutableNodes.leafNode(CASE_LEAF1_QNAME, "data"))
.build(), returnValue.getData().get(0).getNode());
}
/**
* Test reading simple leaf value.
*/
@Test
public final void modulePatchSimpleLeafValueTest() throws Exception {
final var returnValue = parse(mountPrefix() + "instance-identifier-patch-module:patch-cont/my-list1=leaf1", """
test-patch
this is test patch
edit1
replace
/my-list2=my-leaf20/name
my-leaf20
""");
checkPatchContext(returnValue);
assertEquals(ImmutableNodes.leafNode(LEAF_NAME_QNAME, "my-leaf20"), returnValue.getData().get(0).getNode());
}
}