/* * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * 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.restconf.nb.jaxrs; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.mockito.Mockito.doReturn; import static org.opendaylight.restconf.nb.jaxrs.AbstractRestconfTest.assertEntity; import static org.opendaylight.restconf.nb.jaxrs.AbstractRestconfTest.assertError; import com.google.common.io.CharStreams; import com.google.common.util.concurrent.Futures; import java.io.Reader; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.opendaylight.mdsal.dom.api.DOMActionService; import org.opendaylight.mdsal.dom.api.DOMDataBroker; import org.opendaylight.mdsal.dom.api.DOMRpcService; import org.opendaylight.mdsal.dom.api.DOMSchemaService; import org.opendaylight.mdsal.dom.api.DOMYangTextSourceProvider; import org.opendaylight.mdsal.dom.broker.DOMMountPointServiceImpl; import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService; import org.opendaylight.restconf.nb.rfc8040.databind.DatabindContext; import org.opendaylight.restconf.nb.rfc8040.legacy.ErrorTags; import org.opendaylight.restconf.server.mdsal.DOMSourceResolver; import org.opendaylight.restconf.server.mdsal.MdsalRestconfServer; 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.Revision; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; /** * Unit tests for {@code RestconfSchemaService}. */ @RunWith(MockitoJUnitRunner.StrictStubs.class) public class RestconfSchemaServiceTest { private static final String MOUNT_POINT = "mount-point-1:cont/yang-ext:mount/"; private static final String NULL_MOUNT_POINT = "mount-point-2:cont/yang-ext:mount/"; private static final String NOT_EXISTING_MOUNT_POINT = "mount-point-3:cont/yang-ext:mount/"; private static final String TEST_MODULE = "module1/2014-01-01"; private static final String TEST_MODULE_BEHIND_MOUNT_POINT = "module1-behind-mount-point/2014-02-03"; private static final String NOT_EXISTING_MODULE = "not-existing/2016-01-01"; // schema context with modules private static final EffectiveModelContext SCHEMA_CONTEXT = YangParserTestUtils.parseYangResourceDirectory("/modules"); // schema context with modules behind mount point private static final EffectiveModelContext SCHEMA_CONTEXT_BEHIND_MOUNT_POINT = YangParserTestUtils.parseYangResourceDirectory("/modules/modules-behind-mount-point"); // schema context with mount points private static final EffectiveModelContext SCHEMA_CONTEXT_WITH_MOUNT_POINTS = YangParserTestUtils.parseYangResourceDirectory("/modules/mount-points"); // handlers @Mock private DOMSchemaService schemaService; @Mock private DOMYangTextSourceProvider sourceProvider; @Mock private DOMDataBroker dataBroker; @Mock private DOMActionService actionService; @Mock private DOMRpcService rpcService; @Mock private YangTextSchemaSource yangSource; @Mock private Reader yangReader; // service under test private JaxRsRestconf restconf; @Before public void setup() throws Exception { final var mountPointService = new DOMMountPointServiceImpl(); // create and register mount points mountPointService .createMountPoint(YangInstanceIdentifier.of(QName.create("mount:point:1", "2016-01-01", "cont"))) .addService(DOMSchemaService.class, FixedDOMSchemaService.of(SCHEMA_CONTEXT_BEHIND_MOUNT_POINT)) .register(); mountPointService .createMountPoint(YangInstanceIdentifier.of(QName.create("mount:point:2", "2016-01-01", "cont"))) .register(); restconf = new JaxRsRestconf(new MdsalRestconfServer( () -> DatabindContext.ofModel(schemaService.getGlobalContext(), new DOMSourceResolver(sourceProvider)), dataBroker, rpcService, actionService, mountPointService)); } /** * Get schema with identifier of existing module and check if correct module was found. */ @Test public void getSchemaTest() throws Exception { // prepare conditions - return not-mount point schema context doReturn(SCHEMA_CONTEXT).when(schemaService).getGlobalContext(); doReturn(Futures.immediateFuture(yangSource)).when(sourceProvider) .getSource(new SourceIdentifier("module1", Revision.of("2014-01-01"))); doReturn(yangReader).when(yangSource).openStream(); assertSame(yangReader, assertEntity(Reader.class, 200, ar -> restconf.modulesYangGET(TEST_MODULE, ar))); } /** * Get schema with identifier of not-existing module. Trying to create SchemaExportContext with * not-existing module should result in error. */ @Test public void getSchemaForNotExistingModuleTest() { // prepare conditions - return not-mount point schema context doReturn(SCHEMA_CONTEXT).when(schemaService).getGlobalContext(); final var error = assertError(ar -> restconf.modulesYinGET(NOT_EXISTING_MODULE, ar)); assertEquals("Source not-existing@2016-01-01 not found", error.getErrorMessage()); assertEquals(ErrorTag.DATA_MISSING, error.getErrorTag()); assertEquals(ErrorType.APPLICATION, error.getErrorType()); } /** * Get schema with identifier of existing module behind mount point and check if correct module was found. */ @Test public void getSchemaMountPointTest() throws Exception { // prepare conditions - return schema context with mount points doReturn(SCHEMA_CONTEXT_WITH_MOUNT_POINTS).when(schemaService).getGlobalContext(); final var reader = assertEntity(Reader.class, 200, ar -> restconf.modulesYangGET(MOUNT_POINT + TEST_MODULE_BEHIND_MOUNT_POINT, ar)); assertEquals(""" module module1-behind-mount-point { namespace module:1:behind:mount:point; prefix mod1bemopo; revision 2014-02-03; rpc rpc-behind-module1; } """, CharStreams.toString(reader)); } /** * Get schema with identifier of not-existing module behind mount point. Trying to create * SchemaExportContext with not-existing module behind mount point should result in error. */ @Test public void getSchemaForNotExistingModuleMountPointTest() { // prepare conditions - return schema context with mount points doReturn(SCHEMA_CONTEXT_WITH_MOUNT_POINTS).when(schemaService).getGlobalContext(); final var error = assertError(ar -> restconf.modulesYangGET(MOUNT_POINT + NOT_EXISTING_MODULE, ar)); assertEquals("Source not-existing@2016-01-01 not found", error.getErrorMessage()); assertEquals(ErrorTag.DATA_MISSING, error.getErrorTag()); assertEquals(ErrorType.APPLICATION, error.getErrorType()); } /** * Try to get schema with null SchemaContext behind mount point when using * NULL_MOUNT_POINT. Test is expected to fail with NullPointerException. */ @Test public void getSchemaNullSchemaContextBehindMountPointTest() { // prepare conditions - return correct schema context for mount points (this is not null) doReturn(SCHEMA_CONTEXT_WITH_MOUNT_POINTS).when(schemaService).getGlobalContext(); // make test - call service on mount point with null schema context // NULL_MOUNT_POINT contains null schema context final var error = assertError( ar -> restconf.modulesYangGET(NULL_MOUNT_POINT + TEST_MODULE_BEHIND_MOUNT_POINT, ar)); assertEquals("Mount point mount-point-2:cont does not expose DOMSchemaService", error.getErrorMessage()); assertEquals(ErrorType.PROTOCOL, error.getErrorType()); assertEquals(ErrorTags.RESOURCE_DENIED_TRANSPORT, error.getErrorTag()); } /** * Try to get schema with empty (not valid) identifier catching RestconfDocumentedException. Error * type, error tag and error status code are compared to expected values. */ @Test public void getSchemaWithEmptyIdentifierTest() { // prepare conditions - return correct schema context doReturn(SCHEMA_CONTEXT).when(schemaService).getGlobalContext(); final var error = assertError(ar -> restconf.modulesYangGET("", ar)); assertEquals("Identifier must start with character from set 'a-zA-Z_", error.getErrorMessage()); assertEquals(ErrorType.PROTOCOL, error.getErrorType()); assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag()); } /** * Try to get schema with empty (not valid) identifier behind mount point catching * RestconfDocumentedException. Error type, error tag and error status code are compared to expected * values. */ @Test public void getSchemaWithEmptyIdentifierMountPointTest() { // prepare conditions - return correct schema context with mount points doReturn(SCHEMA_CONTEXT_WITH_MOUNT_POINTS).when(schemaService).getGlobalContext(); // make test and verify final var error = assertError(ar -> restconf.modulesYangGET(MOUNT_POINT + "", ar)); assertEquals("Identifier must start with character from set 'a-zA-Z_", error.getErrorMessage()); assertEquals(ErrorType.PROTOCOL, error.getErrorType()); assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag()); } /** * Try to get schema with not-parsable identifier catching RestconfDocumentedException. Error type, * error tag and error status code are compared to expected values. */ @Test public void getSchemaWithNotParsableIdentifierTest() { // prepare conditions - return correct schema context without mount points doReturn(SCHEMA_CONTEXT).when(schemaService).getGlobalContext(); // make test and verify final var error = assertError(ar -> restconf.modulesYangGET("01_module/2016-01-01", ar)); assertEquals("Identifier must start with character from set 'a-zA-Z_", error.getErrorMessage()); assertEquals(ErrorType.PROTOCOL, error.getErrorType()); assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag()); } /** * Try to get schema behind mount point with not-parsable identifier catching * RestconfDocumentedException. Error type, error tag and error status code are compared to expected * values. */ @Test public void getSchemaWithNotParsableIdentifierMountPointTest() { // prepare conditions - return correct schema context with mount points doReturn(SCHEMA_CONTEXT_WITH_MOUNT_POINTS).when(schemaService).getGlobalContext(); // make test and verify final var error = assertError(ar -> restconf.modulesYangGET(MOUNT_POINT + "01_module/2016-01-01", ar)); assertEquals("Identifier must start with character from set 'a-zA-Z_", error.getErrorMessage()); assertEquals(ErrorType.PROTOCOL, error.getErrorType()); assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag()); } /** * Try to get schema with wrong (not valid) identifier catching RestconfDocumentedException. Error * type, error tag and error status code are compared to expected values. * *

* Not valid identifier contains only revision without module name. */ @Test public void getSchemaWrongIdentifierTest() { // prepare conditions - return correct schema context without mount points doReturn(SCHEMA_CONTEXT).when(schemaService).getGlobalContext(); // make test and verify final var error = assertError(ar -> restconf.modulesYangGET("2014-01-01", ar)); assertEquals("Identifier must start with character from set 'a-zA-Z_", error.getErrorMessage()); assertEquals(ErrorType.PROTOCOL, error.getErrorType()); assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag()); } /** * Try to get schema with wrong (not valid) identifier behind mount point catching * RestconfDocumentedException. Error type, error tag and error status code are compared to expected * values. * *

* Not valid identifier contains only revision without module name. */ @Test public void getSchemaWrongIdentifierMountPointTest() { // prepare conditions - return correct schema context with mount points doReturn(SCHEMA_CONTEXT_WITH_MOUNT_POINTS).when(schemaService).getGlobalContext(); // make test and verify final var error = assertError(ar -> restconf.modulesYangGET(MOUNT_POINT + "2014-01-01", ar)); assertEquals("Identifier must start with character from set 'a-zA-Z_", error.getErrorMessage()); assertEquals(ErrorType.PROTOCOL, error.getErrorType()); assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag()); } /** * Try to get schema with identifier which does not contain revision catching * RestconfDocumentedException. Error type, error tag and error status code are compared to expected * values. */ @Test public void getSchemaWithoutRevisionTest() { // prepare conditions - return correct schema context without mount points doReturn(SCHEMA_CONTEXT).when(schemaService).getGlobalContext(); // make test and verify final var error = assertError(ar -> restconf.modulesYangGET("module", ar)); assertEquals("Revision date must be supplied.", error.getErrorMessage()); assertEquals(ErrorType.PROTOCOL, error.getErrorType()); assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag()); } /** * Try to get schema behind mount point with identifier when does not contain revision catching * RestconfDocumentedException. Error type, error tag and error status code are compared to expected * values. */ @Test public void getSchemaWithoutRevisionMountPointTest() { // prepare conditions - return correct schema context with mount points doReturn(SCHEMA_CONTEXT_WITH_MOUNT_POINTS).when(schemaService).getGlobalContext(); // make test and verify final var error = assertError(ar -> restconf.modulesYangGET(MOUNT_POINT + "module", ar)); assertEquals("Revision date must be supplied.", error.getErrorMessage()); assertEquals(ErrorType.PROTOCOL, error.getErrorType()); assertEquals(ErrorTag.INVALID_VALUE, error.getErrorTag()); } /** * Negative test when mount point module is not found in current SchemaContext for mount points. * IllegalArgumentException exception is expected. */ @Test public void getSchemaContextWithNotExistingMountPointTest() { // prepare conditions - return schema context with mount points doReturn(SCHEMA_CONTEXT_WITH_MOUNT_POINTS).when(schemaService).getGlobalContext(); final var error = assertError( ar -> restconf.modulesYangGET(NOT_EXISTING_MOUNT_POINT + TEST_MODULE_BEHIND_MOUNT_POINT, ar)); assertEquals("Failed to lookup for module with name 'mount-point-3'.", error.getErrorMessage()); assertEquals(ErrorType.PROTOCOL, error.getErrorType()); assertEquals(ErrorTag.UNKNOWN_ELEMENT, error.getErrorTag()); } }