2 * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.client.mdsal;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertTrue;
14 import static org.mockito.ArgumentMatchers.any;
15 import static org.mockito.ArgumentMatchers.eq;
16 import static org.mockito.ArgumentMatchers.same;
17 import static org.mockito.Mockito.CALLS_REAL_METHODS;
18 import static org.mockito.Mockito.doNothing;
19 import static org.mockito.Mockito.doReturn;
20 import static org.mockito.Mockito.mock;
21 import static org.mockito.Mockito.never;
22 import static org.mockito.Mockito.reset;
23 import static org.mockito.Mockito.spy;
24 import static org.mockito.Mockito.timeout;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.withSettings;
27 import static org.opendaylight.netconf.api.xml.XmlNetconfConstants.URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0;
29 import com.google.common.base.CharMatcher;
30 import com.google.common.base.Strings;
31 import com.google.common.util.concurrent.ListenableFuture;
32 import io.netty.channel.Channel;
33 import io.netty.channel.ChannelFuture;
34 import io.netty.channel.EventLoopGroup;
35 import io.netty.channel.nio.NioEventLoopGroup;
36 import io.netty.util.HashedWheelTimer;
37 import io.netty.util.Timer;
38 import io.netty.util.concurrent.Future;
39 import io.netty.util.concurrent.GenericFutureListener;
40 import io.netty.util.concurrent.GlobalEventExecutor;
41 import java.io.ByteArrayInputStream;
42 import java.net.InetSocketAddress;
43 import java.util.ArrayList;
45 import java.util.UUID;
46 import java.util.concurrent.TimeUnit;
47 import java.util.concurrent.TimeoutException;
48 import javax.xml.parsers.ParserConfigurationException;
49 import org.junit.Before;
50 import org.junit.Test;
51 import org.junit.runner.RunWith;
52 import org.mockito.ArgumentCaptor;
53 import org.mockito.Mock;
54 import org.mockito.MockMakers;
55 import org.mockito.junit.MockitoJUnitRunner;
56 import org.opendaylight.netconf.api.NetconfMessage;
57 import org.opendaylight.netconf.api.NetconfTerminationReason;
58 import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
59 import org.opendaylight.netconf.client.NetconfClientDispatcherImpl;
60 import org.opendaylight.netconf.client.NetconfClientSession;
61 import org.opendaylight.netconf.client.NetconfClientSessionListener;
62 import org.opendaylight.netconf.client.conf.NetconfClientConfiguration;
63 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfiguration;
64 import org.opendaylight.netconf.client.conf.NetconfReconnectingClientConfigurationBuilder;
65 import org.opendaylight.netconf.client.mdsal.api.NetconfSessionPreferences;
66 import org.opendaylight.netconf.client.mdsal.api.RemoteDevice;
67 import org.opendaylight.netconf.client.mdsal.api.RemoteDeviceId;
68 import org.opendaylight.netconf.client.mdsal.impl.NetconfMessageTransformUtil;
69 import org.opendaylight.netconf.nettyutil.ReconnectStrategy;
70 import org.opendaylight.netconf.nettyutil.TimedReconnectStrategy;
71 import org.opendaylight.netconf.nettyutil.handler.ssh.authentication.LoginPasswordHandler;
72 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
73 import org.opendaylight.yangtools.util.xml.UntrustedXML;
74 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
75 import org.opendaylight.yangtools.yang.common.ErrorTag;
76 import org.opendaylight.yangtools.yang.common.ErrorType;
77 import org.opendaylight.yangtools.yang.common.QName;
78 import org.opendaylight.yangtools.yang.common.RpcError;
79 import org.opendaylight.yangtools.yang.common.RpcResult;
80 import org.opendaylight.yangtools.yang.common.Uint32;
81 import org.slf4j.Logger;
82 import org.slf4j.LoggerFactory;
83 import org.w3c.dom.Document;
84 import org.w3c.dom.Element;
86 @RunWith(MockitoJUnitRunner.StrictStubs.class)
87 public class NetconfDeviceCommunicatorTest {
88 private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceCommunicatorTest.class);
89 private static final SessionIdType SESSION_ID = new SessionIdType(Uint32.ONE);
92 RemoteDevice<NetconfDeviceCommunicator> mockDevice;
94 private NetconfClientSession spySession;
95 private NetconfDeviceCommunicator communicator;
98 public void setUp() throws Exception {
99 communicator = new NetconfDeviceCommunicator(
100 new RemoteDeviceId("test", InetSocketAddress.createUnresolved("localhost", 22)), mockDevice, 10);
101 // FIXME: spy() except we override the MockMaker in use
102 spySession = mock(NetconfClientSession.class, withSettings()
103 .spiedInstance(new NetconfClientSession(mock(NetconfClientSessionListener.class), mock(Channel.class),
104 SESSION_ID, Set.of()))
105 .defaultAnswer(CALLS_REAL_METHODS)
106 .mockMaker(MockMakers.SUBCLASS));
109 void setupSession() {
110 doNothing().when(mockDevice).onRemoteSessionUp(any(NetconfSessionPreferences.class),
111 any(NetconfDeviceCommunicator.class));
112 communicator.onSessionUp(spySession);
115 private ListenableFuture<RpcResult<NetconfMessage>> sendRequest() throws Exception {
116 return sendRequest(UUID.randomUUID().toString(), true);
119 @SuppressWarnings("unchecked")
120 private ListenableFuture<RpcResult<NetconfMessage>> sendRequest(final String messageID,
121 final boolean doLastTest) throws Exception {
122 Document doc = UntrustedXML.newDocumentBuilder().newDocument();
123 Element element = doc.createElement("request");
124 element.setAttribute("message-id", messageID);
125 doc.appendChild(element);
126 NetconfMessage message = new NetconfMessage(doc);
128 ChannelFuture mockChannelFuture = mock(ChannelFuture.class);
129 doReturn(mockChannelFuture).when(mockChannelFuture)
130 .addListener(any(GenericFutureListener.class));
131 doReturn(mockChannelFuture).when(spySession).sendMessage(same(message));
133 ListenableFuture<RpcResult<NetconfMessage>> resultFuture =
134 communicator.sendRequest(message, QName.create("", "mockRpc"));
136 assertNotNull("ListenableFuture is null", resultFuture);
142 public void testOnSessionUp() {
143 final var testCapability = "urn:opendaylight:params:xml:ns:test?module=test-module&revision=2014-06-02";
144 final var serverCapabilities = Set.of(
145 XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_CAPABILITY_ROLLBACK_ON_ERROR_1_0,
146 NetconfMessageTransformUtil.IETF_NETCONF_MONITORING.getNamespace().toString(),
148 doReturn(serverCapabilities).when(spySession).getServerCapabilities();
150 final var netconfSessionPreferences = ArgumentCaptor.forClass(NetconfSessionPreferences.class);
151 doNothing().when(mockDevice).onRemoteSessionUp(netconfSessionPreferences.capture(), eq(communicator));
153 communicator.onSessionUp(spySession);
155 verify(spySession).getServerCapabilities();
156 verify(mockDevice).onRemoteSessionUp(netconfSessionPreferences.capture(), eq(communicator));
158 NetconfSessionPreferences actualCapabilites = netconfSessionPreferences.getValue();
159 assertTrue(actualCapabilites.containsNonModuleCapability(
160 "urn:ietf:params:netconf:capability:rollback-on-error:1.0"));
161 assertFalse(actualCapabilites.containsNonModuleCapability(testCapability));
162 assertEquals(Set.of(QName.create("urn:opendaylight:params:xml:ns:test", "2014-06-02", "test-module")),
163 actualCapabilites.moduleBasedCaps().keySet());
164 assertTrue(actualCapabilites.isRollbackSupported());
165 assertTrue(actualCapabilites.isMonitoringSupported());
166 assertEquals(SESSION_ID, actualCapabilites.sessionId());
169 @SuppressWarnings("unchecked")
170 @Test(timeout = 5000)
171 public void testOnSessionDown() throws Exception {
174 ListenableFuture<RpcResult<NetconfMessage>> resultFuture1 = sendRequest();
175 final ListenableFuture<RpcResult<NetconfMessage>> resultFuture2 = sendRequest();
177 doNothing().when(mockDevice).onRemoteSessionDown();
179 communicator.onSessionDown(spySession, new Exception("mock ex"));
181 verifyErrorRpcResult(resultFuture1.get(), ErrorType.TRANSPORT, ErrorTag.OPERATION_FAILED);
182 verifyErrorRpcResult(resultFuture2.get(), ErrorType.TRANSPORT, ErrorTag.OPERATION_FAILED);
184 verify(mockDevice).onRemoteSessionDown();
188 communicator.onSessionDown(spySession, new Exception("mock ex"));
190 verify(mockDevice, never()).onRemoteSessionDown();
194 public void testOnSessionTerminated() throws Exception {
197 ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest();
199 doNothing().when(mockDevice).onRemoteSessionDown();
201 String reasonText = "testing terminate";
202 NetconfTerminationReason reason = new NetconfTerminationReason(reasonText);
203 communicator.onSessionTerminated(spySession, reason);
205 RpcError rpcError = verifyErrorRpcResult(resultFuture.get(), ErrorType.TRANSPORT, ErrorTag.OPERATION_FAILED);
206 assertEquals("RpcError message", reasonText, rpcError.getMessage());
208 verify(mockDevice).onRemoteSessionDown();
212 public void testClose() throws Exception {
213 communicator.close();
214 verify(mockDevice, never()).onRemoteSessionDown();
217 @SuppressWarnings({"rawtypes", "unchecked"})
219 public void testSendRequest() throws Exception {
222 NetconfMessage message = new NetconfMessage(UntrustedXML.newDocumentBuilder().newDocument());
223 QName rpc = QName.create("", "mockRpc");
225 ArgumentCaptor<GenericFutureListener> futureListener =
226 ArgumentCaptor.forClass(GenericFutureListener.class);
228 ChannelFuture mockChannelFuture = mock(ChannelFuture.class);
229 doReturn(mockChannelFuture).when(mockChannelFuture).addListener(futureListener.capture());
230 doReturn(mockChannelFuture).when(spySession).sendMessage(same(message));
232 ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest(message, rpc);
234 verify(spySession).sendMessage(same(message));
236 assertNotNull("ListenableFuture is null", resultFuture);
238 verify(mockChannelFuture).addListener(futureListener.capture());
239 Future<Void> operationFuture = mock(Future.class);
240 doReturn(true).when(operationFuture).isSuccess();
241 futureListener.getValue().operationComplete(operationFuture);
244 resultFuture.get(1, TimeUnit.MILLISECONDS); // verify it's not cancelled or has an error set
245 } catch (TimeoutException e) {
246 LOG.info("Operation failed due timeout.");
251 public void testSendRequestWithNoSession() throws Exception {
252 NetconfMessage message = new NetconfMessage(UntrustedXML.newDocumentBuilder().newDocument());
253 QName rpc = QName.create("", "mockRpc");
255 ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest(message, rpc);
257 assertNotNull("ListenableFuture is null", resultFuture);
259 // Should have an immediate result
260 RpcResult<NetconfMessage> rpcResult = resultFuture.get(3, TimeUnit.MILLISECONDS);
262 verifyErrorRpcResult(rpcResult, ErrorType.TRANSPORT, ErrorTag.OPERATION_FAILED);
265 private static NetconfMessage createSuccessResponseMessage(final String messageID)
266 throws ParserConfigurationException {
267 Document doc = UntrustedXML.newDocumentBuilder().newDocument();
269 doc.createElementNS(URN_IETF_PARAMS_XML_NS_NETCONF_BASE_1_0, XmlNetconfConstants.RPC_REPLY_KEY);
270 rpcReply.setAttribute("message-id", messageID);
271 Element element = doc.createElementNS("ns", "data");
272 element.setTextContent(messageID);
273 rpcReply.appendChild(element);
274 doc.appendChild(rpcReply);
276 return new NetconfMessage(doc);
279 @SuppressWarnings({ "rawtypes", "unchecked" })
281 public void testSendRequestWithWithSendFailure() throws Exception {
284 NetconfMessage message = new NetconfMessage(UntrustedXML.newDocumentBuilder().newDocument());
285 QName rpc = QName.create("", "mockRpc");
287 ArgumentCaptor<GenericFutureListener> futureListener =
288 ArgumentCaptor.forClass(GenericFutureListener.class);
290 ChannelFuture mockChannelFuture = mock(ChannelFuture.class);
291 doReturn(mockChannelFuture).when(mockChannelFuture).addListener(futureListener.capture());
292 doReturn(mockChannelFuture).when(spySession).sendMessage(same(message));
294 ListenableFuture<RpcResult<NetconfMessage>> resultFuture = communicator.sendRequest(message, rpc);
296 assertNotNull("ListenableFuture is null", resultFuture);
298 verify(mockChannelFuture).addListener(futureListener.capture());
300 Future<Void> operationFuture = mock(Future.class);
301 doReturn(false).when(operationFuture).isSuccess();
302 doReturn(new Exception("mock error")).when(operationFuture).cause();
303 futureListener.getValue().operationComplete(operationFuture);
305 // Should have an immediate result
306 RpcResult<NetconfMessage> rpcResult = resultFuture.get(3, TimeUnit.MILLISECONDS);
308 RpcError rpcError = verifyErrorRpcResult(rpcResult, ErrorType.TRANSPORT, ErrorTag.OPERATION_FAILED);
309 assertEquals("RpcError message contains \"mock error\"", true,
310 rpcError.getMessage().contains("mock error"));
313 //Test scenario verifying whether missing message is handled
315 public void testOnMissingResponseMessage() throws Exception {
319 String messageID1 = UUID.randomUUID().toString();
320 ListenableFuture<RpcResult<NetconfMessage>> resultFuture1 = sendRequest(messageID1, true);
322 String messageID2 = UUID.randomUUID().toString();
323 ListenableFuture<RpcResult<NetconfMessage>> resultFuture2 = sendRequest(messageID2, true);
325 String messageID3 = UUID.randomUUID().toString();
326 ListenableFuture<RpcResult<NetconfMessage>> resultFuture3 = sendRequest(messageID3, true);
328 //response messages 1,2 are omitted
329 communicator.onMessage(spySession, createSuccessResponseMessage(messageID3));
331 verifyResponseMessage(resultFuture3.get(), messageID3);
335 public void testOnSuccessfulResponseMessage() throws Exception {
338 String messageID1 = UUID.randomUUID().toString();
339 ListenableFuture<RpcResult<NetconfMessage>> resultFuture1 = sendRequest(messageID1, true);
341 String messageID2 = UUID.randomUUID().toString();
342 final ListenableFuture<RpcResult<NetconfMessage>> resultFuture2 = sendRequest(messageID2, true);
344 communicator.onMessage(spySession, createSuccessResponseMessage(messageID1));
345 communicator.onMessage(spySession, createSuccessResponseMessage(messageID2));
347 verifyResponseMessage(resultFuture1.get(), messageID1);
348 verifyResponseMessage(resultFuture2.get(), messageID2);
352 public void testOnResponseMessageWithError() throws Exception {
355 String messageID = UUID.randomUUID().toString();
356 ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest(messageID, true);
358 communicator.onMessage(spySession, createErrorResponseMessage(messageID));
360 RpcError rpcError = verifyErrorRpcResult(resultFuture.get(), ErrorType.RPC, ErrorTag.MISSING_ATTRIBUTE);
361 assertEquals("RpcError message", "Missing attribute", rpcError.getMessage());
363 String errorInfo = rpcError.getInfo();
364 assertNotNull("RpcError info is null", errorInfo);
365 assertTrue("Error info contains \"foo\"", errorInfo.contains("<bad-attribute>foo</bad-attribute>"));
366 assertTrue("Error info contains \"bar\"", errorInfo.contains("<bad-element>bar</bad-element>"));
370 public void testOnResponseMessageWithMultipleErrors() throws Exception {
373 String messageID = UUID.randomUUID().toString();
374 ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest(messageID, true);
376 communicator.onMessage(spySession, createMultiErrorResponseMessage(messageID));
378 RpcError rpcError = verifyErrorRpcResult(resultFuture.get(), ErrorType.PROTOCOL, ErrorTag.OPERATION_FAILED);
380 String errorInfo = rpcError.getInfo();
381 assertNotNull("RpcError info is null", errorInfo);
383 String errorInfoMessages = rpcError.getInfo();
384 String errMsg1 = "Number of member links configured, i.e [1], "
385 + "for interface [ae0]is lesser than the required minimum [2].";
386 String errMsg2 = "configuration check-out failed";
387 assertTrue(String.format("Error info contains \"%s\" or \"%s\'", errMsg1, errMsg2),
388 errorInfoMessages.contains(errMsg1) && errorInfoMessages.contains(errMsg2));
392 * Test whether reconnect is scheduled properly.
395 public void testNetconfDeviceReconnectInCommunicator() {
396 final RemoteDevice<NetconfDeviceCommunicator> device = mock(RemoteDevice.class);
398 final TimedReconnectStrategy timedReconnectStrategy =
399 new TimedReconnectStrategy(GlobalEventExecutor.INSTANCE, 10000, 0, 1.0, null, 100L, null);
400 final ReconnectStrategy reconnectStrategy = spy(new ReconnectStrategy() {
403 public int getConnectTimeout() throws Exception {
404 return timedReconnectStrategy.getConnectTimeout();
409 public Future<Void> scheduleReconnect(final Throwable cause) {
410 return timedReconnectStrategy.scheduleReconnect(cause);
415 public void reconnectSuccessful() {
416 timedReconnectStrategy.reconnectSuccessful();
420 final EventLoopGroup group = new NioEventLoopGroup();
421 final Timer time = new HashedWheelTimer();
423 final NetconfDeviceCommunicator listener = new NetconfDeviceCommunicator(
424 new RemoteDeviceId("test", InetSocketAddress.createUnresolved("localhost", 22)), device, 10);
425 final NetconfReconnectingClientConfiguration cfg = NetconfReconnectingClientConfigurationBuilder.create()
426 .withAddress(new InetSocketAddress("localhost", 65000))
427 .withReconnectStrategy(reconnectStrategy)
428 .withConnectStrategyFactory(() -> reconnectStrategy)
429 .withAuthHandler(new LoginPasswordHandler("admin", "admin"))
430 .withConnectionTimeoutMillis(10000)
431 .withProtocol(NetconfClientConfiguration.NetconfClientProtocol.SSH)
432 .withSessionListener(listener)
435 listener.initializeRemoteConnection(new NetconfClientDispatcherImpl(group, group, time), cfg);
437 verify(reconnectStrategy,
438 timeout(TimeUnit.MINUTES.toMillis(4)).times(101)).scheduleReconnect(any(Throwable.class));
441 group.shutdownGracefully();
446 public void testOnResponseMessageWithWrongMessageID() throws Exception {
449 String messageID = UUID.randomUUID().toString();
450 ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest(messageID, true);
452 communicator.onMessage(spySession, createSuccessResponseMessage(UUID.randomUUID().toString()));
454 RpcError rpcError = verifyErrorRpcResult(resultFuture.get(), ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE);
455 assertFalse("RpcError message non-empty", Strings.isNullOrEmpty(rpcError.getMessage()));
457 String errorInfo = rpcError.getInfo();
458 assertNotNull("RpcError info is null", errorInfo);
459 assertTrue("Error info contains \"actual-message-id\"", errorInfo.contains("actual-message-id"));
460 assertTrue("Error info contains \"expected-message-id\"", errorInfo.contains("expected-message-id"));
464 public void testConcurrentMessageLimit() throws Exception {
466 ArrayList<String> messageID = new ArrayList<>();
468 for (int i = 0; i < 10; i++) {
469 messageID.add(UUID.randomUUID().toString());
470 ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest(messageID.get(i), false);
471 assertEquals("ListenableFuture is null", true, resultFuture instanceof UncancellableFuture);
474 final String notWorkingMessageID = UUID.randomUUID().toString();
475 ListenableFuture<RpcResult<NetconfMessage>> resultFuture = sendRequest(notWorkingMessageID, false);
476 assertEquals("ListenableFuture is null", false, resultFuture instanceof UncancellableFuture);
478 communicator.onMessage(spySession, createSuccessResponseMessage(messageID.get(0)));
480 resultFuture = sendRequest(messageID.get(0), false);
481 assertNotNull("ListenableFuture is null", resultFuture);
484 private static NetconfMessage createMultiErrorResponseMessage(final String messageID) throws Exception {
485 // multiple rpc-errors which simulate actual response like in NETCONF-666
486 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\""
487 + " message-id=\"" + messageID + "\">"
489 + "<nc:error-type>protocol</nc:error-type>\n"
490 + "<nc:error-tag>operation-failed</nc:error-tag>\n"
491 + "<nc:error-severity>error</nc:error-severity>\n"
492 + "<source-daemon>\n"
494 + "</source-daemon>\n"
495 + "<nc:error-message>\n"
496 + "Number of member links configured, i.e [1], "
497 + "for interface [ae0]is lesser than the required minimum [2].\n"
498 + "</nc:error-message>\n"
499 + "</nc:rpc-error>\n"
501 + "<nc:error-type>protocol</nc:error-type>\n"
502 + "<nc:error-tag>operation-failed</nc:error-tag>\n"
503 + "<nc:error-severity>error</nc:error-severity>\n"
504 + "<nc:error-message>\n"
505 + "configuration check-out failed\n"
506 + "</nc:error-message>\n"
507 + "</nc:rpc-error>\n"
510 ByteArrayInputStream bis = new ByteArrayInputStream(xmlStr.getBytes());
511 Document doc = UntrustedXML.newDocumentBuilder().parse(bis);
512 return new NetconfMessage(doc);
515 private static NetconfMessage createErrorResponseMessage(final String messageID) throws Exception {
516 String xmlStr = "<rpc-reply xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\""
517 + " message-id=\"" + messageID + "\">"
519 + " <error-type>rpc</error-type>"
520 + " <error-tag>missing-attribute</error-tag>"
521 + " <error-severity>error</error-severity>"
522 + " <error-message>Missing attribute</error-message>"
524 + " <bad-attribute>foo</bad-attribute>"
525 + " <bad-element>bar</bad-element>"
530 ByteArrayInputStream bis = new ByteArrayInputStream(xmlStr.getBytes());
531 Document doc = UntrustedXML.newDocumentBuilder().parse(bis);
532 return new NetconfMessage(doc);
535 private static void verifyResponseMessage(final RpcResult<NetconfMessage> rpcResult, final String dataText) {
536 assertNotNull("RpcResult is null", rpcResult);
537 assertTrue("isSuccessful", rpcResult.isSuccessful());
538 NetconfMessage messageResult = rpcResult.getResult();
539 assertNotNull("getResult", messageResult);
540 // List<SimpleNode<?>> nodes = messageResult.getSimpleNodesByName(
541 // QName.create( URI.create( "ns" ), null, "data" ) );
542 // assertNotNull( "getSimpleNodesByName", nodes );
543 // assertEquals( "List<SimpleNode<?>> size", 1, nodes.size() );
544 // assertEquals( "SimpleNode value", dataText, nodes.iterator().next().getValue() );
547 private static RpcError verifyErrorRpcResult(final RpcResult<NetconfMessage> rpcResult,
548 final ErrorType expErrorType, final ErrorTag expErrorTag) {
549 assertNotNull("RpcResult is null", rpcResult);
550 assertFalse("isSuccessful", rpcResult.isSuccessful());
551 assertNotNull("RpcResult errors is null", rpcResult.getErrors());
552 assertEquals("Errors size", 1, rpcResult.getErrors().size());
553 RpcError rpcError = rpcResult.getErrors().iterator().next();
554 assertEquals("getErrorSeverity", ErrorSeverity.ERROR, rpcError.getSeverity());
555 assertEquals("getErrorType", expErrorType, rpcError.getErrorType());
556 assertEquals("getErrorTag", expErrorTag, rpcError.getTag());
558 final String msg = rpcError.getMessage();
559 assertNotNull("getMessage is null", msg);
560 assertFalse("getMessage is empty", msg.isEmpty());
561 assertFalse("getMessage is blank", CharMatcher.whitespace().matchesAllOf(msg));