/*
|
* The contents of this file are subject to the terms of the Common Development and
|
* Distribution License (the License). You may not use this file except in compliance with the
|
* License.
|
*
|
* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
|
* specific language governing permission and limitations under the License.
|
*
|
* When distributing Covered Software, include this CDDL Header Notice in each file and include
|
* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
|
* Header, with the fields enclosed by brackets [] replaced by your own identifying
|
* information: "Portions Copyright [year] [name of copyright owner]".
|
*
|
* Copyright 2006-2009 Sun Microsystems, Inc.
|
* Portions Copyright 2011-2016 ForgeRock AS.
|
* Portions Copyright 2026 3A Systems, LLC
|
*/
|
package org.opends.server.tasks;
|
|
import java.io.File;
|
import java.io.IOException;
|
import java.io.Writer;
|
import java.lang.reflect.Field;
|
import java.nio.charset.StandardCharsets;
|
import java.nio.file.Files;
|
import java.util.Arrays;
|
import java.util.UUID;
|
|
import org.forgerock.opendj.ldap.ResultCode;
|
import org.opends.server.TestCaseUtils;
|
import org.opends.server.api.LocalBackend;
|
import org.opends.server.api.TestTaskListener;
|
import org.opends.server.backends.task.Task;
|
import org.opends.server.backends.task.TaskState;
|
import org.opends.server.core.AddOperation;
|
import org.opends.server.core.BackendConfigManager;
|
import org.opends.server.core.DirectoryServer;
|
import org.opends.server.tools.makeldif.MakeLDIFInputStream;
|
import org.opends.server.types.Entry;
|
import org.opends.server.types.LDIFImportConfig;
|
import org.forgerock.opendj.ldap.schema.ObjectClass;
|
import org.testng.annotations.AfterClass;
|
import org.testng.annotations.BeforeClass;
|
import org.testng.annotations.DataProvider;
|
import org.testng.annotations.Test;
|
|
import static org.opends.server.protocols.internal.InternalClientConnection.*;
|
import static org.testng.Assert.*;
|
|
/**
|
* Tests invocation of the import and export tasks, but does not aim to
|
* thoroughly test the underlying backend implementations.
|
*/
|
public class TestImportAndExport extends TasksTestCase
|
{
|
/**
|
* A makeldif template used to create some test entries.
|
*/
|
private static String[] template = new String[] {
|
"define suffix=dc=example,dc=com",
|
"define maildomain=example.com",
|
"define numusers=101",
|
"",
|
"branch: [suffix]",
|
"",
|
"branch: ou=People,[suffix]",
|
"subordinateTemplate: person:[numusers]",
|
"",
|
"template: person",
|
"rdnAttr: uid",
|
"objectClass: top",
|
"objectClass: person",
|
"objectClass: organizationalPerson",
|
"objectClass: inetOrgPerson",
|
"givenName: <first>",
|
"sn: <last>",
|
"cn: {givenName} {sn}",
|
"initials: {givenName:1}<random:chars:" +
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ:1>{sn:1}",
|
"employeeNumber: <sequential:0>",
|
"uid: user.{employeeNumber}",
|
"mail: {uid}@[maildomain]",
|
"userPassword: password",
|
"telephoneNumber: <random:telephone>",
|
"homePhone: <random:telephone>",
|
"pager: <random:telephone>",
|
"mobile: <random:telephone>",
|
"street: <random:numeric:5> <file:streets> Street",
|
"l: <file:cities>",
|
"st: <file:states>",
|
"postalCode: <random:numeric:5>",
|
"postalAddress: {cn}${street}${l}, {st} {postalCode}",
|
"description: This is the description for {cn}.",
|
""};
|
|
/**
|
* A temporary LDIF file containing some test entries.
|
*/
|
private File ldifFile;
|
|
/**
|
* A temporary file to contain rejected entries.
|
*/
|
private File rejectFile;
|
|
@BeforeClass
|
public void setUp() throws Exception
|
{
|
// The server must be running for these tests.
|
TestCaseUtils.startServer();
|
|
// Create a temporary test LDIF file.
|
ldifFile = File.createTempFile("import-test", ".ldif");
|
String resourcePath = DirectoryServer.getInstanceRoot() + File.separator +
|
"config" + File.separator + "MakeLDIF";
|
LdifFileWriter.makeLdif(ldifFile.getPath(), resourcePath, template);
|
|
// Create a temporary rejects file.
|
rejectFile = File.createTempFile("import-test-rejects", ".ldif");
|
|
TestTaskListener.registerListeners();
|
}
|
|
@AfterClass
|
public void tearDown()
|
{
|
ldifFile.delete();
|
rejectFile.delete();
|
TestTaskListener.deregisterListeners();
|
}
|
|
/**
|
* Import and export tasks test data provider.
|
*
|
* @return The array of tasks test data. The first column is a task entry
|
* and the second column is the expected completed task state.
|
*/
|
@DataProvider(name = "importexport")
|
public Object[][] createData() throws Exception
|
{
|
return new Object[][] {
|
// A fairly simple, valid import task using backend ID.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-backend-id: userRoot",
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-reject-file: " + rejectFile.getPath(),
|
"ds-task-import-overwrite-rejects: TRUE",
|
"ds-task-import-exclude-attribute: description",
|
"ds-task-import-exclude-filter: (st=CA)",
|
"ds-task-import-exclude-branch: o=exclude,dc=example,dc=com"
|
),
|
TaskState.COMPLETED_SUCCESSFULLY
|
},
|
// A fairly simple, valid import task using include base DN.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-include-branch: dc=example,dc=com",
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-reject-file: " + rejectFile.getPath(),
|
"ds-task-import-overwrite-rejects: TRUE",
|
"ds-task-import-exclude-attribute: description",
|
"ds-task-import-exclude-filter: (st=CA)",
|
"ds-task-import-exclude-branch: o=exclude,dc=example,dc=com"
|
),
|
TaskState.COMPLETED_SUCCESSFULLY
|
},
|
// A complex, valid import task.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-backend-id: userRoot",
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-is-compressed: FALSE",
|
"ds-task-import-is-encrypted: FALSE",
|
"ds-task-import-reject-file: " + rejectFile.getPath(),
|
"ds-task-import-overwrite-rejects: FALSE",
|
"ds-task-import-skip-schema-validation: TRUE",
|
"ds-task-import-include-branch: dc=example,dc=com",
|
"ds-task-import-exclude-branch: o=exclude,dc=example,dc=com",
|
"ds-task-import-include-attribute: cn",
|
"ds-task-import-include-attribute: sn",
|
"ds-task-import-include-attribute: uid",
|
"ds-task-import-include-filter: (objectclass=*)"
|
),
|
TaskState.COMPLETED_SUCCESSFULLY
|
},
|
// A partial, valid import task.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-include-branch: ou=people,dc=example,dc=com",
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-reject-file: " + rejectFile.getPath(),
|
"ds-task-import-overwrite-rejects: TRUE",
|
"ds-task-import-exclude-attribute: description",
|
"ds-task-import-exclude-filter: (st=CA)",
|
"ds-task-import-exclude-branch: o=exclude,dc=example,dc=com"
|
),
|
TaskState.COMPLETED_SUCCESSFULLY
|
},
|
// Rejects file is a directory.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-backend-id: userRoot",
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-reject-file: " + ldifFile.getParent(),
|
"ds-task-import-overwrite-rejects: TRUE"
|
),
|
TaskState.STOPPED_BY_ERROR
|
},
|
};
|
}
|
|
/**
|
* Import and export tasks bad test data provider.
|
*
|
* @return The array of tasks test data. The first column is a task entry
|
* and the second column is the expected completed task state.
|
*/
|
@DataProvider(name = "badimportexport")
|
public Object[][] createBadData() throws Exception
|
{
|
return new Object[][] {
|
// Invalid exclude filter.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-backend-id: userRoot",
|
"ds-task-import-exclude-filter: ()"
|
),
|
ResultCode.UNWILLING_TO_PERFORM
|
},
|
// Invalid include filter.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-backend-id: userRoot",
|
"ds-task-import-include-filter: ()"
|
),
|
ResultCode.UNWILLING_TO_PERFORM
|
},
|
// Backend id does not exist.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-backend-id: doesnotexist"
|
),
|
ResultCode.UNWILLING_TO_PERFORM
|
},
|
// Backend does not support import.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-backend-id: monitor"
|
),
|
ResultCode.UNWILLING_TO_PERFORM
|
},
|
// Backend does not handle include branch.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-backend-id: userRoot",
|
"ds-task-import-include-branch: dc=opends,dc=org"
|
),
|
ResultCode.UNWILLING_TO_PERFORM
|
},
|
// Not specifying a destination.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-ldif-file: " + ldifFile.getPath()
|
),
|
ResultCode.UNWILLING_TO_PERFORM
|
},
|
// ldif file does not exist.
|
{
|
TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() +
|
",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-ldif-file: doesnotexist",
|
"ds-task-import-backend-id: userRoot"
|
),
|
ResultCode.UNWILLING_TO_PERFORM
|
}
|
};
|
}
|
|
/**
|
* Test that various import and export task definitions complete with the
|
* expected state.
|
* @param taskEntry The task entry.
|
* @param expectedState The expected completion state of the task.
|
*/
|
@Test(dataProvider = "importexport")
|
public void testImportExport(Entry taskEntry, TaskState expectedState)
|
throws Exception
|
{
|
int exportBeginCount = TestTaskListener.exportBeginCount.get();
|
int exportEndCount = TestTaskListener.exportEndCount.get();
|
int importBeginCount = TestTaskListener.importBeginCount.get();
|
int importEndCount = TestTaskListener.importEndCount.get();
|
|
ObjectClass exportClass = TestCaseUtils.getServerContext().getSchema().getObjectClass("ds-task-export");
|
|
// Use a big timeout since this test is sensitive to host environment (e.g.
|
// low memory, etc). See issue OPENDJ-256.
|
testTask(taskEntry, expectedState, 600);
|
if (expectedState == TaskState.COMPLETED_SUCCESSFULLY ||
|
expectedState == TaskState.COMPLETED_WITH_ERRORS)
|
{
|
if (taskEntry.hasObjectClass(exportClass))
|
{
|
assertEquals(TestTaskListener.exportBeginCount.get(), exportBeginCount+1);
|
assertEquals(TestTaskListener.exportEndCount.get(), exportEndCount+1);
|
assertEquals(TestTaskListener.exportBeginCount.get(),
|
TestTaskListener.exportEndCount.get());
|
}
|
else
|
{
|
assertEquals(TestTaskListener.importBeginCount.get(), importBeginCount+1);
|
assertEquals(TestTaskListener.importEndCount.get(), importEndCount+1);
|
assertEquals(TestTaskListener.importBeginCount.get(),
|
TestTaskListener.importEndCount.get());
|
}
|
}
|
}
|
|
/**
|
* An import which cannot disable its backend must still tell the import task listeners
|
* that the import is over: a listener which took something offline when the import began
|
* - a replication domain disables itself - has no other chance to put it back. The reject
|
* and skip files it opened before touching the backend must be closed on that road too:
|
* it is the one which ends furthest from the backend, so a close which rides on the
|
* backend having been disabled, or on the import having been launched, misses it.
|
*/
|
@Test
|
public void testImportEndsWhenTheBackendCannotBeDisabled() throws Exception
|
{
|
/*
|
* A backend registered at runtime has no entry in cn=config, and disabling a backend
|
* is a modification of that entry, so TaskUtils.disableBackend() cannot do it.
|
*/
|
final String backendID = "importTaskUnconfiguredBackend";
|
TestCaseUtils.initializeMemoryBackend(backendID, "dc=unconfigured,dc=com", true);
|
File skipFile = File.createTempFile("import-test-skipped", ".ldif");
|
try
|
{
|
int importBeginCount = TestTaskListener.importBeginCount.get();
|
int importEndCount = TestTaskListener.importEndCount.get();
|
|
Entry taskEntry = TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-backend-id: " + backendID,
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-reject-file: " + rejectFile.getPath(),
|
"ds-task-import-skip-file: " + skipFile.getPath(),
|
"ds-task-import-overwrite-rejects: TRUE");
|
|
TestTaskListener.lastImportEndConfig.set(null);
|
testTask(taskEntry, TaskState.STOPPED_BY_ERROR, 60);
|
|
assertEquals(TestTaskListener.importBeginCount.get(), importBeginCount + 1);
|
assertEquals(TestTaskListener.importEndCount.get(), importEndCount + 1);
|
LDIFImportConfig importConfig = TestTaskListener.lastImportEndConfig.get();
|
assertNotNull(importConfig, "The import end was not notified");
|
assertClosed(importConfig.getRejectWriter(), "reject");
|
assertClosed(importConfig.getSkipWriter(), "skip");
|
}
|
finally
|
{
|
skipFile.delete();
|
removeMemoryBackend(backendID);
|
}
|
}
|
|
/**
|
* A failed import must notify the listeners exactly once, as its beginning was notified
|
* once: a replication domain enabled a second time reloads and rewinds its replication
|
* state for nothing.
|
*/
|
@Test
|
public void testFailedImportEndsOnlyOnce() throws Exception
|
{
|
int importBeginCount = TestTaskListener.importBeginCount.get();
|
int importEndCount = TestTaskListener.importEndCount.get();
|
|
// A directory can be read, so the task accepts it, but it cannot be read as LDIF.
|
Entry taskEntry = TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-backend-id: userRoot",
|
"ds-task-import-ldif-file: " + ldifFile.getParent());
|
|
testTask(taskEntry, TaskState.STOPPED_BY_ERROR, 60);
|
|
assertEquals(TestTaskListener.importBeginCount.get(), importBeginCount + 1);
|
assertEquals(TestTaskListener.importEndCount.get(), importEndCount + 1);
|
}
|
|
/**
|
* A failed import must close the reject and skip files it opened. A backend closes the
|
* import config together with its LDIF reader, so an import which fails before that reader
|
* exists leaves the closing to the task, whose error returns must not skip it.
|
*/
|
@Test
|
public void testFailedImportClosesItsRejectAndSkipFiles() throws Exception
|
{
|
File skipFile = File.createTempFile("import-test-skipped", ".ldif");
|
try
|
{
|
// A directory can be read, so the task accepts it, but it cannot be opened as LDIF:
|
// the import fails before the backend creates the reader which would close the config.
|
Entry taskEntry = TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-backend-id: userRoot",
|
"ds-task-import-ldif-file: " + ldifFile.getParent(),
|
"ds-task-import-reject-file: " + rejectFile.getPath(),
|
"ds-task-import-skip-file: " + skipFile.getPath(),
|
"ds-task-import-overwrite-rejects: TRUE");
|
|
TestTaskListener.lastImportEndConfig.set(null);
|
testTask(taskEntry, TaskState.STOPPED_BY_ERROR, 60);
|
|
LDIFImportConfig importConfig = TestTaskListener.lastImportEndConfig.get();
|
assertNotNull(importConfig, "The import end was not notified");
|
assertClosed(importConfig.getRejectWriter(), "reject");
|
assertClosed(importConfig.getSkipWriter(), "skip");
|
}
|
finally
|
{
|
skipFile.delete();
|
}
|
}
|
|
/**
|
* An import which cannot open its skip file must close the reject file it already opened.
|
* That failure returns before the import is announced, so the config cannot be read through
|
* the listener the other cases use, and is read from the task the scheduler kept instead.
|
*/
|
@Test
|
public void testImportWhichCannotOpenItsSkipFileClosesItsRejectFile() throws Exception
|
{
|
Entry taskEntry = TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-backend-id: userRoot",
|
"ds-task-import-ldif-file: " + ldifFile.getPath(),
|
"ds-task-import-reject-file: " + rejectFile.getPath(),
|
// The task stores the path as it is given, and a directory cannot be opened for writing.
|
"ds-task-import-skip-file: " + ldifFile.getParent(),
|
"ds-task-import-overwrite-rejects: TRUE");
|
|
testTask(taskEntry, TaskState.STOPPED_BY_ERROR, 60);
|
|
LDIFImportConfig importConfig = importConfigOf(getDoneTask(taskEntry.getName()));
|
assertNotNull(importConfig, "The task never built an import config");
|
assertClosed(importConfig.getRejectWriter(), "reject");
|
assertNull(importConfig.getSkipWriter(), "The skip writer was opened after all");
|
}
|
|
/**
|
* A template import which cannot open its reject file must stop the generator thread its config
|
* started when it was built. That failure is the first return after the config exists, and it
|
* returns before the import is announced and before the try whose finally closes the config.
|
*/
|
@Test
|
public void testTemplateImportWhichCannotOpenItsRejectFileStopsItsGenerator() throws Exception
|
{
|
File templateFile = File.createTempFile("import-test", ".template");
|
try
|
{
|
Files.write(templateFile.toPath(), Arrays.asList(template), StandardCharsets.UTF_8);
|
Entry taskEntry = TestCaseUtils.makeEntry(
|
"dn: ds-task-id=" + UUID.randomUUID() + ",cn=Scheduled Tasks,cn=Tasks",
|
"objectclass: top",
|
"objectclass: ds-task",
|
"objectclass: ds-task-import",
|
"ds-task-class-name: org.opends.server.tasks.ImportTask",
|
"ds-task-import-backend-id: userRoot",
|
"ds-task-import-template-file: " + templateFile.getPath(),
|
// The task stores the path as it is given, and a directory cannot be opened for writing.
|
"ds-task-import-reject-file: " + ldifFile.getParent(),
|
"ds-task-import-overwrite-rejects: TRUE");
|
|
testTask(taskEntry, TaskState.STOPPED_BY_ERROR, 60);
|
|
LDIFImportConfig importConfig = importConfigOf(getDoneTask(taskEntry.getName()));
|
assertNotNull(importConfig, "The task never built an import config");
|
assertNull(importConfig.getRejectWriter(), "The reject writer was opened after all");
|
Thread generator = generatorOf(importConfig);
|
generator.join(10000);
|
assertFalse(generator.isAlive(), "The generator is still running after the import ended");
|
}
|
finally
|
{
|
templateFile.delete();
|
}
|
}
|
|
/** The thread generating the entries of a template import, which neither class exposes. */
|
private static Thread generatorOf(LDIFImportConfig importConfig) throws Exception
|
{
|
Field ldifInputStream = LDIFImportConfig.class.getDeclaredField("ldifInputStream");
|
ldifInputStream.setAccessible(true);
|
Field generatorThread = MakeLDIFInputStream.class.getDeclaredField("generatorThread");
|
generatorThread.setAccessible(true);
|
return (Thread) generatorThread.get(ldifInputStream.get(importConfig));
|
}
|
|
/** The config an import task worked with, which the task keeps to itself. */
|
private static LDIFImportConfig importConfigOf(Task task) throws Exception
|
{
|
Field importConfig = ImportTask.class.getDeclaredField("importConfig");
|
importConfig.setAccessible(true);
|
return (LDIFImportConfig) importConfig.get(task);
|
}
|
|
private static void assertClosed(Writer writer, String name)
|
{
|
assertNotNull(writer, "The " + name + " writer was never opened");
|
try
|
{
|
writer.write("still open");
|
fail("The " + name + " writer is still open after the import ended");
|
}
|
catch (IOException expected)
|
{
|
// A closed BufferedWriter refuses the write: that is the closed state being checked.
|
}
|
}
|
|
private void removeMemoryBackend(String backendID) throws Exception
|
{
|
BackendConfigManager backendConfigManager = TestCaseUtils.getServerContext().getBackendConfigManager();
|
LocalBackend<?> backend = backendConfigManager.getLocalBackendById(backendID);
|
if (backend != null)
|
{
|
backend.finalizeBackend();
|
backendConfigManager.deregisterLocalBackend(backend);
|
}
|
}
|
|
/**
|
* Add a task definition and check that it completes with the expected state.
|
* @param taskEntry The task entry.
|
* @param resultCode The expected result code of the task add.
|
* @throws Exception If the test fails.
|
*/
|
@Test(dataProvider = "badimportexport")
|
public void testBadTask(Entry taskEntry, ResultCode resultCode)
|
throws Exception
|
{
|
AddOperation addOperation = getRootConnection().processAdd(taskEntry);
|
assertEquals(addOperation.getResultCode(), resultCode);
|
}
|
|
}
|