blob: c68ae5aec9fbe25e4fa463044036d8574a85af99 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2021 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
* Remy Chi Jian Suen (Versant Corporation) - bug 255005
* Jeanderson Candido <http://jeandersonbc.github.io> - Bug 444070
*******************************************************************************/
package org.eclipse.ui.tests.leaks;
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPageLayout;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPartSite;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.dialogs.SaveAsDialog;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.internal.part.NullEditorInput;
import org.eclipse.ui.progress.IWorkbenchSiteProgressService;
import org.eclipse.ui.tests.api.MockViewPart;
import org.eclipse.ui.tests.harness.util.FileUtil;
import org.eclipse.ui.tests.harness.util.UITestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Very simple leak tests to determine if any of our heavy objects are not being
* disposed properly. Note that the results of these tests will in no way
* actually assist you in tracking down the leak.
*
* @since 3.1
*/
@RunWith(JUnit4.class)
public class LeakTests extends UITestCase {
private IWorkbenchPage fActivePage;
private IWorkbenchWindow fWin;
private IProject proj;
public LeakTests() {
super(LeakTests.class.getSimpleName());
}
public static void checkRef(ReferenceQueue<?> queue, Reference<?> ref)
throws IllegalArgumentException, InterruptedException {
boolean flag = false;
for (int i = 0; i < 100; i++) {
System.runFinalization();
System.gc();
Thread.yield();
processEvents();
Reference<?> checkRef = queue.remove(100);
if (checkRef != null && checkRef.equals(ref)) {
flag = true;
break;
}
}
assertTrue("Reference not enqueued", flag);
}
/**
* @param queue
* @param object
* @return
*/
private Reference createReference(ReferenceQueue queue, Object object) {
return new PhantomReference<>(object, queue);
}
@Override
protected void doSetUp() throws Exception {
super.doSetUp();
fWin = openTestWindow(IDE.RESOURCE_PERSPECTIVE_ID);
fActivePage = fWin.getActivePage();
}
@Override
protected void doTearDown() throws Exception {
super.doTearDown();
fWin = null;
fActivePage = null;
if (proj != null) {
FileUtil.deleteProject(proj);
proj = null;
}
}
@Test
public void testSimpleEditorLeak() throws Exception {
proj = FileUtil.createProject("testEditorLeaks");
IFile file = FileUtil.createFile("test.mock1", proj);
ReferenceQueue queue = new ReferenceQueue();
IEditorPart editor = IDE.openEditor(fActivePage, file);
assertNotNull(editor);
Reference ref = createReference(queue, editor);
try {
fActivePage.closeEditor(editor, false);
editor = null;
checkRef(queue, ref);
} finally {
ref.clear();
}
}
@Test
public void testSimpleViewLeak() throws Exception {
ReferenceQueue queue = new ReferenceQueue();
IViewPart view = fActivePage.showView(MockViewPart.ID);
assertNotNull(view);
Reference ref = createReference(queue, view);
try {
fActivePage.hideView(view);
view = null;
checkRef(queue, ref);
} finally {
ref.clear();
}
}
@Test
public void testBug255005ServiceLeak() throws Exception {
ReferenceQueue queue = new ReferenceQueue();
IViewPart view = fActivePage.showView(MockViewPart.ID);
assertNotNull(view);
// create a job to schedule
Job doNothingJob = new Job("Does Nothing") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
return Status.OK_STATUS;
}
};
// retrieve the progress service
IWorkbenchSiteProgressService service = view
.getSite().getService(IWorkbenchSiteProgressService.class);
// schedule it
service.schedule(doNothingJob);
// create a reference for our service
Reference ref = createReference(queue, service);
// wait for the job to complete
doNothingJob.join();
try {
// hide the view
fActivePage.hideView(view);
// remove our references
service = null;
view = null;
// check for leaks
checkRef(queue, ref);
} finally {
ref.clear();
}
}
@Test
public void testBug255005SiteLeak() throws Exception {
ReferenceQueue queue = new ReferenceQueue();
IViewPart view = fActivePage.showView(MockViewPart.ID);
assertNotNull(view);
// create a job to schedule
Job doNothingJob = new Job("Does Nothing") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
return Status.OK_STATUS;
}
};
// retrieve the progress service
IWorkbenchSiteProgressService service = view
.getSite().getService(IWorkbenchSiteProgressService.class);
// schedule it
service.schedule(doNothingJob);
IWorkbenchPartSite site = view.getSite();
// create a reference for our site
Reference ref = createReference(queue, site);
// wait for the job to complete
doNothingJob.join();
try {
// hide the view
fActivePage.hideView(view);
// remove our references
service = null;
site = null;
view = null;
// check for leaks
checkRef(queue, ref);
} finally {
ref.clear();
}
}
@Test
public void testBug265449PropertiesLeak() throws Exception {
// create a project to be selected by the 'Navigator'
proj = FileUtil.createProject("projectToSelect");
// show the 'Navigator'
IViewPart navigator = fActivePage.showView(IPageLayout.ID_PROJECT_EXPLORER);
// show the 'Properties' view
IViewPart propertiesView = fActivePage.showView(IPageLayout.ID_PROP_SHEET);
// select the project in the 'Navigator', this will cause the 'Properties'
// view to show something, and create a PropertySheetPage, which was leaking
navigator.getSite().getSelectionProvider().setSelection(new StructuredSelection(proj));
// create a reference for the 'Properties' view
ReferenceQueue queue = new ReferenceQueue();
Reference ref = createReference(queue, propertiesView);
try {
// hide the views
fActivePage.hideView(navigator);
fActivePage.hideView(propertiesView);
// remove our references
navigator = null;
propertiesView = null;
// check for leaks
checkRef(queue, ref);
} finally {
ref.clear();
}
}
@Test
public void testTextEditorContextMenu() throws Exception {
proj = FileUtil.createProject("testEditorLeaks");
IEditorInput input = new NullEditorInput();
ReferenceQueue queue = new ReferenceQueue();
IEditorPart editor = IDE.openEditor(fActivePage, input, "org.eclipse.ui.tests.leak.contextEditor");
assertTrue(editor instanceof ContextEditorPart);
Reference ref = createReference(queue, editor);
ContextEditorPart contextMenuEditor = (ContextEditorPart) editor;
contextMenuEditor.showMenu();
processEvents();
contextMenuEditor.hideMenu();
processEvents();
try {
contextMenuEditor = null;
fActivePage.closeEditor(editor, false);
editor = null;
checkRef(queue, ref);
} finally {
ref.clear();
}
}
@Test
public void testSimpleWindowLeak() throws Exception {
// turn off window management so that we dont have a reference to our
// new
// window in the listener
manageWindows(false);
try {
ReferenceQueue queue = new ReferenceQueue();
IWorkbenchWindow newWindow = openTestWindow();
assertNotNull(newWindow);
Reference ref = createReference(queue, newWindow);
try {
newWindow.close();
newWindow = null;
checkRef(queue, ref);
} finally {
ref.clear();
}
} finally {
manageWindows(true);
}
}
/**
* Test for leaks if dialog is disposed before it is closed.
* This is really testing the framework rather than individual
* dialogs, since many dialogs or windows will fail if the shell
* is destroyed prior to closing them.
* See bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=123296
*/
@Test
public void testDestroyedDialogLeaks() throws Exception {
ReferenceQueue queue = new ReferenceQueue();
// Use SaveAs dialog because it's simple to invoke and utilizes
// framework function such as storing dialog bounds.
// We are really testing the framework itself here.
Dialog newDialog = new SaveAsDialog(fWin.getShell());
newDialog.setBlockOnOpen(false);
newDialog.open();
assertNotNull(newDialog);
Reference ref = createReference(queue, newDialog);
try {
// Dispose the window before closing it.
newDialog.getShell().dispose();
newDialog.close();
newDialog = null;
checkRef(queue, ref);
} finally {
ref.clear();
}
}
}