/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2007-2008 Sun Microsystems, Inc. */ package org.opends.server.admin.server; import java.net.ServerSocket; import java.util.Collection; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; import javax.naming.ldap.LdapName; import org.opends.messages.Message; import org.opends.server.TestCaseUtils; import org.opends.server.admin.AdminTestCase; import org.opends.server.admin.AdministratorAction; import org.opends.server.admin.AggregationPropertyDefinition; import org.opends.server.admin.IllegalPropertyValueStringException; import org.opends.server.admin.ManagedObjectNotFoundException; import org.opends.server.admin.PropertyException; import org.opends.server.admin.PropertyOption; import org.opends.server.admin.TestCfg; import org.opends.server.admin.TestChildCfg; import org.opends.server.admin.TestChildCfgDefn; import org.opends.server.admin.TestParentCfg; import org.opends.server.admin.UndefinedDefaultBehaviorProvider; import org.opends.server.admin.client.OperationRejectedException; import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor; import org.opends.server.admin.condition.Conditions; import org.opends.server.admin.std.client.ConnectionHandlerCfgClient; import org.opends.server.admin.std.client.LDAPConnectionHandlerCfgClient; import org.opends.server.admin.std.client.RootCfgClient; import org.opends.server.admin.std.meta.LDAPConnectionHandlerCfgDefn; import org.opends.server.admin.std.server.ConnectionHandlerCfg; import org.opends.server.admin.std.server.RootCfg; import org.opends.server.config.ConfigException; import org.opends.server.core.DirectoryServer; import org.opends.server.types.ConfigChangeResult; import org.opends.server.types.ResultCode; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; /** * Test cases for aggregations on the server-side. */ @Test(sequential = true) public final class AggregationServerTest extends AdminTestCase { /** * Dummy change listener for triggering change constraint * call-backs. */ private static final class DummyChangeListener implements ConfigurationChangeListener<TestChildCfg> { /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationChange( TestChildCfg configuration) { return new ConfigChangeResult(ResultCode.SUCCESS, false); } /** * {@inheritDoc} */ public boolean isConfigurationChangeAcceptable(TestChildCfg configuration, List<Message> unacceptableReasons) { return true; } } /** * Dummy delete listener for triggering delete constraint * call-backs. */ private static final class DummyDeleteListener implements ConfigurationDeleteListener<TestChildCfg> { /** * {@inheritDoc} */ public ConfigChangeResult applyConfigurationDelete( TestChildCfg configuration) { return new ConfigChangeResult(ResultCode.SUCCESS, false); } /** * {@inheritDoc} */ public boolean isConfigurationDeleteAcceptable(TestChildCfg configuration, List<Message> unacceptableReasons) { return true; } } private static final String TEST_CHILD_7_DN = "cn=test child 7,cn=test children,cn=test parent 1,cn=test parents,cn=config"; private static final String TEST_CHILD_6_DN = "cn=test child 6,cn=test children,cn=test parent 1,cn=test parents,cn=config"; // The name of the test connection handler. private static final String TEST_CONNECTION_HANDLER_NAME = "Test Connection Handler"; // Test child 1 LDIF. private static final String[] TEST_CHILD_1 = new String[] { "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top", "objectclass: ds-cfg-test-child-dummy", "cn: test child 1", "ds-cfg-enabled: true", "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider", "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real" }; // Test child 2 LDIF. private static final String[] TEST_CHILD_2 = new String[] { "dn: cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top", "objectclass: ds-cfg-test-child-dummy", "cn: test child 2", "ds-cfg-enabled: true", "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider", "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real", "ds-cfg-rotation-policy: cn=LDAP Connection Handler, cn=connection handlers, cn=config" }; // Test child 3 LDIF (invalid reference). private static final String[] TEST_CHILD_3 = new String[] { "dn: cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top", "objectclass: ds-cfg-test-child-dummy", "cn: test child 3", "ds-cfg-enabled: true", "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider", "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real", "ds-cfg-rotation-policy: cn=LDAP Connection Handler, cn=bad rdn, cn=config" }; // Test child 4 LDIF. private static final String[] TEST_CHILD_4 = new String[] { "dn: cn=test child 4,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top", "objectclass: ds-cfg-test-child-dummy", "cn: test child 4", "ds-cfg-enabled: true", "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider", "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real", "ds-cfg-rotation-policy: cn=LDAP Connection Handler, cn=connection handlers, cn=config", "ds-cfg-rotation-policy: cn=LDAPS Connection Handler, cn=connection handlers, cn=config" }; // Test child 5 LDIF. private static final String[] TEST_CHILD_5 = new String[] { "dn: cn=test child 5,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top", "objectclass: ds-cfg-test-child-dummy", "cn: test child 5", "ds-cfg-enabled: true", "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider", "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real", "ds-cfg-rotation-policy: cn=BAD Connection Handler 1, cn=connection handlers, cn=config", "ds-cfg-rotation-policy: cn=BAD Connection Handler 2, cn=connection handlers, cn=config", "ds-cfg-rotation-policy: cn=LDAP Connection Handler, cn=connection handlers, cn=config" }; // Test child 6 LDIF. private static final String[] TEST_CHILD_6 = new String[] { "dn: cn=test child 6,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top", "objectclass: ds-cfg-test-child-dummy", "cn: test child 6", "ds-cfg-enabled: true", "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider", "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real", "ds-cfg-rotation-policy: cn=" + TEST_CONNECTION_HANDLER_NAME + ", cn=connection handlers, cn=config" }; // Test child 7 LDIF. private static final String[] TEST_CHILD_7 = new String[] { "dn: cn=test child 7,cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top", "objectclass: ds-cfg-test-child-dummy", "cn: test child 7", "ds-cfg-enabled: false", "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider", "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real", "ds-cfg-rotation-policy: cn=" + TEST_CONNECTION_HANDLER_NAME + ", cn=connection handlers, cn=config" }; // Test LDIF. private static final String[] TEST_LDIF = new String[] { // Base entries. "dn: cn=test parents,cn=config", "objectclass: top", "objectclass: ds-cfg-branch", "cn: test parents", "", // Parent 1. "dn: cn=test parent 1,cn=test parents,cn=config", "objectclass: top", "objectclass: ds-cfg-test-parent-dummy", "cn: test parent 1", "ds-cfg-enabled: true", "ds-cfg-java-class: org.opends.server.extensions.UserDefinedVirtualAttributeProvider", "ds-cfg-attribute-type: description", "ds-cfg-conflict-behavior: virtual-overrides-real", "", // Child base entries. "dn:cn=test children,cn=test parent 1,cn=test parents,cn=config", "objectclass: top", "objectclass: ds-cfg-branch", "cn: test children", "" }; // JNDI LDAP context. private JNDIDirContextAdaptor adaptor = null; // The saved test child configuration "aggregation-property" // property definition. private AggregationPropertyDefinition<ConnectionHandlerCfgClient, ConnectionHandlerCfg> aggregationPropertyDefinitionDefault = null; // An aggregation where the target must be enabled if the source is // enabled. private AggregationPropertyDefinition<ConnectionHandlerCfgClient, ConnectionHandlerCfg> aggregationPropertyDefinitionTargetAndSourceMustBeEnabled = null; // An aggregation where the target must be enabled. private AggregationPropertyDefinition<ConnectionHandlerCfgClient, ConnectionHandlerCfg> aggregationPropertyDefinitionTargetMustBeEnabled = null; /** * Sets up tests * * @throws Exception * If the server could not be initialized. */ @BeforeClass public void setUp() throws Exception { // This test suite depends on having the schema available, so // we'll start the server. TestCaseUtils.startServer(); TestCfg.setUp(); // Add test managed objects. TestCaseUtils.addEntries(TEST_LDIF); // Save the aggregation property definition so that it can be // replaced and restored later. aggregationPropertyDefinitionDefault = TestChildCfgDefn.getInstance() .getAggregationPropertyPropertyDefinition(); // Create the two test aggregation properties. AggregationPropertyDefinition.Builder<ConnectionHandlerCfgClient, ConnectionHandlerCfg> builder; TestChildCfgDefn d = TestChildCfgDefn.getInstance(); builder = AggregationPropertyDefinition.createBuilder(d, "aggregation-property"); builder.setOption(PropertyOption.MULTI_VALUED); builder.setAdministratorAction(new AdministratorAction( AdministratorAction.Type.NONE, d, "aggregation-property")); builder .setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<String>()); builder.setParentPath("/"); builder.setRelationDefinition("connection-handler"); builder.setTargetIsEnabledCondition(Conditions.contains("enabled", "true")); aggregationPropertyDefinitionTargetMustBeEnabled = builder.getInstance(); TestCfg .initializePropertyDefinition(aggregationPropertyDefinitionTargetMustBeEnabled); builder = AggregationPropertyDefinition.createBuilder(d, "aggregation-property"); builder.setOption(PropertyOption.MULTI_VALUED); builder.setAdministratorAction(new AdministratorAction( AdministratorAction.Type.NONE, d, "aggregation-property")); builder .setDefaultBehaviorProvider(new UndefinedDefaultBehaviorProvider<String>()); builder.setParentPath("/"); builder.setRelationDefinition("connection-handler"); builder.setTargetIsEnabledCondition(Conditions.contains("enabled", "true")); builder.setTargetNeedsEnablingCondition(Conditions.contains( "mandatory-boolean-property", "true")); aggregationPropertyDefinitionTargetAndSourceMustBeEnabled = builder .getInstance(); TestCfg .initializePropertyDefinition(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled); } /** * Tears down test environment. * * @throws Exception * If the test entries could not be removed. */ @AfterClass public void tearDown() throws Exception { TestCfg.cleanup(); // Restore the test child aggregation definition. TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault); // Remove test entries. deleteSubtree("cn=test parents,cn=config"); } /** * Tests that aggregation is rejected when the LDAP DN contains a * valid RDN but an invalid parent DN. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testAggregationBadBaseDN() throws Exception { // Add the entry. TestCaseUtils.addEntry(TEST_CHILD_3); try { TestParentCfg parent = getParent("test parent 1"); parent.getTestChild("test child 3"); Assert .fail("Unexpectedly added test child 3 when it had a bad aggregation value"); } catch (ConfigException e) { // Check that we have a decoding exception as the cause and // there was only one cause the illegal property value. Throwable cause = e.getCause(); if (cause instanceof ServerManagedObjectDecodingException) { ServerManagedObjectDecodingException de = (ServerManagedObjectDecodingException) cause; Collection<PropertyException> causes = de.getCauses(); Assert.assertEquals(causes.size(), 1); cause = causes.iterator().next(); if (cause instanceof IllegalPropertyValueStringException) { IllegalPropertyValueStringException pe = (IllegalPropertyValueStringException) cause; Assert.assertEquals(pe.getPropertyDefinition(), TestChildCfgDefn .getInstance().getAggregationPropertyPropertyDefinition()); Assert.assertEquals(pe.getIllegalValueString(), "cn=LDAP Connection Handler, cn=bad rdn, cn=config"); } else { // Got an unexpected cause. throw e; } } else { // Got an unexpected cause. throw e; } } finally { deleteSubtree("cn=test child 3,cn=test children,cn=test parent 1,cn=test parents,cn=config"); } } /** * Tests that aggregation is rejected by a constraint violation when * the DN values are dangling. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testAggregationDanglingReference() throws Exception { // Add the entry. TestCaseUtils.addEntry(TEST_CHILD_5); try { TestParentCfg parent = getParent("test parent 1"); parent.getTestChild("test child 5"); Assert .fail("Unexpectedly added test child 5 when it had a dangling reference"); } catch (ConfigException e) { // Check that we have a constraint violation as the cause. Throwable cause = e.getCause(); if (cause instanceof ConstraintViolationException) { ConstraintViolationException cve = (ConstraintViolationException) cause; Collection<Message> causes = cve.getMessages(); Assert.assertEquals(causes.size(), 2); } else { // Got an unexpected cause. throw e; } } finally { deleteSubtree("cn=test child 5,cn=test children,cn=test parent 1,cn=test parents,cn=config"); } } /** * Tests that aggregation is rejected by a constraint violation when * an enabled component references a disabled component and the * referenced component must always be enabled. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testAggregationDisabledReference1() throws Exception { // Add the entry and the connection handler. TestCaseUtils.addEntry(TEST_CHILD_6); try { createConnectionHandler(false); } catch (Exception e) { deleteSubtree(TEST_CHILD_6_DN); throw e; } // Register the temporary aggregation definition. TestCfg.removeConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); TestCfg .addPropertyDefinition(aggregationPropertyDefinitionTargetMustBeEnabled); TestCfg.addConstraint(aggregationPropertyDefinitionTargetMustBeEnabled .getSourceConstraint()); try { TestParentCfg parent = getParent("test parent 1"); parent.getTestChild("test child 6"); Assert .fail("Unexpectedly added test child 6 when it had a disabled reference"); } catch (ConfigException e) { // Check that we have a constraint violation as the cause. Throwable cause = e.getCause(); if (cause instanceof ConstraintViolationException) { ConstraintViolationException cve = (ConstraintViolationException) cause; Collection<Message> causes = cve.getMessages(); Assert.assertEquals(causes.size(), 1); } else { // Got an unexpected cause. throw e; } } finally { // Put back the default aggregation definition. TestCfg.removeConstraint(aggregationPropertyDefinitionTargetMustBeEnabled .getSourceConstraint()); TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault); TestCfg.addConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); try { deleteSubtree(TEST_CHILD_6_DN); } finally { deleteConnectionHandler(); } } } /** * Tests that aggregation is rejected by a constraint violation when * a disabled component references a disabled component and the * referenced component must always be enabled. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testAggregationDisabledReference2() throws Exception { // Add the entry. TestCaseUtils.addEntry(TEST_CHILD_7); try { createConnectionHandler(false); } catch (Exception e) { deleteSubtree(TEST_CHILD_7_DN); throw e; } // Register the temporary aggregation definition. TestCfg.removeConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); TestCfg .addPropertyDefinition(aggregationPropertyDefinitionTargetMustBeEnabled); TestCfg.addConstraint(aggregationPropertyDefinitionTargetMustBeEnabled .getSourceConstraint()); try { TestParentCfg parent = getParent("test parent 1"); parent.getTestChild("test child 7"); Assert .fail("Unexpectedly added test child 7 when it had a disabled reference"); } catch (ConfigException e) { // Check that we have a constraint violation as the cause. Throwable cause = e.getCause(); if (cause instanceof ConstraintViolationException) { ConstraintViolationException cve = (ConstraintViolationException) cause; Collection<Message> causes = cve.getMessages(); Assert.assertEquals(causes.size(), 1); } else { // Got an unexpected cause. throw e; } } finally { // Put back the default aggregation definition. TestCfg.removeConstraint(aggregationPropertyDefinitionTargetMustBeEnabled .getSourceConstraint()); TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault); TestCfg.addConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); try { deleteSubtree(TEST_CHILD_7_DN); } finally { deleteConnectionHandler(); } } } /** * Tests that aggregation is rejected by a constraint violation when * an enabled component references a disabled component and the * referenced component must always be enabled when the referencing * component is enabled. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testAggregationDisabledReference3() throws Exception { // Add the entry. TestCaseUtils.addEntry(TEST_CHILD_6); try { createConnectionHandler(false); } catch (Exception e) { deleteSubtree(TEST_CHILD_6_DN); throw e; } // Register the temporary aggregation definition. TestCfg.removeConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); TestCfg .addPropertyDefinition(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled); TestCfg .addConstraint(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled .getSourceConstraint()); try { TestParentCfg parent = getParent("test parent 1"); parent.getTestChild("test child 6"); Assert .fail("Unexpectedly added test child 6 when it had a disabled reference"); } catch (ConfigException e) { // Check that we have a constraint violation as the cause. Throwable cause = e.getCause(); if (cause instanceof ConstraintViolationException) { ConstraintViolationException cve = (ConstraintViolationException) cause; Collection<Message> causes = cve.getMessages(); Assert.assertEquals(causes.size(), 1); } else { // Got an unexpected cause. throw e; } } finally { // Put back the default aggregation definition. TestCfg .removeConstraint(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled .getSourceConstraint()); TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault); TestCfg.addConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); try { deleteSubtree(TEST_CHILD_6_DN); } finally { deleteConnectionHandler(); } } } /** * Tests that aggregation is allowed when a disabled component * references a disabled component and the referenced component must * always be enabled when the referencing component is enabled. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testAggregationDisabledReference4() throws Exception { // Add the entry. TestCaseUtils.addEntry(TEST_CHILD_7); try { createConnectionHandler(false); } catch (Exception e) { deleteSubtree(TEST_CHILD_7_DN); throw e; } // Register the temporary aggregation definition. TestCfg.removeConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); TestCfg .addPropertyDefinition(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled); TestCfg .addConstraint(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled .getSourceConstraint()); try { TestParentCfg parent = getParent("test parent 1"); parent.getTestChild("test child 7"); } finally { // Put back the default aggregation definition. TestCfg .removeConstraint(aggregationPropertyDefinitionTargetAndSourceMustBeEnabled .getSourceConstraint()); TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault); TestCfg.addConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); try { deleteSubtree(TEST_CHILD_7_DN); } finally { deleteConnectionHandler(); } } } /** * Tests that aggregation contains no values when it contains does * not contain any DN attribute values. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testAggregationEmpty() throws Exception { // Add the entry. TestCaseUtils.addEntry(TEST_CHILD_1); try { TestParentCfg parent = getParent("test parent 1"); assertChild1(parent.getTestChild("test child 1")); } finally { deleteSubtree("cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config"); } } /** * Tests that aggregation contains multiple valid values when it * contains a multiple valid DN attribute values. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testAggregationMultipleValues() throws Exception { // Add the entry. TestCaseUtils.addEntry(TEST_CHILD_4); try { TestParentCfg parent = getParent("test parent 1"); assertChild4(parent.getTestChild("test child 4")); } finally { deleteSubtree("cn=test child 4,cn=test children,cn=test parent 1,cn=test parents,cn=config"); } } /** * Tests that aggregation contains single valid value when it * contains a single valid DN attribute values. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testAggregationSingle() throws Exception { // Add the entry. TestCaseUtils.addEntry(TEST_CHILD_2); try { TestParentCfg parent = getParent("test parent 1"); assertChild2(parent.getTestChild("test child 2")); } finally { deleteSubtree("cn=test child 2,cn=test children,cn=test parent 1,cn=test parents,cn=config"); } } /** * Tests that it is impossible to delete a referenced component when * the referenced component must always exist regardless of whether * the referencing component is enabled or not. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testCannotDeleteReferencedComponent() throws Exception { // Add the entry. TestCaseUtils.addEntry(TEST_CHILD_7); try { createConnectionHandler(true); } catch (Exception e) { deleteSubtree(TEST_CHILD_7_DN); throw e; } // Register the temporary aggregation definition. TestCfg.removeConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); TestCfg .addPropertyDefinition(aggregationPropertyDefinitionTargetMustBeEnabled); TestCfg.addConstraint(aggregationPropertyDefinitionTargetMustBeEnabled .getSourceConstraint()); ConfigurationDeleteListener<TestChildCfg> dl = new DummyDeleteListener(); ConfigurationChangeListener<TestChildCfg> cl = new DummyChangeListener(); try { // Retrieve the parent and child managed objects and register // delete and change listeners respectively in order to trigger // the constraint call-backs. TestParentCfg parent = getParent("test parent 1"); parent.addTestChildDeleteListener(dl); TestChildCfg child = parent.getTestChild("test child 7"); child.addChangeListener(cl); // Now attempt to delete the referenced connection handler. // This should fail. try { deleteConnectionHandler(); Assert.fail("Successfully deleted a referenced component"); } catch (OperationRejectedException e) { // This is the expected exception - do nothing. } } finally { try { deleteSubtree(TEST_CHILD_7_DN); } finally { try { deleteConnectionHandler(); } catch (ManagedObjectNotFoundException e) { // Ignore as it may have been deleted already. } finally { // Remove the temporary delete listener. TestParentCfg parent = getParent("test parent 1"); parent.removeTestChildDeleteListener(dl); // Put back the default aggregation definition. TestCfg .removeConstraint(aggregationPropertyDefinitionTargetMustBeEnabled .getSourceConstraint()); TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault); TestCfg.addConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); } } } } /** * Tests that it is impossible to disable a referenced component * when the referenced component must always be enabled regardless * of whether the referencing component is enabled or not. * * @throws Exception * If the test unexpectedly fails. */ @Test public void testCannotDisableReferencedComponent() throws Exception { // Add the entry. TestCaseUtils.addEntry(TEST_CHILD_7); try { createConnectionHandler(true); } catch (Exception e) { deleteSubtree(TEST_CHILD_7_DN); throw e; } // Register the temporary aggregation definition. TestCfg.removeConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); TestCfg .addPropertyDefinition(aggregationPropertyDefinitionTargetMustBeEnabled); TestCfg.addConstraint(aggregationPropertyDefinitionTargetMustBeEnabled .getSourceConstraint()); ConfigurationDeleteListener<TestChildCfg> dl = new DummyDeleteListener(); ConfigurationChangeListener<TestChildCfg> cl = new DummyChangeListener(); try { // Retrieve the parent and child managed objects and register // delete and change listeners respectively in order to trigger // the constraint call-backs. TestParentCfg parent = getParent("test parent 1"); parent.addTestChildDeleteListener(dl); TestChildCfg child = parent.getTestChild("test child 7"); child.addChangeListener(cl); // Now attempt to disable the referenced connection handler. // This should fail. try { RootCfgClient root = TestCaseUtils.getRootConfiguration(); ConnectionHandlerCfgClient client = root .getConnectionHandler(TEST_CONNECTION_HANDLER_NAME); client.setEnabled(false); client.commit(); Assert.fail("Successfully disabled a referenced component"); } catch (OperationRejectedException e) { // This is the expected exception - do nothing. } } finally { try { deleteSubtree(TEST_CHILD_7_DN); } finally { try { deleteConnectionHandler(); } finally { // Remove the temporary delete listener. TestParentCfg parent = getParent("test parent 1"); parent.removeTestChildDeleteListener(dl); // Put back the default aggregation definition. TestCfg .removeConstraint(aggregationPropertyDefinitionTargetMustBeEnabled .getSourceConstraint()); TestCfg.addPropertyDefinition(aggregationPropertyDefinitionDefault); TestCfg.addConstraint(aggregationPropertyDefinitionDefault .getSourceConstraint()); } } } } // Assert that the values of child 1 are correct. private void assertChild1(TestChildCfg child) { Assert.assertEquals(child.getMandatoryClassProperty(), "org.opends.server.extensions.UserDefinedVirtualAttributeProvider"); Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(), DirectoryServer.getAttributeType("description")); assertSetEquals(child.getAggregationProperty(), new String[0]); } // Assert that the values of child 2 are correct. private void assertChild2(TestChildCfg child) { Assert.assertEquals(child.getMandatoryClassProperty(), "org.opends.server.extensions.UserDefinedVirtualAttributeProvider"); Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(), DirectoryServer.getAttributeType("description")); // Test normalization. assertSetEquals(child.getAggregationProperty(), "LDAP Connection Handler"); assertSetEquals(child.getAggregationProperty(), " LDAP Connection Handler "); assertSetEquals(child.getAggregationProperty(), " ldap connection HANDLER "); } // Assert that the values of child 4 are correct. private void assertChild4(TestChildCfg child) { Assert.assertEquals(child.getMandatoryClassProperty(), "org.opends.server.extensions.UserDefinedVirtualAttributeProvider"); Assert.assertEquals(child.getMandatoryReadOnlyAttributeTypeProperty(), DirectoryServer.getAttributeType("description")); assertSetEquals(child.getAggregationProperty(), "LDAPS Connection Handler", "LDAP Connection Handler"); } // Asserts that the actual set of DNs contains the expected values. private void assertSetEquals(SortedSet<String> actual, String... expected) { SortedSet<String> values = new TreeSet<String>(TestChildCfgDefn .getInstance().getAggregationPropertyPropertyDefinition()); if (expected != null) { for (String value : expected) { values.add(value); } } Assert.assertEquals((Object) actual, (Object) values); } // Creates a test connection handler for testing. private void createConnectionHandler(boolean enabled) throws Exception { ServerSocket freeSocket = TestCaseUtils.bindFreePort(); int freePort = freeSocket.getLocalPort(); freeSocket.close(); RootCfgClient root = TestCaseUtils.getRootConfiguration(); LDAPConnectionHandlerCfgClient client = root.createConnectionHandler( LDAPConnectionHandlerCfgDefn.getInstance(), TEST_CONNECTION_HANDLER_NAME, null); client.setEnabled(enabled); client.setListenPort(freePort); client.commit(); } // Deletes the test connection handler after testing. private void deleteConnectionHandler() throws Exception { RootCfgClient root = TestCaseUtils.getRootConfiguration(); root.removeConnectionHandler(TEST_CONNECTION_HANDLER_NAME); } // Deletes the named sub-tree. private void deleteSubtree(String dn) throws Exception { getAdaptor().deleteSubtree(new LdapName(dn)); } // Gets the JNDI connection for the test server instance. private synchronized JNDIDirContextAdaptor getAdaptor() throws Exception { if (adaptor == null) { adaptor = JNDIDirContextAdaptor.simpleSSLBind("127.0.0.1", TestCaseUtils .getServerAdminPort(), "cn=directory manager", "password"); } return adaptor; } // Gets the named parent configuration. private TestParentCfg getParent(String name) throws IllegalArgumentException, ConfigException { ServerManagementContext ctx = ServerManagementContext.getInstance(); ServerManagedObject<RootCfg> root = ctx.getRootConfigurationManagedObject(); TestParentCfg parent = root.getChild( TestCfg.getTestOneToManyParentRelationDefinition(), name) .getConfiguration(); return parent; } }