Skip to content

Some UI Tests leak Shells #2615

@jukzi

Description

@jukzi

i analyzed SwtLeakTestSuite for OOME #2432:

org.eclipse.ui.tests.dialogs.UIWizardsAuto.testWizardWindowTitle(org.eclipse.ui.tests.dialogs.UIWizardsAuto) Test leaked modal shell(s): [Dialog Verification, Dialog Verification]
org.eclipse.ui.tests.dialogs.UIPreferencesAuto.testFieldEditorEnablePref(org.eclipse.ui.tests.dialogs.UIPreferencesAuto) Test leaked modal shell(s): [Preferences, Dialog Verification]
org.eclipse.ui.tests.dialogs.DeprecatedUIPreferencesAuto.testFieldEditorEnablePref(org.eclipse.ui.tests.dialogs.DeprecatedUIPreferencesAuto) Test leaked modal shell(s): [Preferences, Dialog Verification]
org.eclipse.ui.tests.activities.MenusTest.testNoNamespaceFactory(org.eclipse.ui.tests.activities.MenusTest) Test leaked modal shell(s): [junit-workspace - Eclipse SDK]
org.eclipse.ui.tests.contexts.PartContextTest.testContextActivation(org.eclipse.ui.tests.contexts.PartContextTest) Test leaked modal shell(s): [junit-workspace - Eclipse SDK]
org.eclipse.ui.tests.contexts.PartContextTest.testBasicContextActivation(org.eclipse.ui.tests.contexts.PartContextTest) Test leaked modal shell(s): [junit-workspace - Eclipse SDK]
org.eclipse.ui.tests.contexts.PartContextTest.testPageBookPageContextActivation(org.eclipse.ui.tests.contexts.PartContextTest) Test leaked modal shell(s): [junit-workspace - ContextTest/test02.xml - Eclipse SDK]
org.eclipse.ui.tests.concurrency.NestedSyncExecDeadlockTest.testOK(org.eclipse.ui.tests.concurrency.NestedSyncExecDeadlockTest) Test leaked modal shell(s): []
org.eclipse.ui.tests.concurrency.NestedSyncExecDeadlockTest.testDeadlock(org.eclipse.ui.tests.concurrency.NestedSyncExecDeadlockTest) Test leaked modal shell(s): []
org.eclipse.ui.tests.concurrency.TestBug108162.testBug(org.eclipse.ui.tests.concurrency.TestBug108162) Test leaked modal shell(s): []
org.eclipse.ui.tests.concurrency.TestBug98621.testBug(org.eclipse.ui.tests.concurrency.TestBug98621) Test leaked modal shell(s): []
org.eclipse.ui.tests.concurrency.TestBug269121.testBug(org.eclipse.ui.tests.concurrency.TestBug269121) Test leaked modal shell(s): []
org.eclipse.ui.tests.statushandlers.SupportTrayTest.testSelfClosure(org.eclipse.ui.tests.statushandlers.SupportTrayTest) Test leaked modal shell(s): []
org.eclipse.ui.tests.statushandlers.SupportTrayTest.testJFacePolicySupportProvider(org.eclipse.ui.tests.statushandlers.SupportTrayTest) Test leaked modal shell(s): []
org.eclipse.ui.tests.statushandlers.WizardsStatusHandlingTestCase.testWizardWithNoDefaultContructor(org.eclipse.ui.tests.statushandlers.WizardsStatusHandlingTestCase) Test leaked modal shell(s): [Dialog Verification]
org.eclipse.ui.tests.stress.OpenCloseTest.testOpenCloseIntro(org.eclipse.ui.tests.stress.OpenCloseTest) Test leaked modal shell(s): []

image

I used this code for analysis (@RunWith(SwtLeakTestSuite.class) in UiTestSuite):

package org.eclipse.ui.tests;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
import org.junit.runner.Description;
import org.junit.runner.Result;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
import org.junit.runner.notification.RunNotifier;
import org.junit.runner.notification.StoppedByUserException;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.RunnerBuilder;

public class SwtLeakTestSuite extends Suite {

    private class TracingRunNotifier extends RunNotifier {
		IWorkbench workbench;
		Set<Shell> preExistingShells;
        private RunNotifier fNotifier;

        public TracingRunNotifier(RunNotifier notifier) {
            fNotifier = notifier;
        }

        @Override
        public void addListener(RunListener listener) {
            fNotifier.addListener(listener);
        }

        @Override
        public void removeListener(RunListener listener) {
            fNotifier.removeListener(listener);
        }

        @Override
        public void fireTestRunStarted(Description description) {
            fNotifier.fireTestRunStarted(description);
        }

        @Override
        public void fireTestRunFinished(Result result) {
            fNotifier.fireTestRunFinished(result);
        }

        @Override
        public void fireTestStarted(Description description) throws StoppedByUserException {
			workbench = PlatformUI.getWorkbench();
			preExistingShells = Set.of(workbench.getDisplay().getShells());
            fNotifier.fireTestStarted(description);
        }

        @Override
        public void fireTestFailure(Failure failure) {
            fNotifier.fireTestFailure(failure);
        }

        @Override
        public void fireTestAssumptionFailed(Failure failure) {
            fNotifier.fireTestAssumptionFailed(failure);
        }

        @Override
        public void fireTestIgnored(Description description) {
            fNotifier.fireTestIgnored(description);
        }

        @Override
        public void fireTestFinished(Description description) {
			// Check for shell leak.
			List<String> leakedModalShellTitles = new ArrayList<>();
			Shell[] shells = workbench.getDisplay().getShells();
			for (Shell shell : shells) {
				if (!shell.isDisposed() && !preExistingShells.contains(shell)) {
					leakedModalShellTitles.add(shell.getText());
//					shell.close();
				}
			}
			if (!leakedModalShellTitles.isEmpty()) {
				System.err.println(description.getClassName() + "." + description.getDisplayName()
						+ " Test leaked modal shell(s): ["
						+ String.join(", ", leakedModalShellTitles) + "]");
			}
            fNotifier.fireTestFinished(description);
        }

        @Override
        public void pleaseStop() {
            fNotifier.pleaseStop();
        }

        @Override
        public void addFirstListener(RunListener listener) {
            fNotifier.addFirstListener(listener);
        }
    }

	public SwtLeakTestSuite(Class<?> klass, RunnerBuilder builder) throws InitializationError {
        super(klass, builder);
    }

    @Override
    protected void runChild(Runner runner, RunNotifier notifier) {
        super.runChild(runner, new TracingRunNotifier(notifier));
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingregressiontestjunit test related things

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions