Bug 479450 - fix new race-condition in FeatureBasedLaunchTest

Change-Id: I6b91e49707f9edd79c2d00672c0016e425444a21
Signed-off-by: Hannes Wellmann <wellmann.hannes1@gmx.net>
Reviewed-on: https://git.eclipse.org/r/c/pde/eclipse.pde.ui/+/192067
Tested-by: Andrey Loskutov <loskutov@gmx.de>
Tested-by: PDE Bot <pde-bot@eclipse.org>
Reviewed-by: Andrey Loskutov <loskutov@gmx.de>
diff --git a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
index 1d65cea..5662fa6 100644
--- a/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
+++ b/ui/org.eclipse.pde.ui.tests/src/org/eclipse/pde/ui/tests/launcher/FeatureBasedLaunchTest.java
@@ -29,7 +29,6 @@
 import java.util.stream.Collectors;
 import org.eclipse.core.resources.*;
 import org.eclipse.core.runtime.*;
-import org.eclipse.core.runtime.jobs.Job;
 import org.eclipse.debug.core.*;
 import org.eclipse.jface.operation.IRunnableWithProgress;
 import org.eclipse.pde.core.plugin.IMatchRules;
@@ -1308,12 +1307,12 @@
 	}
 
 	private static void createFeatureProject(String id, String version, CoreConsumer<IFeature> featureSetup)
-			throws Throwable {
+			throws Exception {
 		createFeature(id, version, id + "_" + version.replace('.', '_'), featureSetup);
 	}
 
 	private static IFeature createFeature(String id, String version, String projectName,
-			CoreConsumer<IFeature> featureSetup) throws Throwable {
+			CoreConsumer<IFeature> featureSetup) throws Exception {
 		FeatureData featureData = new FeatureData();
 		featureData.id = id;
 		featureData.version = version;
@@ -1334,30 +1333,29 @@
 			}
 		};
 		operation.run(new NullProgressMonitor());
+
+		flushPendingResourceChangeEvents(project);
+
 		FeatureModelManager featureModelManager = PDECore.getDefault().getFeatureModelManager();
 		return featureModelManager.getFeatureModel(project).getFeature();
 	}
 
-	// Created Feature-projects get reloaded shortly after their creation, in
-	// the end of the auto-build job (due to some pending resource-changed
-	// events). In the beginning of the reload the feature model is reset and
-	// all fields become null/0. So if the model is read inbetween the model
-	// state could be inconsistent. This creates a race condition, which
-	// occasionally leads to test-failure. All my attempts to consume all
-	// resource-change events immediately to resolve the race-condition failed.
-	// I also tried to await the World-Changed event fired on a FeatureModel
-	// once it was reloaded but then the test spent most of its runtime waiting.
-	// Blocking all other operations was the simplest and fastest solution.
-	@BeforeClass
-	public static void acquireWorkspaceRuleToAvoidFeatureReloadByAutobuild() {
-		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
-		Job.getJobManager().beginRule(root, null);
-	}
-
-	@AfterClass
-	public static void releaseWorkspaceRule() {
-		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
-		Job.getJobManager().endRule(root);
+	private static void flushPendingResourceChangeEvents(IProject project) throws CoreException {
+		// The create-feature operation above creates/modifies the feature.xml,
+		// but not all resource-change-events generated by the operation are
+		// handled when the operation exists. If these change-events are not
+		// handled now they are handled asynchronously by the Autobuild-job. The
+		// problem is that the Feature-model is reset/reload while processing
+		// the changes (which first sets all fields to null/zero and then
+		// re-reads them), but the reload is NOT guarded by corresponding locks.
+		// So if this happens asynchronously and the model is read inbetween the model
+		// state could be inconsistent, which occasionally leads to
+		// test-failure. Furthermore the feature-models are only added to the
+		// FeatureModelManager while processing the resource-changes.
+		// Consequently it has to be ensured that all pending resource change
+		// events are properly processed now and in this thread:
+		// -> Building the project ensures this
+		ResourcesPlugin.getWorkspace().run(m -> project.build(IncrementalProjectBuilder.FULL_BUILD, null), null);
 	}
 
 	private static void addRequiredPlugin(IFeature feature, String id, String version, int matchRule)