Schema determination is asynchronous
[netconf.git] / plugins / netconf-client-mdsal / src / test / java / org / opendaylight / netconf / client / mdsal / NetconfStateSchemasTest.java
index 0d091216207724f99ae4c36d994c14b2b8965bdf..5dfebde7919a77bcecf780716926aee7c0b88155 100644 (file)
@@ -8,32 +8,28 @@
 package org.opendaylight.netconf.client.mdsal;
 
 import static org.hamcrest.CoreMatchers.hasItem;
-import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
 import java.net.InetSocketAddress;
+import java.util.List;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
-import org.opendaylight.mdsal.dom.api.DOMRpcResult;
 import org.opendaylight.mdsal.dom.api.DOMRpcService;
 import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
 import org.opendaylight.netconf.client.mdsal.api.NetconfSessionPreferences;
@@ -45,10 +41,11 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.netconf.mon
 import org.opendaylight.yangtools.util.xml.UntrustedXML;
 import org.opendaylight.yangtools.yang.common.ErrorTag;
 import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.OperationFailedException;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcError;
 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
 import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
@@ -56,71 +53,61 @@ import org.opendaylight.yangtools.yang.data.impl.schema.NormalizationResultHolde
 import org.opendaylight.yangtools.yang.data.spi.node.ImmutableNodes;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @RunWith(MockitoJUnitRunner.StrictStubs.class)
 public class NetconfStateSchemasTest extends AbstractBaseSchemasTest {
-    private static final Logger LOG = LoggerFactory.getLogger(NetconfStateSchemasTest.class);
     private static final NetconfSessionPreferences CAPS = NetconfSessionPreferences.fromStrings(Set.of(
         "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04"));
+    private static final RemoteDeviceId DEVICE_ID = new RemoteDeviceId("device", new InetSocketAddress(99));
 
-    private final RemoteDeviceId deviceId = new RemoteDeviceId("device", new InetSocketAddress(99));
-    private final int numberOfSchemas = 73;
-    private final int numberOfLegalSchemas = numberOfSchemas - 3;
-
-    private ContainerNode compositeNodeSchemas;
+    private static EffectiveModelContext MODEL_CONTEXT = BASE_SCHEMAS.baseSchemaForCapabilities(CAPS).modelContext();
+    private static ContainerNode SCHEMAS_PAYLOAD;
 
     @Mock
     private DOMRpcService rpc;
 
-    private EffectiveModelContext modelContext;
-
-    @Before
-    public void setUp() throws Exception {
-        modelContext = BASE_SCHEMAS.baseSchemaForCapabilities(CAPS).modelContext();
-
+    @BeforeClass
+    public static void setUp() throws Exception {
         final var resultHolder = new NormalizationResultHolder();
         final var writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
         final var xmlParser = XmlParserStream.create(writer,
-            SchemaInferenceStack.ofDataTreePath(modelContext, NetconfState.QNAME, Schemas.QNAME).toInference(), false);
+            SchemaInferenceStack.ofDataTreePath(MODEL_CONTEXT, NetconfState.QNAME, Schemas.QNAME).toInference(), false);
 
-        xmlParser.parse(UntrustedXML.createXMLStreamReader(getClass().getResourceAsStream(
+        xmlParser.parse(UntrustedXML.createXMLStreamReader(NetconfStateSchemasTest.class.getResourceAsStream(
                 "/netconf-state.schemas.payload.xml")));
-        compositeNodeSchemas = (ContainerNode) resultHolder.getResult().data();
+        SCHEMAS_PAYLOAD = (ContainerNode) resultHolder.getResult().data();
     }
 
     @Test
     public void testCreate() throws Exception {
-        final var schemas = NetconfStateSchemas.create(deviceId, compositeNodeSchemas);
+        final var future = SettableFuture.<NetconfStateSchemas>create();
+        NetconfStateSchemas.create(future, DEVICE_ID, SCHEMAS_PAYLOAD);
+        final var schemas = Futures.getDone(future);
 
         final var availableYangSchemasQNames = schemas.getAvailableYangSchemasQNames();
-        assertEquals(numberOfLegalSchemas, availableYangSchemasQNames.size());
+        assertEquals(69, availableYangSchemasQNames.size());
 
         assertThat(availableYangSchemasQNames,
                 hasItem(QName.create("urn:TBD:params:xml:ns:yang:network-topology", "2013-07-12", "network-topology")));
     }
 
-    @Ignore
     @Test
+    @Ignore("We cannot handle a container as data -- only anyxml")
     public void testCreate2() throws Exception {
-        final ContainerNode netconfState = ImmutableNodes.newContainerBuilder()
-                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NetconfState.QNAME))
-                .withChild(compositeNodeSchemas)
-                .build();
-        final ContainerNode data = ImmutableNodes.newContainerBuilder()
-                .withNodeIdentifier(NetconfMessageTransformUtil.NETCONF_DATA_NODEID)
-                .withChild(netconfState)
-                .build();
         final ContainerNode rpcReply = ImmutableNodes.newContainerBuilder()
-                .withNodeIdentifier(new YangInstanceIdentifier
-                        .NodeIdentifier(NetconfMessageTransformUtil.NETCONF_RPC_REPLY_QNAME))
-                .withChild(data)
+                .withNodeIdentifier(new NodeIdentifier(NetconfMessageTransformUtil.NETCONF_RPC_REPLY_QNAME))
+                .withChild(ImmutableNodes.newContainerBuilder()
+                    .withNodeIdentifier(NetconfMessageTransformUtil.NETCONF_DATA_NODEID)
+                    .withChild(ImmutableNodes.newContainerBuilder()
+                        .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NetconfState.QNAME))
+                        .withChild(SCHEMAS_PAYLOAD)
+                        .build())
+                    .build())
                 .build();
         doReturn(Futures.immediateFuture(new DefaultDOMRpcResult(rpcReply))).when(rpc).invokeRpc(eq(Get.QNAME), any());
-        final NetconfStateSchemas stateSchemas = NetconfStateSchemas.create(rpc, CAPS, deviceId, modelContext);
-        final Set<QName> availableYangSchemasQNames = stateSchemas.getAvailableYangSchemasQNames();
-        assertEquals(numberOfLegalSchemas, availableYangSchemasQNames.size());
+        final var stateSchemas = assertSchemas(CAPS);
+        final var availableYangSchemasQNames = stateSchemas.getAvailableYangSchemasQNames();
+        assertEquals(69, availableYangSchemasQNames.size());
 
         assertThat(availableYangSchemasQNames,
                 hasItem(QName.create("urn:TBD:params:xml:ns:yang:network-topology", "2013-07-12", "network-topology")));
@@ -128,57 +115,36 @@ public class NetconfStateSchemasTest extends AbstractBaseSchemasTest {
 
     @Test
     public void testCreateMonitoringNotSupported() throws Exception {
-        final var caps = NetconfSessionPreferences.fromStrings(Set.of());
-        final var stateSchemas = NetconfStateSchemas.create(rpc, caps, deviceId, modelContext);
+        final var stateSchemas = assertSchemas(NetconfSessionPreferences.fromStrings(Set.of()));
         assertEquals(Set.of(), stateSchemas.getAvailableYangSchemasQNames());
     }
 
     @Test
     public void testCreateFail() throws Exception {
-        when(rpc.invokeRpc(eq(Get.QNAME), any())).thenReturn(
-                Futures.immediateFailedFuture(new DOMRpcImplementationNotAvailableException("not available")));
-        final var stateSchemas = NetconfStateSchemas.create(rpc, CAPS, deviceId, modelContext);
-        assertEquals(Set.of(), stateSchemas.getAvailableYangSchemasQNames());
+        final var domEx = new DOMRpcImplementationNotAvailableException("not available");
+        doReturn(Futures.immediateFailedFuture(domEx)).when(rpc).invokeRpc(eq(Get.QNAME), any());
+        assertSame(domEx, assertSchemasFailure());
     }
 
     @Test
     public void testCreateRpcError() throws Exception {
-        final RpcError rpcError = RpcResultBuilder.newError(ErrorType.RPC, new ErrorTag("fail"), "fail");
-        doReturn(Futures.immediateFuture(new DefaultDOMRpcResult(rpcError))).when(rpc)
-            .invokeRpc(eq(Get.QNAME), any());
-        final var stateSchemas = NetconfStateSchemas.create(rpc, CAPS, deviceId, modelContext);
-        assertEquals(Set.of(), stateSchemas.getAvailableYangSchemasQNames());
+        final var rpcError = RpcResultBuilder.newError(ErrorType.RPC, new ErrorTag("fail"), "fail");
+        doReturn(Futures.immediateFuture(new DefaultDOMRpcResult(rpcError))).when(rpc).invokeRpc(eq(Get.QNAME), any());
+
+        final var ex = assertInstanceOf(OperationFailedException.class, assertSchemasFailure());
+        assertEquals(List.of(rpcError), ex.getErrorList());
     }
 
-    @Test
-    public void testCreateInterrupted() {
-        //NetconfStateSchemas.create calls Thread.currentThread().interrupt(), so it must run in its own thread
-        final var testFuture = Executors.newSingleThreadExecutor().submit(() -> {
-            final ListenableFuture<DOMRpcResult> interruptedFuture = mock(ListenableFuture.class);
-            try {
-                when(interruptedFuture.get()).thenThrow(new InterruptedException("interrupted"));
-                doReturn(interruptedFuture).when(rpc).invokeRpc(eq(Get.QNAME), any());
-                NetconfStateSchemas.create(rpc, CAPS, deviceId, modelContext);
-            } catch (final InterruptedException | ExecutionException e) {
-                LOG.info("Operation failed.", e);
-            }
-        });
-
-        assertThat(assertThrows(ExecutionException.class, () -> testFuture.get(3, TimeUnit.SECONDS)).getCause(),
-            instanceOf(RuntimeException.class));
+    private NetconfStateSchemas assertSchemas(final NetconfSessionPreferences prefs) {
+        try {
+            return Futures.getDone(NetconfStateSchemas.forDevice(rpc, prefs, DEVICE_ID, MODEL_CONTEXT));
+        } catch (ExecutionException e) {
+            throw new AssertionError(e);
+        }
     }
 
-    @Test
-    public void testRemoteYangSchemaEquals() throws Exception {
-        final NetconfStateSchemas.RemoteYangSchema schema1 =
-                new NetconfStateSchemas.RemoteYangSchema(NetconfState.QNAME);
-        final NetconfStateSchemas.RemoteYangSchema schema2 =
-                new NetconfStateSchemas.RemoteYangSchema(NetconfState.QNAME);
-        final NetconfStateSchemas.RemoteYangSchema schema3 =
-                new NetconfStateSchemas.RemoteYangSchema(Schemas.QNAME);
-        assertEquals(schema1, schema2);
-        assertEquals(schema2, schema1);
-        assertNotEquals(schema1, schema3);
-        assertNotEquals(schema2, schema3);
+    private Throwable assertSchemasFailure() {
+        final var future = NetconfStateSchemas.forDevice(rpc, CAPS, DEVICE_ID, MODEL_CONTEXT);
+        return assertThrows(ExecutionException.class, () -> Futures.getDone(future)).getCause();
     }
 }