| | |
| | | */ |
| | | package org.opends.server.admin.server; |
| | | |
| | | import static org.fest.assertions.Assertions.*; |
| | | import static org.mockito.Matchers.*; |
| | | import static org.mockito.Mockito.*; |
| | | |
| | | import java.io.IOException; |
| | | import java.util.List; |
| | | |
| | | import javax.naming.OperationNotSupportedException; |
| | | import javax.naming.ldap.LdapName; |
| | | |
| | | import org.forgerock.i18n.LocalizableMessage; |
| | | import org.forgerock.i18n.LocalizableMessageBuilder; |
| | | import org.forgerock.opendj.ldap.Entry; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.forgerock.opendj.ldif.LDIF; |
| | | import org.mockito.ArgumentCaptor; |
| | | import org.opends.server.admin.AdminTestCase; |
| | | 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.api.ConfigAddListener; |
| | | import org.opends.server.api.ConfigChangeListener; |
| | | import org.opends.server.api.ConfigDeleteListener; |
| | | import org.opends.server.config.ConfigException; |
| | | import org.opends.server.config.ConfigurationRepository; |
| | | import org.opends.server.types.ConfigChangeResult; |
| | | import org.testng.Assert; |
| | | import org.testng.annotations.AfterClass; |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | /** |
| | | * Test cases for constraints on the server-side. |
| | | */ |
| | | @SuppressWarnings("javadoc") |
| | | public final class ConstraintTest extends AdminTestCase { |
| | | |
| | | // Child DN. |
| | | private static final String TEST_CHILD_1_DN = "cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config"; |
| | | |
| | | /** |
| | | * A test child add listener. |
| | | */ |
| | | private static class AddListener implements ConfigurationAddListener<TestChildCfg> { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ConfigChangeResult applyConfigurationAdd(TestChildCfg configuration) { |
| | | return new ConfigChangeResult(ResultCode.SUCCESS, false); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isConfigurationAddAcceptable(TestChildCfg configuration, List<Message> unacceptableReasons) { |
| | | public boolean isConfigurationAddAcceptable(TestChildCfg configuration, |
| | | List<LocalizableMessage> unacceptableReasons) { |
| | | return true; |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * A test child delete listener. |
| | | */ |
| | | private static class DeleteListener implements ConfigurationDeleteListener<TestChildCfg> { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ConfigChangeResult applyConfigurationDelete(TestChildCfg configuration) { |
| | | return new ConfigChangeResult(ResultCode.SUCCESS, false); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isConfigurationDeleteAcceptable(TestChildCfg configuration, List<Message> unacceptableReasons) { |
| | | public boolean isConfigurationDeleteAcceptable(TestChildCfg configuration, |
| | | List<LocalizableMessage> unacceptableReasons) { |
| | | return true; |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | | * A test child change listener. |
| | | */ |
| | | private static class ChangeListener implements ConfigurationChangeListener<TestChildCfg> { |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public ConfigChangeResult applyConfigurationChange(TestChildCfg configuration) { |
| | | return new ConfigChangeResult(ResultCode.SUCCESS, false); |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | public boolean isConfigurationChangeAcceptable(TestChildCfg configuration, List<Message> unacceptableReasons) { |
| | | public boolean isConfigurationChangeAcceptable(TestChildCfg configuration, |
| | | List<LocalizableMessage> unacceptableReasons) { |
| | | return true; |
| | | } |
| | | |
| | | } |
| | | |
| | | // 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" }; |
| | | private static final Entry TEST_CHILD_1 = LDIF.makeEntry( |
| | | "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 LDIF. |
| | | private static final Entry NEW_TEST_CHILD_1 = LDIF.makeEntry( |
| | | "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", |
| | | "ds-cfg-base-dn: dc=new value 1,dc=com", |
| | | "ds-cfg-base-dn: dc=new value 2,dc=com", |
| | | "ds-cfg-group-dn: dc=new value 3,dc=com", |
| | | "ds-cfg-group-dn: dc=new value 4,dc=com"); |
| | | |
| | | private static final Entry TEST_BASE_CHILD = LDIF.makeEntry( |
| | | "dn:cn=test children,cn=test parent 1,cn=test parents,cn=config", |
| | | "objectclass: top", |
| | | "objectclass: ds-cfg-branch", |
| | | "cn: test children"); |
| | | |
| | | // Parent 1 - uses default values for |
| | | // optional-multi-valued-dn-property. |
| | | private static final Entry TEST_PARENT_1 = LDIF.makeEntry( |
| | | "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"); |
| | | |
| | | 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 - uses default values for |
| | | // optional-multi-valued-dn-property. |
| | | "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", "", }; |
| | | // Base entries. |
| | | "dn: cn=test parents,cn=config", |
| | | "objectclass: top", |
| | | "objectclass: ds-cfg-branch", |
| | | "cn: test parents", |
| | | ""}; |
| | | |
| | | // JNDI LDAP context. |
| | | private JNDIDirContextAdaptor adaptor = 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(); |
| | | disableClassValidationForProperties(); |
| | | TestCfg.setUp(); |
| | | |
| | | // Add test managed objects. |
| | | TestCaseUtils.addEntries(TEST_LDIF); |
| | | } |
| | | |
| | | /** |
| | | * Tears down test environment. |
| | | * |
| | | * @throws Exception |
| | | * If the test entries could not be removed. |
| | | */ |
| | | @AfterClass |
| | | public void tearDown() throws Exception { |
| | | TestCfg.cleanup(); |
| | | |
| | | // Remove test entries. |
| | | deleteSubtree("cn=test parents,cn=config"); |
| | | } |
| | | |
| | | /** |
| | | * Tests that retrieval can succeed. |
| | | * |
| | | * @throws Exception |
| | | * If the test unexpectedly fails. |
| | | */ |
| | | /** Success just ensure there is no exception raised */ |
| | | @Test |
| | | public void testGetManagedObjectSuccess() throws Exception { |
| | | MockConstraint constraint = new MockConstraint(true, false); |
| | | |
| | | // arrange |
| | | ConfigurationRepository configRepository = createConfigRepositoryWithEntries(TEST_PARENT_1, TEST_BASE_CHILD, |
| | | TEST_CHILD_1); |
| | | ServerManagementContext context = new ServerManagementContext(configRepository); |
| | | MockConstraint constraint = new MockConstraint(true, false, configRepository); |
| | | try { |
| | | TestCaseUtils.addEntry(TEST_CHILD_1); |
| | | TestCfg.addConstraint(constraint); |
| | | TestParentCfg parentCfg = getParentCfg(TEST_PARENT_1, context); |
| | | |
| | | TestParentCfg parent = getParent("test parent 1"); |
| | | parent.getTestChild("test child 1"); |
| | | // act |
| | | parentCfg.getTestChild(entryName(TEST_CHILD_1)); |
| | | } finally { |
| | | TestCfg.removeConstraint(constraint); |
| | | |
| | | try { |
| | | deleteSubtree(TEST_CHILD_1_DN); |
| | | } catch (Exception e) { |
| | | // Do nothing. |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tests that retrieval can fail. |
| | | * |
| | | * @throws Exception |
| | | * If the test unexpectedly fails. |
| | | */ |
| | | @Test |
| | | public void testGetManagedObjectFail() throws Exception { |
| | | MockConstraint constraint = new MockConstraint(false, true); |
| | | |
| | | // arrange |
| | | ConfigurationRepository configRepository = createConfigRepositoryWithEntries(TEST_PARENT_1, TEST_BASE_CHILD, |
| | | TEST_CHILD_1); |
| | | ServerManagementContext context = new ServerManagementContext(configRepository); |
| | | MockConstraint constraint = new MockConstraint(false, true, configRepository); |
| | | try { |
| | | TestCaseUtils.addEntry(TEST_CHILD_1); |
| | | TestCfg.addConstraint(constraint); |
| | | TestParentCfg parentCfg = getParentCfg(TEST_PARENT_1, context); |
| | | |
| | | TestParentCfg parent = getParent("test parent 1"); |
| | | parent.getTestChild("test child 1"); |
| | | // act |
| | | parentCfg.getTestChild(entryName(TEST_CHILD_1)); |
| | | |
| | | failWasExpected(ConfigException.class); |
| | | } catch (ConfigException e) { |
| | | // assert |
| | | Throwable cause = e.getCause(); |
| | | if (cause instanceof ConstraintViolationException) { |
| | | ConstraintViolationException cve = (ConstraintViolationException) cause; |
| | | Assert.assertEquals(cve.getMessages().size(), 1); |
| | | Assert.assertSame(cve.getManagedObject().getManagedObjectDefinition(), TestChildCfgDefn.getInstance()); |
| | | } else { |
| | | // Wrong cause. |
| | | throw e; |
| | | } |
| | | assertThat(e.getCause()).isNotNull().isInstanceOf(ConstraintViolationException.class); |
| | | ConstraintViolationException cve = (ConstraintViolationException) cause; |
| | | assertThat(cve.getMessages().size()).isEqualTo(1); |
| | | assertThat(cve.getManagedObject().getManagedObjectDefinition()).isSameAs(TestChildCfgDefn.getInstance()); |
| | | } finally { |
| | | TestCfg.removeConstraint(constraint); |
| | | |
| | | try { |
| | | deleteSubtree(TEST_CHILD_1_DN); |
| | | } catch (Exception e) { |
| | | // Do nothing. |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tests that an add constraint can succeed. |
| | | * |
| | | * @throws Exception |
| | | * If the test unexpectedly fails. |
| | | */ |
| | | @Test |
| | | public void testAddConstraintSuccess() throws Exception { |
| | | TestParentCfg parent = getParent("test parent 1"); |
| | | AddListener listener = new AddListener(); |
| | | parent.addTestChildAddListener(listener); |
| | | |
| | | MockConstraint constraint = new MockConstraint(true, false); |
| | | TestCfg.addConstraint(constraint); |
| | | |
| | | try { |
| | | try { |
| | | // Add the entry. |
| | | addEntry(ResultCode.SUCCESS, TEST_CHILD_1); |
| | | } finally { |
| | | try { |
| | | deleteSubtree(TEST_CHILD_1_DN); |
| | | } catch (Exception e) { |
| | | // Do nothing. |
| | | } |
| | | } |
| | | } finally { |
| | | TestCfg.removeConstraint(constraint); |
| | | parent.removeTestChildAddListener(listener); |
| | | } |
| | | @DataProvider |
| | | Object[][] constraintValues() { |
| | | return new Object[][] { |
| | | // value of constraint used |
| | | { true }, // success |
| | | { false } // failure |
| | | }; |
| | | } |
| | | |
| | | /** |
| | | * Tests that an add constraint can fail. |
| | | * |
| | | * @throws Exception |
| | | * If the test unexpectedly fails. |
| | | */ |
| | | @Test |
| | | public void testAddConstraintFail() throws Exception { |
| | | TestParentCfg parent = getParent("test parent 1"); |
| | | AddListener listener = new AddListener(); |
| | | parent.addTestChildAddListener(listener); |
| | | |
| | | MockConstraint constraint = new MockConstraint(false, true); |
| | | TestCfg.addConstraint(constraint); |
| | | |
| | | @Test(dataProvider = "constraintValues") |
| | | public void testAddConstraint(boolean isUsableConstraint) throws Exception { |
| | | // arrange |
| | | ConfigurationRepository configRepository = createConfigRepositoryWithEntries(TEST_PARENT_1, TEST_BASE_CHILD, |
| | | TEST_CHILD_1); |
| | | ServerManagementContext context = new ServerManagementContext(configRepository); |
| | | TestParentCfg parentCfg = getParentCfg(TEST_PARENT_1, context); |
| | | parentCfg.addTestChildAddListener(new AddListener()); |
| | | MockConstraint constraint = new MockConstraint(isUsableConstraint, false, configRepository); |
| | | try { |
| | | try { |
| | | // Add the entry. |
| | | addEntry(ResultCode.UNWILLING_TO_PERFORM, TEST_CHILD_1); |
| | | } finally { |
| | | try { |
| | | deleteSubtree(TEST_CHILD_1_DN); |
| | | } catch (Exception e) { |
| | | // Do nothing. |
| | | } |
| | | } |
| | | } finally { |
| | | TestCfg.removeConstraint(constraint); |
| | | parent.removeTestChildAddListener(listener); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tests that a delete constraint can succeed. |
| | | * |
| | | * @throws Exception |
| | | * If the test unexpectedly fails. |
| | | */ |
| | | @Test |
| | | public void testDeleteConstraintSuccess() throws Exception { |
| | | TestParentCfg parent = getParent("test parent 1"); |
| | | DeleteListener listener = new DeleteListener(); |
| | | parent.addTestChildDeleteListener(listener); |
| | | |
| | | MockConstraint constraint = new MockConstraint(false, true); |
| | | TestCfg.addConstraint(constraint); |
| | | |
| | | try { |
| | | // Add the entry. |
| | | TestCaseUtils.addEntry(TEST_CHILD_1); |
| | | |
| | | // Now delete it - this should trigger the constraint. |
| | | deleteSubtree(TEST_CHILD_1_DN); |
| | | } finally { |
| | | TestCfg.removeConstraint(constraint); |
| | | parent.removeTestChildDeleteListener(listener); |
| | | |
| | | try { |
| | | // Clean up. |
| | | deleteSubtree(TEST_CHILD_1_DN); |
| | | } catch (Exception e) { |
| | | // Ignore. |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tests that a delete constraint can fail. |
| | | * |
| | | * @throws Exception |
| | | * If the test unexpectedly fails. |
| | | */ |
| | | @Test |
| | | public void testDeleteConstraintFail() throws Exception { |
| | | TestParentCfg parent = getParent("test parent 1"); |
| | | DeleteListener listener = new DeleteListener(); |
| | | parent.addTestChildDeleteListener(listener); |
| | | |
| | | MockConstraint constraint = new MockConstraint(true, false); |
| | | TestCfg.addConstraint(constraint); |
| | | |
| | | try { |
| | | // Add the entry. |
| | | TestCaseUtils.addEntry(TEST_CHILD_1); |
| | | try { |
| | | // Now delete it - this should trigger the constraint. |
| | | deleteSubtree(TEST_CHILD_1_DN); |
| | | |
| | | // Should not have succeeded. |
| | | Assert.fail("Delete constraint failed to prevent deletion"); |
| | | } catch (OperationNotSupportedException e) { |
| | | // Ignore - this is the expected exception. |
| | | } |
| | | } finally { |
| | | TestCfg.removeConstraint(constraint); |
| | | parent.removeTestChildDeleteListener(listener); |
| | | |
| | | try { |
| | | // Clean up. |
| | | deleteSubtree(TEST_CHILD_1_DN); |
| | | } catch (Exception e) { |
| | | // Ignore. |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tests that a modify constraint can succeed. |
| | | * |
| | | * @throws Exception |
| | | * If the test unexpectedly fails. |
| | | */ |
| | | @Test |
| | | public void testChangeConstraintSuccess() throws Exception { |
| | | TestParentCfg parent = getParent("test parent 1"); |
| | | |
| | | MockConstraint constraint = new MockConstraint(true, false); |
| | | |
| | | try { |
| | | // Add the entry. |
| | | TestCaseUtils.addEntry(TEST_CHILD_1); |
| | | TestChildCfg child = parent.getTestChild("test child 1"); |
| | | |
| | | TestCfg.addConstraint(constraint); |
| | | ChangeListener listener = new ChangeListener(); |
| | | child.addChangeListener(listener); |
| | | |
| | | // Now modify it. |
| | | String[] changes = new String[] { |
| | | "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config", |
| | | "changetype: modify", "replace: ds-cfg-base-dn", "ds-cfg-base-dn: dc=new value 1,dc=com", |
| | | "ds-cfg-base-dn: dc=new value 2,dc=com", "-", "replace: ds-cfg-group-dn", |
| | | "ds-cfg-group-dn: dc=new value 3,dc=com", "ds-cfg-group-dn: dc=new value 4,dc=com" }; |
| | | // act |
| | | boolean isAcceptable = simulateEntryAdd(TEST_CHILD_1, configRepository); |
| | | |
| | | int result = TestCaseUtils.applyModifications(true, changes); |
| | | Assert.assertEquals(result, ResultCode.SUCCESS.getIntValue()); |
| | | // assert : success depends on constraint used |
| | | assertThat(isAcceptable).isEqualTo(isUsableConstraint); |
| | | } finally { |
| | | TestCfg.removeConstraint(constraint); |
| | | try { |
| | | deleteSubtree(TEST_CHILD_1_DN); |
| | | } catch (Exception e) { |
| | | // Ignore. |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Test(dataProvider = "constraintValues") |
| | | public void testDeleteConstraint(boolean isDeleteAllowedConstraint) throws Exception { |
| | | // arrange |
| | | ConfigurationRepository configRepository = createConfigRepositoryWithEntries(TEST_PARENT_1, TEST_BASE_CHILD, |
| | | TEST_CHILD_1); |
| | | ServerManagementContext context = new ServerManagementContext(configRepository); |
| | | TestParentCfg parentCfg = getParentCfg(TEST_PARENT_1, context); |
| | | parentCfg.addTestChildDeleteListener(new DeleteListener()); |
| | | MockConstraint constraint = new MockConstraint(false, isDeleteAllowedConstraint, configRepository); |
| | | try { |
| | | TestCfg.addConstraint(constraint); |
| | | |
| | | // act |
| | | boolean isAcceptable = simulateEntryDelete(TEST_CHILD_1, configRepository); |
| | | |
| | | // assert : success depends on constraint used |
| | | assertThat(isAcceptable).isEqualTo(isDeleteAllowedConstraint); |
| | | } finally { |
| | | TestCfg.removeConstraint(constraint); |
| | | } |
| | | } |
| | | |
| | | @Test(dataProvider = "constraintValues") |
| | | public void testChangeConstraint(boolean isUsableConstraint) throws Exception { |
| | | // arrange |
| | | ConfigurationRepository configRepository = createConfigRepositoryWithEntries(TEST_PARENT_1, TEST_BASE_CHILD, |
| | | TEST_CHILD_1); |
| | | ServerManagementContext context = new ServerManagementContext(configRepository); |
| | | MockConstraint constraint = new MockConstraint(isUsableConstraint, false, configRepository); |
| | | TestParentCfg parentCfg = getParentCfg(TEST_PARENT_1, context); |
| | | TestChildCfg childCfg = parentCfg.getTestChild(entryName(TEST_CHILD_1)); |
| | | |
| | | try { |
| | | TestCfg.addConstraint(constraint); |
| | | childCfg.addChangeListener(new ChangeListener()); |
| | | |
| | | // act |
| | | // It is not an issue to use the same child entry here |
| | | // as we're only interested in constraint checking |
| | | boolean isAcceptable = simulateEntryChange(TEST_CHILD_1, configRepository); |
| | | |
| | | // assert : success depends on constraint used |
| | | assertThat(isAcceptable).isEqualTo(isUsableConstraint); |
| | | } finally { |
| | | TestCfg.removeConstraint(constraint); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tests that a modify constraint can fail. |
| | | * |
| | | * @throws Exception |
| | | * If the test unexpectedly fails. |
| | | * Simulate an entry add by triggering configAddIsAcceptable method of last registered add listener. |
| | | * @return true if add is acceptable, false otherwise. |
| | | */ |
| | | @Test |
| | | public void testChangeConstraintFail() throws Exception { |
| | | TestParentCfg parent = getParent("test parent 1"); |
| | | MockConstraint constraint = new MockConstraint(false, true); |
| | | private boolean simulateEntryAdd(Entry entry, ConfigurationRepository configRepository) throws IOException { |
| | | // use argument capture to retrieve the actual listener |
| | | ArgumentCaptor<ConfigAddListener> registeredListener = ArgumentCaptor.forClass(ConfigAddListener.class); |
| | | verify(configRepository).registerAddListener(eq(entry.getName().parent()), registeredListener.capture()); |
| | | |
| | | try { |
| | | // Add the entry. |
| | | TestCaseUtils.addEntry(TEST_CHILD_1); |
| | | TestChildCfg child = parent.getTestChild("test child 1"); |
| | | |
| | | TestCfg.addConstraint(constraint); |
| | | ChangeListener listener = new ChangeListener(); |
| | | child.addChangeListener(listener); |
| | | |
| | | // Now modify it. |
| | | String[] changes = new String[] { |
| | | "dn: cn=test child 1,cn=test children,cn=test parent 1,cn=test parents,cn=config", |
| | | "changetype: modify", "replace: ds-cfg-base-dn", "ds-cfg-base-dn: dc=new value 1,dc=com", |
| | | "ds-cfg-base-dn: dc=new value 2,dc=com", "-", "replace: ds-cfg-group-dn", |
| | | "ds-cfg-group-dn: dc=new value 3,dc=com", "ds-cfg-group-dn: dc=new value 4,dc=com" }; |
| | | |
| | | int result = TestCaseUtils.applyModifications(true, changes); |
| | | Assert.assertEquals(result, ResultCode.UNWILLING_TO_PERFORM.getIntValue()); |
| | | } finally { |
| | | TestCfg.removeConstraint(constraint); |
| | | try { |
| | | deleteSubtree(TEST_CHILD_1_DN); |
| | | } catch (Exception e) { |
| | | // Ignore. |
| | | } |
| | | } |
| | | return registeredListener.getValue().configAddIsAcceptable(entry, new LocalizableMessageBuilder()); |
| | | } |
| | | |
| | | // Add an entry and check its result. |
| | | private void addEntry(ResultCode expected, String... lines) throws Exception { |
| | | Entry entry = TestCaseUtils.makeEntry(lines); |
| | | /** |
| | | * Simulate an entry delete by triggering configDeleteIsAcceptable method of last registered add listener. |
| | | * @return true if delete is acceptable, false otherwise. |
| | | */ |
| | | private boolean simulateEntryDelete(Entry entry, ConfigurationRepository configRepository) throws IOException { |
| | | // use argument capture to retrieve the actual listener |
| | | ArgumentCaptor<ConfigDeleteListener> registeredListener = ArgumentCaptor.forClass(ConfigDeleteListener.class); |
| | | verify(configRepository).registerDeleteListener(eq(entry.getName().parent()), registeredListener.capture()); |
| | | |
| | | InternalClientConnection conn = InternalClientConnection.getRootConnection(); |
| | | |
| | | AddOperation add = conn.processAdd(entry.getDN(), entry.getObjectClasses(), entry.getUserAttributes(), |
| | | entry.getOperationalAttributes()); |
| | | |
| | | Assert.assertEquals(add.getResultCode(), expected, add.getErrorMessage().toString()); |
| | | return registeredListener.getValue().configDeleteIsAcceptable(entry, new LocalizableMessageBuilder()); |
| | | } |
| | | |
| | | // Deletes the named sub-tree. |
| | | private void deleteSubtree(String dn) throws Exception { |
| | | getAdaptor().deleteSubtree(new LdapName(dn)); |
| | | /** |
| | | * Simulate an entry change by triggering configChangeIsAcceptable method on last registered change listener. |
| | | * @return true if change is acceptable, false otherwise. |
| | | */ |
| | | private boolean simulateEntryChange(Entry newEntry, ConfigurationRepository configRepository) { |
| | | // use argument capture to retrieve the actual listener |
| | | ArgumentCaptor<ConfigChangeListener> registeredListener = ArgumentCaptor.forClass(ConfigChangeListener.class); |
| | | verify(configRepository).registerChangeListener(eq(newEntry.getName()), registeredListener.capture()); |
| | | |
| | | return registeredListener.getValue().configChangeIsAcceptable(newEntry, new LocalizableMessageBuilder()); |
| | | } |
| | | |
| | | // 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 { |
| | | ServerManagedObject<RootCfg> root = serverContext.getRootConfigurationManagedObject(); |
| | | TestParentCfg parent = root.getChild(TestCfg.getTestOneToManyParentRelationDefinition(), name) |
| | | .getConfiguration(); |
| | | return parent; |
| | | } |
| | | } |