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;
    }
}