package org.opendaylight.controller.netconf.confignetconfconnector;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.opendaylight.controller.config.util.xml.XmlUtil.readXmlToElement;
import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElement;
import static org.opendaylight.controller.netconf.util.test.XmlUnitUtil.assertContainsElementWithText;
-import static org.opendaylight.controller.netconf.util.xml.XmlUtil.readXmlToElement;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import io.netty.channel.Channel;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.ObjectName;
import org.custommonkey.xmlunit.NodeTester;
import org.custommonkey.xmlunit.XMLAssert;
import org.custommonkey.xmlunit.XMLUnit;
-import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.annotations.AbstractServiceInterface;
import org.opendaylight.controller.config.api.annotations.ServiceInterfaceAnnotation;
+import org.opendaylight.controller.config.facade.xml.ConfigSubsystemFacade;
+import org.opendaylight.controller.config.facade.xml.osgi.EnumResolver;
+import org.opendaylight.controller.config.facade.xml.osgi.YangStoreService;
+import org.opendaylight.controller.config.facade.xml.transactions.TransactionProvider;
import org.opendaylight.controller.config.manager.impl.AbstractConfigTest;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
+import org.opendaylight.controller.config.util.xml.DocumentedException;
+import org.opendaylight.controller.config.util.xml.XmlMappingConstants;
+import org.opendaylight.controller.config.util.xml.XmlUtil;
import org.opendaylight.controller.config.yang.test.impl.ComplexDtoBInner;
import org.opendaylight.controller.config.yang.test.impl.ComplexList;
import org.opendaylight.controller.config.yang.test.impl.Deep;
import org.opendaylight.controller.config.yang.test.impl.Peers;
import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
-import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Commit;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.DiscardChanges;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.Lock;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.get.Get;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.getconfig.GetConfig;
import org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc.RuntimeRpc;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreContext;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreService;
-import org.opendaylight.controller.netconf.confignetconfconnector.transactions.TransactionProvider;
+import org.opendaylight.controller.netconf.impl.NetconfServerSession;
+import org.opendaylight.controller.netconf.impl.NetconfServerSessionListener;
import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultCloseSession;
import org.opendaylight.controller.netconf.impl.osgi.AggregatedNetconfOperationServiceFactory;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationRouter;
import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperation;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationChainedExecution;
+import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil;
import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
-import org.opendaylight.controller.netconf.util.xml.XmlUtil;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity1;
import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.test.types.rev131127.TestIdentity2;
-import org.opendaylight.yangtools.yang.data.impl.codec.CodecRegistry;
-import org.opendaylight.yangtools.yang.data.impl.codec.IdentityCodec;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
private TestImplModuleFactory factory4;
@Mock
- YangStoreContext yangStoreSnapshot;
+ YangStoreService yangStoreSnapshot;
@Mock
NetconfOperationRouter netconfOperationRouter;
@Mock
private TransactionProvider transactionProvider;
+ private ConfigSubsystemFacade configSubsystemFacade;
+
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
doNothing().when(mockedContext).addServiceListener(any(ServiceListener.class), anyString());
doReturn(new ServiceReference<?>[]{}).when(mockedContext).getServiceReferences(anyString(), anyString());
+ doReturn(yangStoreSnapshot).when(yangStoreSnapshot).getCurrentSnapshot();
doReturn(getMbes()).when(this.yangStoreSnapshot).getModuleMXBeanEntryMap();
doReturn(getModules()).when(this.yangStoreSnapshot).getModules();
+ doReturn(new EnumResolver() {
+ @Override
+ public String fromYang(final String enumType, final String enumYangValue) {
+ return Preconditions.checkNotNull(getEnumMapping().get(enumYangValue),
+ "Unable to resolve enum value %s, for enum %s with mappings %s", enumYangValue, enumType, getEnumMapping());
+ }
+
+ @Override
+ public String toYang(final String enumType, final String enumYangValue) {
+ return Preconditions.checkNotNull(getEnumMapping().inverse().get(enumYangValue),
+ "Unable to resolve enum value %s, for enum %s with mappings %s", enumYangValue, enumType, getEnumMapping().inverse());
+ }
+ }).when(this.yangStoreSnapshot).getEnumResolver();
this.factory = new NetconfTestImplModuleFactory();
this.factory2 = new DepTestImplModuleFactory();
this.factory3, factory4));
transactionProvider = new TransactionProvider(this.configRegistryClient, NETCONF_SESSION_ID);
+
+ configSubsystemFacade = new ConfigSubsystemFacade(configRegistryClient, configRegistryClient, yangStoreSnapshot, "mapping-test");
}
private ObjectName createModule(final String instanceName) throws InstanceAlreadyExistsException, InstanceNotFoundException, URISyntaxException, ValidationException, ConflictingVersionException {
edit("netconfMessages/editConfig_identities.xml");
commit();
- getConfigRunning();
+ Document configRunning = getConfigRunning();
+ String asString = XmlUtil.toString(configRunning);
+ assertThat(asString, containsString("test-identity2"));
+ assertThat(asString, containsString("test-identity1"));
+ assertEquals(2, countSubstringOccurence(asString, "</identities>"));
+
+ edit("netconfMessages/editConfig_identities_inner_replace.xml");
+ commit();
+ configRunning = getConfigRunning();
+ asString = XmlUtil.toString(configRunning);
+ // test-identity1 was removed by replace
+ assertThat(asString, not(containsString("test-identity2")));
+ // now only 1 identities entry is present
+ assertEquals(1, countSubstringOccurence(asString, "</identities>"));
+ }
+
+ private int countSubstringOccurence(final String string, final String substring) {
+ final Matcher matches = Pattern.compile(substring).matcher(string);
+ int count = 0;
+ while (matches.find()) {
+ count++;
+ }
+ return count;
}
@Override
- protected CodecRegistry getCodecRegistry() {
- IdentityCodec<?> idCodec = mock(IdentityCodec.class);
- doReturn(TestIdentity1.class).when(idCodec).deserialize(TestIdentity1.QNAME);
- doReturn(TestIdentity2.class).when(idCodec).deserialize(TestIdentity2.QNAME);
-
- CodecRegistry codecReg = super.getCodecRegistry();
- doReturn(idCodec).when(codecReg).getIdentityCodec();
- return codecReg;
+ protected BindingRuntimeContext getBindingRuntimeContext() {
+ final BindingRuntimeContext ret = super.getBindingRuntimeContext();
+ doReturn(TestIdentity1.class).when(ret).getIdentityClass(TestIdentity1.QNAME);
+ doReturn(TestIdentity2.class).when(ret).getIdentityClass(TestIdentity2.QNAME);
+ return ret;
}
@Test
"ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
"ref_from_code_to_instance-from-code_1", "ref_dep_user_another"));
+ edit("netconfMessages/editConfig_removeServiceNameOnTest.xml");
+ config = getConfigCandidate();
+ assertCorrectServiceNames(config, Sets.newHashSet("user_to_instance_from_code", "ref_dep_user",
+ "ref_dep_user_two", "ref_from_code_to_instance-from-code_dep_1",
+ "ref_from_code_to_instance-from-code_1"));
+
+ try {
+ edit("netconfMessages/editConfig_removeServiceNameOnTest.xml");
+ fail("Should've failed, non-existing service instance");
+ } catch (DocumentedException e) {
+ assertEquals(e.getErrorSeverity(), DocumentedException.ErrorSeverity.error);
+ assertEquals(e.getErrorTag(), DocumentedException.ErrorTag.operation_failed);
+ assertEquals(e.getErrorType(), DocumentedException.ErrorType.application);
+ }
+
edit("netconfMessages/editConfig_replace_default.xml");
config = getConfigCandidate();
assertCorrectServiceNames(config, Collections.<String>emptySet());
}
- private void closeSession() throws NetconfDocumentedException, ParserConfigurationException, SAXException,
- IOException {
+ private void closeSession() throws ParserConfigurationException, SAXException,
+ IOException, DocumentedException {
+ final Channel channel = mock(Channel.class);
+ doReturn("channel").when(channel).toString();
+ final NetconfServerSessionListener listener = mock(NetconfServerSessionListener.class);
+ final NetconfServerSession session =
+ new NetconfServerSession(listener, channel, 1L,
+ NetconfHelloMessageAdditionalHeader.fromString("[netconf;10.12.0.102:48528;ssh;;;;;;]"));
DefaultCloseSession closeOp = new DefaultCloseSession(NETCONF_SESSION_ID, sessionCloseable);
+ closeOp.setNetconfSession(session);
executeOp(closeOp, "netconfMessages/closeSession.xml");
}
private void edit(String resource) throws ParserConfigurationException, SAXException, IOException,
- NetconfDocumentedException {
- EditConfig editOp = new EditConfig(yangStoreSnapshot, transactionProvider, configRegistryClient,
- NETCONF_SESSION_ID);
+ DocumentedException {
+ EditConfig editOp = new EditConfig(configSubsystemFacade, NETCONF_SESSION_ID);
executeOp(editOp, resource);
}
- private void commit() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
- Commit commitOp = new Commit(transactionProvider, configRegistryClient, NETCONF_SESSION_ID);
+ private void commit() throws ParserConfigurationException, SAXException, IOException, DocumentedException {
+ Commit commitOp = new Commit(configSubsystemFacade, NETCONF_SESSION_ID);
executeOp(commitOp, "netconfMessages/commit.xml");
}
- private Document lockCandidate() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
+ private Document lockCandidate() throws ParserConfigurationException, SAXException, IOException, DocumentedException {
Lock commitOp = new Lock(NETCONF_SESSION_ID);
return executeOp(commitOp, "netconfMessages/lock.xml");
}
- private Document unlockCandidate() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
+ private Document unlockCandidate() throws ParserConfigurationException, SAXException, IOException, DocumentedException {
UnLock commitOp = new UnLock(NETCONF_SESSION_ID);
return executeOp(commitOp, "netconfMessages/unlock.xml");
}
private Document getConfigCandidate() throws ParserConfigurationException, SAXException, IOException,
- NetconfDocumentedException {
- GetConfig getConfigOp = new GetConfig(yangStoreSnapshot, Optional.<String> absent(), transactionProvider,
- configRegistryClient, NETCONF_SESSION_ID);
+ DocumentedException {
+ GetConfig getConfigOp = new GetConfig(configSubsystemFacade, Optional.<String> absent(), NETCONF_SESSION_ID);
return executeOp(getConfigOp, "netconfMessages/getConfig_candidate.xml");
}
private Document getConfigRunning() throws ParserConfigurationException, SAXException, IOException,
- NetconfDocumentedException {
- GetConfig getConfigOp = new GetConfig(yangStoreSnapshot, Optional.<String> absent(), transactionProvider,
- configRegistryClient, NETCONF_SESSION_ID);
+ DocumentedException {
+ GetConfig getConfigOp = new GetConfig(configSubsystemFacade, Optional.<String> absent(), NETCONF_SESSION_ID);
return executeOp(getConfigOp, "netconfMessages/getConfig.xml");
}
@Ignore("second edit message corrupted")
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testConfigNetconfReplaceDefaultEx() throws Exception {
createModule(INSTANCE_NAME);
try {
edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespaces.xml");
fail();
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
String message = e.getMessage();
assertContainsString(message, "Element simpleInt present multiple times with different namespaces");
assertContainsString(message, TEST_NAMESPACE);
- assertContainsString(message, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ assertContainsString(message, XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
}
}
try {
edit("netconfMessages/namespaces/editConfig_differentNamespaceTO.xml");
fail();
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
String message = e.getMessage();
assertContainsString(message, "Unrecognised elements");
assertContainsString(message, "simple-int2");
try {
edit("netconfMessages/namespaces/editConfig_sameAttrDifferentNamespacesList.xml");
fail();
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
String message = e.getMessage();
assertContainsString(message, "Element allow-user present multiple times with different namespaces");
assertContainsString(message, TEST_NAMESPACE);
- assertContainsString(message, XmlNetconfConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
+ assertContainsString(message, XmlMappingConstants.URN_OPENDAYLIGHT_PARAMS_XML_NS_YANG_CONTROLLER_CONFIG);
}
}
}
// TODO add <modules operation="replace"> functionality
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testConfigNetconfReplaceModuleEx() throws Exception {
createModule(INSTANCE_NAME);
LOG.info("Reading {}", file);
try {
edit(file);
- } catch (NetconfDocumentedException e) {
+ } catch (DocumentedException e) {
assertContainsString(e.getMessage(), "Unrecognised elements");
assertContainsString(e.getMessage(), "unknownAttribute");
continue;
assertEquals(3 + 3, afterReplace);
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test(expected = DocumentedException.class)
public void testEx() throws Exception {
commit();
}
- @Test(expected = NetconfDocumentedException.class)
+ @Test
public void testEx2() throws Exception {
- discard();
+ //check abort before tx creation
+ assertContainsElement(discard(), readXmlToElement("<ok xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>"));
+
+ //check abort after tx creation
+ edit("netconfMessages/editConfig.xml");
+ assertContainsElement(discard(), readXmlToElement("<ok xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"/>"));
}
- private void discard() throws ParserConfigurationException, SAXException, IOException, NetconfDocumentedException {
- DiscardChanges discardOp = new DiscardChanges(transactionProvider, configRegistryClient, NETCONF_SESSION_ID);
- executeOp(discardOp, "netconfMessages/discardChanges.xml");
+ @Test
+ public void testFailedDiscardChangesAbort() throws Exception {
+ final ConfigSubsystemFacade facade = mock(ConfigSubsystemFacade.class);
+ doThrow(new RuntimeException("Mocked runtime exception, Abort has to fail")).when(facade).abortConfiguration();
+
+ DiscardChanges discardOp = new DiscardChanges(facade, NETCONF_SESSION_ID);
+
+ try {
+ executeOp(discardOp, "netconfMessages/discardChanges.xml");
+ fail("Should've failed, abort on mocked is supposed to throw RuntimeException");
+ } catch (DocumentedException e) {
+ assertTrue(e.getErrorTag() == DocumentedException.ErrorTag.operation_failed);
+ assertTrue(e.getErrorSeverity() == DocumentedException.ErrorSeverity.error);
+ assertTrue(e.getErrorType() == DocumentedException.ErrorType.application);
+ }
+ }
+
+ private Document discard() throws ParserConfigurationException, SAXException, IOException, DocumentedException {
+ DiscardChanges discardOp = new DiscardChanges(configSubsystemFacade, NETCONF_SESSION_ID);
+ return executeOp(discardOp, "netconfMessages/discardChanges.xml");
}
private void checkBinaryLeafEdited(final Document response) throws NodeTestException, SAXException, IOException {
// Default
assertContainsElement(response, readXmlToElement("<extended-twice xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">2</extended-twice>"));
- assertContainsElement(response, readXmlToElement("<extended-enum xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">TWO</extended-enum>"));
+ assertContainsElement(response, readXmlToElement("<extended-enum xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">two</extended-enum>"));
// Default
- assertContainsElement(response, readXmlToElement("<extended-enum xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">ONE</extended-enum>"));
+ assertContainsElement(response, readXmlToElement("<extended-enum xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:test:impl\">one</extended-enum>"));
}
private void assertContainsString(String string, String substring) {
- assertThat(string, CoreMatchers.containsString(substring));
+ assertThat(string, containsString(substring));
}
private void checkEnum(final Document response) throws Exception {
- String expectedEnumContent = "TWO";
+ String expectedEnumContent = "two";
XMLAssert.assertXpathEvaluatesTo(expectedEnumContent,
getXpathForNetconfImplSubnode(INSTANCE_NAME,"extended-enum"),
public SchemaContext getSchemaContext() {
return schemaContext ;
}
- }, mockedContext);
+ });
+ final BindingRuntimeContext bindingRuntimeContext = mock(BindingRuntimeContext.class);
+ doReturn(getEnumMapping()).when(bindingRuntimeContext).getEnumMapping(any(Class.class));
+ yangStoreService.refresh(bindingRuntimeContext);
mBeanEntries.putAll(yangStoreService.getModuleMXBeanEntryMap());
return mBeanEntries;
}
+ private BiMap<String, String> getEnumMapping() {
+ final HashBiMap<String, String> enumBiMap = HashBiMap.create();
+ // Enum constants mapping from yang -> Java and back
+ enumBiMap.put("one", "One");
+ enumBiMap.put("two", "Two");
+ enumBiMap.put("version1", "Version1");
+ enumBiMap.put("version2", "Version2");
+ return enumBiMap;
+ }
+
private Set<org.opendaylight.yangtools.yang.model.api.Module> getModules() throws Exception {
SchemaContext resolveSchemaContext = getSchemaContext();
return resolveSchemaContext.getModules();
assertEquals(8, getElementsSize(response, "deep4"));
// TODO assert keys
- RuntimeRpc netconf = new RuntimeRpc(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
+ RuntimeRpc netconf = new RuntimeRpc(configSubsystemFacade, NETCONF_SESSION_ID);
response = executeOp(netconf, "netconfMessages/rpc.xml");
assertContainsElementWithText(response, "testarg1");
assertContainsElementWithText(response, "2");
}
- private Document get() throws NetconfDocumentedException, ParserConfigurationException, SAXException, IOException {
- Get getOp = new Get(yangStoreSnapshot, configRegistryClient, NETCONF_SESSION_ID);
+ private Document get() throws ParserConfigurationException, SAXException, IOException, DocumentedException {
+ Get getOp = new Get(configSubsystemFacade, NETCONF_SESSION_ID);
return executeOp(getOp, "netconfMessages/get.xml");
}
}
private Document executeOp(final NetconfOperation op, final String filename) throws ParserConfigurationException,
- SAXException, IOException, NetconfDocumentedException {
+ SAXException, IOException, DocumentedException {
final Document request = XmlFileLoader.xmlFileToDocument(filename);