Skip to content

Commit 2242d7e

Browse files
Tobianasihrasko
authored andcommitted
Add NettyRestConf Tests
Add tests based of CommunityRestConf tests to properly verify netty restconf and its configuration. JIRA: LIGHTY-333 Signed-off-by: tobias.pobocik <[email protected]>
1 parent e19bebc commit 2242d7e

File tree

5 files changed

+321
-0
lines changed

5 files changed

+321
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2025 PANTHEON.tech, s.r.o. and others. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
6+
* and is available at https://www.eclipse.org/legal/epl-v10.html
7+
*/
8+
9+
package io.lighty.modules.northbound.netty.restconf.community.impl.tests;
10+
11+
import io.lighty.core.controller.impl.config.ConfigurationException;
12+
import io.lighty.modules.northbound.netty.restconf.community.impl.config.NettyRestConfConfiguration;
13+
import io.lighty.modules.northbound.netty.restconf.community.impl.util.NettyRestConfUtils;
14+
import java.net.InetAddress;
15+
import org.testng.Assert;
16+
import org.testng.annotations.Test;
17+
18+
public class NettyRestConfConfigurationTest {
19+
20+
@Test
21+
public void testNettyRestConfConfiguration() {
22+
final NettyRestConfConfiguration defaultRestConfConfiguration =
23+
NettyRestConfUtils.getDefaultNettyRestConfConfiguration();
24+
final NettyRestConfConfiguration restConfConfiguration =
25+
new NettyRestConfConfiguration(defaultRestConfConfiguration);
26+
27+
Assert.assertEquals(defaultRestConfConfiguration, restConfConfiguration);
28+
Assert.assertTrue(defaultRestConfConfiguration.hashCode() == restConfConfiguration.hashCode());
29+
30+
restConfConfiguration.setHttpPort(3333);
31+
restConfConfiguration.setInetAddress(InetAddress.getLoopbackAddress());
32+
33+
Assert.assertNotEquals(defaultRestConfConfiguration, restConfConfiguration);
34+
Assert.assertFalse(defaultRestConfConfiguration.hashCode() == restConfConfiguration.hashCode());
35+
}
36+
37+
@Test
38+
public void testNettyRestConfConfigurationUtilsLoadFromStream() throws ConfigurationException {
39+
final var resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("restconf-config.json");
40+
final var restConfConfiguration = NettyRestConfUtils.getNettyRestConfConfiguration(resourceAsStream);
41+
Assert.assertNotNull(restConfConfiguration);
42+
Assert.assertTrue(restConfConfiguration.getHttpPort() == 5555);
43+
Assert.assertEquals(restConfConfiguration.getInetAddress().getHostAddress(), "127.0.0.3");
44+
}
45+
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (c) 2025 PANTHEON.tech, s.r.o. and others. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
6+
* and is available at https://www.eclipse.org/legal/epl-v10.html
7+
*/
8+
package io.lighty.modules.northbound.netty.restconf.community.impl.tests;
9+
10+
import org.testng.Assert;
11+
import org.testng.annotations.Test;
12+
13+
public class NettyRestConfTest extends NettyRestConfTestBase {
14+
15+
@Test
16+
public void simpleRestconfTest() {
17+
Assert.assertNotNull(getLightyController());
18+
Assert.assertNotNull(getNettyRestConf());
19+
}
20+
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
* Copyright (c) 2025 PANTHEON.tech, s.r.o. and others. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
6+
* and is available at https://www.eclipse.org/legal/epl-v10.html
7+
*/
8+
package io.lighty.modules.northbound.netty.restconf.community.impl.tests;
9+
10+
import com.google.common.util.concurrent.ListenableFuture;
11+
import io.lighty.aaa.config.CertificateManagerConfig;
12+
import io.lighty.aaa.util.AAAConfigUtils;
13+
import io.lighty.core.controller.api.LightyController;
14+
import io.lighty.core.controller.impl.LightyControllerBuilder;
15+
import io.lighty.core.controller.impl.util.ControllerConfigUtils;
16+
import io.lighty.modules.northbound.netty.restconf.community.impl.NettyRestConf;
17+
import io.lighty.modules.northbound.netty.restconf.community.impl.NettyRestConfBuilder;
18+
import io.lighty.modules.northbound.netty.restconf.community.impl.util.NettyRestConfUtils;
19+
import java.lang.reflect.Method;
20+
import java.util.Set;
21+
import java.util.concurrent.TimeUnit;
22+
import org.opendaylight.yangtools.binding.meta.YangModuleInfo;
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
import org.testng.ITestResult;
26+
import org.testng.annotations.AfterClass;
27+
import org.testng.annotations.AfterMethod;
28+
import org.testng.annotations.BeforeClass;
29+
import org.testng.annotations.BeforeMethod;
30+
31+
/**
32+
* author: vincent on 15.8.2017.
33+
*/
34+
public abstract class NettyRestConfTestBase {
35+
36+
private static final Logger LOG = LoggerFactory.getLogger(NettyRestConfTestBase.class);
37+
public static final long SHUTDOWN_TIMEOUT_MILLIS = 60_000;
38+
39+
private LightyController lightyController;
40+
private NettyRestConf nettyRestConf;
41+
42+
@BeforeClass(timeOut = 60_000)
43+
public void startControllerAndRestConf() throws Exception {
44+
45+
final Set<YangModuleInfo> moduleInfos = new java.util.HashSet<>(NettyRestConfUtils.YANG_MODELS);
46+
moduleInfos.add(org.opendaylight.yang.svc.v1.instance.identifier.patch.module.rev151121
47+
.YangModuleInfoImpl.getInstance());
48+
moduleInfos.add(org.opendaylight.yang.svc.v1.urn.opendaylight.yang.aaa.cert.mdsal.rev160321
49+
.YangModuleInfoImpl.getInstance());
50+
51+
LOG.info("Building LightyController");
52+
LightyControllerBuilder lightyControllerBuilder = new LightyControllerBuilder();
53+
lightyController = lightyControllerBuilder.from(ControllerConfigUtils.getDefaultSingleNodeConfiguration(
54+
moduleInfos)).build();
55+
56+
LOG.info("Starting LightyController (waiting 10s after start)");
57+
ListenableFuture<Boolean> started = lightyController.start();
58+
started.get();
59+
LOG.info("LightyController started");
60+
61+
final var defaultAAAConfiguration = AAAConfigUtils.createDefaultAAAConfiguration();
62+
defaultAAAConfiguration.setCertificateManager(
63+
CertificateManagerConfig.getDefault(lightyController.getServices().getBindingDataBroker(),
64+
lightyController.getServices().getRpcProviderService()));
65+
66+
LOG.info("Building NettyRestConf");
67+
NettyRestConfBuilder builder = NettyRestConfBuilder.from(
68+
NettyRestConfUtils.getDefaultNettyRestConfConfiguration(lightyController.getServices()))
69+
.withWebEnvironment(NettyRestConfUtils.getAaaWebEnvironment(
70+
lightyController.getServices().getBindingDataBroker(),
71+
lightyController.getServices().getRpcProviderService(),
72+
defaultAAAConfiguration));
73+
nettyRestConf = builder.build();
74+
75+
LOG.info("Starting NettyRestConf (waiting 10s after start)");
76+
nettyRestConf.start().get(10_000, TimeUnit.MILLISECONDS);
77+
LOG.info("NettyRestConf started");
78+
}
79+
80+
@BeforeMethod
81+
public void handleTestMethodName(Method method) {
82+
String testName = method.getName();
83+
LOG.info("Running test {}", testName);
84+
}
85+
86+
@AfterMethod
87+
public void afterTest(ITestResult result) {
88+
LOG.info("Test {} completed and resulted in {}, with throwables {}",
89+
result.getName(), parseTestNGStatus(result.getStatus()), result.getThrowable());
90+
}
91+
92+
@AfterClass
93+
public void shutdownLighty() {
94+
if (nettyRestConf != null) {
95+
nettyRestConf.shutdown(SHUTDOWN_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
96+
}
97+
if (lightyController != null) {
98+
lightyController.shutdown(SHUTDOWN_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
99+
}
100+
}
101+
102+
private static String parseTestNGStatus(int testResultStatus) {
103+
switch (testResultStatus) {
104+
case -1:
105+
return "CREATED";
106+
case 1:
107+
return "SUCCESS";
108+
case 2:
109+
return "FAILURE";
110+
case 3:
111+
return "SKIP";
112+
case 4:
113+
return "SUCCESS_PERCENTAGE_FAILURE";
114+
case 16:
115+
return "STARTED";
116+
default:
117+
return "N/A";
118+
}
119+
}
120+
121+
LightyController getLightyController() {
122+
return lightyController;
123+
}
124+
125+
NettyRestConf getNettyRestConf() {
126+
return nettyRestConf;
127+
}
128+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright (c) 2025 PANTHEON.tech, s.r.o. and others. All rights reserved.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
6+
* and is available at https://www.eclipse.org/legal/epl-v10.html
7+
*/
8+
package io.lighty.modules.northbound.netty.restconf.community.impl.tests;
9+
10+
import static org.testng.Assert.assertEquals;
11+
import static org.testng.Assert.assertNotNull;
12+
import static org.testng.AssertJUnit.assertTrue;
13+
14+
import java.util.Collections;
15+
import java.util.List;
16+
import java.util.concurrent.TimeUnit;
17+
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
18+
import org.opendaylight.netconf.databind.DatabindContext;
19+
import org.opendaylight.netconf.databind.DatabindPath;
20+
import org.opendaylight.restconf.mdsal.spi.data.MdsalRestconfStrategy;
21+
import org.opendaylight.restconf.server.api.DataYangPatchResult;
22+
import org.opendaylight.restconf.server.api.PatchContext;
23+
import org.opendaylight.restconf.server.api.PatchEntity;
24+
import org.opendaylight.restconf.server.api.testlib.CompletingServerRequest;
25+
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.patch.rev170222.yang.patch.yang.patch.Edit;
26+
import org.opendaylight.yangtools.yang.common.QName;
27+
import org.opendaylight.yangtools.yang.common.Revision;
28+
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
29+
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
30+
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
31+
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
32+
import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
33+
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
34+
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
35+
import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
36+
import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
37+
import org.testng.annotations.Test;
38+
39+
public class YangPatchTest extends NettyRestConfTestBase {
40+
41+
private static final QName BASE_Q_NAME = QName.create("instance:identifier:patch:module",
42+
"instance-identifier-patch-module", Revision.of("2015-11-21")).intern();
43+
private static final QName EXAMPLE_LIST = QName.create(BASE_Q_NAME, "my-list1").intern();
44+
private static final QName EXAMPLE_LIST_NAME = QName.create(BASE_Q_NAME, "name").intern();
45+
private static final QName MY_LEAF_11 = QName.create(EXAMPLE_LIST, "my-leaf11").intern();
46+
private static final QName MY_LEAF_12 = QName.create(EXAMPLE_LIST, "my-leaf12").intern();
47+
private static final QName CONTAINER_ID = QName.create(EXAMPLE_LIST, "patch-cont").intern();
48+
private static final String MY_LIST_1_A = "my-list1 - A";
49+
private static final String I_AM_LEAF_11_0 = "I am leaf11-0";
50+
private static final String I_AM_LEAF_12_1 = "I am leaf12-1";
51+
52+
@Test
53+
public void patchDataReplaceTest() throws Exception {
54+
assertNotNull(getLightyController());
55+
assertNotNull(getNettyRestConf());
56+
57+
final ContainerNode patchContainerNode = getContainerWithData();
58+
final YangInstanceIdentifier targetNodeMerge = YangInstanceIdentifier.builder()
59+
.node(CONTAINER_ID)
60+
.build();
61+
62+
final DatabindContext databindContext = DatabindContext.ofModel(getLightyController()
63+
.getServices().getDOMSchemaService().getGlobalContext());
64+
65+
final PatchEntity entityReplace = new PatchEntity(
66+
"edit1", Edit.Operation.Replace, getPath(targetNodeMerge, databindContext), patchContainerNode);
67+
final PatchContext patchContext = new PatchContext("test-patch", List.of(entityReplace));
68+
69+
final var strategy = new MdsalRestconfStrategy(DatabindContext.ofModel(getLightyController()
70+
.getServices().getDOMSchemaService().getGlobalContext()), getLightyController().getServices()
71+
.getClusteredDOMDataBroker());
72+
73+
final CompletingServerRequest<DataYangPatchResult> dataYangPatchRequest = new CompletingServerRequest<>();
74+
75+
strategy.patchData(dataYangPatchRequest, new DatabindPath.Data(DatabindContext.ofModel(getLightyController()
76+
.getServices().getDOMSchemaService().getGlobalContext())) ,patchContext);
77+
assertTrue(dataYangPatchRequest.getResult().status().ok());
78+
79+
final ContainerNode response = (ContainerNode) getLightyController().getServices().getClusteredDOMDataBroker()
80+
.newReadOnlyTransaction()
81+
.read(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.of())
82+
.get(5000, TimeUnit.MILLISECONDS).orElseThrow();
83+
final DataContainerChild bodyOfResponse = response.body().iterator().next();
84+
assertEquals(bodyOfResponse, getContainerWithData());
85+
}
86+
87+
private static ContainerNode getContainerWithData() {
88+
final LeafNode<?> nameLeafA = ImmutableNodes.newLeafBuilder()
89+
.withNodeIdentifier(NodeIdentifier.create(EXAMPLE_LIST_NAME))
90+
.withValue(MY_LIST_1_A)
91+
.build();
92+
final LeafNode<?> buildLeaf1 = ImmutableNodes.newLeafBuilder()
93+
.withNodeIdentifier(NodeIdentifier.create(MY_LEAF_11))
94+
.withValue(I_AM_LEAF_11_0)
95+
.build();
96+
final LeafNode<?> buildLeaf2 = ImmutableNodes.newLeafBuilder()
97+
.withNodeIdentifier(NodeIdentifier.create(MY_LEAF_12))
98+
.withValue(I_AM_LEAF_12_1)
99+
.build();
100+
final MapEntryNode mapEntryNode = ImmutableNodes.newMapEntryBuilder()
101+
.withNodeIdentifier(NodeIdentifierWithPredicates.of(EXAMPLE_LIST))
102+
.withValue(List.of(nameLeafA, buildLeaf1, buildLeaf2))
103+
.build();
104+
final SystemMapNode myList = ImmutableNodes.newSystemMapBuilder()
105+
.withNodeIdentifier(NodeIdentifier.create(EXAMPLE_LIST))
106+
.withValue(Collections.singletonList(mapEntryNode))
107+
.build();
108+
return ImmutableNodes.newContainerBuilder()
109+
.withNodeIdentifier(NodeIdentifier.create(CONTAINER_ID))
110+
.withValue(Collections.singletonList(myList))
111+
.build();
112+
}
113+
114+
private DatabindPath.Data getPath(final YangInstanceIdentifier path, final DatabindContext databindContext) {
115+
final var childAndStack = new DatabindPath.Data(
116+
databindContext).databind().schemaTree().enterPath(path).orElseThrow();
117+
return new DatabindPath.Data(databindContext, childAndStack.stack().toInference(), path, childAndStack.node());
118+
}
119+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"restconf": {
3+
"inetAddress": "127.0.0.3",
4+
"httpPort": 5555,
5+
"restconfServletContextPath": "/restconf-path"
6+
}
7+
}

0 commit comments

Comments
 (0)