* 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.controller.sal.restconf.impl.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.CheckedFuture;
-import com.google.common.util.concurrent.Futures;
import java.io.FileNotFoundException;
-import java.net.URI;
-import java.net.URISyntaxException;
import java.util.Arrays;
-import java.util.Collections;
+import java.util.Collection;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
+import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
-import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
-import org.opendaylight.controller.md.sal.dom.spi.DefaultDOMRpcResult;
import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.ErrorTags;
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
-import org.opendaylight.restconf.common.context.NormalizedNodeContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError;
-import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
-import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
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.common.XMLNamespace;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
-import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeAttrBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.api.SchemaPath;
-import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
public class InvokeRpcMethodTest {
private static UriInfo uriInfo;
- private static SchemaContext schemaContext;
+ private static EffectiveModelContext schemaContext;
private final RestconfImpl restconfImpl;
private final ControllerContext controllerContext;
@BeforeClass
public static void init() throws FileNotFoundException, ReactorException {
schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs", "/invoke-rpc");
- final Set<Module> allModules = schemaContext.getModules();
+ final Collection<? extends Module> allModules = schemaContext.getModules();
assertNotNull(allModules);
final Module module = TestUtils.resolveModule("invoke-rpc-module", allModules);
assertNotNull(module);
uriInfo = mock(UriInfo.class);
final MultivaluedMap<String, String> map = new MultivaluedHashMap<>();
- map.put("prettyPrint", Collections.singletonList("true"));
- when(uriInfo.getQueryParameters(any(Boolean.class))).thenReturn(map);
+ map.put("prettyPrint", List.of("true"));
+ doReturn(map).when(uriInfo).getQueryParameters(any(Boolean.class));
}
/**
* string - first argument).
*/
@Test
- @Ignore
public void invokeRpcMethodTest() {
- try {
- controllerContext.findModuleNameByNamespace(new URI("invoke:rpc:module"));
- } catch (final URISyntaxException e) {
- assertTrue("Uri wasn't created sucessfuly", false);
- }
+ controllerContext.findModuleNameByNamespace(XMLNamespace.of("invoke:rpc:module"));
final NormalizedNodeContext payload = prepareDomPayload();
final NormalizedNodeContext rpcResponse =
restconfImpl.invokeRpc("invoke-rpc-module:rpc-test", payload, uriInfo);
- assertTrue(rpcResponse != null);
- assertTrue(rpcResponse.getData() == null);
+ assertNotNull(rpcResponse);
+ assertNull(rpcResponse.getData());
}
private NormalizedNodeContext prepareDomPayload() {
- final SchemaContext schema = controllerContext.getGlobalSchema();
+ final EffectiveModelContext schema = controllerContext.getGlobalSchema();
final Module rpcModule = schema.findModules("invoke-rpc-module").iterator().next();
assertNotNull(rpcModule);
final QName rpcQName = QName.create(rpcModule.getQNameModule(), "rpc-test");
- final QName rpcInputQName = QName.create(rpcModule.getQNameModule(),"input");
- final Set<RpcDefinition> setRpcs = rpcModule.getRpcs();
- ContainerSchemaNode rpcInputSchemaNode = null;
- for (final RpcDefinition rpc : setRpcs) {
+ RpcDefinition rpcSchemaNode = null;
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
- rpcInputSchemaNode = SchemaNodeUtils.getRpcDataSchema(rpc, rpcInputQName);
+ rpcSchemaNode = rpc;
break;
}
}
- assertNotNull(rpcInputSchemaNode);
-
- final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> container =
- Builders.containerBuilder(rpcInputSchemaNode);
+ assertNotNull(rpcSchemaNode);
+ final InputSchemaNode rpcInputSchemaNode = rpcSchemaNode.getInput();
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> container =
+ SchemaAwareBuilders.containerBuilder(rpcInputSchemaNode);
final QName contQName = QName.create(rpcModule.getQNameModule(), "cont");
final DataSchemaNode contSchemaNode = rpcInputSchemaNode.getDataChildByName(contQName);
assertTrue(contSchemaNode instanceof ContainerSchemaNode);
- final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> contNode =
- Builders.containerBuilder((ContainerSchemaNode) contSchemaNode);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contNode =
+ SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) contSchemaNode);
final QName lfQName = QName.create(rpcModule.getQNameModule(), "lf");
final DataSchemaNode lfSchemaNode = ((ContainerSchemaNode) contSchemaNode).getDataChildByName(lfQName);
assertTrue(lfSchemaNode instanceof LeafSchemaNode);
final LeafNode<Object> lfNode =
- Builders.leafBuilder((LeafSchemaNode) lfSchemaNode).withValue("any value").build();
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) lfSchemaNode).withValue("any value").build();
contNode.withChild(lfNode);
container.withChild(contNode.build());
- return new NormalizedNodeContext(
- new InstanceIdentifierContext<>(null, rpcInputSchemaNode, null, schema), container.build());
+ return new NormalizedNodeContext(InstanceIdentifierContext.ofLocalRpc(schema, rpcSchemaNode),
+ container.build());
}
@Test
public void testInvokeRpcWithNoPayloadRpc_FailNoErrors() {
- final DOMRpcException exception = new DOMRpcImplementationNotAvailableException("testExeption");
- final CheckedFuture<DOMRpcResult, DOMRpcException> future = Futures.immediateFailedCheckedFuture(exception);
-
final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
- final SchemaPath type = SchemaPath.create(true, qname);
- when(brokerFacade.invokeRpc(eq(type), any(NormalizedNode.class))).thenReturn(future);
+ doReturn(immediateFailedFluentFuture(new DOMRpcImplementationNotAvailableException("testExeption")))
+ .when(brokerFacade).invokeRpc(eq(qname), any());
- try {
- this.restconfImpl.invokeRpc("toaster:cancel-toast", "", uriInfo);
- fail("Expected an exception to be thrown.");
- } catch (final RestconfDocumentedException e) {
- verifyRestconfDocumentedException(e, 0, ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED,
- Optional.<String>absent(), Optional.<String>absent());
- }
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED,
+ Optional.empty(), Optional.empty());
}
void verifyRestconfDocumentedException(final RestconfDocumentedException restDocumentedException, final int index,
final ErrorType expErrorType, final ErrorTag expErrorTag, final Optional<String> expErrorMsg,
final Optional<String> expAppTag) {
- RestconfError actual = null;
- try {
- actual = restDocumentedException.getErrors().get(index);
- } catch (final ArrayIndexOutOfBoundsException ex) {
- fail("RestconfError not found at index " + index);
- }
+
+ final List<RestconfError> errors = restDocumentedException.getErrors();
+ assertTrue("RestconfError not found at index " + index, errors.size() > index);
+
+ RestconfError actual = errors.get(index);
assertEquals("getErrorType", expErrorType, actual.getErrorType());
assertEquals("getErrorTag", expErrorTag, actual.getErrorTag());
RpcResultBuilder.newWarning(RpcError.ErrorType.RPC, "in-use", "bar",
"app-tag", null, null));
- final DOMRpcResult resutl = new DefaultDOMRpcResult(rpcErrors);
- final CheckedFuture<DOMRpcResult, DOMRpcException> future = Futures.immediateCheckedFuture(resutl);
+ final DOMRpcResult result = new DefaultDOMRpcResult(rpcErrors);
+ final QName path = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+ doReturn(immediateFluentFuture(result)).when(brokerFacade).invokeRpc(eq(path), any());
- final SchemaPath path = SchemaPath.create(true,
- QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast"));
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
- when(brokerFacade.invokeRpc(eq(path), any(NormalizedNode.class))).thenReturn(future);
+ // We are performing pass-through here of error-tag, hence the tag remains as specified, but we want to make
+ // sure the HTTP status remains the same as
+ final ErrorTag bogus = new ErrorTag("bogusTag");
+ verifyRestconfDocumentedException(ex, 0, ErrorType.TRANSPORT, bogus, Optional.of("foo"), Optional.empty());
+ assertEquals(ErrorTags.statusOf(ErrorTag.OPERATION_FAILED), ErrorTags.statusOf(bogus));
- try {
- this.restconfImpl.invokeRpc("toaster:cancel-toast", "", uriInfo);
- fail("Expected an exception to be thrown.");
- } catch (final RestconfDocumentedException e) {
- verifyRestconfDocumentedException(e, 0, ErrorType.TRANSPORT, ErrorTag.OPERATION_FAILED, Optional.of("foo"),
- Optional.<String>absent());
- verifyRestconfDocumentedException(e, 1, ErrorType.RPC, ErrorTag.IN_USE, Optional.of("bar"),
- Optional.of("app-tag"));
- }
+ verifyRestconfDocumentedException(ex, 1, ErrorType.RPC, ErrorTag.IN_USE, Optional.of("bar"),
+ Optional.of("app-tag"));
}
@Test
public void testInvokeRpcWithNoPayload_Success() {
- final NormalizedNode<?, ?> resultObj = null;
+ final NormalizedNode resultObj = null;
final DOMRpcResult expResult = new DefaultDOMRpcResult(resultObj);
- final CheckedFuture<DOMRpcResult, DOMRpcException> future = Futures.immediateCheckedFuture(expResult);
final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
- final SchemaPath path = SchemaPath.create(true, qname);
- when(brokerFacade.invokeRpc(eq(path), any(NormalizedNode.class))).thenReturn(future);
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(qname), any());
- final NormalizedNodeContext output = this.restconfImpl.invokeRpc("toaster:cancel-toast", "", uriInfo);
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo);
assertNotNull(output);
assertEquals(null, output.getData());
// additional validation in the fact that the restconfImpl does not
}
@Test
- public void testInvokeRpcMethodExpectingNoPayloadButProvidePayload() {
- try {
- this.restconfImpl.invokeRpc("toaster:cancel-toast", " a payload ", uriInfo);
- fail("Expected an exception");
- } catch (final RestconfDocumentedException e) {
- verifyRestconfDocumentedException(e, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
- Optional.<String>absent(), Optional.<String>absent());
- }
+ public void testInvokeRpcWithEmptyOutput() {
+ final ContainerNode resultObj = mock(ContainerNode.class);
+ doReturn(Set.of()).when(resultObj).body();
+ doCallRealMethod().when(resultObj).isEmpty();
+ final DOMRpcResult expResult = new DefaultDOMRpcResult(resultObj);
+
+ final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(qname), any());
+
+ WebApplicationException exceptionToBeThrown = assertThrows(WebApplicationException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
+ assertEquals(Response.Status.NO_CONTENT.getStatusCode(), exceptionToBeThrown.getResponse().getStatus());
}
@Test
public void testInvokeRpcMethodWithBadMethodName() {
- try {
- this.restconfImpl.invokeRpc("toaster:bad-method", "", uriInfo);
- fail("Expected an exception");
- } catch (final RestconfDocumentedException e) {
- verifyRestconfDocumentedException(e, 0, ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT,
- Optional.<String>absent(), Optional.<String>absent());
- }
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:bad-method", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT,
+ Optional.empty(), Optional.empty());
}
@Test
@Ignore
public void testInvokeRpcMethodWithInput() {
final DOMRpcResult expResult = mock(DOMRpcResult.class);
- final CheckedFuture<DOMRpcResult, DOMRpcException> future = Futures.immediateCheckedFuture(expResult);
- final SchemaPath path = SchemaPath.create(true,
- QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast"));
+ final QName path = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast");
final Module rpcModule = schemaContext.findModules("toaster").iterator().next();
assertNotNull(rpcModule);
final QName rpcQName = QName.create(rpcModule.getQNameModule(), "make-toast");
- final QName rpcInputQName = QName.create(rpcModule.getQNameModule(),"input");
- final Set<RpcDefinition> setRpcs = rpcModule.getRpcs();
RpcDefinition rpcDef = null;
- ContainerSchemaNode rpcInputSchemaNode = null;
-
- for (final RpcDefinition rpc : setRpcs) {
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
- rpcInputSchemaNode = SchemaNodeUtils.getRpcDataSchema(rpc, rpcInputQName);
rpcDef = rpc;
break;
}
}
assertNotNull(rpcDef);
- assertNotNull(rpcInputSchemaNode);
- final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder =
- Builders.containerBuilder(rpcInputSchemaNode);
- final NormalizedNodeContext payload =
- new NormalizedNodeContext(new InstanceIdentifierContext<>(null, rpcInputSchemaNode,
- null, schemaContext), containerBuilder.build());
+ final NormalizedNodeContext payload = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofLocalRpcInput(schemaContext, rpcDef),
+ SchemaAwareBuilders.containerBuilder(rpcDef.getInput()).build());
- when(brokerFacade.invokeRpc(eq(path), any(NormalizedNode.class))).thenReturn(future);
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(path), any(NormalizedNode.class));
- final NormalizedNodeContext output = this.restconfImpl.invokeRpc("toaster:make-toast", payload, uriInfo);
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:make-toast", payload, uriInfo);
assertNotNull(output);
assertEquals(null, output.getData());
// additional validation in the fact that the restconfImpl does not
@Test
public void testThrowExceptionWhenSlashInModuleName() {
- try {
- this.restconfImpl.invokeRpc("toaster/slash", "", uriInfo);
- fail("Expected an exception.");
- } catch (final RestconfDocumentedException e) {
- verifyRestconfDocumentedException(e, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
- Optional.<String>absent(), Optional.<String>absent());
- }
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster/slash", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ Optional.empty(), Optional.empty());
}
@Test
final QName rpcQName = QName.create(rpcModule.getQNameModule(), "testOutput");
final QName rpcOutputQName = QName.create(rpcModule.getQNameModule(),"output");
- final Set<RpcDefinition> setRpcs = rpcModule.getRpcs();
RpcDefinition rpcDef = null;
- ContainerSchemaNode rpcOutputSchemaNode = null;
- for (final RpcDefinition rpc : setRpcs) {
+ ContainerLike rpcOutputSchemaNode = null;
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
- rpcOutputSchemaNode = SchemaNodeUtils.getRpcDataSchema(rpc, rpcOutputQName);
+ rpcOutputSchemaNode = rpc.getOutput();
rpcDef = rpc;
break;
}
}
assertNotNull(rpcDef);
assertNotNull(rpcOutputSchemaNode);
- final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder =
- Builders.containerBuilder(rpcOutputSchemaNode);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> containerBuilder =
+ SchemaAwareBuilders.containerBuilder(rpcOutputSchemaNode);
final DataSchemaNode leafSchema = rpcOutputSchemaNode
.getDataChildByName(QName.create(rpcModule.getQNameModule(), "textOut"));
assertTrue(leafSchema instanceof LeafSchemaNode);
- final NormalizedNodeAttrBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
- Builders.leafBuilder((LeafSchemaNode) leafSchema);
+ final NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) leafSchema);
leafBuilder.withValue("brm");
containerBuilder.withChild(leafBuilder.build());
final ContainerNode container = containerBuilder.build();
final DOMRpcResult result = new DefaultDOMRpcResult(container);
- final CheckedFuture<DOMRpcResult, DOMRpcException> future = Futures.immediateCheckedFuture(result);
- when(brokerFacade.invokeRpc(eq(rpcDef.getPath()), any(NormalizedNode.class))).thenReturn(future);
+ doReturn(immediateFluentFuture(result)).when(brokerFacade).invokeRpc(eq(rpcDef.getQName()), any());
- final NormalizedNodeContext output = this.restconfImpl.invokeRpc("toaster:testOutput", "", uriInfo);
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:testOutput", null, uriInfo);
assertNotNull(output);
assertNotNull(output.getData());
assertSame(container, output.getData());
* invoked.
*/
@Test
- @Ignore // FIXME find how to use mockito for it
public void testMountedRpcCallNoPayload_Success() throws Exception {
+ // FIXME find how to use mockito for it
}
}