Full JUnit test source
package io.lighty.test.netconf;
import io.lighty.clients.rest.common.query.parameters.QueryParameters;
import io.lighty.clients.rest.common.query.parameters.QueryParametersBuilder;
import io.lighty.clients.rest.common.response.Response;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.FixMethodOrder;
import org.junit.Test;
import io.lighty.clients.rest.connector.BindingAwareRestConnectorBuilder;
import io.lighty.clients.rest.connector.api.BindingAwareRestConnector;
import io.lighty.clients.rest.device.aware.api.BindingAwareMountRestDevice;
import io.lighty.clients.rest.device.aware.api.BindingAwareRestDevice;
import io.lighty.core.common.models.ModuleId;
import io.lighty.core.common.models.YangModuleUtils;
import io.lighty.kit.examples.Main;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.junit.runners.MethodSorters;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.Toaster;
import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.ToasterBuilder;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPassword;
import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPasswordBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopologyBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.CreateTopologyInput;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.CreateTopologyInputBuilder;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.GetNodeFromTopologyByIdInput;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.GetNodeFromTopologyByIdInputBuilder;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.GetNodeFromTopologyByIdOutput;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.GetTopologyByIdInput;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.GetTopologyByIdInputBuilder;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.GetTopologyByIdOutput;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.NetworkTopologyRpcsListener;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.NewTopologyCreated;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.NewTopologyCreatedBuilder;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.RemoveTopologyInput;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.RemoveTopologyInputBuilder;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.TopologyDeleted;
import org.opendaylight.yang.gen.v1.urn.tech.pantheon.netconfdevice.network.topology.rpcs.rev180320.TopologyDeletedBuilder;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import java.util.function.BiConsumer;
import java.util.logging.Logger;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class NetconfRestconfITTests {
private final static Logger LOG = Logger.getLogger(NetconfRestconfITTests.class.getName());
private static BindingAwareMountRestDevice mountPointToasterDevice;
private static BindingAwareMountRestDevice mountPointTopologyDevice;
private static BindingAwareRestDevice device;
private static long totalDuration;
private static long startupDuration;
static final QueryParameters config = new QueryParametersBuilder().content("config").build();
@BeforeClass
public static void beforeClass() throws Exception {
totalDuration = System.nanoTime();
LOG.info("initializing test environment");
ExecutorService executorService = Executors.newFixedThreadPool(5);
LOG.info("init restconf netconf controller");
executorService.submit( ()-> {
try {
Main.start();
} catch(Exception e) {
LOG.info("Error on controller startup.");
}
} );
LOG.info("init testtool devices");
executorService.submit( ()-> {
try {
io.lighty.netconf.device.topology.Main.start(new String[]{"17830"});
} catch(Exception e) {
LOG.info("Error on topology device startup.");
}
} );
executorService.submit( ()-> {
try {
io.lighty.netconf.device.toaster.Main.start(new String[]{"17831"});
} catch(Exception e) {
LOG.info("Error on toaster device startup.");
}
} );
executorService.shutdown();
executorService.awaitTermination(15, TimeUnit.SECONDS);
LOG.info("all components initialized");
LOG.info("Create device : 0.0.0.0:8888");
final KeyStore keyStore = KeyStore.getInstance("JKS");
final String password = "keystore";
keyStore.load(NetconfRestconfITTests.class.getClassLoader().getResourceAsStream("KeyStore.jks"),
password.toCharArray());
final Set<ModuleId> moduleIds = new HashSet<>();
for (final YangModuleInfo yangModuleInfo : YangModuleUtils.getAllModelsFromClasspath()) {
moduleIds.add(new ModuleId(yangModuleInfo.getNamespace(), yangModuleInfo.getName(), yangModuleInfo
.getRevision()));
}
final BindingAwareRestConnector restConnector =
new BindingAwareRestConnectorBuilder().address(new InetSocketAddress("0.0.0.0", 8888))
.keyStore(keyStore).keyStorePwd(password).userName("admin").password("admin").models(moduleIds)
.build();
device = restConnector.connect();
mountPointTopologyDevice = device.getConnectedNetconfDevice(
new TopologyId("topology-netconf"), prepareNetconfNodeProperties("Node1", 17830)).get();
mountPointToasterDevice = device.getConnectedNetconfDevice(
new TopologyId("topology-netconf"), prepareNetconfNodeProperties("Node2", 17831)).get();
startupDuration = System.nanoTime() - totalDuration;
}
@Test
public void testRestClientCreateSubscriptionAll() throws Exception {
final BindingAwareMountRestDevice mountPoint = mountPointTopologyDevice;
final CountDownLatch cdlTopologyCreated = new CountDownLatch(1);
final CountDownLatch cdlTopologyDeleted = new CountDownLatch(1);
LOG.info("Start listen on notificaions");
mountPoint.registerNotificationListener(new NetworkTopologyRpcsListener() {
@Override
public void onTopologyDeleted(final TopologyDeleted notification) {
LOG.info("Notification on delete arrived");
final List<TopologyId> topologyIds = new ArrayList<>();
topologyIds.add(new TopologyId("topology_foo"));
final TopologyDeleted build = new TopologyDeletedBuilder()
.setTopologyIds(topologyIds)
.build();
Assert.assertEquals(notification, build);
cdlTopologyDeleted.countDown();
}
@Override
public void onNewTopologyCreated(final NewTopologyCreated notification) {
LOG.info("Notification on create arrived");
final NewTopologyCreated build = new NewTopologyCreatedBuilder()
.setTopologyId(new TopologyId("topology_foo"))
.build();
Assert.assertEquals(notification, build);
cdlTopologyCreated.countDown();
}
});
LOG.info("Create topology");
SchemaPath schemaPath = SchemaPath.create(true,
QName.create(CreateTopologyInput.QNAME, "create-topology"));
final CreateTopologyInput createTopologyInput =
new CreateTopologyInputBuilder()
.setTopologyId(new TopologyId("topology_foo"))
.build();
CompletableFuture<Response<DataObject, Exception>> responseCompletableFuture =
mountPoint.invokeRpc(schemaPath, createTopologyInput);
addCallbackOnRpcWithoutOutput(responseCompletableFuture);
final boolean awaitCreated = cdlTopologyCreated.await(5, TimeUnit.SECONDS);
Assert.assertTrue(awaitCreated);
InstanceIdentifier<NetworkTopology> topologyII = InstanceIdentifier.create(NetworkTopology.class);
Response<NetworkTopology, Exception> topologyResponse = mountPoint.get(topologyII, null).get();
Assert.assertEquals(topologyResponse.getStatusCode(), 200);
Assert.assertEquals(topologyResponse.getData().getTopology().size(), 2);
Assert.assertEquals(topologyResponse.getData().getTopology().get(1).getTopologyId().getValue(),
"topology_foo");
LOG.info("Remove Topology");
schemaPath = SchemaPath.create(true,
QName.create(RemoveTopologyInput.QNAME, "remove-topology"));
final RemoveTopologyInput removeTopologyInput =
new RemoveTopologyInputBuilder()
.setTopologyId(new TopologyId("topology_foo"))
.build();
responseCompletableFuture = mountPoint.invokeRpc(schemaPath, removeTopologyInput);
addCallbackOnRpcWithoutOutput(responseCompletableFuture);
final boolean awaitDeleted = cdlTopologyDeleted.await(5, TimeUnit.SECONDS);
Assert.assertTrue(awaitDeleted);
topologyII = InstanceIdentifier.create(NetworkTopology.class);
topologyResponse = mountPoint.get(topologyII, null).get();
Assert.assertEquals(topologyResponse.getStatusCode(), 200);
Assert.assertEquals(topologyResponse.getData().getTopology().size(), 1);
Assert.assertEquals(topologyResponse.getData().getTopology().get(0).getTopologyId().getValue(),
"default-topology");
}
@Test
public void testToasterReadDeleteDatastoreOperations() throws Exception {
final long darknessFactor = 20L;
final BindingAwareMountRestDevice mountPointToaster = mountPointToasterDevice;
final InstanceIdentifier<Toaster> instanceIdentifier = InstanceIdentifier.create(Toaster.class);
final Toaster toaster = new ToasterBuilder().setDarknessFactor(darknessFactor).build();
final CompletionStage<Response<Void, Exception>> put = mountPointToaster.put(instanceIdentifier, toaster, null);
addCallbackOnEdit(put, "Put");
final CompletionStage<Response<Toaster, Exception>> completableFuture = mountPointToaster.get(instanceIdentifier, null);
addCallbackOnGet(completableFuture, darknessFactor);
final CompletionStage<Response<Void, Exception>> delete = mountPointToaster.delete(instanceIdentifier);
addCallbackOnEdit(delete, "Delete");
}
@Test
public void testTopologyDeviceRPCInputOutput() throws Exception {
LOG.info("Reading topology using rpcs that contain input and output statement");
final int topologyCount = 100;
writeInitialDataIntoTopologyDevice(topologyCount);
SchemaPath schemaPath = SchemaPath.create(true,
QName.create(GetTopologyByIdInput.QNAME,
"get-topology-by-id"));
final GetTopologyByIdInput input = new GetTopologyByIdInputBuilder()
.setTopologyId(new TopologyId("topology-89"))
.build();
final Response<GetTopologyByIdOutput, Exception> rpcResponse = mountPointTopologyDevice.invokeRpc(schemaPath, input,
GetTopologyByIdOutput.class).get();
Assert.assertEquals(rpcResponse.getStatusCode(), 200);
int size = rpcResponse.getData().getTopology().size();
Assert.assertEquals(size, 1);
String testValue = rpcResponse.getData().getTopology().get(0).getTopologyId().getValue();
Assert.assertEquals(testValue, "topology-89");
size = rpcResponse.getData().getTopology().get(0).getNode().size();
Assert.assertEquals(size, 1);
testValue = rpcResponse.getData().getTopology().get(0).getNode().get(0).getNodeId().getValue();
Assert.assertEquals(testValue, "node-89");
schemaPath = SchemaPath.create(true,
QName.create(GetNodeFromTopologyByIdInput.QNAME,
"get-node-from-topology-by-id"));
final GetNodeFromTopologyByIdInput input2 = new GetNodeFromTopologyByIdInputBuilder()
.setTopologyId(new TopologyId("topology-89"))
.setIsConfig(true)
.setNodeId(new NodeId("node-89"))
.build();
final Response<GetNodeFromTopologyByIdOutput, Exception> response2 =
mountPointTopologyDevice.invokeRpc(schemaPath, input2, GetNodeFromTopologyByIdOutput.class).get();
Assert.assertEquals(response2.getStatusCode(), 200);
size = response2.getData().getNode().size();
Assert.assertEquals(size, 1);
testValue = response2.getData().getNode().get(0).getNodeId().getValue();
Assert.assertEquals(testValue, "node-89");
}
@AfterClass
public static void afterClass() throws Exception {
long shutdownDuration = System.nanoTime();
LOG.info("shutting down test environment");
device.close();
mountPointToasterDevice.close();
mountPointTopologyDevice.close();
ExecutorService executorService = Executors.newFixedThreadPool(5);
executorService.submit( ()-> {
io.lighty.netconf.device.topology.Main.shutdown();
});
executorService.submit( ()-> {
io.lighty.netconf.device.toaster.Main.shutdown();
});
executorService.submit( ()-> {
Main.shutdown();
});
executorService.shutdown();
executorService.awaitTermination(15, TimeUnit.SECONDS);
shutdownDuration = System.nanoTime() - shutdownDuration;
totalDuration = System.nanoTime() - totalDuration;
LOG.info("startupDuration duration: " + ((double)startupDuration/1000000000.0) + "s");
LOG.info("shutdownDuration duration: " + ((double)shutdownDuration/1000000000.0) + "s");
LOG.info("total test duration: " + ((double)totalDuration/1000000000.0) + "s");
}
private static void addCallbackOnRpcWithoutOutput(
final CompletableFuture<Response<DataObject, Exception>> completionStage)
throws InterruptedException {
final CountDownLatch ctl = new CountDownLatch(1);
completionStage.whenComplete(new BiConsumer<Response<DataObject, Exception>, Throwable>() {
@Override
public void accept(final Response<DataObject, Exception> t, final Throwable u) {
Assert.assertEquals(t.getStatusCode(), 200);
LOG.info("RPC invoke - status code = " + t.getStatusCode());
ctl.countDown();
}
});
ctl.await();
}
private static Node prepareNetconfNodeProperties(final String nodeName, final int port) {
final NodeId nodeId = new NodeId(nodeName);
final LoginPassword loginPassword = new LoginPasswordBuilder()
.setUsername("admin")
.setPassword("admin")
.build();
final NetconfNode netconfNode = new NetconfNodeBuilder()
.setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
.setPort(new PortNumber(Integer.valueOf(port)))
.setCredentials(loginPassword)
.setTcpOnly(false)
.setSchemaless(false)
.setTcpOnly(false)
.build();
return new NodeBuilder()
.setNodeId(nodeId)
.setKey(new NodeKey(nodeId))
.addAugmentation(NetconfNode.class, netconfNode)
.build();
}
private static void addCallbackOnEdit(
final CompletionStage<Response<Void, Exception>> completionStage, final String operation)
throws InterruptedException {
final CountDownLatch ctl = new CountDownLatch(1);
completionStage.whenComplete(new BiConsumer<Response<Void, Exception>, Throwable>() {
@Override
public void accept(final Response<Void, Exception> t, final Throwable u) {
LOG.info(operation + "data - status code = " + t.getStatusCode());
Assert.assertNull(t.getError());
ctl.countDown();
}
});
final boolean await = ctl.await(5, TimeUnit.SECONDS);
Assert.assertTrue(await);
}
private static void addCallbackOnGet(
final CompletionStage<Response<Toaster, Exception>> completableFuture, long expectedDarknessFactor)
throws InterruptedException {
final CountDownLatch ctl = new CountDownLatch(1);
completableFuture.whenComplete(new BiConsumer<Response<Toaster, Exception>, Throwable>() {
@Override
public void accept(final Response<Toaster, Exception> t, final Throwable u) {
final Toaster data = t.getData();
LOG.info("Get data - status code = " + t.getStatusCode());
if (data == null) {
LOG.info(t.getError().getMessage());
} else {
final Long darknessFactor = data.getDarknessFactor();
Assert.assertEquals(darknessFactor.longValue(), expectedDarknessFactor);
LOG.info(data.toString());
ctl.countDown();
}
}
});
final boolean await = ctl.await(5, TimeUnit.SECONDS);
Assert.assertTrue(await);
}
private void writeInitialDataIntoTopologyDevice(int topologyCount) throws Exception {
final NetworkTopology networkTopologyData = new NetworkTopologyBuilder()
.setTopology(createToplogies(topologyCount))
.build();
final InstanceIdentifier<NetworkTopology> topologyII = InstanceIdentifier.create(NetworkTopology.class);
final Response<Void, Exception> response = mountPointTopologyDevice
.put(topologyII, networkTopologyData, null)
.get();
Assert.assertEquals(response.getStatusCode(), 204);
readNetworkTopologyData(topologyCount);
}
private void readNetworkTopologyData(int expectedTopologyCount) throws Exception {
final InstanceIdentifier<NetworkTopology> topologyII = InstanceIdentifier.create(NetworkTopology.class);
final Response<NetworkTopology, Exception> topologyResponse =
mountPointTopologyDevice.get(topologyII, config).get();
if (expectedTopologyCount == 0) {
Assert.assertEquals(topologyResponse.getStatusCode(), 404);
} else {
Assert.assertEquals(topologyResponse.getStatusCode(), 200);
Assert.assertEquals(topologyResponse.getData().getTopology().size(), expectedTopologyCount);
}
}
static List<Topology> createToplogies(int topologyCount) throws Exception {
List<Topology> topologies = new ArrayList<>();
for (int i = 0; i < topologyCount; i++) {
List<Node> nodes = new ArrayList<>();
final NodeId nodeId = new NodeId("node-" + i);
nodes.add(new NodeBuilder()
.setKey(new NodeKey(nodeId))
.setNodeId(nodeId)
.build());
final TopologyId topologyId = new TopologyId("topology-" + i);
final TopologyKey topologyKey = new TopologyKey(topologyId);
topologies.add(new TopologyBuilder()
.setKey(topologyKey)
.setTopologyId(topologyId)
.setNode(nodes)
.build());
}
return topologies;
}
}