Prevent NPE for Credentials
[netconf.git] / apps / netconf-topology / src / test / java / org / opendaylight / netconf / topology / spi / NetconfNodeHandlerTest.java
index 1442988cce9214309c822e7c1796de75021a80f9..18873a58b9ae4cb9af5d4df7411179ffba62d812 100644 (file)
@@ -7,9 +7,8 @@
  */
 package org.opendaylight.netconf.topology.spi;
 
-import static org.hamcrest.CoreMatchers.instanceOf;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.eq;
@@ -28,22 +27,24 @@ import io.netty.util.TimerTask;
 import java.net.InetSocketAddress;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.runner.RunWith;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
+import org.mockito.junit.jupiter.MockitoExtension;
 import org.opendaylight.aaa.encrypt.AAAEncryptionService;
 import org.opendaylight.netconf.api.CapabilityURN;
 import org.opendaylight.netconf.client.NetconfClientFactory;
+import org.opendaylight.netconf.client.NetconfClientFactoryImpl;
 import org.opendaylight.netconf.client.NetconfClientSession;
 import org.opendaylight.netconf.client.mdsal.NetconfDeviceCapabilities;
 import org.opendaylight.netconf.client.mdsal.NetconfDeviceSchema;
-import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemas;
+import org.opendaylight.netconf.client.mdsal.api.BaseNetconfSchemaProvider;
 import org.opendaylight.netconf.client.mdsal.api.CredentialProvider;
 import org.opendaylight.netconf.client.mdsal.api.DeviceActionFactory;
 import org.opendaylight.netconf.client.mdsal.api.NetconfSessionPreferences;
@@ -53,15 +54,18 @@ import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices;
 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceServices.Rpcs;
 import org.opendaylight.netconf.client.mdsal.api.SchemaResourceManager;
 import org.opendaylight.netconf.client.mdsal.api.SslContextFactoryProvider;
-import org.opendaylight.netconf.client.mdsal.impl.DefaultBaseNetconfSchemas;
+import org.opendaylight.netconf.client.mdsal.impl.DefaultBaseNetconfSchemaProvider;
 import org.opendaylight.netconf.common.NetconfTimer;
+import org.opendaylight.netconf.common.impl.DefaultNetconfTimer;
 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.device.rev240120.credentials.credentials.LoginPwUnencryptedBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev240120.credentials.credentials.login.pw.unencrypted.LoginPasswordUnencryptedBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev231121.NetconfNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev240611.credentials.credentials.KeyAuthBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev240611.credentials.credentials.LoginPwUnencryptedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev240611.credentials.credentials.key.auth.KeyBasedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.device.rev240611.credentials.credentials.login.pw.unencrypted.LoginPasswordUnencryptedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev240611.NetconfNodeBuilder;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
 import org.opendaylight.yangtools.yang.common.Decimal64;
 import org.opendaylight.yangtools.yang.common.Uint16;
@@ -70,13 +74,13 @@ import org.opendaylight.yangtools.yang.data.api.schema.MountPointContext;
 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 import org.opendaylight.yangtools.yang.parser.impl.DefaultYangParserFactory;
 
