Skip to content

Commit

Permalink
Fix test for save state cleanup on snapshot save / bug 297635 #460
Browse files Browse the repository at this point in the history
The existing test TestBug297635 relies on reflection to test some
internal state change of the SavedState class that saves temporary
states until some save operation. The test was prone to fail because it
relied on internal state changes that depend an specific overall system
state (e.g., have an unsaved workspace state, so that no concurrent
automatic snapshot save is allowed to occur during test execution). It
used reflection to access an internal, highly volatile state.

The bug for which the test case serves as a regression test was due to
missing cleanup triggered by SavedState.forgetSavedTree(). Instead of
checking for internal state changes performed by the cleanup, the
rewritten test only checks for a call of the according method. To this
end, it temporarily inserts a spy on the SaveManager. Since a Workspace
and SaveManager are not easy to set up in an isolated way for testing
purposes, the test still relies on reflection, but only to inject a spy
on the SaveManager rather than to validate internal states.

Since the test is not required to be run as a session test anymore, it
is moved to the ordinary regression resource tests.

Fixes #460.
  • Loading branch information
HeikoKlare committed Oct 13, 2023
1 parent 5f450df commit f9a5b76
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 193 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Require-Bundle: org.eclipse.core.resources,
org.eclipse.core.filesystem,
org.eclipse.core.runtime,
org.eclipse.pde.junit.runtime;bundle-version="3.5.0"
Import-Package: org.mockito
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-17
Eclipse-BundleShape: dir
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@
Bug_029116.class, Bug_029671.class, Bug_029851.class, Bug_032076.class, Bug_044106.class, Bug_092108.class,
Bug_097608.class, Bug_098740.class, Bug_126104.class, Bug_127562.class, Bug_132510.class, Bug_134364.class,
Bug_147232.class, Bug_160251.class, Bug_165892.class, Bug_192631.class, Bug_226264.class, Bug_231301.class,
Bug_233939.class, Bug_265810.class, Bug_264182.class, Bug_288315.class, Bug_303517.class, Bug_329836.class,
Bug_331445.class, Bug_332543.class, Bug_378156.class, IFileTest.class, IFolderTest.class, IProjectTest.class,
Bug_233939.class, Bug_265810.class, Bug_264182.class, Bug_297635.class, Bug_288315.class, Bug_303517.class,
Bug_329836.class, Bug_331445.class, Bug_332543.class, Bug_378156.class,
IFileTest.class, IFolderTest.class, IProjectTest.class,
IResourceTest.class, IWorkspaceTest.class, LocalStoreRegressionTests.class, NLTest.class,
PR_1GEAB3C_Test.class,
PR_1GH2B0N_Test.class, PR_1GHOM0N_Test.class, Bug_530868.class, Bug_185247_recursiveLinks.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*******************************************************************************
* Copyright (c) 2010, 2015 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
* Alexander Kurtakov <akurtako@redhat.com> - Bug 459343
*******************************************************************************/
package org.eclipse.core.tests.resources.regression;

import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;

import java.lang.reflect.Field;
import java.util.function.Consumer;
import org.eclipse.core.internal.resources.SaveManager;
import org.eclipse.core.resources.ISaveContext;
import org.eclipse.core.resources.ISaveParticipant;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.tests.harness.BundleTestingHelper;
import org.eclipse.core.tests.resources.ResourceTest;
import org.eclipse.core.tests.resources.content.ContentTypeTest;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;

/**
* Tests regression of bug 297635
*/
public class Bug_297635 extends ResourceTest {

@Override
protected void setUp() throws Exception {
super.setUp();
BundleWithSaveParticipant.install();
saveFull();
}

@Override
protected void tearDown() throws Exception {
BundleWithSaveParticipant.uninstall();
super.tearDown();
}

public void testCleanSaveStateBySaveParticipantOnSnapshotSave() throws Exception {
executeWithSaveManagerSpy(saveManagerSpy -> {
try {
saveSnapshot(saveManagerSpy);
} catch (CoreException e) {
}
verify(saveManagerSpy).forgetSavedTree(BundleWithSaveParticipant.getBundleName());
});
}

private void saveFull() throws CoreException {
getWorkspace().save(true, getMonitor());
}

private void saveSnapshot(SaveManager saveManager) throws CoreException {
saveManager.save(ISaveContext.SNAPSHOT, true, null, getMonitor());
}

private void executeWithSaveManagerSpy(Consumer<SaveManager> executeOnSpySaveManager) throws Exception {
IWorkspace workspace = getWorkspace();
String saveManagerFieldName = "saveManager";
SaveManager originalSaveManager = (SaveManager) getField(workspace, saveManagerFieldName);
SaveManager spySaveManager = spy(originalSaveManager);
try {
setField(workspace, saveManagerFieldName, spySaveManager);
executeOnSpySaveManager.accept(spySaveManager);
} finally {
setField(workspace, saveManagerFieldName, originalSaveManager);
}
}

private static Object getField(Object object, String fieldName) throws Exception {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(object);
}

private static void setField(Object object, String fieldName, Object value) throws Exception {
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);
}

private static final class BundleWithSaveParticipant {
private static String TEST_BUNDLE_LOCATION = "content/bundle01";

private static Bundle bundle;

private static ISaveParticipant saveParticipant = new ISaveParticipant() {
@Override
public void doneSaving(ISaveContext context) {
// nothing to do
}

@Override
public void prepareToSave(ISaveContext context) {
context.needDelta();
context.needSaveNumber();
}

@Override
public void rollback(ISaveContext context) {
// nothing to do
}

@Override
public void saving(ISaveContext context) {
// nothing to do
}
};

public static String getBundleName() {
if (bundle == null) {
throw new IllegalStateException("Bundle has not been installed");
}
return bundle.getSymbolicName();
}

public static void uninstall() throws BundleException {
if (bundle == null) {
throw new IllegalStateException("Bundle has not been installed");
}
bundle.uninstall();
}

public static void install() throws Exception {
bundle = BundleTestingHelper.installBundle("", getContext(),
ContentTypeTest.TEST_FILES_ROOT + TEST_BUNDLE_LOCATION);
BundleTestingHelper.resolveBundles(getContext(), new Bundle[] { bundle });
bundle.start(Bundle.START_TRANSIENT);
registerSaveParticipant(bundle);
}

private static BundleContext getContext() {
return Platform.getBundle(PI_RESOURCES_TESTS).getBundleContext();
}

private static void registerSaveParticipant(Bundle saveParticipantsBundle) throws CoreException {
getWorkspace().addSaveParticipant(saveParticipantsBundle.getSymbolicName(), saveParticipant);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
TestBug12575.class, WorkspaceDescriptionTest.class, TestBug30015.class,
TestMasterTableCleanup.class,
ProjectPreferenceSessionTest.class, TestBug113943.class, TestCreateLinkedResourceInHiddenProject.class,
Bug_266907.class, TestBug297635.class, TestBug323833.class,
Bug_266907.class, TestBug323833.class,
org.eclipse.core.tests.resources.regression.TestMultipleBuildersOfSameType.class,
org.eclipse.core.tests.resources.usecase.SnapshotTest.class, ProjectDescriptionDynamicTest.class,
TestBug202384.class, TestBug369177.class, TestBug316182.class, TestBug294854.class, TestBug426263.class,
Expand Down

This file was deleted.

0 comments on commit f9a5b76

Please sign in to comment.