* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
-
package org.opendaylight.netconf.sal.connect.netconf.listener;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.same;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import javax.xml.parsers.ParserConfigurationException;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
+import org.mockito.junit.MockitoJUnitRunner;
import org.opendaylight.netconf.api.NetconfMessage;
import org.opendaylight.netconf.api.NetconfTerminationReason;
+import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.netconf.client.NetconfClientDispatcherImpl;
import org.opendaylight.netconf.client.NetconfClientSession;
import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
-import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPassword;
+import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
+import org.opendaylight.netconf.nettyutil.TimedReconnectStrategy;
+import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPasswordHandler;
import org.opendaylight.netconf.sal.connect.api.RemoteDevice;
import org.opendaylight.netconf.sal.connect.netconf.util.NetconfMessageTransformUtil;
import org.opendaylight.netconf.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.protocol.framework.ReconnectStrategy;
-import org.opendaylight.protocol.framework.TimedReconnectStrategy;
import org.opendaylight.yangtools.util.xml.UntrustedXML;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
public class NetconfDeviceCommunicatorTest {
private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceCommunicatorTest.class);
@Before
public void setUp() throws Exception {
- MockitoAnnotations.initMocks(this);
-
communicator = new NetconfDeviceCommunicator(
new RemoteDeviceId("test", InetSocketAddress.createUnresolved("localhost", 22)), mockDevice, 10);
}
ChannelFuture mockChannelFuture = mock(ChannelFuture.class);
doReturn(mockChannelFuture).when(mockChannelFuture)
- .addListener(any((GenericFutureListener.class)));
+ .addListener(any(GenericFutureListener.class));
doReturn(mockChannelFuture).when(mockSession).sendMessage(same(message));
ListenableFuture<RpcResult<NetconfMessage>> resultFuture =
- communicator.sendRequest(message, QName.create("mock rpc"));
+ communicator.sendRequest(message, QName.create("", "mockRpc"));
if (doLastTest) {
assertNotNull("ListenableFuture is null", resultFuture);
}
setupSession();
NetconfMessage message = new NetconfMessage(UntrustedXML.newDocumentBuilder().newDocument());
- QName rpc = QName.create("mock rpc");
+ QName rpc = QName.create("", "mockRpc");
ArgumentCaptor<GenericFutureListener> futureListener =
ArgumentCaptor.forClass(GenericFutureListener.class);
verify(mockChannelFuture).addListener(futureListener.capture());
Future<Void> operationFuture = mock(Future.class);
doReturn(true).when(operationFuture).isSuccess();
- doReturn(true).when(operationFuture).isDone();
futureListener.getValue().operationComplete(operationFuture);
try {
@Test
public void testSendRequestWithNoSession() throws Exception {
NetconfMessage message = new NetconfMessage(UntrustedXML.newDocumentBuilder().newDocument());
- QName rpc = QName.create("mock rpc");
+ QName rpc = QName.create("", "mockRpc");
ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest(message, rpc);
throws ParserConfigurationException {
Document doc = UntrustedXML.newDocumentBuilder().newDocument();
Element rpcReply =
- doc.createElementNS(URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, XmlMappingConstants.RPC_REPLY_KEY);
+ doc.createElementNS(URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, XmlNetconfConstants.RPC_REPLY_KEY);
rpcReply.setAttribute("message-id", messageID);
Element element = doc.createElementNS("ns", "data");
element.setTextContent(messageID);
setupSession();
NetconfMessage message = new NetconfMessage(UntrustedXML.newDocumentBuilder().newDocument());
- QName rpc = QName.create("mock rpc");
+ QName rpc = QName.create("", "mockRpc");
ArgumentCaptor<GenericFutureListener> futureListener =
ArgumentCaptor.forClass(GenericFutureListener.class);
Future<Void> operationFuture = mock(Future.class);
doReturn(false).when(operationFuture).isSuccess();
- doReturn(true).when(operationFuture).isDone();
doReturn(new Exception("mock error")).when(operationFuture).cause();
futureListener.getValue().operationComplete(operationFuture);
String errorInfo = rpcError.getInfo();
assertNotNull("RpcError info is null", errorInfo);
- assertEquals("Error info contains \"foo\"", true,
- errorInfo.contains("<bad-attribute>foo</bad-attribute>"));
- assertEquals("Error info contains \"bar\"", true,
- errorInfo.contains("<bad-element>bar</bad-element>"));
+ assertTrue("Error info contains \"foo\"", errorInfo.contains("<bad-attribute>foo</bad-attribute>"));
+ assertTrue("Error info contains \"bar\"", errorInfo.contains("<bad-element>bar</bad-element>"));
+ }
+
+ @Test
+ public void testOnResponseMessageWithMultipleErrors() throws Exception {
+ setupSession();
+
+ String messageID = UUID.randomUUID().toString();
+ ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest(messageID, true);
+
+ communicator.onMessage(mockSession, createMultiErrorResponseMessage(messageID));
+
+ RpcError rpcError = verifyErrorRpcResult(resultFuture.get(), RpcError.ErrorType.PROTOCOL,
+ "operation-failed");
+
+ String errorInfo = rpcError.getInfo();
+ assertNotNull("RpcError info is null", errorInfo);
+
+ String errorInfoMessages = rpcError.getInfo();
+ String errMsg1 = "Number of member links configured, i.e [1], "
+ + "for interface [ae0]is lesser than the required minimum [2].";
+ String errMsg2 = "configuration check-out failed";
+ assertTrue(String.format("Error info contains \"%s\" or \"%s\'", errMsg1, errMsg2),
+ errorInfoMessages.contains(errMsg1) && errorInfoMessages.contains(errMsg2));
}
/**
new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, 10000, 0, 1.0, null, 100L, null);
final ReconnectStrategy reconnectStrategy = spy(new ReconnectStrategy() {
@Override
+ @Deprecated
public int getConnectTimeout() throws Exception {
return timedReconnectStrategy.getConnectTimeout();
}
@Override
+ @Deprecated
public Future<Void> scheduleReconnect(final Throwable cause) {
return timedReconnectStrategy.scheduleReconnect(cause);
}
@Override
+ @Deprecated
public void reconnectSuccessful() {
timedReconnectStrategy.reconnectSuccessful();
}
.withAddress(new InetSocketAddress("localhost", 65000))
.withReconnectStrategy(reconnectStrategy)
.withConnectStrategyFactory(() -> reconnectStrategy)
- .withAuthHandler(new LoginPassword("admin", "admin"))
+ .withAuthHandler(new LoginPasswordHandler("admin", "admin"))
.withConnectionTimeoutMillis(10000)
.withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH)
.withSessionListener(listener)
RpcError rpcError = verifyErrorRpcResult(resultFuture.get(), RpcError.ErrorType.PROTOCOL,
"bad-attribute");
- assertEquals("RpcError message non-empty", true,
- !Strings.isNullOrEmpty(rpcError.getMessage()));
+ assertFalse("RpcError message non-empty", Strings.isNullOrEmpty(rpcError.getMessage()));
String errorInfo = rpcError.getInfo();
assertNotNull("RpcError info is null", errorInfo);
- assertEquals("Error info contains \"actual-message-id\"", true,
- errorInfo.contains("actual-message-id"));
- assertEquals("Error info contains \"expected-message-id\"", true,
- errorInfo.contains("expected-message-id"));
+ assertTrue("Error info contains \"actual-message-id\"", errorInfo.contains("actual-message-id"));
+ assertTrue("Error info contains \"expected-message-id\"", errorInfo.contains("expected-message-id"));
}
@Test
assertNotNull("ListenableFuture is null", resultFuture);
}
+ private static NetconfMessage createMultiErrorResponseMessage(final String messageID) throws Exception {
+ // multiple rpc-errors which simulate actual response like in NETCONF-666
+ String xmlStr = "<nc:rpc-reply xmlns:nc=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\" xmlns:junos=\"http://xml.juniper.net/junos/18.4R1/junos\""
+ + " message-id=\"" + messageID + "\">"
+ + "<nc:rpc-error>\n"
+ + "<nc:error-type>protocol</nc:error-type>\n"
+ + "<nc:error-tag>operation-failed</nc:error-tag>\n"
+ + "<nc:error-severity>error</nc:error-severity>\n"
+ + "<source-daemon>\n"
+ + "dcd\n"
+ + "</source-daemon>\n"
+ + "<nc:error-message>\n"
+ + "Number of member links configured, i.e [1], "
+ + "for interface [ae0]is lesser than the required minimum [2].\n"
+ + "</nc:error-message>\n"
+ + "</nc:rpc-error>\n"
+ + "<nc:rpc-error>\n"
+ + "<nc:error-type>protocol</nc:error-type>\n"
+ + "<nc:error-tag>operation-failed</nc:error-tag>\n"
+ + "<nc:error-severity>error</nc:error-severity>\n"
+ + "<nc:error-message>\n"
+ + "configuration check-out failed\n"
+ + "</nc:error-message>\n"
+ + "</nc:rpc-error>\n"
+ + "</nc:rpc-reply>";
+
+ ByteArrayInputStream bis = new ByteArrayInputStream(xmlStr.getBytes());
+ Document doc = UntrustedXML.newDocumentBuilder().parse(bis);
+ return new NetconfMessage(doc);
+ }
+
private static NetconfMessage createErrorResponseMessage(final String messageID) throws Exception {
String xmlStr = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\""
+ " message-id=\"" + messageID + "\">"
private static void verifyResponseMessage(final RpcResult<NetconfMessage> rpcResult, final String dataText) {
assertNotNull("RpcResult is null", rpcResult);
- assertEquals("isSuccessful", true, rpcResult.isSuccessful());
+ assertTrue("isSuccessful", rpcResult.isSuccessful());
NetconfMessage messageResult = rpcResult.getResult();
assertNotNull("getResult", messageResult);
// List<SimpleNode<?>> nodes = messageResult.getSimpleNodesByName(
private static RpcError verifyErrorRpcResult(final RpcResult<NetconfMessage> rpcResult,
final RpcError.ErrorType expErrorType, final String expErrorTag) {
assertNotNull("RpcResult is null", rpcResult);
- assertEquals("isSuccessful", false, rpcResult.isSuccessful());
+ assertFalse("isSuccessful", rpcResult.isSuccessful());
assertNotNull("RpcResult errors is null", rpcResult.getErrors());
assertEquals("Errors size", 1, rpcResult.getErrors().size());
RpcError rpcError = rpcResult.getErrors().iterator().next();
final String msg = rpcError.getMessage();
assertNotNull("getMessage is null", msg);
assertFalse("getMessage is empty", msg.isEmpty());
- assertFalse("getMessage is blank", CharMatcher.WHITESPACE.matchesAllOf(msg));
+ assertFalse("getMessage is blank", CharMatcher.whitespace().matchesAllOf(msg));
return rpcError;
}
}