/*
* 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 legal-notices/CDDLv1_0.txt
* or http://forgerock.org/license/CDDLv1.0.html.
* 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 legal-notices/CDDLv1_0.txt.
* 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 2006-2010 Sun Microsystems, Inc.
* Portions Copyright 2011-2015 ForgeRock AS
* Portions Copyright 2013 Manuel Gaupp
*/
package org.opends.server;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.net.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.config.ConfigurationFramework;
import org.forgerock.opendj.config.dsconfig.DSConfig;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.io.ASN1;
import org.forgerock.opendj.io.ASN1Reader;
import org.forgerock.opendj.io.ASN1Writer;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.admin.client.ManagementContext;
import org.opends.server.admin.client.ldap.JNDIDirContextAdaptor;
import org.opends.server.admin.client.ldap.LDAPConnection;
import org.opends.server.admin.client.ldap.LDAPManagementContext;
import org.opends.server.admin.std.client.RootCfgClient;
import org.opends.server.api.Backend;
import org.opends.server.api.WorkQueue;
import org.opends.server.api.plugin.PluginType;
import org.opends.server.backends.MemoryBackend;
import org.opends.server.backends.pluggable.BackendImpl;
import org.opends.server.backends.pluggable.EntryContainer;
import org.opends.server.backends.pluggable.RootContainer;
import org.opends.server.core.AddOperation;
import org.opends.server.core.DeleteOperation;
import org.opends.server.core.DirectoryServer;
import org.opends.server.extensions.ConfigFileHandler;
import org.opends.server.loggers.*;
import org.opends.server.plugins.InvocationCounterPlugin;
import org.opends.server.protocols.ldap.BindRequestProtocolOp;
import org.opends.server.protocols.ldap.BindResponseProtocolOp;
import org.opends.server.protocols.ldap.LDAPMessage;
import org.opends.server.protocols.ldap.LDAPReader;
import org.opends.server.tools.LDAPModify;
import org.opends.server.types.*;
import org.opends.server.types.FilePermission;
import org.opends.server.util.BuildVersion;
import org.opends.server.util.EmbeddedUtils;
import org.opends.server.util.LDIFReader;
import org.testng.Assert;
import com.forgerock.opendj.util.OperatingSystem;
import static org.opends.server.loggers.TextAccessLogPublisher.*;
import static org.opends.server.loggers.TextErrorLogPublisher.*;
import static org.opends.server.loggers.TextHTTPAccessLogPublisher.*;
import static org.opends.server.protocols.internal.InternalClientConnection.*;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import static org.testng.Assert.*;
/**
* This class defines some utility functions which can be used by test cases.
*/
@SuppressWarnings("javadoc")
public final class TestCaseUtils {
/** The name of the system property that specifies the server build root. */
public static final String PROPERTY_BUILD_ROOT = "org.opends.server.BuildRoot";
public static final String PROPERTY_BUILD_DIR = "org.opends.server.BuildDir";
/**
* The name of the system property that specifies an existing OpenDS
* installation root (inside or outside of the source tree).
*/
public static final String PROPERTY_INSTALLED_ROOT =
"org.opends.server.InstalledRoot";
/**
* The name of the system property that specifies an LDIF file
* with changes compare to the default config.ldif.
*/
public static final String PROPERTY_CONFIG_CHANGE_FILE =
"org.opends.server.ConfigChangeFile";
/**
* The name of the system property that specifies if the test instance
* directory needs to be wiped out before starting the setup or not. This will
* let the caller the possibility to copy some files (ie extensions) inside
* the test instance directory before the server starts up.
*/
public static final String PROPERTY_CLEANUP_REQUIRED =
"org.opends.server.CleanupDirectories";
/**
* The name of the system property that specifies the ldap port.
* Set this property when running the server if you want to use a given
* port number, otherwise a port is chosen randomly at test startup time.
*/
public static final String PROPERTY_LDAP_PORT =
"org.opends.server.LdapPort";
/**
* The name of the system property that specifies the admin port. Set this
* property when running the server if you want to use a given port number,
* otherwise a port is chosen randomly at test startup time.
*/
public static final String PROPERTY_ADMIN_PORT =
"org.opends.server.AdminPort";
/**
* If this System property is set to true, then the classes/ directory
* will be copied into the server package setup for the tests. This allows
* the server tools (e.g. ldapsearch) to be used on a live server, but it
* takes a while to copy all of the files, so we don't do it by default.
*/
public static final String PROPERTY_COPY_CLASSES_TO_TEST_PKG =
"org.opends.test.copyClassesToTestPackage";
/**
* The string representation of the DN that will be used as the base entry for
* the test backend. This must not be changed, as there are a number of test
* cases that depend on this specific value of "o=test".
*/
public static final String TEST_ROOT_DN_STRING = "o=test";
/** The backend if for the test backend. */
public static final String TEST_BACKEND_ID = "test";
/**
* The string representation of the OpenDMK jar file location
* that will be used as base to determine if snmp is included or not.
*/
public static final String PROPERTY_OPENDMK_LOCATION =
"org.opends.server.snmp.opendmk";
/** The test text writer for the Debug Logger. */
public static TestTextWriter DEBUG_TEXT_WRITER = new TestTextWriter();
/** The test text writer for the Error Logger. */
public static TestTextWriter ERROR_TEXT_WRITER = new TestTextWriter();
/** The test text writer for the Access Logger. */
public static TestTextWriter ACCESS_TEXT_WRITER = new TestTextWriter();
/** The test text writer for the HTTP Access Logger. */
public static TestTextWriter HTTP_ACCESS_TEXT_WRITER = new TestTextWriter();
/**
* Indicates whether the server has already been started. The value of this
* constant must not be altered by anything outside the
* <CODE>startServer</CODE> method.
*/
public static boolean SERVER_STARTED;
/**
* This is used to store the schema as it was before starting the fake server
* (for example, it could have been the real schema) so test tearDown can set it back.
*/
private static Schema schemaBeforeStartingFakeServer;
/** The LDAP port the server is bound to on start. */
private static int serverLdapPort;
/** The Administration port the server is bound to on start. */
private static int serverAdminPort;
/** The JMX port the server is bound to on start. */
private static int serverJmxPort;
/** The LDAPS port the server is bound to on start. */
private static int serverLdapsPort;
/** Incremented by one each time the server has restarted. */
private static int serverRestarts;
/** The config directory in the test environment. */
private static File testConfigDir;
/**
* Setup in-memory versions of everything needed to run unit tests with the
* {@link DirectoryServer} class.
* <p>
* This method is trying hard to provide sensible defaults and core data you
* would expect from a normal install, including AttributeTypes, etc.
*
* @see #shutdownFakeServer() Matching method that must be called in the test
* tear down.
*/
public static void startFakeServer() throws Exception
{
schemaBeforeStartingFakeServer = DirectoryServer.getSchema();
DirectoryServer.setSchema(initializeInMemory(new Schema()));
}
private static Schema initializeInMemory(final Schema schema) throws Exception
{
for (AttributeType attributeType : AttributeTypeConstants.ALL)
{
schema.registerAttributeType(attributeType, true);
}
return schema;
}
/**
* Starts the Directory Server so that it will be available for use while
* running the unit tests. This will only actually start the server once, so
* subsequent attempts to start it will be ignored because it will already be
* available.
*
* @throws Exception If an unexpected problem occurs.
*/
public static void startServer() throws Exception
{
System.setProperty(PROPERTY_RUNNING_UNIT_TESTS, "true");
try {
if (SERVER_STARTED)
{
return;
}
InvocationCounterPlugin.resetStartupCalled();
// Retrieves the location of a typical installation directory to use as a
// source to build our test instance.
String installedRoot = System.getProperty(PROPERTY_INSTALLED_ROOT);
// Get the build root and use it to create a test package directory.
String buildRoot = System.getProperty(PROPERTY_BUILD_ROOT);
String buildDirStr = System.getProperty(PROPERTY_BUILD_DIR,
buildRoot + File.separator + "target");
File buildDir = new File(buildDirStr);
File unitRoot = new File(buildDir, "unit-tests");
File testInstallRoot;
File testInstanceRoot;
if (installedRoot == null) {
testInstallRoot = new File(unitRoot, "package-install");
testInstanceRoot = new File(unitRoot, "package-instance");
} else {
testInstallRoot = new File(unitRoot, "package");
testInstanceRoot = testInstallRoot;
}
System.out.println("unitRoot=" + unitRoot);
System.out.println("testInstallRoot=" + testInstallRoot);
System.out.println("testInstanceRoot=" + testInstanceRoot);
File testSrcRoot = new File(buildRoot + File.separator + "tests" +
File.separator + "unit-tests-testng");
System.out.println("testSrcRoot=" + testSrcRoot);
String cleanupRequiredString = System.getProperty(PROPERTY_CLEANUP_REQUIRED, "true");
boolean cleanupRequired = !"false".equalsIgnoreCase(cleanupRequiredString);
if (cleanupRequired) {
deleteDirectory(testInstallRoot);
deleteDirectory(testInstanceRoot);
testInstallRoot.mkdirs();
testInstanceRoot.mkdirs();
}
File testInstanceSchema =
new File (testInstanceRoot, "config" + File.separator + "schema");
testInstanceSchema.mkdirs();
//db_verify is second jeb backend used by the jeb verify test cases
//db_rebuild is the third jeb backend used by the jeb rebuild test cases
//db_unindexed is the forth backend used by the unindexed search privilege
//test cases
String[] installSubDirectories = { "bin", "lib", "bat", "config"};
String[] instanceSubDirectories = { "bak", "changelogDb", "classes",
"config", "db", "import-tmp", "db_verify",
"ldif", "locks", "logs", "db_rebuild",
"db_unindexed", "db_index_test",
"db_import_test"};
for (String s : installSubDirectories)
{
new File(testInstallRoot, s).mkdir();
}
for (String s : instanceSubDirectories)
{
new File(testInstanceRoot, s).mkdir();
}
// Copy the configuration, schema, and MakeLDIF resources into the
// appropriate place under the test package.
File serverClassesDir = new File(buildDir, "classes");
File unitClassesDir = new File(unitRoot, "classes");
File libDir = new File(buildDirStr + "/package/opendj/lib");
File upgradeDir = new File(buildDirStr + "/package/opendj/template/config/upgrade");
System.out.println("libDir=" + libDir);
File resourceDir = new File(buildRoot, "resource");
File testResourceDir = new File(testSrcRoot, "resource");
// Set the class variable
testConfigDir = new File(testInstanceRoot, "config");
File testSchemaDir = new File(testInstanceRoot, "config");
File testClassesDir = new File(testInstanceRoot, "classes");
File testLibDir = new File(testInstallRoot, "lib");
File testBinDir = new File(testInstallRoot, "bin");
// Snmp resource
String opendmkJarFileLocation =
System.getProperty(PROPERTY_OPENDMK_LOCATION);
File opendmkJar = new File(opendmkJarFileLocation, "jdmkrt.jar");
File snmpResourceDir = new File(buildRoot + File.separator + "src" +
File.separator + "snmp" + File.separator +
"resource");
File snmpConfigDir = new File(snmpResourceDir, "config");
File testSnmpResourceDir = new File (testConfigDir + File.separator + "snmp");
if (Boolean.getBoolean(PROPERTY_COPY_CLASSES_TO_TEST_PKG))
{
copyDirectory(serverClassesDir, testClassesDir);
copyDirectory(unitClassesDir, testClassesDir);
}
if (installedRoot != null)
{
copyDirectory(new File(installedRoot), testInstallRoot);
// Get the instance location
}
else
{
copyDirectory(libDir, testLibDir);
copyDirectory(new File(resourceDir, "bin"), testBinDir);
copyDirectory(new File(resourceDir, "config"), testConfigDir );
// copy upgrade directory
copyDirectory(upgradeDir, new File(testConfigDir, "upgrade"));
copyDirectory(new File(resourceDir, "schema"),
new File(testSchemaDir, "schema"));
copyDirectory(new File(resourceDir, "MakeLDIF"),
new File(testConfigDir, "MakeLDIF"));
copyDirectory(new File(snmpResourceDir, "security"),
new File(testSnmpResourceDir, "security"));
copyFileFromTo("server.keystore", testResourceDir, testConfigDir);
copyFileFromTo("server.truststore", testResourceDir, testConfigDir);
copyFileFromTo("client.keystore", testResourceDir, testConfigDir);
copyFileFromTo("client-emailAddress.keystore", testResourceDir, testConfigDir);
copyFileFromTo("client.truststore", testResourceDir, testConfigDir);
copyFileFromTo("server-cert.p12", testResourceDir, testConfigDir);
copyFileFromTo("client-cert.p12", testResourceDir, testConfigDir);
// Update the install.loc file
File installLoc = new File(testInstallRoot + File.separator + "instance.loc");
installLoc.deleteOnExit();
try (FileWriter w = new FileWriter(installLoc))
{
w.write(testInstanceRoot.getAbsolutePath());
}
if (opendmkJar.exists())
{
appendFile(new File(snmpConfigDir, "config.snmp.ldif"),
new File(testConfigDir, "config.ldif"));
}
for (File f : testBinDir.listFiles())
{
try
{
FilePermission.setPermissions(f, FilePermission.decodeUNIXMode("755"));
} catch (Exception e) {}
}
// Make the shell scripts in the bin directory executable, if possible.
if (OperatingSystem.isUnixBased())
{
try
{
FilePermission perm = FilePermission.decodeUNIXMode("755");
for (File f : testBinDir.listFiles())
{
if (f.getName().endsWith(".sh"))
{
FilePermission.setPermissions(f, perm);
}
}
} catch (Exception e) {}
}
}
// Find some free ports for the listeners and write them to the
// config-chamges.ldif file.
serverLdapPort = getFreePort(PROPERTY_LDAP_PORT);
serverAdminPort = getFreePort(PROPERTY_ADMIN_PORT);
serverJmxPort = findFreePort();
serverLdapsPort = findFreePort();
String defaultConfigChangeFile = testResourceDir + File.separator
+ "config-changes.ldif";
String configChangeFile = System.getProperty(
PROPERTY_CONFIG_CHANGE_FILE, defaultConfigChangeFile);
try (BufferedReader reader = new BufferedReader(new FileReader(new File(configChangeFile)));
FileOutputStream outFile = new FileOutputStream(new File(testConfigDir, "config-changes.ldif"));
PrintStream writer = new PrintStream(outFile))
{
String line;
while ((line = reader.readLine()) != null)
{
line = line
.replaceAll("#ldapport#", String.valueOf(serverLdapPort))
.replaceAll("#adminport#", String.valueOf(serverAdminPort))
.replaceAll("#jmxport#", String.valueOf(serverJmxPort))
.replaceAll("#ldapsport#", String.valueOf(serverLdapsPort));
writer.println(line);
}
}
// Create a configuration for the server.
DirectoryEnvironmentConfig config = new DirectoryEnvironmentConfig();
config.setServerRoot(testInstallRoot);
config.setInstanceRoot(testInstanceRoot);
config.setForceDaemonThreads(true);
config.setConfigClass(ConfigFileHandler.class);
config.setConfigFile(new File(testConfigDir, "config.ldif"));
// Initialize the configuration framework for DSConfig.
ConfigurationFramework.getInstance()
.initialize(testInstallRoot.getAbsolutePath(),
testInstanceRoot.getAbsolutePath());
AccessLogger.getInstance().addLogPublisher(
(AccessLogPublisher) getStartupTextAccessPublisher(ACCESS_TEXT_WRITER, false));
HTTPAccessLogger.getInstance().addLogPublisher(
(HTTPAccessLogPublisher) getStartupTextHTTPAccessPublisher(HTTP_ACCESS_TEXT_WRITER));
// Enable more verbose error logger.
ErrorLogger.getInstance().addLogPublisher(
(ErrorLogPublisher) getToolStartupTextErrorPublisher(ERROR_TEXT_WRITER));
DebugLogger.getInstance().addPublisherIfRequired(DEBUG_TEXT_WRITER);
// Writing the buildinfo with the current version.
try (final FileWriter buildInfoWriter = new FileWriter(new File(testConfigDir, "buildinfo")))
{
buildInfoWriter.write(BuildVersion.binaryVersion().toString());
}
EmbeddedUtils.startServer(config);
assertTrue(InvocationCounterPlugin.startupCalled());
// Save config.ldif for when we restart the server
backupServerConfigLdif();
SERVER_STARTED = true;
initializeTestBackend(true);
} catch (Exception e) {
e.printStackTrace(originalSystemErr);
throw e;
}
}
private static int getFreePort(String portPropertyName) throws IOException
{
String port = System.getProperty(portPropertyName);
if (port == null)
{
return findFreePort();
}
int portNb = Integer.parseInt(port);
// Check this port is free
bindPort(portNb).close();
return portNb;
}
/**
* Similar to startServer, but it will restart the server each time it is
* called. Since this is somewhat expensive, it should be called under
* two circumstances. Either in an @AfterClass method for a test that
* makes lots of configuration changes to the server, or in a @BeforeClass
* method for a test that is very sensitive to running in a clean server.
*
* @throws IOException If a problem occurs while interacting with the
* filesystem to prepare the test package root.
*
* @throws InitializationException If a problem occurs while starting the
* server.
*
* @throws ConfigException If there is a problem with the server
* configuration.
*/
public static synchronized void restartServer()
throws IOException, InitializationException, ConfigException,
DirectoryException, Exception
{
if (!SERVER_STARTED) {
startServer();
return;
}
try {
long startMs = System.currentTimeMillis();
clearLoggersContents();
EmbeddedUtils.stopServer(null, null);
restoreServerConfigLdif();
EmbeddedUtils.startServer(DirectoryServer.getEnvironmentConfig());
clearJEBackends();
initializeTestBackend(true);
// This generates too much noise, so it's disabled by default.
// outputLogContentsIfError("Potential problem during in-core restart. You be the judge.");
// Keep track of these so we can report how long they took in the test summary
long durationMs = System.currentTimeMillis() - startMs;
restartTimesMs.add(durationMs);
serverRestarts++;
} catch (Exception e) {
e.printStackTrace(originalSystemErr);
throw e;
}
}
private static List<Long> restartTimesMs = new ArrayList<>();
public static List<Long> getRestartTimesMs() {
return Collections.unmodifiableList(restartTimesMs);
}
private static void clearJEBackends() throws Exception
{
for (Backend<?> backend : DirectoryServer.getBackends().values()) {
if (backend instanceof BackendImpl) {
clearBackend(backend.getBackendID());
}
}
}
public static void clearDataBackends() throws Exception
{
clearJEBackends();
clearMemoryBackend(TEST_BACKEND_ID);
}
private static File getTestConfigDir()
{
if (testConfigDir == null) {
throw new RuntimeException("The testConfigDir variable is not set yet!");
}
return testConfigDir;
}
public static File getBuildRoot()
{
String buildRoot = System.getProperty(PROPERTY_BUILD_ROOT);
return new File(buildRoot);
}
private static void backupServerConfigLdif() throws IOException
{
File testConfigDir = getTestConfigDir();
copyFile(new File(testConfigDir, "config.ldif"),
new File(testConfigDir, "config.ldif.for-restart"));
}
private static void restoreServerConfigLdif() throws IOException {
File testConfigDir = getTestConfigDir();
File from = new File(testConfigDir, "config.ldif.for-restart");
File to = new File(testConfigDir, "config.ldif");
// Sometimes this fails because config.ldif is in use, so we wait
// and try it again.
try {
copyFile(from, to);
} catch (IOException e) {
sleep(1000);
copyFile(from, to);
}
}
/**
* Bring the server to a quiescent state. This includes waiting for all
* operations to complete. This can be used in a @BeforeMethod setup method
* to make sure that the server has finished processing all operations
* from previous tests.
*/
public static void quiesceServer()
{
waitForOpsToComplete();
}
/**
* This can be made public if quiesceServer becomes too heavy-weight in
* some circumstance.
*/
private static void waitForOpsToComplete()
{
try {
WorkQueue<?> workQueue = DirectoryServer.getWorkQueue();
final long NO_TIMEOUT = -1;
workQueue.waitUntilIdle(NO_TIMEOUT);
} catch (Exception e) {
// Ignore it, maybe the server hasn't been started.
}
}
/**
* Binds to the given socket port on the local host.
* @return the bounded Server socket.
*
* @throws IOException in case of underlying exception.
* @throws SocketException in case of underlying exception.
*/
private static ServerSocket bindPort(int port)
throws IOException
{
ServerSocket serverLdapSocket = new ServerSocket();
serverLdapSocket.setReuseAddress(true);
serverLdapSocket.bind(new InetSocketAddress("127.0.0.1", port));
return serverLdapSocket;
}
/**
* Find and binds to a free server socket port on the local host.
* @return the bounded Server socket.
*
* @throws IOException in case of underlying exception.
* @throws SocketException in case of underlying exception.
*/
public static ServerSocket bindFreePort() throws IOException
{
return bindPort(0);
}
/**
* Find a free port on the local host.
*
* @throws IOException
* in case of underlying exception.
* @return the free port number found
*/
public static int findFreePort() throws IOException
{
return findFreePorts(1)[0];
}
/**
* Find nb free ports on the local host.
*
* @param nb
* the number of free ports to find
* @throws IOException
* in case of underlying exception.
* @return an array with the free port numbers found
*/
public static int[] findFreePorts(int nb) throws IOException
{
final ServerSocket[] sockets = new ServerSocket[nb];
try
{
final int[] ports = new int[nb];
for (int i = 0; i < nb; i++)
{
final ServerSocket socket = bindFreePort();
sockets[i] = socket;
ports[i] = socket.getLocalPort();
}
return ports;
}
finally
{
close(sockets);
}
}
/**
* Finds a free server socket port on the local host.
*
* @return The free port.
*/
public static SocketAddress findFreeSocketAddress()
{
try (ServerSocket serverLdapSocket = bindFreePort())
{
return serverLdapSocket.getLocalSocketAddress();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
/**
* Undo all the setup done by #startFakeServer().
*
* @see #startFakeServer() Matching method that starts the fake server
*/
public static void shutdownFakeServer()
{
DirectoryServer.setSchema(schemaBeforeStartingFakeServer);
}
/**
* Shut down the server. This should only be called at the end of the test
* suite and not by any unit tests.
*
* @param reason
* The reason for the shutdown.
*/
static void shutdownServer(LocalizableMessage reason)
{
if (SERVER_STARTED)
{
InvocationCounterPlugin.resetShutdownCalled();
DirectoryServer.shutDown("org.opends.server.TestCaseUtils", reason);
assertTrue(InvocationCounterPlugin.shutdownCalled());
SERVER_STARTED = false;
}
}
/**
* Initializes a memory-based backend that may be used to perform operations
* while testing the server. This will ensure that the memory backend is
* created in the server if it does not yet exist, and that it is empty. Note
* that the base DN for the test backend will always be "o=test", and it must
* not be changed. It is acceptable for test cases using this backend to
* hard-code their sample data to use this base DN, although they may still
* reference the <CODE>TEST_ROOT_DN_STRING</CODE> constant if they wish.
*
* @param createBaseEntry Indicate whether to automatically create the base
* entry and add it to the backend.
*
* @throws Exception If an unexpected problem occurs.
*/
public static void initializeTestBackend(boolean createBaseEntry) throws Exception
{
initializeMemoryBackend(TEST_BACKEND_ID, TEST_ROOT_DN_STRING, createBaseEntry);
}
/**
* Initializes a memory-based backend that may be used to perform operations
* while testing the server. This will ensure that the memory backend is
* created in the server if it does not yet exist, and that it is empty.
*
* @param backendID the ID of the backend to create
* @param namingContext the naming context to create in the backend
* @param createBaseEntry Indicate whether to automatically create the base
* entry and add it to the backend.
*
* @throws Exception If an unexpected problem occurs.
*/
public static void initializeMemoryBackend(
String backendID,
String namingContext,
boolean createBaseEntry
) throws Exception
{
startServer();
DN baseDN = DN.valueOf(namingContext);
// Retrieve backend. Warning: it is important to perform this each time,
// because a test may have disabled then enabled the backend (i.e a test
// performing an import task). As it is a memory backend, when the backend
// is re-enabled, a new backend object is in fact created and old reference
// to memory backend must be invalidated. So to prevent this problem, we
// retrieve the memory backend reference each time before cleaning it.
MemoryBackend memoryBackend =
(MemoryBackend)DirectoryServer.getBackend(backendID);
if (memoryBackend == null)
{
memoryBackend = new MemoryBackend();
memoryBackend.setBackendID(backendID);
memoryBackend.setBaseDNs(new DN[] {baseDN});
memoryBackend.openBackend();
DirectoryServer.registerBackend(memoryBackend);
}
memoryBackend.clearMemoryBackend();
if (createBaseEntry)
{
Entry e = createEntry(baseDN);
memoryBackend.addEntry(e, null);
}
}
/**
* Clears a memory-based backend.
*/
public static void clearMemoryBackend(String backendID) throws Exception
{
MemoryBackend memoryBackend = (MemoryBackend) DirectoryServer.getBackend(backendID);
// FIXME JNR I suspect we could call finalizeBackend() here (but also in other
// places in this class), because finalizeBackend() calls clearMemoryBackend().
if (memoryBackend != null)
{
memoryBackend.clearMemoryBackend();
}
}
/**
* Clears all the entries from the backend determined by the backend id passed into the method.
*
* @throws Exception If an unexpected problem occurs.
*/
public static void clearBackend(String backendId) throws Exception
{
clearBackend(backendId, null);
}
/**
* Clears all the entries from the backend determined by the backend id passed into the method.
*
* @param backendId The backend id to clear
* @param baseDN If not null, the suffix of the backend to create
* @throws Exception If an unexpected problem occurs.
*/
public static void clearBackend(String backendId, String baseDN) throws Exception
{
Backend<?> b = DirectoryServer.getBackend(backendId);
if (clearBackend(b) && baseDN != null)
{
Entry e = createEntry(DN.valueOf(baseDN));
DirectoryServer.getBackend(backendId).addEntry(e, null);
}
}
private static boolean clearBackend(Backend<?> b)
{
if (b instanceof BackendImpl)
{
final BackendImpl backend = (BackendImpl) b;
final RootContainer rootContainer = backend.getRootContainer();
if (rootContainer != null)
{
for (EntryContainer ec : rootContainer.getEntryContainers())
{
ec.clear();
// assertEquals(ec.getHighestEntryID().longValue(), 0L);
}
rootContainer.resetNextEntryID();
return true;
}
}
return false;
}
/**
* Create a temporary directory with the specified prefix.
*
* @param prefix
* The directory prefix.
* @return The temporary directory.
* @throws IOException
* If the temporary directory could not be created.
*/
public static File createTemporaryDirectory(String prefix)
throws IOException {
File tmpDir = File.createTempFile(prefix, null);
if (!tmpDir.delete()) {
throw new IOException("Unable to delete temporary file: " + tmpDir);
}
if (!tmpDir.mkdir()) {
throw new IOException("Unable to create temporary directory: " + tmpDir);
}
return tmpDir;
}
/**
* Copy a directory and its contents.
*
* @param src
* The name of the directory to copy.
* @param dst
* The name of the destination directory.
* @throws IOException
* If the directory could not be copied.
*/
public static void copyDirectory(File src, File dst) throws IOException {
if (src.isDirectory()) {
// Create the destination directory if it does not exist.
if (!dst.exists()) {
dst.mkdirs();
}
// Recursively copy sub-directories and files.
for (String child : src.list()) {
copyDirectory(new File(src, child), new File(dst, child));
}
} else {
copyFile(src, dst);
}
}
/**
* Delete a directory and its contents.
*
* @param dir
* The name of the directory to delete.
* @throws IOException
* If the directory could not be deleted.
*/
public static void deleteDirectory(File dir) throws IOException {
if (dir == null || !dir.exists())
{
return;
}
if (dir.isDirectory()) {
// Recursively delete sub-directories and files.
for (String child : dir.list()) {
deleteDirectory(new File(dir, child));
}
}
dir.delete();
}
private static void copyFileFromTo(String filename, File fromDir, File toDir) throws IOException
{
copyFile(new File(fromDir, filename), new File(toDir, filename));
}
/**
* Copy a file.
*
* @param src
* The name of the source file.
* @param dst
* The name of the destination file.
* @throws IOException
* If the file could not be copied.
*/
public static void copyFile(File src, File dst) throws IOException {
copyOrAppend(src, dst, false);
}
public static void appendFile(File src, File dst) throws IOException
{
copyOrAppend(src, dst, true);
}
private static void copyOrAppend(File src, File dst, boolean append)
throws IOException
{
try (InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst, append))
{
// Transfer bytes from in to out
byte[] buf = new byte[8192];
int len;
while ((len = in.read(buf)) > 0)
{
out.write(buf, 0, len);
}
}
}
/**
* Get the LDAP port the test environment Directory Server instance is
* running on.
*
* @return The port number.
*/
public static int getServerLdapPort()
{
return serverLdapPort;
}
/**
* Get the Admin port the test environment Directory Server instance is
* running on.
*
* @return The port number.
*/
public static int getServerAdminPort()
{
return serverAdminPort;
}
/**
* Get the JMX port the test environment Directory Server instance is
* running on.
*
* @return The port number.
*/
public static int getServerJmxPort()
{
return serverJmxPort;
}
/**
* Get the LDAPS port the test environment Directory Server instance is
* running on.
*
* @return The port number.
*/
public static int getServerLdapsPort()
{
return serverLdapsPort;
}
/**
* Get the number of times the server has done a restart during the unit tests.
*
* @return the number of server restarts.
*/
public static int getNumServerRestarts()
{
return serverRestarts;
}
/**
* Method for getting a file from the test resources directory.
*
* @return The directory as a File
*/
public static File getTestResource(String filename)
{
String buildRoot = System.getProperty(PROPERTY_BUILD_ROOT);
File testResourceDir = new File(buildRoot + File.separator + "tests" +
File.separator + "unit-tests-testng" +
File.separator + "resource");
return new File(testResourceDir, filename);
}
public static File getUnitTestRootPath()
{
final String buildRoot = System.getProperty(PROPERTY_BUILD_ROOT);
final String path = System.getProperty(PROPERTY_BUILD_DIR, buildRoot + File.separator + "target");
return new File(path, "unit-tests");
}
/** Prevent instantiation. */
private TestCaseUtils() {
// No implementation.
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// Various methods for converting LDIF Strings to Entries
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
/**
* Returns a modifiable List of entries parsed from the provided LDIF.
* It's best to call this after the server has been initialized so
* that schema checking happens.
* <p>
* Also take a look at the makeLdif method below since this makes
* expressing LDIF a little bit cleaner.
*
* @param ldif of the entries to parse.
* @return a List of EntryS parsed from the ldif string.
* @see #makeLdif
*/
public static List<Entry> entriesFromLdifString(String ldif) throws Exception {
LDIFImportConfig ldifImportConfig = new LDIFImportConfig(new StringReader(ldif));
ldifImportConfig.setValidateSchema(false);
try (LDIFReader reader = new LDIFReader(ldifImportConfig))
{
List<Entry> entries = new ArrayList<>();
Entry entry;
while ((entry = reader.readEntry()) != null)
{
entries.add(entry);
}
return entries;
}
}
/**
* This is used as a convenience when and LDIF string only includes a single
* entry. It's best to call this after the server has been initialized so
* that schema checking happens.
* <p>
* Also take a look at the makeLdif method below since this makes
* expressing LDIF a little bit cleaner.
*
* @return the first Entry parsed from the ldif String
* @see #makeLdif
*/
public static Entry entryFromLdifString(String ldif) throws Exception {
return entriesFromLdifString(ldif).get(0);
}
/**
* This method provides the minor convenience of not having to specify the
* newline character at the end of every line of LDIF in test code.
* This is an admittedly small advantage, but it does make things a little
* easier and less error prone. For example, this
*
<pre>
private static final String JOHN_SMITH_LDIF = TestCaseUtils.makeLdif(
"dn: cn=John Smith,dc=example,dc=com",
"objectclass: inetorgperson",
"cn: John Smith",
"sn: Smith",
"givenname: John");
</pre>
is a <bold>little</bold> easier to work with than
<pre>
private static final String JOHN_SMITH_LDIF =
"dn: cn=John Smith,dc=example,dc=com\n" +
"objectclass: inetorgperson\n" +
"cn: John Smith\n" +
"sn: Smith\n" +
"givenname: John\n";
</pre>
*
* @return the concatenation of each line followed by a newline character
*/
public static String makeLdif(String... lines) {
StringBuilder buffer = new StringBuilder();
for (String line : lines) {
buffer.append(line).append(EOL);
}
// Append an extra line so we can append LDIF Strings.
buffer.append(EOL);
return buffer.toString();
}
/**
* This is a convenience method that constructs an Entry from the specified
* lines of LDIF. Here's a sample usage
*
<pre>
Entry john = TestCaseUtils.makeEntry(
"dn: cn=John Smith,dc=example,dc=com",
"objectclass: inetorgperson",
"cn: John Smith",
"sn: Smith",
"givenname: John");
</pre>
* @see #makeLdif
*/
public static Entry makeEntry(String... lines) throws Exception {
return entryFromLdifString(makeLdif(lines));
}
/**
* This is a convenience method that constructs an List of EntryS from the
* specified lines of LDIF. Here's a sample usage
*
<pre>
List<Entry> smiths = TestCaseUtils.makeEntries(
"dn: cn=John Smith,dc=example,dc=com",
"objectclass: inetorgperson",
"cn: John Smith",
"sn: Smith",
"givenname: John",
"",
"dn: cn=Jane Smith,dc=example,dc=com",
"objectclass: inetorgperson",
"cn: Jane Smith",
"sn: Smith",
"givenname: Jane");
</pre>
* @see #makeLdif
*/
public static List<Entry> makeEntries(String... lines) throws Exception {
return entriesFromLdifString(makeLdif(lines));
}
/**
* Adds the provided entry to the Directory Server using an internal
* operation.
*
* @param entry The entry to be added.
*
* @throws Exception If an unexpected problem occurs.
*/
public static void addEntry(Entry entry) throws Exception
{
AddOperation addOperation = getRootConnection().processAdd(entry);
assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS);
}
/**
* Deletes the provided entry from the Directory Server using an
* internal operation.
*
* @param entry The entry to be deleted.
*
* @throws Exception If an unexpected problem occurs.
*/
public static void deleteEntry(Entry entry) throws Exception
{
deleteEntry(entry.getName());
}
/**
* Deletes the provided entry from the Directory Server using an
* internal operation.
*
* @param dn The dn of entry to be deleted
*
* @throws Exception If an unexpected problem occurs.
*/
public static void deleteEntry(DN dn) throws Exception
{
DeleteOperation deleteOperation = getRootConnection().processDelete(dn);
assertEquals(deleteOperation.getResultCode(), ResultCode.SUCCESS);
}
public static boolean canBind(String dn, String pw) throws Exception
{
// Check that the user can bind.
try (Socket s = new Socket("127.0.0.1", TestCaseUtils.getServerLdapPort());)
{
TestCaseUtils.configureSocket(s);
ASN1Reader r = ASN1.getReader(s.getInputStream());
ASN1Writer w = ASN1.getWriter(s.getOutputStream());
BindRequestProtocolOp bindRequest =
new BindRequestProtocolOp(
ByteString.valueOfUtf8(dn),
3,
ByteString.valueOfUtf8(pw));
LDAPMessage message = new LDAPMessage(1, bindRequest);
message.write(w);
message = LDAPReader.readMessage(r);
BindResponseProtocolOp bindResponse = message.getBindResponseProtocolOp();
return bindResponse.getResultCode() == 0;
} catch (Exception t) {
t.printStackTrace();
return false;
}
}
/**
* Configures a socket for use in unit tests. This should only be used if the
* socket is not expected to timeout.
*
* @param s
* The socket.
* @throws Exception
* If an unexpected exception occurred while configuring the socket.
*/
public static void configureSocket(Socket s) throws Exception
{
s.setSoTimeout(60 * 1000);
}
/**
* Adds the provided entry to the Directory Server using an internal
* operation.
*
* @param lines The lines that make up the entry to be added.
* @return the added entry
* @throws Exception If an unexpected problem occurs.
*/
public static Entry addEntry(String... lines) throws Exception
{
final Entry entry = makeEntry(lines);
AddOperation addOperation = getRootConnection().processAdd(entry);
assertEquals(addOperation.getResultCode(), ResultCode.SUCCESS,
addOperation.getErrorMessage().toString());
final Entry e = DirectoryServer.getEntry(entry.getName());
assertNotNull(e);
return e;
}
/**
* Adds the provided entry to the Directory Server using an internal
* operation.
*
* @param lines The lines that make up the entry to be added.
*
* @return result code for this operation.
*
* @throws Exception If an unexpected problem occurs.
*/
public static ResultCode addEntryOperation(String... lines) throws Exception
{
Entry entry = makeEntry(lines);
AddOperation addOperation = getRootConnection().processAdd(entry);
return addOperation.getResultCode();
}
/**
* Adds the provided set of entries to the Directory Server using internal
* operations.
*
* @param entries The entries to be added.
*
* @throws Exception If an unexpected problem occurs.
*/
public static void addEntries(List<Entry> entries) throws Exception
{
for (Entry entry : entries)
{
addEntry(entry);
}
}
/**
* Adds the provided set of entries to the Directory Server using internal
* operations.
*
* @param lines The lines defining the entries to add. If there are
* multiple entries, then they should be separated by blank
* lines.
*
* @throws Exception If an unexpected problem occurs.
*/
public static void addEntries(String... lines) throws Exception
{
for (Entry entry : makeEntries(lines))
{
addEntry(entry);
}
}
/**
* Applies a set of modifications to the server as described in the provided
* set of lines (using LDIF change form). The changes will be applied over
* LDAP using the ldapmodify tool using the "cn=Directory Manager" account.
*
* @param lines The set of lines including the changes to make to the
* server.
*
* @return The result code from applying the set of modifications. if it is
* nonzero, then there was a failure of some kind.
*
* @throws Exception If an unexpected problem occurs.
*/
public static int applyModifications(boolean useAdminPort, String... lines)
throws Exception
{
if (! SERVER_STARTED)
{
startServer();
}
String path = createTempFile(lines);
String[] args =
{
"--noPropertiesFile",
"-h", "127.0.0.1",
"-p", String.valueOf(serverLdapPort),
"-D", "cn=Directory Manager",
"-w", "password",
"-a",
"-f", path
};
String[] adminArgs =
{
"--noPropertiesFile",
"-h", "127.0.0.1",
"-p", String.valueOf(serverAdminPort),
"-Z", "-X",
"-D", "cn=Directory Manager",
"-w", "password",
"-a",
"-f", path
};
if (useAdminPort) {
return LDAPModify.mainModify(adminArgs, false, null, null);
}
return LDAPModify.mainModify(args, false, null, null);
}
/**
* Creates a temporary text file with the specified contents. It will be
* marked for automatic deletion when the JVM exits.
*
* @return The absolute path to the file that was created.
*
* @throws Exception If an unexpected problem occurs.
*/
public static String createTempFile(String... lines) throws Exception
{
File f = File.createTempFile("LDAPModifyTestCase", ".txt");
f.deleteOnExit();
final String EOL = System.getProperty("line.separator");
try (FileWriter w = new FileWriter(f))
{
for (String s : lines)
{
w.write(s + EOL);
}
}
return f.getAbsolutePath();
}
/** Convenience method so we don't have to catch InterruptedException everywhere. */
public static void sleep(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
// Ignore it.
}
}
/**
* Return a Map constructed via alternating key and value pairs.
*/
public static Map<String, String> makeMap(String... keyValuePairs)
{
Map<String, String> map = new LinkedHashMap<>();
for (int i = 0; i < keyValuePairs.length; i += 2) {
map.put(keyValuePairs[i], keyValuePairs[i+1]);
}
return map;
}
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
/** The set of loggers for which the console logger has been disabled. */
private static final Map<Logger, Handler> disabledLogHandlers = new HashMap<>();
/** The original System.err print stream. Use this if you absolutely
* must write something to System.err. */
public static final PrintStream originalSystemErr = System.err;
/** The original System.out print stream. Use this if you absolutely
* must write something to System.out. */
public static final PrintStream originalSystemOut = System.out;
/** System.err is redirected to here so that we can only print it out
* if a test fails. */
private static final ByteArrayOutputStream redirectedSystemErr = new ByteArrayOutputStream();
/** System.out is redirected to here so that we can only print it out
* if a test fails. */
private static final ByteArrayOutputStream redirectedSystemOut = new ByteArrayOutputStream();
public static synchronized void suppressOutput() {
String suppressStr = System.getProperty("org.opends.test.suppressOutput");
if ("true".equalsIgnoreCase(suppressStr))
{
System.setOut(new PrintStream(redirectedSystemOut));
System.setErr(new PrintStream(redirectedSystemErr));
LogManager logManager = LogManager.getLogManager();
Enumeration<String> loggerNames = logManager.getLoggerNames();
while (loggerNames.hasMoreElements())
{
String loggerName = loggerNames.nextElement();
Logger logger = logManager.getLogger(loggerName);
if(logger == null)
{
break;
}
for (Handler h : logger.getHandlers())
{
if (h instanceof ConsoleHandler)
{
disabledLogHandlers.put(logger, h);
logger.removeHandler(h);
break;
}
}
}
}
}
/**
* @return everything written to System.out since the last time
* clearSystemOutContents was called.
*/
public static synchronized String getSystemOutContents() {
return redirectedSystemOut.toString();
}
/**
* @return everything written to System.err since the last time
* clearSystemErrContents was called.
*/
public static synchronized String getSystemErrContents() {
return redirectedSystemErr.toString();
}
/**
* Clear everything written to System.out since the last time
* clearSystemOutContents was called.
*/
public static synchronized void clearSystemOutContents() {
redirectedSystemOut.reset();
}
/**
* Clear everything written to System.err since the last time
* clearSystemErrContents was called.
*/
public static synchronized void clearSystemErrContents() {
redirectedSystemErr.reset();
}
/**
* Clear everything written to the Access, Error, or Debug loggers.
*/
public static synchronized void clearLoggersContents() {
ACCESS_TEXT_WRITER.clear();
ERROR_TEXT_WRITER.clear();
DEBUG_TEXT_WRITER.clear();
clearSystemOutContents();
clearSystemErrContents();
}
/**
* Append the contents of the Access Log, Error Log, Debug Loggers,
* System.out, System.err to the specified buffer.
*/
public static void appendLogsContents(StringBuilder logsContents)
{
appendMessages(logsContents, TestCaseUtils.ACCESS_TEXT_WRITER, "Access Log Messages:");
appendMessages(logsContents, TestCaseUtils.ERROR_TEXT_WRITER, "Error Log Messages:");
appendMessages(logsContents, TestCaseUtils.DEBUG_TEXT_WRITER, "Debug Log Messages:");
appendStreamContent(logsContents, TestCaseUtils.getSystemOutContents(), "System.out");
appendStreamContent(logsContents, TestCaseUtils.getSystemErrContents(), "System.err");
}
private static void appendStreamContent(StringBuilder out, String content, String name)
{
if (content.length() > 0)
{
out.append(EOL).append(name).append(" contents:").append(EOL).append(content);
}
}
private static void appendMessages(StringBuilder out,
TestTextWriter textWriter, String loggerType)
{
List<String> messages = textWriter.getMessages();
if (!messages.isEmpty())
{
out.append(EOL);
out.append(loggerType);
out.append(EOL);
for (String message : messages)
{
out.append(message);
out.append(EOL);
}
}
}
public static synchronized void unsupressOutput() {
System.setOut(originalSystemOut);
System.setErr(originalSystemErr);
for (Logger l : disabledLogHandlers.keySet())
{
Handler h = disabledLogHandlers.get(l);
l.addHandler(h);
}
disabledLogHandlers.clear();
}
/** Read the contents of a file and return it as a String. */
public static String readFile(String name) throws IOException {
return readFile(new File(name));
}
/** Read the contents of a file and return it as a String. */
public static String readFile(File file) throws IOException {
return new String(readFileBytes(file));
}
/**
* Returns the contents of file as a List of the lines as defined by
* java.io.BufferedReader#readLine() (i.e. the line terminator is not
* included). An ArrayList is explicitly returned, so that callers know that
* random access is not expensive.
*/
public static ArrayList<String> readFileToLines(File file) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
ArrayList<String> lines = new ArrayList<>();
String line;
while ((line = reader.readLine()) != null) {
lines.add(line);
}
return lines;
}
/** Read the contents of a file and return it as a String. */
private static byte[] readFileBytes(File file) throws IOException {
FileInputStream fis = new FileInputStream(file);
return readInputStreamBytes(fis, true);
}
/**
* @param close - if true, close when finished reading.
* @return input stream content.
*/
private static byte[] readInputStreamBytes(InputStream is, boolean close) throws IOException {
byte[] bytes = null;
if (is != null) {
ByteArrayOutputStream bout = new ByteArrayOutputStream(1024);
try {
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = is.read(buf)) != -1) {
bout.write(buf, 0, bytesRead);
} // end of while ((read(buf) != -1)
bytes = bout.toByteArray();
}
finally {
if (close)
{
close(is);
}
}
}
return bytes;
}
/** Store the contents of a String in a file. */
public static void writeFile(File file, String contents) throws IOException {
writeFile(file.getAbsolutePath(), contents);
}
/** Store the contents of a String in a file. */
public static void writeFile(String name, String contents) throws IOException {
writeFile(name, contents.getBytes());
}
/** Store the contents of a String in a file. */
public static void writeFile(String path, byte[] contents) throws IOException {
try (FileOutputStream fos = new FileOutputStream(path))
{
fos.write(contents);
}
}
/**
* Invokes the dsconfig tool with the provided set of arguments. Note that
* the address, port, bind DN (cn=Directory Manager), and password will always
* be provided, so they should not be included in the argument list. The
* given arguments should include only the subcommand and its associated
* options, along with any other global options that may not be included by
* default.
* <BR><BR>
* An assertion will be used to ensure that the dsconfig invocation is
* successful. If running dsconfig returns a non-zero result, then an
* assertion error will be thrown.
*
* @param args The set of arguments that should be provided when invoking
* the dsconfig tool
*/
public static void dsconfig(String... args)
{
String hostName;
try {
hostName = InetAddress.getLocalHost().getHostName();
} catch (Exception e) {
hostName = "Unknown (" + e + ")";
}
String[] fullArgs = new String[args.length + 11];
fullArgs[0] = "-h";
fullArgs[1] = hostName;
fullArgs[2] = "-p";
fullArgs[3] = String.valueOf(serverAdminPort);
fullArgs[4] = "-D";
fullArgs[5] = "cn=Directory Manager";
fullArgs[6] = "-w";
fullArgs[7] = "password";
fullArgs[8] = "-n";
fullArgs[9] = "--noPropertiesFile";
fullArgs[10] = "-X";
System.arraycopy(args, 0, fullArgs, 11, args.length);
assertEquals(DSConfig.main(fullArgs, System.out, System.err), 0);
}
/**
* Gets the root configuration associated with the active server
* instance. This root configuration can then be used to access and
* modify the server's configuration using that administration
* framework's strongly typed API.
* <p>
* Note: were possible the {@link #dsconfig(String...)} method
* should be used in preference to this method in order to perform
* end-to-end testing.
*
* @return Returns the root configuration associated with the active
* server instance.
* @throws Exception
* If the management context could not be initialized
* against the active server instance.
*/
public static RootCfgClient getRootConfiguration() throws Exception
{
LDAPConnection connection = JNDIDirContextAdaptor.simpleSSLBind(
"127.0.0.1",
serverAdminPort,
"cn=Directory Manager",
"password");
ManagementContext context = LDAPManagementContext.createFromContext(connection);
return context.getRootConfiguration();
}
/**
* Return a String representation of all of the current threads.
* @return a dump of all Threads on the server
*/
public static String threadStacksToString()
{
Map<Thread,StackTraceElement[]> threadStacks = Thread.getAllStackTraces();
// Re-arrange all of the elements by thread ID so that there is some logical order.
Map<Long, Map.Entry<Thread, StackTraceElement[]>> orderedStacks = new TreeMap<>();
for (Map.Entry<Thread,StackTraceElement[]> e : threadStacks.entrySet())
{
orderedStacks.put(e.getKey().getId(), e);
}
final StringBuilder buffer = new StringBuilder();
for (Map.Entry<Thread,StackTraceElement[]> e : orderedStacks.values())
{
Thread t = e.getKey();
StackTraceElement[] stackElements = e.getValue();
long id = t.getId();
buffer.append("id=");
buffer.append(id);
buffer.append(" ---------- ");
buffer.append(t.getName());
buffer.append(" ----------");
buffer.append(EOL);
if (stackElements != null)
{
for (StackTraceElement stackElement : stackElements)
{
buffer.append(" ").append(stackElement.getClassName());
buffer.append(".");
buffer.append(stackElement.getMethodName());
buffer.append("(");
buffer.append(stackElement.getFileName());
buffer.append(":");
if (stackElement.isNativeMethod())
{
buffer.append("native");
}
else
{
buffer.append(stackElement.getLineNumber());
}
buffer.append(")").append(EOL);
}
}
buffer.append(EOL);
}
return buffer.toString();
}
public static void enableBackend(String backendID)
{
setBackendEnabled(backendID, true);
}
public static void disableBackend(String backendID)
{
setBackendEnabled(backendID, false);
}
private static void setBackendEnabled(String backendID, boolean enabled)
{
dsconfig("set-backend-prop", "--backend-name", backendID,
"--set", "enabled:" + enabled);
}
public static HashSet<PluginType> getPluginTypes(Entry e)
{
HashSet<PluginType> pluginTypes = new HashSet<>();
List<Attribute> attrList = e.getAttribute("ds-cfg-plugin-type");
if (attrList != null)
{
for (Attribute a : attrList)
{
for (ByteString v : a)
{
pluginTypes.add(PluginType.forName(v.toString().toLowerCase()));
}
}
}
return pluginTypes;
}
/** Saves a thread dump in a file with the provided id used in file prefix. */
public static void generateThreadDump(String id)
{
String date = new SimpleDateFormat("yyyyMMdd_hhmmss").format(new Date().getTime());
try (BufferedWriter writer = new BufferedWriter(new FileWriter("/tmp/thread_dump_" + id + "_" + date)))
{
writer.write(generateThreadDump());
}
catch (Exception e)
{
// do nothing
}
}
/** Generates a thread dump programmatically. */
public static String generateThreadDump() {
final StringBuilder dump = new StringBuilder();
final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
final ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds(), 100);
for (ThreadInfo threadInfo : threadInfos) {
dump.append('"');
dump.append(threadInfo.getThreadName());
dump.append("\" ");
final Thread.State state = threadInfo.getThreadState();
dump.append("\n java.lang.Thread.State: ");
dump.append(state);
final StackTraceElement[] stackTraceElements = threadInfo.getStackTrace();
for (final StackTraceElement stackTraceElement : stackTraceElements) {
dump.append("\n at ");
dump.append(stackTraceElement);
}
dump.append("\n\n");
}
return dump.toString();
}
/** FIXME Replace with {@link Assert#assertNotEquals(Object, Object)} once we upgrade to testng >= 6.1. */
public static void assertNotEquals(Object actual1, Object actual2)
{
assertNotEquals(actual1, actual2, null);
}
/** FIXME Replace with {@link Assert#assertNotEquals(Object, Object, String)} once we upgrade to testng >= 6.1. */
public static void assertNotEquals(Object actual1, Object actual2, String message)
{
boolean fail = false;
try
{
Assert.assertEquals(actual1, actual2);
fail = true;
}
catch (AssertionError e)
{
}
if (fail)
{
Assert.fail(message);
}
}
}