ErrorSeverity errorSeverity = ErrorSeverity.ERROR;
Map<String, String> errorInfo = null;
String errorMessage = "";
+ StringBuilder allErrorMessages = new StringBuilder();
Node rpcReply = fromDoc.getDocumentElement();
- // FIXME: BUG? - we only handle one rpc-error.
+ // FIXME: BUG? - we only handle one rpc-error. For now, shove extra errorMessages
+ // found in multiple rpc-error in the errorInfo Map to at least let them propagate
+ // back to caller.
+ int rpcErrorCount = 0;
NodeList replyChildren = rpcReply.getChildNodes();
for (int i = 0; i < replyChildren.getLength(); i++) {
Node replyChild = replyChildren.item(i);
- if (RPC_ERROR.equals(replyChild.getNodeName())) {
+ if (RPC_ERROR.equals(replyChild.getLocalName())) {
+ rpcErrorCount++;
NodeList rpcErrorChildren = replyChild.getChildNodes();
for (int j = 0; j < rpcErrorChildren.getLength(); j++) {
Node rpcErrorChild = rpcErrorChildren.item(j);
- if (ERROR_TYPE.equals(rpcErrorChild.getNodeName())) {
+ if (ERROR_TYPE.equals(rpcErrorChild.getLocalName())) {
errorType = ErrorType.from(rpcErrorChild.getTextContent());
- } else if (ERROR_TAG.equals(rpcErrorChild.getNodeName())) {
+ } else if (ERROR_TAG.equals(rpcErrorChild.getLocalName())) {
errorTag = ErrorTag.from(rpcErrorChild.getTextContent());
- } else if (ERROR_SEVERITY.equals(rpcErrorChild.getNodeName())) {
+ } else if (ERROR_SEVERITY.equals(rpcErrorChild.getLocalName())) {
errorSeverity = ErrorSeverity.from(rpcErrorChild.getTextContent());
- } else if (ERROR_MESSAGE.equals(rpcErrorChild.getNodeName())) {
+ } else if (ERROR_MESSAGE.equals(rpcErrorChild.getLocalName())) {
errorMessage = rpcErrorChild.getTextContent();
- } else if (ERROR_INFO.equals(rpcErrorChild.getNodeName())) {
+ allErrorMessages.append(errorMessage);
+ } else if (ERROR_INFO.equals(rpcErrorChild.getLocalName())) {
errorInfo = parseErrorInfo(rpcErrorChild);
}
}
+ }
+ }
- break;
+ if (rpcErrorCount > 1) {
+ if (errorInfo == null) {
+ errorInfo = new HashMap<>();
}
+ errorInfo.put("Multiple Errors Found", allErrorMessages.toString());
}
return new DocumentedException(errorMessage, errorType, errorTag, errorSeverity, errorInfo);
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));
+ }
+
/**
* Test whether reconnect is scheduled properly.
*/
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 + "\">"