-@RunWith(MockitoJUnitRunner.StrictStubs.class)
-public class NetconfNodeHandlerTest {
+@ExtendWith(MockitoExtension.class)
+class NetconfNodeHandlerTest {
     private static final RemoteDeviceId DEVICE_ID = new RemoteDeviceId("netconf-topology",
         new InetSocketAddress(InetAddresses.forString("127.0.0.1"), 9999));
     private static final NodeId NODE_ID = new NodeId("testing-node");
 
-    private static BaseNetconfSchemas BASE_SCHEMAS;
+    private static BaseNetconfSchemaProvider BASE_SCHEMAS;
 
     // Core setup
     @Mock
@@ -119,18 +123,18 @@ public class NetconfNodeHandlerTest {
     private NetconfTopologySchemaAssembler schemaAssembler;
     private NetconfNodeHandler handler;
 
-    @BeforeClass
-    public static void beforeClass() throws Exception {
-        BASE_SCHEMAS = new DefaultBaseNetconfSchemas(new DefaultYangParserFactory());
+    @BeforeAll
+    static void beforeClass() throws Exception {
+        BASE_SCHEMAS = new DefaultBaseNetconfSchemaProvider(new DefaultYangParserFactory());
     }
 
-    @BeforeClass
-    public static void afterClass() throws Exception {
+    @AfterAll
+    static void afterClass() throws Exception {
         BASE_SCHEMAS = null;
     }
 
-    @Before
-    public void before() {
+    @BeforeEach
+    void before() {
         schemaAssembler = new NetconfTopologySchemaAssembler(1, 1, 0, TimeUnit.SECONDS);
 
         // Instantiate the handler
@@ -162,13 +166,13 @@ public class NetconfNodeHandlerTest {
                 .build(), null);
     }
 
-    @After
-    public void after() {
+    @AfterEach
+    void after() {
         schemaAssembler.close();
     }
 
     @Test
-    public void successfulOnDeviceConnectedPropagates() throws Exception {
+    void successfulOnDeviceConnectedPropagates() throws Exception {
         assertSuccessfulConnect();
         assertEquals(1, handler.attempts());
 
@@ -189,7 +193,7 @@ public class NetconfNodeHandlerTest {
     }
 
     @Test
-    public void failedSchemaCausesReconnect() throws Exception {
+    void failedSchemaCausesReconnect() throws Exception {
         assertSuccessfulConnect();
         assertEquals(1, handler.attempts());
 
@@ -207,7 +211,7 @@ public class NetconfNodeHandlerTest {
     }
 
     @Test
-    public void downAfterUpCausesReconnect() throws Exception {
+    void downAfterUpCausesReconnect() throws Exception {
         // Let's borrow common bits
         successfulOnDeviceConnectedPropagates();
 
@@ -225,7 +229,7 @@ public class NetconfNodeHandlerTest {
     }
 
     @Test
-    public void socketFailuresAreRetried() throws Exception {
+    void socketFailuresAreRetried() throws Exception {
         final var firstFuture = SettableFuture.create();
         final var secondFuture = SettableFuture.create();
         doReturn(firstFuture, secondFuture).when(clientFactory).createClient(any());
@@ -246,7 +250,7 @@ public class NetconfNodeHandlerTest {
         final var throwableCaptor = ArgumentCaptor.forClass(Throwable.class);
         doNothing().when(delegate).onDeviceFailed(throwableCaptor.capture());
         secondFuture.setException(new AssertionError("second"));
-        assertThat(throwableCaptor.getValue(), instanceOf(ConnectGivenUpException.class));
+        assertInstanceOf(ConnectGivenUpException.class, throwableCaptor.getValue());
 
         // but nothing else happens
         assertEquals(2, handler.attempts());
@@ -260,4 +264,50 @@ public class NetconfNodeHandlerTest {
         verify(clientFactory).createClient(any());
         verifyNoInteractions(delegate);
     }
+
+    @Test
+    void failToConnectOnUnsupportedConfiguration() {
+        final var defaultTimer = new DefaultNetconfTimer();
+        final var factory = new NetconfClientFactoryImpl(defaultTimer);
+
+        final var keyId = "keyId";
+        final var keyAuthHandler = new NetconfNodeHandler(factory, defaultTimer, BASE_SCHEMAS, schemaManager,
+            schemaAssembler, new NetconfClientConfigurationBuilderFactoryImpl(encryptionService, credentialProvider,
+                sslContextFactoryProvider),
+            deviceActionFactory, delegate, DEVICE_ID, NODE_ID, new NetconfNodeBuilder()
+                .setHost(new Host(new IpAddress(new Ipv4Address("127.0.0.1"))))
+                .setPort(new PortNumber(Uint16.valueOf(9999)))
+                .setReconnectOnChangedSchema(true)
+                .setSchemaless(true)
+                .setTcpOnly(false)
+                .setProtocol(null)
+                .setBackoffMultiplier(Decimal64.valueOf("1.5"))
+                .setConcurrentRpcLimit(Uint16.ONE)
+                // One reconnection attempt
+                .setMaxConnectionAttempts(Uint32.ONE)
+                .setDefaultRequestTimeoutMillis(Uint32.valueOf(1000))
+                .setMinBackoffMillis(Uint16.valueOf(100))
+                .setKeepaliveDelay(Uint32.valueOf(1000))
+                .setConnectionTimeoutMillis(Uint32.valueOf(1000))
+                .setMaxBackoffMillis(Uint32.valueOf(1000))
+                .setBackoffJitter(Decimal64.valueOf("0.0"))
+                .setCredentials(new KeyAuthBuilder()
+                    .setKeyBased(new KeyBasedBuilder()
+                        .setUsername("testuser")
+                        .setKeyId(keyId)
+                        .build())
+                    .build())
+                .build(), null);
+
+        // return null when attempt to load credentials fot key id
+        doReturn(null).when(credentialProvider).credentialForId(any());
+        doNothing().when(delegate).onDeviceFailed(any());
+        keyAuthHandler.connect();
+        verify(credentialProvider).credentialForId(eq(keyId));
+        // attempt to connect fails due to unsupported configuration, and there is attempt to reconnect
+        final var captor = ArgumentCaptor.forClass(Throwable.class);
+        verify(delegate).onDeviceFailed(captor.capture());
+        assertInstanceOf(ConnectGivenUpException.class, captor.getValue());
+        assertEquals(1, keyAuthHandler.attempts());
+    }
 }