/*
|
* 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 2008 Sun Microsystems, Inc.
|
* Portions Copyright 2014 ForgeRock AS
|
*/
|
package org.opends.server.extensions;
|
|
|
|
import java.io.File;
|
import java.lang.reflect.Field;
|
import java.lang.reflect.Method;
|
import java.util.ArrayList;
|
import org.opends.server.TestCaseUtils;
|
import org.opends.server.admin.server.AdminTestCaseUtils;
|
import org.testng.annotations.BeforeClass;
|
import org.opends.server.admin.std.meta.*;
|
import org.opends.server.admin.std.server.EntryCacheCfg;
|
import org.opends.server.api.Backend;
|
import org.opends.server.core.DirectoryServer;
|
import org.opends.server.types.Entry;
|
import org.opends.server.util.ServerConstants;
|
import org.testng.annotations.AfterClass;
|
import org.testng.annotations.Test;
|
import static org.testng.Assert.*;
|
|
|
|
/**
|
* The entry cache pre-load test class.
|
*/
|
@Test(groups = { "entrycache", "slow" }, sequential=true)
|
public class PreloadEntryCacheTestCase
|
extends ExtensionsTestCase
|
{
|
/**
|
* Number of unique dummy test entries.
|
*/
|
protected int NUMTESTENTRIES = 1000;
|
|
/**
|
* Dummy test entries.
|
*/
|
protected ArrayList<Entry> testEntriesList;
|
|
/**
|
* Entry cache configuration instance.
|
*/
|
protected EntryCacheCfg configuration;
|
|
/**
|
* Temporary folder to setup dummy JE backend environment in.
|
*/
|
private File jeBackendTempDir;
|
|
/**
|
* Initialize the entry cache pre-load test.
|
*
|
* @throws Exception If an unexpected problem occurs.
|
*/
|
@BeforeClass()
|
public void preloadEntryCacheTestInit()
|
throws Exception
|
{
|
// Ensure that the server is running.
|
TestCaseUtils.startServer();
|
|
// Make sure JE directory exist.
|
jeBackendTempDir = TestCaseUtils.createTemporaryDirectory("db-cachetest");
|
String jeDir = jeBackendTempDir.getAbsolutePath();
|
|
// Create dummy JE backend for this test.
|
TestCaseUtils.dsconfig("create-backend", "--backend-name", "cacheTest",
|
"--type", "local-db", "--set", "db-directory:" + jeDir, "--set",
|
"base-dn:o=cachetest", "--set", "writability-mode:enabled", "--set",
|
"enabled:true");
|
|
// Configure the entry cache, use FileSystemEntryCache.
|
Entry cacheConfigEntry = TestCaseUtils.makeEntry(
|
"dn: cn=Soft Reference,cn=Entry Caches,cn=config",
|
"objectClass: ds-cfg-soft-reference-entry-cache",
|
"objectClass: ds-cfg-entry-cache",
|
"objectClass: top",
|
"cn: Soft Reference",
|
"ds-cfg-cache-level: 1",
|
"ds-cfg-java-class: " +
|
"org.opends.server.extensions.SoftReferenceEntryCache",
|
"ds-cfg-enabled: true");
|
configuration = AdminTestCaseUtils.getConfiguration(
|
EntryCacheCfgDefn.getInstance(), cacheConfigEntry);
|
|
// Make parent entry.
|
Entry parentEntry = TestCaseUtils.makeEntry(
|
"dn: o=cachetest",
|
"o: cachetest",
|
"objectClass: top",
|
"objectClass: organization");
|
TestCaseUtils.addEntry(parentEntry);
|
|
// Make some dummy test entries.
|
testEntriesList = new ArrayList<Entry>(NUMTESTENTRIES);
|
for(int i = 0; i < NUMTESTENTRIES; i++ ) {
|
Entry testEntry = TestCaseUtils.makeEntry(
|
"dn: uid=test" + Integer.toString(i) + ".user" + Integer.toString(i)
|
+ ",o=cachetest",
|
"objectClass: person",
|
"objectClass: inetorgperson",
|
"objectClass: top",
|
"objectClass: organizationalperson",
|
"postalAddress: somewhere in Testville" + Integer.toString(i),
|
"street: Under Construction Street" + Integer.toString(i),
|
"l: Testcounty" + Integer.toString(i),
|
"st: Teststate" + Integer.toString(i),
|
"telephoneNumber: +878 8378 8378" + Integer.toString(i),
|
"mobile: +878 8378 8378" + Integer.toString(i),
|
"homePhone: +878 8378 8378" + Integer.toString(i),
|
"pager: +878 8378 8378" + Integer.toString(i),
|
"mail: test" + Integer.toString(i) + ".user" + Integer.toString(i)
|
+ "@testdomain.net",
|
"postalCode: 8378" + Integer.toString(i),
|
"userPassword: testpassword" + Integer.toString(i),
|
"description: description for Test" + Integer.toString(i) + "User"
|
+ Integer.toString(i),
|
"cn: Test" + Integer.toString(i) + "User" + Integer.toString(i),
|
"sn: User" + Integer.toString(i),
|
"givenName: Test" + Integer.toString(i),
|
"initials: TST" + Integer.toString(i),
|
"employeeNumber: 8378" + Integer.toString(i),
|
"uid: test" + Integer.toString(i) + ".user" + Integer.toString(i)
|
);
|
testEntriesList.add(testEntry);
|
TestCaseUtils.addEntry(testEntry);
|
}
|
|
// Initialize the cache reflecting on DirectoryServer
|
// and EntryCacheConfigManager.
|
final Field[] directoryFields =
|
DirectoryServer.class.getDeclaredFields();
|
for (int i = 0; i < directoryFields.length; ++i) {
|
if (directoryFields[i].getName().equals("entryCacheConfigManager")) {
|
directoryFields[i].setAccessible(true);
|
final Method[] cacheManagerMethods =
|
directoryFields[i].getType().getDeclaredMethods();
|
for (int j = 0; j < cacheManagerMethods.length; ++j) {
|
if (cacheManagerMethods[j].getName().equals(
|
"loadAndInstallEntryCache")) {
|
cacheManagerMethods[j].setAccessible(true);
|
cacheManagerMethods[j].invoke(directoryFields[i].get(
|
DirectoryServer.getInstance()),
|
configuration.getJavaClass(), configuration);
|
}
|
}
|
}
|
}
|
|
// Attempt to force GC to possibly free some memory.
|
System.gc();
|
}
|
|
|
|
/**
|
* Tests the entry cache pre-load.
|
*/
|
@Test()
|
public void testEntryCachePreload()
|
throws Exception
|
{
|
// Make sure the entry cache is empty.
|
assertNull(toVerboseString(),
|
"Expected empty cache. " + "Cache contents:" + ServerConstants.EOL +
|
toVerboseString());
|
|
// Preload.
|
Backend backend = DirectoryServer.getBackend("cacheTest");
|
backend.preloadEntryCache();
|
|
// Check that all test entries are preloaded.
|
for(int i = 0; i < NUMTESTENTRIES; i++ ) {
|
assertNotNull(DirectoryServer.getEntryCache().getEntry(
|
testEntriesList.get(i).getName()), "Expected to find " +
|
testEntriesList.get(i).getName() +
|
" in the cache. Cache contents:" +
|
ServerConstants.EOL + toVerboseString());
|
}
|
}
|
|
|
|
/**
|
* Finalize the entry cache pre-load test.
|
*
|
* @throws Exception If an unexpected problem occurs.
|
*/
|
@AfterClass()
|
public void preloadEntryCacheTestFini()
|
throws Exception
|
{
|
// Dummy JE backend cleanup.
|
TestCaseUtils.dsconfig("delete-backend", "--backend-name", "cacheTest");
|
TestCaseUtils.deleteDirectory(jeBackendTempDir);
|
|
// Sanity in-core restart.
|
TestCaseUtils.restartServer();
|
}
|
|
|
|
/**
|
* Reflection of the toVerboseString implementation method.
|
*/
|
protected String toVerboseString()
|
throws Exception
|
{
|
final Method[] cacheMethods =
|
DirectoryServer.getEntryCache().getClass().getDeclaredMethods();
|
|
for (int i = 0; i < cacheMethods.length; ++i) {
|
if (cacheMethods[i].getName().equals("toVerboseString")) {
|
cacheMethods[i].setAccessible(true);
|
Object verboseString =
|
cacheMethods[i].invoke(DirectoryServer.getEntryCache(),
|
(Object[]) null);
|
return (String) verboseString;
|
}
|
}
|
|
return null;
|
}
|
}
|