/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.plugin.ij.framework.core;
import com.intellij.history.integration.LocalHistoryImpl;
import com.intellij.ide.highlighter.ModuleFileType;
import com.intellij.ide.highlighter.ProjectFileType;
import com.intellij.ide.startup.impl.StartupManagerImpl;
import com.intellij.idea.IdeaLogger;
import com.intellij.idea.IdeaTestApplication;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.DataProvider;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.command.impl.UndoManagerImpl;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.editor.impl.DocumentImpl;
import com.intellij.openapi.module.EmptyModuleType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.module.impl.ModuleManagerImpl;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.project.impl.ProjectImpl;
import com.intellij.openapi.project.impl.ProjectManagerImpl;
import com.intellij.openapi.project.impl.TooManyProjectLeakedException;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.impl.ProjectRootManagerImpl;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.ShutDownTracker;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.impl.local.LocalFileSystemImpl;
import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFSImpl;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.codeStyle.CodeStyleSchemes;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.impl.DocumentCommitThread;
import com.intellij.psi.impl.PsiManagerEx;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageManagerImpl;
import com.intellij.testFramework.CompositeException;
import com.intellij.testFramework.EditorListenerTracker;
import com.intellij.testFramework.LightPlatformTestCase;
import com.intellij.testFramework.TestLoggerFactory;
import com.intellij.testFramework.ThreadTracker;
import com.intellij.util.PatchedWeakReference;
import com.intellij.util.indexing.IndexableSetContributor;
import com.intellij.util.indexing.IndexedRootsProvider;
import com.intellij.util.ui.UIUtil;
import gw.lang.reflect.TypeSystem;
import gw.lang.reflect.module.IModule;
import gw.plugin.ij.core.PluginLoaderUtil;
import junit.framework.TestCase;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
/**
* @author yole
*/
public abstract class PlatformTestCase extends UsefulTestCase implements DataProvider {
public static final String TEST_DIR_PREFIX = "idea_test_";
protected static IdeaTestApplication ourApplication;
protected ProjectManagerEx myProjectManager;
protected Project myProject;
// only used for single module test class, we can ignore it for now.
protected Module myModule;
protected static final Collection<File> myFilesToDelete = new HashSet<>();
protected boolean myAssertionsInTestDetected;
protected static final Logger LOG = Logger.getInstance("#com.intellij.testFramework.PlatformTestCase");
public static Thread ourTestThread;
private static TestCase ourTestCase = null;
public static final long DEFAULT_TEST_TIME = 300L;
public static long ourTestTime = DEFAULT_TEST_TIME;
private EditorListenerTracker myEditorListenerTracker;
private ThreadTracker myThreadTracker;
private boolean ourHaveShutdownHook;
protected static boolean ourPlatformPrefixInitialized;
private static Set<VirtualFile> ourEternallyLivingFilesCache;
static {
Logger.setFactory(TestLoggerFactory.getInstance());
}
protected static long getTimeRequired() {
return DEFAULT_TEST_TIME;
}
@Nullable
protected String getApplicationConfigDirPath() throws Exception {
return null;
}
protected void initApplication() throws Exception {
boolean firstTime = ourApplication == null;
autodetectPlatformPrefix();
ourApplication = IdeaTestApplication.getInstance(getApplicationConfigDirPath());
ourApplication.setDataProvider(this);
if (firstTime) {
cleanPersistedVFSContent();
}
}
private static void autodetectPlatformPrefix() {
if (ourPlatformPrefixInitialized) {
return;
}
URL resource = PlatformTestCase.class.getClassLoader().getResource("idea/ApplicationInfo.xml");
if (resource == null) {
resource = PlatformTestCase.class.getClassLoader().getResource("idea/IdeaApplicationInfo.xml");
if (resource == null) {
setPlatformPrefix("PlatformLangXml");
}
else {
setPlatformPrefix("Idea");
}
}
}
private static void cleanPersistedVFSContent() {
((PersistentFSImpl)PersistentFS.getInstance()).cleanPersistedContents();
}
@Override
protected CodeStyleSettings getCurrentCodeStyleSettings() {
if (CodeStyleSchemes.getInstance().getCurrentScheme() == null) return new CodeStyleSettings();
return CodeStyleSettingsManager.getSettings(getProject());
}
@Override
protected void beforeMethod() throws Exception {
super.beforeMethod();
if (ourTestCase != null) {
String message = "Previous test " + ourTestCase + " hasn't called tearDown(). Probably overridden without super call.";
ourTestCase = null;
fail(message);
}
IdeaLogger.ourErrorsOccurred = null;
LOG.info(getName() + "(" + getClass().getName() + ").setUp()");
myEditorListenerTracker = new EditorListenerTracker();
myThreadTracker = new ThreadTracker();
ourTestCase = this;
}
@Override
protected void beforeClass() throws Exception {
super.beforeClass();
LOG.info(getClass().getName() + ".beforeClass()");
//FSRecords.invalidateCaches(); //TODO-dp this may be too brutal
// initialize application only once
initApplication();
// setup new project for each test class
setUpProject();
storeSettings();
if (myProject != null) {
ProjectManagerEx.getInstanceEx().openTestProject(myProject);
CodeStyleSettingsManager.getInstance(myProject).setTemporarySettings(new CodeStyleSettings());
InjectedLanguageManagerImpl.pushInjectors(getProject());
}
DocumentCommitThread.getInstance().clearQueue();
DocumentImpl.CHECK_DOCUMENT_CONSISTENCY = !isPerformanceTest();
}
public Project getProject() {
return myProject;
}
public final PsiManager getPsiManager() {
return PsiManager.getInstance(myProject);
}
public Module getModule() {
return myModule;
}
public IModule getGosuModule() {
return TypeSystem.getExecutionEnvironment( PluginLoaderUtil.getFrom( myModule.getProject() ) ).getModule(myModule.getName());
}
protected boolean isExistingProject() {
return false;
}
protected void setUpProject() throws Exception {
myProjectManager = ProjectManagerEx.getInstanceEx();
assertNotNull("Cannot instantiate ProjectManager component", myProjectManager);
File projectFile = getIprFile();
myProject = createProject(projectFile, getClass().getName() + "." + getName(), isExistingProject());
myProjectManager.openTestProject(myProject);
LocalFileSystem.getInstance().refreshIoFiles(myFilesToDelete);
setUpModule();
setUpJdk();
LightPlatformTestCase.clearUncommittedDocuments(getProject());
//((PsiDocumentManagerImpl) PsiDocumentManager.getInstance(getProject())).clearUncommitedDocuments();
runStartupActivities();
if (!ourHaveShutdownHook) {
ourHaveShutdownHook = true;
registerShutdownHook();
}
}
@NotNull
public static Project createProject(File projectFile, String creationPlace, boolean open) throws Exception {
try {
Project project;
if (open) {
project = ProjectManagerEx.getInstanceEx().loadProject(projectFile.getPath());
} else {
project = ProjectManagerEx.getInstanceEx().newProject(FileUtil.getNameWithoutExtension(projectFile), projectFile.getPath(), false, false);
}
assert project != null;
project.putUserData(CREATION_PLACE, creationPlace);
return project;
}
catch (TooManyProjectLeakedException e) {
StringBuilder leakers = new StringBuilder();
leakers.append("Too many projects leaked: \n");
for (Project project : e.getLeakedProjects()) {
String presentableString = getCreationPlace(project);
leakers.append(presentableString);
leakers.append("\n");
}
fail(leakers.toString());
return null;
}
}
public static String getCreationPlace(Project project) {
String place = project.getUserData(CREATION_PLACE);
Object base;
try {
base = project.isDisposed() ? "" : project.getBaseDir();
}
catch (Exception e) {
base = " (" + e + " while getting base dir)";
}
return project.toString() + (place != null ? place : "") + base;
}
protected void runStartupActivities() {
final StartupManagerImpl startupManager = (StartupManagerImpl)StartupManager.getInstance(myProject);
startupManager.runStartupActivities();
startupManager.startCacheUpdate();
startupManager.runPostStartupActivities();
}
protected File getIprFile() throws IOException {
String prefix = "temp_" + getTestClassName();
System.out.println("Creating temp IPR file at : " + FileUtil.getTempDirectory() + "/" + prefix );
File tempFile = FileUtil.createTempFile(prefix, ProjectFileType.DOT_DEFAULT_EXTENSION);
myFilesToDelete.add(tempFile);
return tempFile;
}
protected void setUpModule() {
new WriteCommandAction.Simple(getProject()) {
@Override
protected void run() throws Throwable {
myModule = createMainModule();
}
}.execute().throwException();
}
protected Module createMainModule() throws IOException {
return createModule(getTestClassName());
}
protected Module createModule(@NonNls final String moduleName) {
return doCreateRealModule(moduleName);
}
protected Module doCreateRealModule(final String moduleName) {
return doCreateRealModuleIn(moduleName, myProject, getModuleType());
}
protected static Module doCreateRealModuleIn(String moduleName, final Project project, final ModuleType moduleType) {
final VirtualFile baseDir = project.getBaseDir();
assertNotNull(baseDir);
final File moduleFile = new File(baseDir.getPath().replace('/', File.separatorChar),
moduleName + ModuleFileType.DOT_DEFAULT_EXTENSION);
FileUtil.createIfDoesntExist(moduleFile);
myFilesToDelete.add(moduleFile);
return new WriteAction<Module>() {
@Override
protected void run(Result<Module> result) throws Throwable {
final VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(moduleFile);
Module module = ModuleManager.getInstance(project).newModule(virtualFile.getPath(), moduleType.getId());
module.getModuleFile();
result.setResult(module);
}
}.execute().getResultObject();
}
protected ModuleType getModuleType() {
return EmptyModuleType.getInstance();
}
public static void cleanupApplicationCaches(Project project) {
if (project != null && !project.isDisposed()) {
UndoManagerImpl globalInstance = (UndoManagerImpl)UndoManager.getGlobalInstance();
if (globalInstance != null) {
globalInstance.dropHistoryInTests();
}
((UndoManagerImpl)UndoManager.getInstance(project)).dropHistoryInTests();
((PsiManagerEx)PsiManager.getInstance(project)).getFileManager().cleanupForNextTest();
}
try {
LocalFileSystemImpl localFileSystem = (LocalFileSystemImpl)LocalFileSystem.getInstance();
if (localFileSystem != null) {
localFileSystem.cleanupForNextTest();
}
}
catch (Exception e) {
// ignore
}
LocalHistoryImpl.getInstanceImpl().cleanupForNextTest();
PatchedWeakReference.clearAll();
}
private static Set<VirtualFile> eternallyLivingFiles() {
if (ourEternallyLivingFilesCache != null) {
return ourEternallyLivingFilesCache;
}
Set<VirtualFile> survivors = new HashSet<>();
for (IndexedRootsProvider provider : IndexedRootsProvider.EP_NAME.getExtensions()) {
for (VirtualFile file : IndexableSetContributor.getRootsToIndex(provider)) {
registerSurvivor(survivors, file);
}
}
ourEternallyLivingFilesCache = survivors;
return survivors;
}
public static void addSurvivingFiles(@NotNull Collection<VirtualFile> files) {
for (VirtualFile each : files) {
registerSurvivor(eternallyLivingFiles(), each);
}
}
private static void registerSurvivor(Set<VirtualFile> survivors, VirtualFile file) {
addSubTree(file, survivors);
while (file != null && survivors.add(file)) {
file = file.getParent();
}
}
private static void addSubTree(VirtualFile root, Set<VirtualFile> to) {
if (root instanceof VirtualDirectoryImpl) {
for (VirtualFile child : ((VirtualDirectoryImpl)root).getCachedChildren()) {
if (child instanceof VirtualDirectoryImpl) {
to.add(child);
addSubTree(child, to);
}
}
}
}
@Override
protected void afterClass() throws Exception {
CompositeException result = new CompositeException();
if (myProject != null) {
try {
LightPlatformTestCase.doTearDown(getProject(), ourApplication, false);
}
catch (Throwable e) {
result.add(e);
}
}
try {
checkForSettingsDamage();
}
catch (Throwable e) {
result.add(e);
}
try {
Project project = getProject();
disposeProject(result);
if (project != null) {
try {
InjectedLanguageManagerImpl.checkInjectorsAreDisposed(project);
}
catch (AssertionError e) {
result.add(e);
}
}
try {
for (final File fileToDelete : myFilesToDelete) {
delete(fileToDelete);
}
LocalFileSystem.getInstance().refreshIoFiles(myFilesToDelete);
}
catch (Throwable e) {
result.add(e);
}
if (!myAssertionsInTestDetected) {
if (IdeaLogger.ourErrorsOccurred != null) {
throw IdeaLogger.ourErrorsOccurred;
}
assertNull("Logger errors occurred in " + getFullName(), IdeaLogger.ourErrorsOccurred);
}
} finally {
myProjectManager = null;
myProject = null;
myModule = null;
myFilesToDelete.clear();
super.afterClass();
}
if (!result.isEmpty()) throw result;
}
@Override
protected void afterMethod() throws Exception {
CompositeException result = new CompositeException();
ourTestCase = null;
try {
try {
super.tearDown();
}
catch (Throwable e) {
result.add(e);
}
//cleanTheWorld();
try {
myEditorListenerTracker.checkListenersLeak();
}
catch (AssertionError error) {
result.add(error);
}
try {
myThreadTracker.checkLeak();
}
catch (AssertionError error) {
result.add(error);
}
try {
LightPlatformTestCase.checkEditorsReleased();
}
catch (Throwable error) {
result.add(error);
}
}
finally {
myEditorListenerTracker = null;
myThreadTracker = null;
}
super.afterMethod(); //To change body of overridden methods use File | Settings | File Templates.
if (!result.isEmpty()) throw result;
}
private void disposeProject(@NotNull CompositeException result) /* throws nothing */ {
try {
DocumentCommitThread.getInstance().clearQueue();
UIUtil.dispatchAllInvocationEvents();
}
catch (Exception e) {
result.add(e);
}
UIUtil.dispatchAllInvocationEvents();
try {
if (myProject != null) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
Disposer.dispose(myProject);
ProjectManagerEx projectManager = ProjectManagerEx.getInstanceEx();
if (projectManager instanceof ProjectManagerImpl) {
projectManager.closeTestProject(myProject);
}
}
});
}
}
catch (Exception e) {
result.add(e);
}
finally {
if (myProject != null) {
try {
PsiDocumentManager documentManager = myProject.getComponent(PsiDocumentManager.class, null);
if (documentManager != null) {
EditorFactory.getInstance().getEventMulticaster().removeDocumentListener((DocumentListener)documentManager);
}
}
catch (Exception ignored) {
}
myProject = null;
}
}
}
public synchronized void closeAndDeleteProject() {
if (myProject != null) {
final VirtualFile projFile = ((ProjectImpl) myProject).getStateStore().getProjectBaseDir();
final File projectFile = projFile == null ? null : VfsUtil.virtualToIoFile(projFile);
if (!myProject.isDisposed()) {
Disposer.dispose(myProject);
}
if (projectFile != null) {
FileUtil.delete(projectFile);
}
myProject = null;
}
}
protected void resetAllFields() {
resetClassFields(getClass());
}
@Override
protected final <T extends Disposable> T disposeOnTearDown(T disposable) {
Disposer.register(myProject, disposable);
return disposable;
}
private void resetClassFields(final Class<?> aClass) {
try {
clearDeclaredFields(this, aClass);
}
catch (IllegalAccessException e) {
LOG.error(e);
}
if (aClass == PlatformTestCase.class) return;
resetClassFields(aClass.getSuperclass());
}
private String getFullName() {
return getClass().getName() + "." + getName();
}
private void delete(File file) {
boolean b = FileUtil.delete(file);
if (!b && file.exists() && !myAssertionsInTestDetected) {
fail("Can't delete " + file.getAbsolutePath() + " in " + getFullName());
}
}
protected void simulateProjectOpen() {
ModuleManagerImpl mm = (ModuleManagerImpl)ModuleManager.getInstance(myProject);
StartupManagerImpl sm = (StartupManagerImpl)StartupManager.getInstance(myProject);
mm.projectOpened();
setUpJdk();
sm.runStartupActivities();
sm.startCacheUpdate();
// extra init for libraries
sm.runPostStartupActivities();
}
protected void setUpJdk() {
//final ProjectJdkEx jdk = ProjectJdkUtil.getDefaultJdk("java 1.4");
final Sdk jdk = getTestProjectJdk();
// ProjectJdkImpl jdk = ProjectJdkTable.getInstance().addJdk(defaultJdk);
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
ProjectRootManagerImpl.getInstance(getProject()).setProjectSdk(jdk);
// set SDK on modules
Module[] modules = ModuleManager.getInstance(myProject).getModules();
for (Module module : modules) {
final ModifiableRootModel rootModel = ModuleRootManager.getInstance(module).getModifiableModel();
rootModel.inheritSdk();
rootModel.commit();
}
}
});
}
@Nullable
protected Sdk getTestProjectJdk() {
return null;
}
protected boolean isRunInWriteAction() {
return true;
}
@Override
protected void invokeTestRunnable(final Runnable runnable) throws Exception {
final Exception[] e = new Exception[1];
Runnable runnable1 = new Runnable() {
@Override
public void run() {
try {
if (ApplicationManager.getApplication().isDispatchThread() && isRunInWriteAction()) {
ApplicationManager.getApplication().runWriteAction(runnable);
}
else {
runnable.run();
}
}
catch (Exception e1) {
e[0] = e1;
}
}
};
if (annotatedWith(WrapInCommand.class)) {
CommandProcessor.getInstance().executeCommand(myProject, runnable1, "", null);
}
else {
runnable1.run();
}
if (e[0] != null) {
throw e[0];
}
}
@Override
public Object getData(String dataId) {
return myProject == null ? null : new TestDataProvider(myProject).getData(dataId);
}
public static File createTempDir(@NonNls final String prefix) throws IOException {
return createTempDir(prefix, true);
}
public static File createTempDir(@NonNls final String prefix, final boolean refresh) throws IOException {
final File tempDirectory = FileUtilRt.createTempDirectory(TEST_DIR_PREFIX + prefix, null, false);
myFilesToDelete.add(tempDirectory);
if (refresh) {
getVirtualFile(tempDirectory);
}
return tempDirectory;
}
@Nullable
protected static VirtualFile getVirtualFile(final File file) {
return LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file);
}
protected File createTempDirectory() throws IOException {
return createTempDir(getTestName(true));
}
protected File createTempDirectory(final boolean refresh) throws IOException {
return createTempDir(getTestName(true), refresh);
}
protected File createTempFile(String name, String text) throws IOException {
File directory = createTempDirectory();
File file = new File(directory, name);
if (!file.createNewFile()) {
throw new IOException("Can't create " + file);
}
FileUtil.writeToFile(file, text);
return file;
}
public static void setContentOnDisk(File file, byte[] bom, String content, Charset charset) throws IOException {
FileOutputStream stream = new FileOutputStream(file);
if (bom != null) {
stream.write(bom);
}
OutputStreamWriter writer = new OutputStreamWriter(stream, charset);
try {
writer.write(content);
}
finally {
writer.close();
}
}
public static VirtualFile createTempFile(@NonNls String ext, @Nullable byte[] bom, @NonNls String content, Charset charset) throws IOException {
File temp = FileUtil.createTempFile("copy", "." + ext);
setContentOnDisk(temp, bom, content, charset);
myFilesToDelete.add(temp);
final VirtualFile file = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(temp);
assert file != null : temp;
return file;
}
@Nullable
protected PsiFile getPsiFile(final Document document) {
return PsiDocumentManager.getInstance(getProject()).getPsiFile(document);
}
@Nullable
protected PsiFile getPsiFile(@NotNull Editor editor) {
return PsiDocumentManager.getInstance(getProject()).getPsiFile(editor.getDocument());
}
public static void initPlatformLangPrefix() {
initPlatformPrefix(IDEA_MARKER_CLASS, "PlatformLangXml");
}
public static void initPlatformPrefix(String classToTest, String prefix) {
if (!ourPlatformPrefixInitialized) {
ourPlatformPrefixInitialized = true;
boolean isUltimate = true;
try {
PlatformTestCase.class.getClassLoader().loadClass(classToTest);
}
catch (ClassNotFoundException e) {
isUltimate = false;
}
if (!isUltimate) {
setPlatformPrefix(prefix);
}
}
}
public static void setPlatformPrefix(String prefix) {
System.setProperty("idea.platform.prefix", prefix);
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface WrapInCommand {
}
protected static VirtualFile createChildData(@NotNull final VirtualFile dir, @NotNull @NonNls final String name) {
return new WriteAction<VirtualFile>() {
@Override
protected void run(Result<VirtualFile> result) throws Throwable {
result.setResult(dir.createChildData(null, name));
}
}.execute().throwException().getResultObject();
}
protected static VirtualFile createChildDirectory(@NotNull final VirtualFile dir, @NotNull @NonNls final String name) {
return new WriteAction<VirtualFile>() {
@Override
protected void run(Result<VirtualFile> result) throws Throwable {
result.setResult(dir.createChildDirectory(null, name));
}
}.execute().throwException().getResultObject();
}
protected static void delete(@NotNull final VirtualFile file) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
try {
file.delete(null);
}
catch (IOException e) {
fail();
}
}
});
}
protected static void rename(@NotNull final VirtualFile vFile1, @NotNull final String newName) {
new WriteCommandAction.Simple(null) {
@Override
protected void run() throws Throwable {
vFile1.rename(this, newName);
}
}.execute().throwException();
}
private void registerShutdownHook() {
// FIXME shutdown hooks run asynchronously and this one must always run after
// the afterClass shutdown hook in StatefulTestCase
ShutDownTracker.getInstance().registerShutdownTask(new Runnable() {
@Override
public void run() {
int retries = 3;
boolean resetAllowed = true;
while (_afterClassExecuting.get() != ExecutionState.COMPLETE && --retries >= 0) {
synchronized (_afterClassMonitor) {
try {
_afterClassMonitor.wait(1000);
} catch (InterruptedException e) {
}
if (_afterClassExecuting.get() == ExecutionState.EXECUTING && resetAllowed) {
retries = 10;
resetAllowed = false;
}
}
}
ShutDownTracker.invokeAndWait(true, true, new Runnable() {
@Override
public void run() {
closeAndDeleteProject();
}
});
}
});
}
}