CQ-4081: Initial import
diff --git a/tests/org.eclipse.e4.enterprise.installer.test/.classpath b/tests/org.eclipse.e4.enterprise.installer.test/.classpath
new file mode 100644
index 0000000..8a8f166
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<classpath>

+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>

+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>

+	<classpathentry kind="src" path="src"/>

+	<classpathentry kind="output" path="bin"/>

+</classpath>

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/.project b/tests/org.eclipse.e4.enterprise.installer.test/.project
new file mode 100644
index 0000000..c0e9017
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<projectDescription>

+	<name>org.eclipse.e4.enterprise.installer.test</name>

+	<comment></comment>

+	<projects>

+	</projects>

+	<buildSpec>

+		<buildCommand>

+			<name>org.eclipse.jdt.core.javabuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+		<buildCommand>

+			<name>org.eclipse.pde.ManifestBuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+		<buildCommand>

+			<name>org.eclipse.pde.SchemaBuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+		<buildCommand>

+			<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+	</buildSpec>

+	<natures>

+		<nature>org.eclipse.pde.PluginNature</nature>

+		<nature>org.eclipse.jdt.core.javanature</nature>

+		<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>

+	</natures>

+</projectDescription>

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/.settings/org.eclipse.jdt.core.prefs b/tests/org.eclipse.e4.enterprise.installer.test/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..eec20cf
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Mon Apr 20 09:46:07 CDT 2009

+eclipse.preferences.version=1

+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled

+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5

+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve

+org.eclipse.jdt.core.compiler.compliance=1.5

+org.eclipse.jdt.core.compiler.debug.lineNumber=generate

+org.eclipse.jdt.core.compiler.debug.localVariable=generate

+org.eclipse.jdt.core.compiler.debug.sourceFile=generate

+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error

+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error

+org.eclipse.jdt.core.compiler.source=1.5

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/META-INF/MANIFEST.MF b/tests/org.eclipse.e4.enterprise.installer.test/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..921c075
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/META-INF/MANIFEST.MF
@@ -0,0 +1,10 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Installer Test Fragment
+Bundle-SymbolicName: org.eclipse.e4.enterprise.installer.test
+Bundle-Version: 4.6.0.qualifier
+Fragment-Host: org.eclipse.e4.enterprise.installer;bundle-version="4.0.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Require-Bundle: org.junit,
+ org.easymock,
+ org.eclipse.e4.ui.test.utils
diff --git a/tests/org.eclipse.e4.enterprise.installer.test/about.html b/tests/org.eclipse.e4.enterprise.installer.test/about.html
new file mode 100644
index 0000000..f77f378
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/about.html
@@ -0,0 +1,22 @@
+<h1>About This Content</h1>
+
+23 June, 2010
+
+<h2>License</h2>
+
+<p>The Eclipse Foundation makes available all content in this plug-in
+("Content"). Unless otherwise indicated below, the Content is provided
+to you under the terms and conditions of the Eclipse Public License
+Version 1.0 ("EPL"). A copy of the EPL is available at
+http://www.eclipse.org/legal/epl-v10.html. For purposes of the EPL,
+"Program" will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse
+Foundation, the Content is being redistributed by another party
+("Redistributor") and different terms and conditions may apply to your
+use of any object code in the Content. Check the Redistributor’s
+license that was provided with the Content. If no such license exists,
+contact the Redistributor. Unless otherwise indicated below, the terms
+and conditions of the EPL still apply to any source code in the
+Content and such source code may be obtained at
+http://www.eclipse.org.</p>
diff --git a/tests/org.eclipse.e4.enterprise.installer.test/build.properties b/tests/org.eclipse.e4.enterprise.installer.test/build.properties
new file mode 100644
index 0000000..41eb6ad
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/build.properties
@@ -0,0 +1,4 @@
+source.. = src/

+output.. = bin/

+bin.includes = META-INF/,\

+               .

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/AbstractBundleTest.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/AbstractBundleTest.java
new file mode 100644
index 0000000..6619aa3
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/AbstractBundleTest.java
@@ -0,0 +1,95 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer;

+

+import java.io.File;

+import java.io.IOException;

+import java.net.URL;

+import java.util.List;

+

+import org.eclipse.e4.enterprise.installer.internal.site.InstallationSite;

+import org.eclipse.e4.enterprise.installer.internal.site.InstallationSiteManager;

+import org.eclipse.e4.ui.test.utils.FixturesLocation;
+import org.eclipse.e4.ui.test.utils.TestCaseX;
+

+

+public abstract class AbstractBundleTest extends TestCaseX {

+

+	public static final URL SITE400_FIXTURE_URL = makeFixtureURL("fixtures/site_4.0.0/site.xml");

+	public static final URL SITE401_FIXTURE_URL = makeFixtureURL("fixtures/site_4.0.1/site.xml");

+	public static final URL SITE500_FIXTURE_URL = makeFixtureURL("fixtures/site_5.0.0/site.xml");

+	

+	

+	protected BundleUpdater testee;

+	

+	private static final String INSTALL_TO_SITE_DIR = System.getProperty("java.io.tmpdir") + File.separator + "AbstractBundleTest";

+			

+	protected File downloadRootDir;

+		

+	public AbstractBundleTest() {

+		super();

+	}

+

+	@Override

+	protected void setUp() throws Exception {

+		//delete anything in the INSTALL_TO_SITE_DIR

+		downloadRootDir = new File(INSTALL_TO_SITE_DIR);

+		testee = new BundleUpdater();

+

+		//if any tests are forced to stop AFTER the set-up but before the tearDown then we might have 

+		//a problem, so we are just running tearDown first for safety

+		tearDown();

+	}

+

+	@Override

+	protected void tearDown() throws Exception {

+		//find the site that exists and get rid of it

+		InstallationSiteManager builder = new InstallationSiteManager(downloadRootDir);

+		InstallationSite currentSite = builder.find();

+		currentSite.removeFromConfiguredSites();

+		deleteDir(downloadRootDir);

+	}

+

+	protected int countOccurancesOfListItemsStartingWithPrefix(List<String> list, String prefix) {

+		int count = 0;

+		for (String string : list) {

+			if (string.startsWith(prefix))

+				count++;

+		}

+		return count;

+	}

+	

+	private static URL makeFixtureURL(String fixturePath) {

+		// DJO: FIXME: Why does this ignore the fixturePath parameter?  This is smelly!  Phew!

+		try {

+//			return FileLocator.toFileURL(find);

+			return new URL(FixturesLocation.FIXTURE_ROOT);

+		} catch (IOException ex) {

+			throw new RuntimeException(ex);

+		}

+	}

+	

+	private boolean deleteDir(File fileOrDir) {

+		if (fileOrDir.isDirectory()) {

+			String[] children = fileOrDir.list();

+			for (int i = 0; i < children.length; i++) {

+				boolean success = deleteDir(new File(fileOrDir, children[i]));

+				if (!success) {

+					return false;

+				}

+			}

+		}

+	

+		// The directory or file can now be deleted

+		return fileOrDir.delete();

+	}

+

+}
\ No newline at end of file
diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/BundleUpdaterConfigTest.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/BundleUpdaterConfigTest.java
new file mode 100644
index 0000000..ef08e05
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/BundleUpdaterConfigTest.java
@@ -0,0 +1,321 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer;

+

+import static org.eclipse.e4.enterprise.installer.BundleUpdaterConfig.DOWNLOAD_ROOT_KEY;

+

+import java.io.ByteArrayInputStream;

+import java.io.File;

+import java.net.MalformedURLException;

+import java.net.URL;

+import java.util.Properties;

+import java.util.Set;

+

+import org.eclipse.e4.enterprise.installer.BundleUpdaterConfig;

+import org.eclipse.e4.enterprise.installer.FeatureVersionedIdentifier;

+import org.eclipse.e4.enterprise.installer.InstallError;

+

+import junit.framework.TestCase;

+

+

+public class BundleUpdaterConfigTest extends TestCase {

+

+	// convertToFeatureVersionSet

+	// -------------------------------------------------------------------------------

+

+	public void testConvertToFeatureVersionSet_MoreThan2SpaceSeparatedString_ThrowsException() throws Exception {

+		String id = "featureID";

+		String version = "1.2.3";

+		String spurious = "spuriousExtraThing";

+

+		String line = id + "  " + version + "  " + spurious;

+

+		try {

+			BundleUpdaterConfig.convertToFeatureVersionSet(convertStringToStream(line));

+			fail();

+		} catch (InstallError e) {

+			// want to be here

+		}

+

+	}

+

+	public void testConvertToFeatureVersionSet_InLineCommentsIgnored() throws Exception {

+		String id1 = "featureID1";

+		String version1 = "1.2.31";

+		String id2 = "featureID2";

+		String version2 = "1.2.32";

+		String id3 = "featureID3";

+		String version3 = "1.2.33";

+		String id4 = "featureID4";

+		String version4 = "1.2.34";

+

+		String comment = "# I am a comment because I start with a hash.";

+

+		String line1 = id1 + " " + version1 + comment + "\n";

+		String line2 = id2 + "  " + version2 + comment + "\n";

+		String line3 = id3 + "   " + version3 + comment + "\n";

+		String line4 = id4 + "     " + version4 + comment + "\n";

+

+		String input = line1 + line2 + line3 + line4;

+

+		Set<FeatureVersionedIdentifier> result = BundleUpdaterConfig.convertToFeatureVersionSet(convertStringToStream(input));

+

+		assertEquals(4, result.size());

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id1, version1)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id2, version2)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id3, version3)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id4, version4)));

+	}

+

+	public void testConvertToFeatureVersionSet_CommentLinesIgnored() throws Exception {

+		String id1 = "featureID1";

+		String version1 = "1.2.31";

+		String id2 = "featureID2";

+		String version2 = "1.2.32";

+		String id3 = "featureID3";

+		String version3 = "1.2.33";

+		String id4 = "featureID4";

+		String version4 = "1.2.34";

+

+		String line1 = id1 + " " + version1 + "\n";

+		String line2 = id2 + "  " + version2 + "\n";

+		String line3 = id3 + "   " + version3 + "\n";

+		String line4 = id4 + "     " + version4 + "\n";

+

+		String commentLine = "# I am a comment because I start with a hash.  \n";

+

+		String input = line1 + commentLine + line2 + commentLine + line3 + commentLine + line4;

+

+		Set<FeatureVersionedIdentifier> result = BundleUpdaterConfig.convertToFeatureVersionSet(convertStringToStream(input));

+

+		assertEquals(4, result.size());

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id1, version1)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id2, version2)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id3, version3)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id4, version4)));

+	}

+

+	public void testConvertToFeatureVersionSet_EmptyLinesIgnored() throws Exception {

+		String id1 = "featureID1";

+		String version1 = "1.2.31";

+		String id2 = "featureID2";

+		String version2 = "1.2.32";

+		String id3 = "featureID3";

+		String version3 = "1.2.33";

+		String id4 = "featureID4";

+		String version4 = "1.2.34";

+

+		String line1 = id1 + " " + version1 + "\n";

+		String line2 = id2 + "  " + version2 + "\n";

+		String line3 = id3 + "   " + version3 + "\n";

+		String line4 = id4 + "     " + version4 + "\n";

+

+		String blankLine = "  \n";

+

+		String input = line1 + blankLine + line2 + blankLine + line3 + blankLine + line4;

+

+		Set<FeatureVersionedIdentifier> result = BundleUpdaterConfig.convertToFeatureVersionSet(convertStringToStream(input));

+

+		assertEquals(4, result.size());

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id1, version1)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id2, version2)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id3, version3)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id4, version4)));

+	}

+

+	public void testConvertToFeatureVersionSet_UnspecifiedVersion_defaultsTo000() throws Exception {

+		String id = "featureID";

+		String version = "";

+		Set<FeatureVersionedIdentifier> result = BundleUpdaterConfig.convertToFeatureVersionSet(convertStringToStream(id + "  " + version));

+

+		assertEquals(1, result.size());

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id, "0.0.0")));

+	}

+

+	public void testConvertToFeatureVersionSet_ManyItems_returnsCorrectlyParsedSet() throws Exception {

+		String id1 = "featureID1";

+		String version1 = "1.2.31";

+		String id2 = "featureID2";

+		String version2 = "1.2.32";

+		String id3 = "featureID3";

+		String version3 = "1.2.33";

+		String id4 = "featureID4";

+		String version4 = "1.2.34";

+

+		String line1 = id1 + " " + version1 + "\n";

+		String line2 = id2 + "  " + version2 + "\n";

+		String line3 = id3 + "   " + version3 + "\n";

+		String line4 = id4 + "     " + version4 + "\n";

+

+		String input = line1 + line2 + line3 + line4;

+

+		Set<FeatureVersionedIdentifier> result = BundleUpdaterConfig.convertToFeatureVersionSet(convertStringToStream(input));

+

+		assertEquals(4, result.size());

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id1, version1)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id2, version2)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id3, version3)));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id4, version4)));

+	}

+

+	public void testConvertToFeatureVersionSet_singleItem_returnsCorrectlyParsedSet() throws Exception {

+		String id = "featureID";

+		String version = "1.2.3";

+		Set<FeatureVersionedIdentifier> result = BundleUpdaterConfig.convertToFeatureVersionSet(convertStringToStream(id + "  " + version));

+

+		assertEquals(1, result.size());

+		assertTrue(result.contains(new FeatureVersionedIdentifier(id, version)));

+	}

+

+	public void testConvertToFeatureVersionSet_EmptyStream_returnsEmptySet() throws Exception {

+		Set<FeatureVersionedIdentifier> result = BundleUpdaterConfig.convertToFeatureVersionSet(convertStringToStream(""));

+

+		assertEquals(0, result.size());

+	}

+

+	private ByteArrayInputStream convertStringToStream(String contents) {

+		ByteArrayInputStream inputStream = new ByteArrayInputStream(contents.getBytes());

+		return inputStream;

+	}

+

+	// parseURLs

+	// -------------------------------------------------------------------------------

+

+	public void testParseURLS_WithAtLeastOneDuffOne_throwsException() throws Exception {

+		String urlAsString1 = "http://www.eclipse.org";

+		String urlAsString2 = "http://news.bbc.co.uk";

+		String urlAsString3 = "I-am-not-a-valid-url";

+		String urlAsString4 = "http://www.theregister.co.uk/";

+

+		String input = urlAsString1 + " " + urlAsString2 + "    " + urlAsString3 + "     " + urlAsString4 + "   ";

+

+		try {

+			BundleUpdaterConfig.parseURLs(input);

+			fail();

+		} catch (InstallError e) {

+			assertTrue(e.getCause() instanceof MalformedURLException);

+		}

+	}

+

+	public void testParseURLS_N_ValidURLsWithVariousSpaces_parsedCorrectly() throws Exception {

+		String urlAsString1 = "http://www.eclipse.org";

+		String urlAsString2 = "http://news.bbc.co.uk";

+		String urlAsString3 = "http://slashdot.org/";

+		String urlAsString4 = "http://www.theregister.co.uk/";

+

+		String s = " ";

+

+		String input = s + s + s + urlAsString1 + s + urlAsString2 + s + s + s + urlAsString3 + s + s + s + s + s + urlAsString4 + s + s;

+

+		URL[] result = BundleUpdaterConfig.parseURLs(input);

+

+		assertEquals(4, result.length);

+		assertEquals(urlAsString1, result[0].toString());

+		assertEquals(urlAsString2, result[1].toString());

+		assertEquals(urlAsString3, result[2].toString());

+		assertEquals(urlAsString4, result[3].toString());

+	}

+

+	public void testParseURLS_TwoValidURLsWithManySpaces_parsedCorrectly() throws Exception {

+		String urlAsString1 = "http://www.eclipse.org";

+		String urlAsString2 = "http://news.bbc.co.uk";

+

+		String fourSpaces = "    ";

+		String input = urlAsString1 + fourSpaces + urlAsString2;

+

+		URL[] result = BundleUpdaterConfig.parseURLs(input);

+

+		assertEquals(2, result.length);

+		assertEquals(urlAsString1, result[0].toString());

+		assertEquals(urlAsString2, result[1].toString());

+	}

+

+	public void testParseURLS_TwoValidURLs_parsedCorrectly() throws Exception {

+		String urlAsString1 = "http://www.eclipse.org";

+		String urlAsString2 = "http://news.bbc.co.uk";

+

+		String input = urlAsString1 + " " + urlAsString2;

+

+		URL[] result = BundleUpdaterConfig.parseURLs(input);

+

+		assertEquals(2, result.length);

+		assertEquals(urlAsString1, result[0].toString());

+		assertEquals(urlAsString2, result[1].toString());

+	}

+

+	public void testParseURLS_SingleURLWithPadding_parsedCorrectly() throws Exception {

+		String urlAsString = "  http://www.eclipse.org    ";

+

+		URL[] result = BundleUpdaterConfig.parseURLs(urlAsString);

+

+		assertEquals(1, result.length);

+		assertEquals(urlAsString.trim(), result[0].toString());

+	}

+

+	public void testParseURLS_SingleURL_parsedCorrectly() throws Exception {

+		String urlAsString = "http://www.eclipse.org";

+

+		URL[] result = BundleUpdaterConfig.parseURLs(urlAsString);

+

+		assertEquals(1, result.length);

+		assertEquals(urlAsString, result[0].toString());

+	}

+

+	public void testParseURLS_KeyPresentValueIsSpace_throwsException() throws Exception {

+		try {

+			BundleUpdaterConfig.parseURLs(" ");

+			fail();

+		} catch (InstallError e) {

+			assertTrue(e.getCause() instanceof MalformedURLException);

+		}

+	}

+

+	public void testParseURLS_KeyPresentValueIsEmptyString_throwsException() throws Exception {

+		try {

+			BundleUpdaterConfig.parseURLs("");

+			fail();

+		} catch (InstallError e) {

+			assertTrue(e.getCause() instanceof MalformedURLException);

+		}

+	}

+

+	public void testParseURLS_KeyPresentButNoValue_ThrowsException() throws Exception {

+		try {

+			BundleUpdaterConfig.parseURLs(null);

+			fail();

+		} catch (InstallError e) {

+			// want to be here

+		}

+	}

+

+	public void testFindDownloadDirectoryRoot_PropertySet_returnsValueOfProperty() throws Exception {

+		String expectedPath = "c:/temp/mytestvalue";

+		Properties properties = new Properties();

+		properties.put(DOWNLOAD_ROOT_KEY, expectedPath);

+		BundleUpdaterConfig.props = properties; // inject our properties into

+		// BundleUpdaterConfig

+

+		File actual = BundleUpdaterConfig.findDownloadDirectoryRoot();

+

+		File expected = new File(expectedPath);

+

+		assertEquals(expected, actual);

+	}

+

+	public void testFindDownloadDirectoryRoot_NoPropertySet_returnsDefaultDownloadRoot() throws Exception {

+		BundleUpdaterConfig.props = new Properties();

+

+		File actual = BundleUpdaterConfig.findDownloadDirectoryRoot();

+		File expected = BundleUpdaterConfig.getDefaultDownloadRoot();

+

+		assertEquals(expected, actual);

+	}

+}

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/BundleUpdaterTest.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/BundleUpdaterTest.java
new file mode 100644
index 0000000..8b22d79
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/BundleUpdaterTest.java
@@ -0,0 +1,600 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer;

+

+import java.io.File;

+import java.io.IOException;

+import java.net.MalformedURLException;

+import java.net.URL;

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.HashSet;

+import java.util.List;

+import java.util.Set;

+

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.core.runtime.IProgressMonitor;

+import org.eclipse.e4.enterprise.installer.internal.FeatureReferenceTree;

+import org.eclipse.e4.enterprise.installer.internal.site.InstallationSite;

+import org.eclipse.e4.enterprise.installer.internal.site.InstallationSiteManager;

+import org.eclipse.e4.enterprise.installer.internal.site.StubInstallationSite;

+import org.eclipse.e4.ui.test.utils.FixturesLocation;
+import org.eclipse.e4.ui.test.utils.TestCaseX;
+import org.eclipse.update.core.IFeature;

+import org.eclipse.update.core.IFeatureReference;

+import org.eclipse.update.core.ISite;

+import org.eclipse.update.core.VersionedIdentifier;

+

+

+public class BundleUpdaterTest extends TestCaseX {

+	private static final String FIXTURE_FEATURE_ID = "org.eclipse.e4.enterprise.installer.test.fixture.feature";

+

+	private static final String FIXTURE_FEATURE_ID_A = "org.eclipse.e4.enterprise.installer.test.fixture.many_a.feature";

+	private static final String FIXTURE_FEATURE_ID_B = "org.eclipse.e4.enterprise.installer.test.fixture.many_b.feature";

+	private static final String FIXTURE_FEATURE_ID_C = "org.eclipse.e4.enterprise.installer.test.fixture.many_c.feature";

+

+	private static final String SITE400_FIXTURE = FixturesLocation.FIXTURE_ROOT + "/site_4.0.0/site.xml";

+	private static final String SITEABC_FIXTURE = FixturesLocation.FIXTURE_ROOT + "/site_ABC/site.xml";

+	private static final String SITE401_FIXTURE = FixturesLocation.FIXTURE_ROOT + "/site_4.0.1/site.xml";

+	private static final String SITE500_FIXTURE = FixturesLocation.FIXTURE_ROOT + "/site_5.0.0/site.xml";

+	private static final String FOO_FIXTURE = FixturesLocation.FIXTURE_ROOT + "/no_site_ABC/foo.xml";

+

+	private URL SITE400_URL;

+	private URL SITEABC_URL;

+	private URL SITE401_URL;

+	private URL SITE500_URL;

+	private URL FOO_URL;

+

+

+	BundleUpdater testee;

+

+	public BundleUpdaterTest() throws MalformedURLException {

+		SITE400_URL = new URL(SITE400_FIXTURE);

+		SITEABC_URL = new URL(SITEABC_FIXTURE);

+		SITE401_URL = new URL(SITE401_FIXTURE);

+		SITE500_URL = new URL(SITE500_FIXTURE);

+		FOO_URL = new URL(FOO_FIXTURE);

+

+	}

+

+	protected void setUp() throws Exception {

+		super.setUp();

+		testee = new BundleUpdater(null);

+	}

+

+	protected void tearDown() throws Exception {

+		super.tearDown();

+	}

+

+

+	// Custom-Asserts--------------------------------------------------------------------------------------------------------------------

+

+	private void assertFeatureFoundIn(List<IFeatureReference> list, String featureID) throws Exception {

+		for (IFeatureReference feature : list) {

+			if (feature.getVersionedIdentifier().getIdentifier().equals(featureID)) {

+				return;

+			}

+		}

+		fail("Expected pruned feature to install list to contain: " + featureID);

+	}

+

+	// calculateFeaturesReferencesToInstall-----------------------------------------------------------------------------------------------

+

+	public void testVersionQualifiersAreOrderedAsAStringComparisonWhenUsingList() throws InstallError {		

+		List<IFeatureReference> featuresToLookIn = new ArrayList<IFeatureReference>();

+		Set<FeatureVersionedIdentifier> featuresToProvision = new HashSet<FeatureVersionedIdentifier>();

+		

+		String featureID = "MyFeature";

+		featuresToLookIn.add(FeatureReferenceMother.createFeatureReferenceFromFVIWithNoChildren(

+				new FeatureVersionedIdentifier(featureID, "1.0.0.M7")));

+		IFeatureReference expectedIFR = FeatureReferenceMother.createFeatureReferenceFromFVIWithNoChildren(

+				new FeatureVersionedIdentifier(featureID, "1.0.0.R3"));

+		featuresToLookIn.add(expectedIFR);

+		

+		featuresToProvision.add(new FeatureVersionedIdentifier(featureID, "0.0.0"));

+		

+		List<IFeatureReference> result = testee.resolveVersionNumbersAsIFRList(featuresToLookIn, featuresToProvision, true);

+		

+		assertEquals(1, result.size());

+		assertTrue(result.contains(expectedIFR));

+	}

+	

+	public void testVersionQualifiersAreOrderedAsAStringComparisonWhenUsingSet() throws InstallError {		

+		FeatureReferenceTree tree = new FeatureReferenceTree();

+		String featureID = "MyFeature";

+		FeatureVersionedIdentifier oldFvi = new FeatureVersionedIdentifier(featureID, "1.0.0.M7");

+		IFeatureReference oldFeature = FeatureReferenceMother.createFeatureReferenceFromFVIWithNoChildren(oldFvi);

+				

+		FeatureVersionedIdentifier newFvi = new FeatureVersionedIdentifier(featureID, "1.0.0.R3");

+		IFeatureReference newFeature = FeatureReferenceMother.createFeatureReferenceFromFVIWithNoChildren(newFvi);

+		

+		tree.add(newFeature);

+		tree.add(oldFeature);

+				

+		Set<FeatureVersionedIdentifier> setToProvision = new HashSet<FeatureVersionedIdentifier>();

+		setToProvision.add(new FeatureVersionedIdentifier(featureID, "0.0.0"));

+		

+		Set<FeatureVersionedIdentifier> result = testee.resolveVersionNumbersAsFVISet(tree, setToProvision, true);

+		

+		assertEquals(1, result.size());

+		assertTrue(result.contains(newFvi));	

+	}

+	

+	// 0 FRs come from local, the rest from remote

+	public void testCalculateFeaturesReferencesToInstall_0FeatureRefsComeFromTheLocalSite() throws Exception {

+		List<IFeatureReference> local = new ArrayList<IFeatureReference>();

+		List<IFeatureReference> remote = new ArrayList<IFeatureReference>();

+		remote.add(new SpecialStubFeatureReference("f1", false));

+		remote.add(new SpecialStubFeatureReference("f2", false));

+		remote.add(new SpecialStubFeatureReference("f3", false));

+

+		List<IFeatureReference> result = testee.calculateFeaturesReferencesToInstall(remote, local);

+

+		for (IFeatureReference featureReference : result) {

+			SpecialStubFeatureReference stubFR = (SpecialStubFeatureReference) featureReference;

+			assertFalse("featureName:" + stubFR.name, stubFR.isLocal);

+		}

+	}

+

+	// 1 FR comes from local, the rest from remote

+	public void testCalculateFeaturesReferencesToInstall_1FeatureRefComesFromTheLocalSite() throws Exception {

+		String featureOnBothLocalAndRemote = "f2";

+		List<IFeatureReference> local = new ArrayList<IFeatureReference>();

+		local.add(new SpecialStubFeatureReference(featureOnBothLocalAndRemote, true));

+		List<IFeatureReference> remote = new ArrayList<IFeatureReference>(); 

+		remote.add(new SpecialStubFeatureReference("f1", false));

+		remote.add(new SpecialStubFeatureReference(featureOnBothLocalAndRemote, false));

+		remote.add(new SpecialStubFeatureReference("f3", false));

+

+		List<IFeatureReference> result = testee.calculateFeaturesReferencesToInstall(remote, local);

+

+		for (IFeatureReference featureReference : result) {

+			SpecialStubFeatureReference stubFR = (SpecialStubFeatureReference) featureReference;

+			String name = stubFR.name;

+			if (featureOnBothLocalAndRemote.equals(name)) {

+				assertTrue("featureName:" + name, stubFR.isLocal);

+			} else {

+				assertFalse("featureName:" + name, stubFR.isLocal);

+			}

+		}

+	}

+

+	// n FRs come from local, the rest from remote

+	public void testCalculateFeaturesReferencesToInstall_ManyFeatureRefComesFromTheLocalSite() throws Exception {

+		String featureOnBothLocalAndRemote1 = "f2";

+		String featureOnBothLocalAndRemote2 = "f3";

+		

+		HashSet<String> localNames = new HashSet<String>(2);

+		localNames.add(featureOnBothLocalAndRemote1);

+		localNames.add(featureOnBothLocalAndRemote2);

+		

+		List<IFeatureReference> local = new ArrayList<IFeatureReference>();

+		local.add(new SpecialStubFeatureReference(featureOnBothLocalAndRemote1, true));

+		local.add(new SpecialStubFeatureReference(featureOnBothLocalAndRemote2, true));

+		

+		List<IFeatureReference> remote = new ArrayList<IFeatureReference>();

+		remote.add(new SpecialStubFeatureReference("f1", false));

+		remote.add(new SpecialStubFeatureReference(featureOnBothLocalAndRemote1, false));

+		remote.add(new SpecialStubFeatureReference(featureOnBothLocalAndRemote2, false));

+		remote.add(new SpecialStubFeatureReference("f4", false));

+		

+		List<IFeatureReference> result = testee.calculateFeaturesReferencesToInstall(remote, local);

+

+		for (IFeatureReference featureReference : result) {

+			SpecialStubFeatureReference stubFR = (SpecialStubFeatureReference) featureReference;

+			String name = stubFR.name;

+			if (localNames.contains(name)) {

+				assertTrue("featureName:" + name, stubFR.isLocal);

+			} else {

+				assertFalse("featureName:" + name, stubFR.isLocal);

+			}

+		}

+	}

+	// all come from local.

+	public void testCalculateFeaturesReferencesToInstall_AllFeatureRefsComeFromTheLocalSite() throws Exception {

+		List<IFeatureReference> local = new ArrayList<IFeatureReference>(); 

+		local.add(new SpecialStubFeatureReference("f1", true));

+		local.add(new SpecialStubFeatureReference("f2", true));

+		local.add(new SpecialStubFeatureReference("f3", true));

+		List<IFeatureReference> remote = new ArrayList<IFeatureReference>();

+

+		List<IFeatureReference> result = testee.calculateFeaturesReferencesToInstall(remote, local);

+

+		for (IFeatureReference featureReference : result) {

+			SpecialStubFeatureReference stubFR = (SpecialStubFeatureReference) featureReference;

+			assertTrue("featureName:" + stubFR.name, stubFR.isLocal);

+		}

+	}

+	// setFeaturesToProvisionAsSetOfAllFeaturesOnRemoteSitesIfUnspecified-----------------------------------------------------------------

+

+	public void testSetFeaturesToProvisionAsSetOfAllFeaturesOnRemoteSitesIfUnspecified_whenProvisingSetNull_CopiesFromIFRs() throws Exception {

+		FeatureReferenceTree input = testee.getAllFeaturesFromUpdateSites(new URL[] { SITEABC_URL });

+

+		Set<FeatureVersionedIdentifier> result = testee.setFeaturesToProvisionToBeOfAllFeaturesOnRemoteSitesIfUnspecified(null, input);

+

+		assertEquals(3, result.size());

+		assertTrue(result.contains(new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID_A, "1.0.0")));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID_B, "1.0.0")));

+		assertTrue(result.contains(new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID_C, "1.0.0")));

+	}

+

+	public void testSetFeaturesToProvisionAsSetOfAllFeaturesOnRemoteSitesIfUnspecified_returnsFirstArgWhenFirstArgNonNull() throws Exception {

+		Set<FeatureVersionedIdentifier> input = new HashSet<FeatureVersionedIdentifier>();

+		input.add(new FeatureVersionedIdentifier("oink", "1.2.3"));

+		input.add(new FeatureVersionedIdentifier("moo", "2.3.4"));

+		input.add(new FeatureVersionedIdentifier("baah", "3.4.5"));

+

+		Set<FeatureVersionedIdentifier> result = testee.setFeaturesToProvisionToBeOfAllFeaturesOnRemoteSitesIfUnspecified(input, new FeatureReferenceTree());

+

+		assertTrue(input.equals(result));

+	}

+

+

+	// extractCorrectVersionsOfFeatureReferenceToProvision------------------------------------------------------------------------------------

+

+	public void testExtractCorrectVersionsOfFeatureReferenceToProvision_whereFeatureToBeProvisionedHasVersion000_updateSitesHaveMultipleVersions_getsLatestVersions_andIsNotOrderDependent() throws Exception {

+		Set<FeatureVersionedIdentifier> featureIDsToProvision = new HashSet<FeatureVersionedIdentifier>();

+		featureIDsToProvision.add(new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID, "0.0.0"));

+		

+		FeatureVersionedIdentifier expectedFVI = new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID, "4.0.1");

+		

+		// Ordered 400, 401

+		FeatureReferenceTree featuresOnUpdateSite = testee.getAllFeaturesFromUpdateSites(new URL[] { SITE400_URL, SITE401_URL });

+		List<IFeatureReference> result = testee.resolveVersionNumbersAsIFRList(featuresOnUpdateSite.getAllReferences(), featureIDsToProvision, true);

+		assertEquals(1, result.size());

+		assertEquals(expectedFVI, new FeatureVersionedIdentifier(result.get(0)));

+		

+		// Ordered 401, 400 - this was causing an error

+		featuresOnUpdateSite = testee.getAllFeaturesFromUpdateSites(new URL[] { SITE401_URL, SITE400_URL });

+		result = testee.resolveVersionNumbersAsIFRList(featuresOnUpdateSite.getAllReferences(), featureIDsToProvision, true);

+		assertEquals(1, result.size());

+		assertEquals(expectedFVI, new FeatureVersionedIdentifier(result.get(0)));

+	}

+	

+	public void testExtractCorrectVersionsOfFeatureReferenceToProvision_featureToProvisionVersion000_UpdateSiteFeatureVersionNot000() throws Exception {

+		Set<FeatureVersionedIdentifier> featureIDsToProvision = new HashSet<FeatureVersionedIdentifier>();

+		featureIDsToProvision.add(new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID, "0.0.0"));

+		

+		FeatureReferenceTree featuresOnUpdateSite = testee.getAllFeaturesFromUpdateSites(new URL[] { SITE400_URL });

+

+		List<IFeatureReference> result = testee.resolveVersionNumbersAsIFRList(featuresOnUpdateSite.getAllReferences(), featureIDsToProvision, true);

+

+		assertEquals(1, result.size());

+		assertEquals(featuresOnUpdateSite.getAllReferences().get(0), result.get(0));

+	}

+

+	

+	public void testExtractCorrectVersionsOfFeatureReferenceToProvision_FeatureNotAvailableThrowsException() throws Exception {

+		Set<FeatureVersionedIdentifier> featureIDsToProvision = new HashSet<FeatureVersionedIdentifier>();

+		featureIDsToProvision.add(new FeatureVersionedIdentifier("a_feature_that_doesnt_exist on_the_site", "1.0.0"));

+

+		try {

+			testee.resolveVersionNumbersAsIFRList(new ArrayList<IFeatureReference>(), featureIDsToProvision, true);

+			fail("Should have failed");

+		} catch (InstallError e) {

+			// success

+		}

+	}

+

+	public void testExtractCorrectVersionsOfFeatureReferenceToProvision_FeatureNotAvailableStillSucceeds() throws Exception {

+		Set<FeatureVersionedIdentifier> featureIDsToProvision = new HashSet<FeatureVersionedIdentifier>();

+		featureIDsToProvision.add(new FeatureVersionedIdentifier("a_feature_that_doesnt_exist on_the_site", "1.0.0"));

+

+		try {

+			testee.resolveVersionNumbersAsIFRList(new ArrayList<IFeatureReference>(), featureIDsToProvision, false);

+			// success

+		} catch (InstallError e) {

+			fail("Should not have failed");

+		}

+	}

+

+	public void testExtractCorrectVersionsOfFeatureReferenceToProvision_featureToProvisionSameAsUpdateSiteFeatures_oneFeature() throws Exception {

+		Set<FeatureVersionedIdentifier> featureIDsToProvision = new HashSet<FeatureVersionedIdentifier>();

+		featureIDsToProvision.add(new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID, "4.0.0"));

+		FeatureReferenceTree featuresOnUpdateSite = testee.getAllFeaturesFromUpdateSites(new URL[] { SITE400_URL });

+

+		List<IFeatureReference> result = testee.resolveVersionNumbersAsIFRList(featuresOnUpdateSite.getAllReferences(), featureIDsToProvision, true);

+

+		assertEquals(1, result.size());

+		assertEquals(featuresOnUpdateSite.getAllReferences().get(0), result.get(0));

+	}

+

+	public void testExtractCorrectVersionsOfFeatureReferenceToProvision_featureToProvisionSameAsUpdateSiteFeatures_threeFeatures() throws Exception {

+		Set<FeatureVersionedIdentifier> featureIDsToProvision = new HashSet<FeatureVersionedIdentifier>();

+		featureIDsToProvision.add(new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID_A, "1.0.0"));

+		featureIDsToProvision.add(new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID_B, "1.0.0"));

+		featureIDsToProvision.add(new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID_C, "1.0.0"));

+		FeatureReferenceTree featuresOnUpdateSite = testee.getAllFeaturesFromUpdateSites(new URL[] { SITEABC_URL });

+

+		List<IFeatureReference> result = testee.resolveVersionNumbersAsIFRList(featuresOnUpdateSite.getAllReferences(), featureIDsToProvision, true);

+

+		assertEquals(3, result.size());

+		

+		assertFeatureFoundIn(result, FIXTURE_FEATURE_ID_A);

+		assertFeatureFoundIn(result, FIXTURE_FEATURE_ID_B);

+		assertFeatureFoundIn(result, FIXTURE_FEATURE_ID_C);				

+	}

+

+	// test where provisioning list is a subset of features on site

+	public void testExtractCorrectVersionsOfFeatureReferenceToProvision_featureToProvisionFewerThanUpdateSiteFeatures() throws Exception {

+		Set<FeatureVersionedIdentifier> featureIDsToProvision = new HashSet<FeatureVersionedIdentifier>();

+		featureIDsToProvision.add(new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID_A, "1.0.0"));

+		featureIDsToProvision.add(new FeatureVersionedIdentifier(FIXTURE_FEATURE_ID_C, "1.0.0"));

+		FeatureReferenceTree featuresOnUpdateSite = testee.getAllFeaturesFromUpdateSites(new URL[] { SITEABC_URL });

+

+		List<IFeatureReference> result = testee.resolveVersionNumbersAsIFRList(featuresOnUpdateSite.getAllReferences(), featureIDsToProvision, true);

+

+		assertEquals(2, result.size());

+		assertFeatureFoundIn(result, FIXTURE_FEATURE_ID_A);

+		assertFeatureFoundIn(result, FIXTURE_FEATURE_ID_C);

+	}

+

+	// getAllFeaturesFromUpdateSites-----------------------------------------------------------------------------------------------------

+

+	public void testGetAllFeaturesFromUpdateSite_AlternativeNameXML_returnsAllFeatures() throws Exception {

+		URL[] updateSites = new URL[] { FOO_URL};

+

+		List<IFeatureReference> result = testee.getAllFeaturesFromUpdateSites(updateSites).getAllReferences();

+		

+		assertFeatureFoundIn(result, FIXTURE_FEATURE_ID_A);

+		assertFeatureFoundIn(result, FIXTURE_FEATURE_ID_B);

+		assertFeatureFoundIn(result, FIXTURE_FEATURE_ID_C);			

+	}

+	

+	public void testGetAllFeaturesFromUpdateSites_worksFor2Sites() throws Exception {

+		URL[] updateSites = new URL[] { SITE400_URL, SITE401_URL };

+

+		FeatureReferenceTree allFeaturesFromUpdateSites = testee.getAllFeaturesFromUpdateSites(updateSites);

+

+		assertEquals(2, allFeaturesFromUpdateSites.getAllReferences().size());

+

+		String[] resultVersions = extractVersionStringsAndSort(allFeaturesFromUpdateSites.getAllReferences());

+

+		assertEquals("org.eclipse.e4.enterprise.installer.test.fixture.feature_4.0.0", resultVersions[0]);

+		assertEquals("org.eclipse.e4.enterprise.installer.test.fixture.feature_4.0.1", resultVersions[1]);

+	}

+

+	private String[] extractVersionStringsAndSort(List<IFeatureReference> allFeaturesFromUpdateSites) throws CoreException {

+		String[] resultVersions = new String[allFeaturesFromUpdateSites.size()];

+		for (int i = 0; i < allFeaturesFromUpdateSites.size(); i++) {

+			resultVersions[i] = allFeaturesFromUpdateSites.get(i).getVersionedIdentifier().toString();

+		}

+		Arrays.sort(resultVersions);

+		return resultVersions;

+	}

+

+	public void testGetAllFeaturesFromUpdateSites_worksForSingleSite() throws Exception {

+		URL[] updateSites = new URL[] { SITE400_URL };

+

+		FeatureReferenceTree allFeaturesFromUpdateSites = testee.getAllFeaturesFromUpdateSites(updateSites);

+

+		assertEquals(1, allFeaturesFromUpdateSites.getAllReferences().size());

+

+		IFeatureReference featureReference = allFeaturesFromUpdateSites.getAllReferences().get(0);

+		assertEquals("org.eclipse.e4.enterprise.installer.test.fixture.feature_4.0.0", featureReference.getVersionedIdentifier().toString());

+	}

+

+	public static class StuntSiteManager extends InstallationSiteManager {

+		public StuntSiteManager(File downloadRootDir) {

+			super(downloadRootDir);

+			downloadRootDir.delete();

+			downloadRootDir.mkdirs();

+		}

+

+		int callCount = 0;

+

+		public int getCallCount() {

+			return callCount;

+		}

+

+		@Override

+		public void restartInitiated() throws IOException {

+			callCount++;

+		}

+	};

+

+	public void testInstallAndRollBackOnError_WhenNoRestartIsNeeded_RestartInitiatedNotInvoked() throws Exception {

+		InstallationSite currentSite = new StubInstallationSite(false);

+		File downloadRoot = File.createTempFile("any", "thing");

+		final StuntSiteManager stuntManager = new StuntSiteManager(downloadRoot);

+		

+		testee.installAndRollBackOnError(stuntManager, currentSite, new ArrayList<IFeatureReference>());

+

+		assertEquals(0, stuntManager.getCallCount());

+	}

+

+	public void testIOExceptionInRestartManager_causesInstallRollbackAndInstallError() throws Exception {

+		final StubInstallationSite newSite = new StubInstallationSite(true);

+		StubInstallationSite currentSite = new StubInstallationSite(true);

+

+		// stubs

+		InstallationSiteManager stuntManager = new InstallationSiteManager(File.createTempFile("any", "thing")) {

+			@Override

+			public InstallationSite create() throws CoreException {

+				return newSite;

+			}

+			@Override

+			public void restartInitiated() throws IOException {

+				throw new IOException();

+			}

+		};	

+

+		try {

+			testee.installAndRollBackOnError(stuntManager, currentSite, new ArrayList<IFeatureReference>());

+			fail();

+		} catch (InstallError e) {

+			// want to be here

+		}

+		

+		/*

+		 * the following expectations embody "rollback". There may be better ways to

+		 * represent "rolling back" as currently we are saying the same thing in

+		 * two places (code, test). Perhaps this could be done with a proper

+		 * transaction of some kind.

+		 * 

+		 * Really, what you want above is to know that

+		 * "roll back has been initiated"; you probably don't need to care how

+		 * the rollback works.

+		 */

+		assertEquals(1, newSite.removeFromConfiguredSitesCount);

+		assertEquals(1, currentSite.addToConfiguredSitesCount);

+	}

+	

+	// ------------------------------------------------------------------------------------

+	

+	public void testResolveVersionNumbersAsVFISet_cannotFindFeatureReference_featuresMustBePresent_throwsInstallError() throws Exception {

+		FeatureReferenceTree tree = new FeatureReferenceTree();

+		Set<FeatureVersionedIdentifier> toProvision = new HashSet<FeatureVersionedIdentifier>();

+		toProvision.add(new FeatureVersionedIdentifier("org.eclipse.foo.bar", "1.1.0"));

+		toProvision.add(new FeatureVersionedIdentifier("org.eclipse.foo2.bar", "1.1.0"));

+		

+		try {

+			testee.resolveVersionNumbersAsFVISet(tree, toProvision, true);

+			fail("Should have thrown an InstallError");

+		} catch (InstallError e) {

+			//success

+		}

+	}

+

+	public void testResolveVersionNumbersAsVFISet_cannotFindFeatureReference_returnsEmptySet() throws Exception {

+		FeatureReferenceTree tree = new FeatureReferenceTree();

+		Set<FeatureVersionedIdentifier> toProvision = new HashSet<FeatureVersionedIdentifier>();

+		toProvision.add(new FeatureVersionedIdentifier("org.eclipse.foo.bar", "1.1.0"));

+		toProvision.add(new FeatureVersionedIdentifier("org.eclipse.foo2.bar", "1.1.0"));

+		

+		Set<FeatureVersionedIdentifier> result = testee.resolveVersionNumbersAsFVISet(tree, toProvision, false);

+		assertTrue("returned set should be empty", result.isEmpty());

+	}

+

+	// ------------------------------------------------------------------------------------

+

+	private class SpecialStubFeatureReference implements IFeatureReference {

+		

+//		This class smells fishy, there is another StubFeatureReference class that should

+//		be used in this test class. The getOuterType() method is added automatically 

+//		by the IDE, probably because this is in an inner class.

+		

+		public String name = "";

+		public boolean isLocal = false;

+

+		public SpecialStubFeatureReference(String name) {

+			this.name = name;

+		}

+

+		public SpecialStubFeatureReference(String name, boolean isLocal) {

+			this.name = name;

+			this.isLocal = isLocal;

+		}

+

+		@Override

+		public int hashCode() {

+			final int prime = 31;

+			int result = 1;

+			result = prime * result + getOuterType().hashCode();

+			result = prime * result + ((name == null) ? 0 : name.hashCode());

+			return result;

+		}

+

+		@Override

+		public boolean equals(Object obj) {

+			if (this == obj)

+				return true;

+			if (obj == null)

+				return false;

+			if (getClass() != obj.getClass())

+				return false;

+			SpecialStubFeatureReference other = (SpecialStubFeatureReference) obj;

+			if (!getOuterType().equals(other.getOuterType()))

+				return false;

+			if (name == null) {

+				if (other.name != null)

+					return false;

+			} else if (!name.equals(other.name))

+				return false;

+			return true;

+		}

+

+		public IFeature getFeature() throws CoreException {

+			// TODO Auto-generated method stub

+			return null;

+		}

+

+		public IFeature getFeature(IProgressMonitor monitor) throws CoreException {

+			// TODO Auto-generated method stub

+			return null;

+		}

+

+		public String getName() {

+			// TODO Auto-generated method stub

+			return null;

+		}

+

+		public ISite getSite() {

+			// TODO Auto-generated method stub

+			return null;

+		}

+

+		public URL getURL() {

+			// TODO Auto-generated method stub

+			return null;

+		}

+

+		public VersionedIdentifier getVersionedIdentifier() throws CoreException {

+			// TODO Auto-generated method stub

+			return null;

+		}

+

+		public boolean isPatch() {

+			// TODO Auto-generated method stub

+			return false;

+		}

+

+		public void setSite(ISite site) {

+			// TODO Auto-generated method stub

+

+		}

+

+		public void setURL(URL url) throws CoreException {

+			// TODO Auto-generated method stub

+

+		}

+

+		public Object getAdapter(Class adapter) {

+			// TODO Auto-generated method stub

+			return null;

+		}

+

+		public String getNL() {

+			// TODO Auto-generated method stub

+			return null;

+		}

+

+		public String getOS() {

+			// TODO Auto-generated method stub

+			return null;

+		}

+

+		public String getOSArch() {

+			// TODO Auto-generated method stub

+			return null;

+		}

+

+		public String getWS() {

+			// TODO Auto-generated method stub

+			return null;

+		}

+

+		private BundleUpdaterTest getOuterType() {

+			return BundleUpdaterTest.this;

+		}

+

+	}

+}

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/FeatureReferenceMother.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/FeatureReferenceMother.java
new file mode 100644
index 0000000..d6b23be
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/FeatureReferenceMother.java
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer;

+

+import org.eclipse.update.core.IFeatureReference;

+import org.eclipse.update.core.IIncludedFeatureReference;

+

+public class FeatureReferenceMother {

+

+	private static final String DEFAULT_ID = "id";

+	private static final String DEFAULT_VERSION = "0.0.1";

+	

+	public static IFeatureReference createFeatureReferenceFromFVIWithChildren(FeatureVersionedIdentifier fvi, IIncludedFeatureReference... featureReference) {

+		StubFeatureReference stub = new StubFeatureReference(new StubFeature(featureReference));

+		stub.setVersionedIdentifier(fvi.featureID, fvi.featureVersion);		

+		return stub;

+	}

+

+	public static IFeatureReference createFeatureReferenceFromFVIWithNoChildren(FeatureVersionedIdentifier fvi) {

+		StubFeatureReference stub = new StubFeatureReference(new StubFeature(new StubFeatureReference[]{}));

+		stub.setVersionedIdentifier(fvi.featureID, fvi.featureVersion);		

+		return stub;

+	}

+	

+	public static IIncludedFeatureReference createFeatureWithNoChildren() {

+		StubFeatureReference stubFeatureReference = new StubFeatureReference(new StubFeature(new StubFeatureReference[]{}));

+		stubFeatureReference.setVersionedIdentifier(DEFAULT_ID, DEFAULT_VERSION);

+		return stubFeatureReference;

+	}

+	

+	public static IFeatureReference createFeatureWithChildren(IIncludedFeatureReference... featureReference) {

+		StubFeatureReference stubFeatureReference = new StubFeatureReference(new StubFeature(featureReference));

+		stubFeatureReference.setVersionedIdentifier(DEFAULT_ID, DEFAULT_VERSION);

+		return stubFeatureReference;

+	}

+	

+	

+	

+	

+}

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/FeatureVersionedIdentifierTest.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/FeatureVersionedIdentifierTest.java
new file mode 100644
index 0000000..b43253c
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/FeatureVersionedIdentifierTest.java
@@ -0,0 +1,34 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer;

+

+import org.eclipse.e4.enterprise.installer.FeatureVersionedIdentifier;

+

+import junit.framework.TestCase;

+

+public class FeatureVersionedIdentifierTest extends TestCase {

+

+	public void testConstructorValidatesVersionCorrectly() throws Exception {

+

+		//valid:

+		new FeatureVersionedIdentifier("name","1.2.3");

+		

+		//invalid:

+		try{

+			FeatureVersionedIdentifier testee = new FeatureVersionedIdentifier("name","1.monkey.foo");

+			fail();

+		}

+		catch (IllegalArgumentException e) {

+			// want to be here

+		}

+	}

+	

+}

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/StubFeature.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/StubFeature.java
new file mode 100644
index 0000000..b060879
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/StubFeature.java
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer;

+

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.update.core.Feature;

+import org.eclipse.update.core.IIncludedFeatureReference;

+

+public class StubFeature extends Feature {

+

+	private final IIncludedFeatureReference[] includedFeatureReferences;

+

+	public StubFeature(IIncludedFeatureReference[] includedFeatureReferences) {

+		this.includedFeatureReferences = includedFeatureReferences;	

+	}

+	

+

+	@Override

+	public IIncludedFeatureReference[] getIncludedFeatureReferences()

+			throws CoreException {

+		return includedFeatureReferences;

+	}

+	

+}

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/StubFeatureReference.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/StubFeatureReference.java
new file mode 100644
index 0000000..24df063
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/StubFeatureReference.java
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer;

+

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.core.runtime.IProgressMonitor;

+import org.eclipse.update.core.IFeature;

+import org.eclipse.update.core.IncludedFeatureReference;

+import org.eclipse.update.core.VersionedIdentifier;

+

+public class StubFeatureReference extends IncludedFeatureReference {

+	

+	private IFeature feature;

+	private VersionedIdentifier versionedIdentifier;

+	

+	public StubFeatureReference(IFeature feature){

+		this.feature = feature;

+	}

+	

+	public void setVersionedIdentifier(String id, String version){

+		versionedIdentifier = new VersionedIdentifier(id, version);

+	}

+	

+	@Override

+	public VersionedIdentifier getVersionedIdentifier() {

+		return versionedIdentifier;

+	}

+	

+	@Override

+	public IFeature getFeature() throws CoreException {

+		return feature;

+	}

+

+	@Override

+	public IFeature getFeature(IProgressMonitor monitor) throws CoreException {

+		return feature;

+	}

+	

+	@Override

+	public int hashCode() {

+		final int prime = 31;

+		int result = 1;

+		result = prime * result + ((feature == null) ? 0 : feature.hashCode());

+		return result;

+	}

+

+	@Override

+	public boolean equals(Object obj) {

+		if (this == obj)

+			return true;

+		if (!super.equals(obj))

+			return false;

+		if (getClass() != obj.getClass())

+			return false;

+		StubFeatureReference other = (StubFeatureReference) obj;

+		if (feature == null) {

+			if (other.feature != null)

+				return false;

+		} else if (!feature.equals(other.feature))

+			return false;

+		return true;

+	}

+

+	

+	

+}

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/FeatureReferenceTreeTest.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/FeatureReferenceTreeTest.java
new file mode 100644
index 0000000..9e7d6e4
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/FeatureReferenceTreeTest.java
@@ -0,0 +1,181 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer.internal;

+

+import java.util.List;

+

+import junit.framework.TestCase;

+

+import org.eclipse.e4.enterprise.installer.FeatureReferenceMother;

+import org.eclipse.e4.enterprise.installer.FeatureVersionedIdentifier;

+import org.eclipse.update.core.IFeatureReference;

+import org.eclipse.update.core.IIncludedFeatureReference;

+

+public class FeatureReferenceTreeTest extends TestCase {

+

+	private FeatureReferenceTree testee;

+

+	public void setUp() {

+		testee = new FeatureReferenceTree();

+	}

+

+	public void testGetDescendants_GivenKnownKeysWithManyDescendants_returnsAllDescendants() throws Exception {

+

+		// f1

+		// ...f11 *

+		// ......f111

+		// ......f112

+		// ......f113

+		// .........f1131

+		// ...f12

+		// ......f121

+		// ...f13

+		// f2 *

+		// ...f21

+		// ...f22

+		// ......f221

+		// ......f222

+

+		IIncludedFeatureReference f111 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference f112 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference f1131 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference f113 = (IIncludedFeatureReference) FeatureReferenceMother.createFeatureWithChildren(f1131);

+		

+		FeatureVersionedIdentifier keyf11 = new FeatureVersionedIdentifier("f11", "11.11.11");

+		IIncludedFeatureReference f11 = (IIncludedFeatureReference) FeatureReferenceMother.createFeatureReferenceFromFVIWithChildren(keyf11, f111, f112, f113);

+

+		IIncludedFeatureReference f121 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference f12 = (IIncludedFeatureReference )FeatureReferenceMother.createFeatureWithChildren(f121);

+		

+		IIncludedFeatureReference f13 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IFeatureReference f1 = FeatureReferenceMother.createFeatureWithChildren(f11, f12, f13);

+		

+		IIncludedFeatureReference f21 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference f221 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference f222 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference f22 = (IIncludedFeatureReference)FeatureReferenceMother.createFeatureWithChildren(f221, f222);

+		

+		FeatureVersionedIdentifier keyf2 = new FeatureVersionedIdentifier("f2", "2.2.2");

+		IFeatureReference f2 = FeatureReferenceMother.createFeatureReferenceFromFVIWithChildren(keyf2, f21,f22);

+

+		testee.add(f1);

+		testee.add(f2);

+		

+		List<IFeatureReference> descendantsF11 = testee.getFeatureReferenceWithDescendants(keyf11);

+		assertEquals(5, descendantsF11.size());

+		assertTrue(descendantsF11.contains(f11));

+		assertTrue(descendantsF11.contains(f111));

+		assertTrue(descendantsF11.contains(f112));

+		assertTrue(descendantsF11.contains(f113));

+		assertTrue(descendantsF11.contains(f1131));

+		

+		List<IFeatureReference> descendantsF2 = testee.getFeatureReferenceWithDescendants(keyf2);

+		assertEquals(5, descendantsF2.size());

+		assertTrue(descendantsF2.contains(f2));

+		assertTrue(descendantsF2.contains(f21));

+		assertTrue(descendantsF2.contains(f22));

+		assertTrue(descendantsF2.contains(f221));

+		assertTrue(descendantsF2.contains(f222));

+	}

+

+	public void testGetDescendants_GivenKnownKeyWithManyDescendants_returnsAllDescendants() throws Exception {

+

+		IIncludedFeatureReference f4 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference f3 = (IIncludedFeatureReference) FeatureReferenceMother.createFeatureWithChildren(f4);

+

+		FeatureVersionedIdentifier key = new FeatureVersionedIdentifier("foo", "1.2.3");

+		IIncludedFeatureReference f2 = (IIncludedFeatureReference) FeatureReferenceMother.createFeatureReferenceFromFVIWithChildren(key, f3);

+		IIncludedFeatureReference f1 = (IIncludedFeatureReference) FeatureReferenceMother.createFeatureWithChildren(f2);

+

+		testee.add(f1);

+	

+		List<IFeatureReference> descendants = testee.getFeatureReferenceWithDescendants(key);

+		assertEquals(3, descendants.size());

+		assertTrue(descendants.contains(f2));

+		assertTrue(descendants.contains(f3));

+		assertTrue(descendants.contains(f4));

+

+		

+	}

+	

+	

+	public void testGetDescendants_GivenKnownKeyWithNoDescendants_returnsTheReference() throws Exception {

+		FeatureVersionedIdentifier key = new FeatureVersionedIdentifier("myFeature", "1.1.1");

+		IFeatureReference keyReference = FeatureReferenceMother.createFeatureReferenceFromFVIWithNoChildren(key);

+		testee.add(keyReference);

+

+		List<IFeatureReference> descendants = testee.getFeatureReferenceWithDescendants(key);

+

+		assertEquals(1, descendants.size());

+		assertEquals(keyReference, descendants.get(0));

+	}

+

+	public void testGetDescendants_GivenUnknownKey_returnsEmptyList() throws Exception {

+		List<IFeatureReference> descendants = testee.getFeatureReferenceWithDescendants(new FeatureVersionedIdentifier("missingfeature", "1.1.1"));

+		assertTrue(descendants.isEmpty());

+	}

+

+	public void testWhenOneReferenceWithChildrenOfChildren_returnsAllFeatureReference() throws Exception {

+

+		IIncludedFeatureReference grandChild1 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference grandChild2 = FeatureReferenceMother.createFeatureWithNoChildren();

+

+		IFeatureReference child1 = FeatureReferenceMother.createFeatureWithChildren(grandChild1, grandChild2);

+

+		IFeatureReference parent = FeatureReferenceMother.createFeatureWithChildren((IIncludedFeatureReference) child1);

+		testee.add(parent);

+

+		assertEquals(4, testee.getAllReferences().size());

+		assertTrue(testee.getAllReferences().contains(parent));

+		assertTrue(testee.getAllReferences().contains(child1));

+		assertTrue(testee.getAllReferences().contains(grandChild1));

+		assertTrue(testee.getAllReferences().contains(grandChild2));

+	}

+

+	public void testWhenOneReferenceWithMultipleChildren_returnsAll() throws Exception {

+		IIncludedFeatureReference child1 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference child2 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference child3 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IIncludedFeatureReference child4 = FeatureReferenceMother.createFeatureWithNoChildren();

+		IFeatureReference parent = FeatureReferenceMother.createFeatureWithChildren(child1, child2, child3, child4);

+		testee.add(parent);

+

+		assertEquals(5, testee.getAllReferences().size());

+		assertTrue(testee.getAllReferences().contains(parent));

+		assertTrue(testee.getAllReferences().contains(child1));

+		assertTrue(testee.getAllReferences().contains(child2));

+		assertTrue(testee.getAllReferences().contains(child3));

+		assertTrue(testee.getAllReferences().contains(child4));

+	}

+

+	public void testWhenOneReferenceWithOneChildHasBeenAdded_returnsBoth() throws Exception {

+		IIncludedFeatureReference child = FeatureReferenceMother.createFeatureWithNoChildren();

+		IFeatureReference parent = FeatureReferenceMother.createFeatureWithChildren(child);

+		testee.add(parent);

+

+		assertEquals(2, testee.getAllReferences().size());

+		assertTrue(testee.getAllReferences().contains(parent));

+		assertTrue(testee.getAllReferences().contains(child));

+	}

+

+	public void testWhenOneReferenceWithNoChildrenHasBeenAdded_OnlyOneReturned() throws Exception {

+		IFeatureReference expectedFeatureReference = FeatureReferenceMother.createFeatureWithNoChildren();

+		testee.add(expectedFeatureReference);

+

+		assertEquals(1, testee.getAllReferences().size());

+		assertEquals(expectedFeatureReference, testee.getAllReferences().get(0));

+	}

+

+	public void testWhenNoObjectsHaveBeenAdded_EmptyListReturned() {

+		assertTrue(testee.getAllReferences().isEmpty());

+	}

+

+}

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/InstallationSiteBuilderTest.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/InstallationSiteBuilderTest.java
new file mode 100644
index 0000000..ee4cca4
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/InstallationSiteBuilderTest.java
@@ -0,0 +1,191 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer.internal.site;

+

+import java.io.File;

+import java.text.SimpleDateFormat;

+import java.util.Date;

+

+import junit.framework.TestCase;

+

+import org.eclipse.e4.enterprise.installer.internal.site.InstallationSite;

+import org.eclipse.e4.enterprise.installer.internal.site.InstallationSiteManager;

+import org.eclipse.e4.enterprise.installer.internal.site.NullInstallationSite;

+import org.eclipse.e4.enterprise.installer.internal.site.UpdateManagerSite;

+import org.eclipse.update.configuration.IConfiguredSite;

+import org.eclipse.update.core.SiteManager;

+

+

+public class InstallationSiteBuilderTest extends TestCase {

+

+	private File downloadRootDir;

+	private InstallationSiteManager testee;

+

+	protected void setUp() throws Exception {

+		downloadRootDir = new File(System.getProperty("java.io.tmpdir") + "/obtest");

+		downloadRootDir.mkdir();

+		testee = new InstallationSiteManager(downloadRootDir);	

+	}

+	

+	protected void tearDown() throws Exception {

+		deleteDir(downloadRootDir);

+	}

+	

+	public void testDirectoryNameFiltering() throws Exception {

+		File root = File.createTempFile("downloadroot", "temp");

+

+		SimpleDateFormat simpleDateFormat = new SimpleDateFormat(InstallationSiteManager.CONFIG_SITE_DIR_DATE_NAME_FORMAT);

+		Date now = new Date();

+		String date = simpleDateFormat.format(now);

+

+		long nowLong = now.getTime();

+

+		File pruneMe1 = new File(root, "I should not be deleted");

+		File pruneMe2 = new File(root, "_I should not be deleted");

+		File pruneMe3 = new File(root, date + "something");

+		File pruneMe4 = new File(root, date.substring(0, 10));

+		

+

+		File expected1 = new File(root, simpleDateFormat.format(now));

+		File expected2 = new File(root, simpleDateFormat.format(new Date(nowLong + 12345)));

+		File expected3 = new File(root, simpleDateFormat.format(new Date(nowLong + 123456)));

+		File expected4 = new File(root, simpleDateFormat.format(new Date(nowLong + 1234567)));

+

+		File[] testData = new File[] { expected4, pruneMe1, expected3, pruneMe2, expected2, pruneMe3, expected1 , pruneMe4};

+

+		File[] result = testee.filterOutFilesThatDoNotMatchExpectedFormat(testData);

+		

+		assertTrue(arrayContains(result, expected1));

+		assertTrue(arrayContains(result, expected2));

+		assertTrue(arrayContains(result, expected3));

+		assertTrue(arrayContains(result, expected4));

+		

+		assertFalse(arrayContains(result, pruneMe1));

+		assertFalse(arrayContains(result, pruneMe2));

+		assertFalse(arrayContains(result, pruneMe3));

+		assertFalse(arrayContains(result, pruneMe4));

+

+		assertEquals(4, result.length);

+	}

+

+	private boolean arrayContains(Object[] array, Object objectToLookFor) {

+		for (Object object : array) {

+			if (object == objectToLookFor) {

+				return true;

+			}

+		}

+		return false;

+	}

+	

+	public void testFind_existingSitePresent_returnsInstallationSite() throws Exception {

+		InstallationSite expectedSite = testee.create();

+		expectedSite.addToConfiguredSites();

+		

+		InstallationSite actualSite = testee.find();

+		

+		assertEquals(expectedSite,actualSite);

+		expectedSite.removeFromConfiguredSites();

+	}

+	

+	public void testFind_noSiteExists_returnsNullInstallationSite() throws Exception {

+		InstallationSite site = testee.find();

+		assertTrue(site instanceof NullInstallationSite);

+	}

+		

+	public void testCreate_creatingNewSite_leavesExistingDirectoriesUntouched() throws Exception {

+		File testSubDir = new File(downloadRootDir,"rubbish");

+		testSubDir.mkdir();

+		

+		testee.create();

+		

+		File[] subdirs = downloadRootDir.listFiles();

+		

+		assertEquals(2,subdirs.length);

+		assertTrue(testSubDir.exists());

+	}

+	

+	public void testCreate_creatingNewSite_makesDirectoryUnderDownloadRootDir() throws Exception {

+		assertEquals(0,downloadRootDir.list().length);

+		testee.create();

+		

+		File[] subdirs = downloadRootDir.listFiles();

+		assertEquals(1,subdirs.length);

+		assertTrue(subdirs[0].isDirectory());

+		

+		File[] subsubdirs = subdirs[0].listFiles();

+		assertEquals(1,subsubdirs.length);

+		assertTrue(subsubdirs[0].isDirectory());

+		assertEquals("eclipse",subsubdirs[0].getName());

+	}

+		

+	public void testFindCurrentDownloadSite_existingSitePresent_returnsSite() throws Exception {

+		UpdateManagerSite expectedSite = (UpdateManagerSite) testee.create();

+		expectedSite.addToConfiguredSites();

+		IConfiguredSite actualSite = testee.findCurrentDownloadSite(downloadRootDir, SiteManager.getLocalSite().getCurrentConfiguration().getConfiguredSites());

+		

+		expectedSite.removeFromConfiguredSites();

+		assertEquals(expectedSite.getConfiguredSite(),actualSite);

+	}

+	

+	public void testFindCurrentDownloadSite_NoPreviouslyCreatedDownloadSites_returnsNullCurrentSite() throws Exception {

+		IConfiguredSite[] onlyEclipseConfiguredSites = SiteManager.getLocalSite().getCurrentConfiguration().getConfiguredSites();

+		IConfiguredSite actual = testee.findCurrentDownloadSite(downloadRootDir,onlyEclipseConfiguredSites);

+		assertNull(actual);

+	}

+	

+	public void testFindCurrentDownloadSite_NoConfiguredSites_returnsNullCurrentSite() throws Exception {

+		IConfiguredSite actual = testee.findCurrentDownloadSite(downloadRootDir,new IConfiguredSite[0]);				

+		assertNull(actual);

+	}

+	

+	public void testIsSubdirectory_SourceIsNull_returnsFalse() {

+		boolean isSubdirectory = testee.isSubdirectory(null, new File("c:\\windows"));

+		assertFalse(isSubdirectory);		

+	}

+	

+	public void testIsSubdirectory_TargetIsNull_returnsFalse() {

+		boolean isSubdirectory = testee.isSubdirectory(new File("c:\\windows"), null);

+		assertFalse(isSubdirectory);		

+	}

+	

+	public void testIsSubdirectory_TargetIsSubdirectoryOfSource_returnsTrue() {		

+		boolean isSubdirectory = testee.isSubdirectory(new File("c:\\windows"), new File("C:\\windows/system"));

+		assertTrue(isSubdirectory);

+	}

+

+	public void testIsSubdirectory_TargetIsNotSubdirectoryOfSource_returnsFalse() {		

+		boolean isSubdirectory = testee.isSubdirectory(new File("c:/windows"), new File("c:/temp"));

+		assertFalse(isSubdirectory);

+	}

+

+	public void testIsSubdirectory_TargetIsSameAsParentButWithTrailingSlash_returnsFalse() {		

+		boolean isSubdirectory = testee.isSubdirectory(new File("c:/windows"), new File("c:/windows/"));

+		assertFalse(isSubdirectory);

+	}

+

+	public void testIsSubdirectory_TargetHasNoDirectorySeparator_returnsFalse() {		

+		boolean isSubdirectory = testee.isSubdirectory(new File("c:/windows"), new File("c:/windowsrubbish"));

+		assertFalse(isSubdirectory);

+	}

+	

+	private boolean deleteDir(File dir) {

+        if (dir.isDirectory()) {

+            String[] children = dir.list();

+            for (int i=0; i<children.length; i++) {

+                boolean success = deleteDir(new File(dir, children[i]));

+                if (!success) {

+                    return false;

+                }

+            }

+        }    

+        return dir.delete();

+    }	

+}

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/RestartManagerTest.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/RestartManagerTest.java
new file mode 100644
index 0000000..5bd29ba
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/RestartManagerTest.java
@@ -0,0 +1,34 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer.internal.site;

+

+import junit.framework.TestCase;

+

+public class RestartManagerTest extends TestCase {

+

+	public RestartManagerTest(String name) {

+		super(name);

+	}

+

+	protected void setUp() throws Exception {

+		super.setUp();

+	}

+

+	protected void tearDown() throws Exception {

+		super.tearDown();

+	}

+	

+	public void testDummyTest() throws Exception {

+		// success: to keep JUnit from complaining that there are no tests here.

+	}

+

+

+}

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/StubInstallationSite.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/StubInstallationSite.java
new file mode 100644
index 0000000..feae759
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/StubInstallationSite.java
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer.internal.site;

+

+import java.lang.reflect.InvocationTargetException;

+

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.core.runtime.IProgressMonitor;

+import org.eclipse.update.core.IFeatureReference;

+

+public class StubInstallationSite extends NullInstallationSite {

+	

+	private final boolean installReturnValue;

+	public int addToConfiguredSitesCount = 0;

+	public int removeFromConfiguredSitesCount = 0;

+

+	public StubInstallationSite(boolean installReturnValue) {

+		this.installReturnValue = installReturnValue;

+		

+	}

+	

+	@Override

+	public boolean install(IFeatureReference[] updateSiteFeatures, IProgressMonitor progressMonitor) throws CoreException, InvocationTargetException {

+		return installReturnValue;

+	}

+

+	@Override

+	public void addToConfiguredSites() {

+		addToConfiguredSitesCount++;

+	}

+	

+	@Override

+	public void removeFromConfiguredSites() {

+		removeFromConfiguredSitesCount++;

+	}

+	

+	

+

+	

+	

+}

diff --git a/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/UpdateManagerSiteTest.java b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/UpdateManagerSiteTest.java
new file mode 100644
index 0000000..7ec2a30
--- /dev/null
+++ b/tests/org.eclipse.e4.enterprise.installer.test/src/org/eclipse/e4/enterprise/installer/internal/site/UpdateManagerSiteTest.java
@@ -0,0 +1,250 @@
+/******************************************************************************
+ * Copyright (c) David Orme and others
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *    David Orme - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.e4.enterprise.installer.internal.site;

+

+import java.io.File;

+import java.io.IOException;

+import java.lang.reflect.InvocationTargetException;

+import java.net.MalformedURLException;

+import java.net.URL;

+import java.util.ArrayList;

+import java.util.Arrays;

+import java.util.LinkedList;

+import java.util.List;

+

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.core.runtime.IProgressMonitor;

+import org.eclipse.core.runtime.NullProgressMonitor;

+import org.eclipse.e4.enterprise.installer.InstallError;

+import org.eclipse.e4.enterprise.installer.internal.site.InstallationSiteManager;

+import org.eclipse.e4.enterprise.installer.internal.site.UpdateManagerSite;

+import org.eclipse.e4.enterprise.installer.internal.site.UpdateManagerSite.UpdateSiteFeatureXML;

+import org.eclipse.e4.ui.test.utils.FixturesLocation;
+import org.eclipse.e4.ui.test.utils.TestCaseX;
+import org.eclipse.update.core.IFeature;

+import org.eclipse.update.core.IFeatureReference;

+import org.eclipse.update.core.ISite;

+import org.eclipse.update.core.ISiteFeatureReference;

+import org.eclipse.update.core.SiteManager;

+import org.eclipse.update.core.VersionedIdentifier;

+

+

+

+public class UpdateManagerSiteTest extends TestCaseX {

+	private UpdateManagerSite testee;

+	private File downloadRootDir;

+

+	protected void setUp() throws Exception {

+		downloadRootDir = new File(System.getProperty("java.io.tmpdir") + "/obtest");

+		testee = (UpdateManagerSite) new InstallationSiteManager(downloadRootDir).create();

+	}

+

+	// downloadToUpdateSet--------------------------------------------------------------------------------------------	

+	private static final String SITE400_FIXTURE = FixturesLocation.FIXTURE_ROOT + "/site_4.0.0/site.xml";

+

+	public void testConvertIntoUpdateSite_CheckThatUpdateSiteContainsSameFeaturesAsConfigSiteItIsGeneratedFrom() throws Exception {

+		UpdateManagerSite testee = createTemporaryDownloadSiteWithDownloadedContents();

+		try {

+			testee.convertIntoUpdateSite();

+			assertUpdateSiteHasIdenticalFeaturesAsDownloadSite(testee);

+		} finally {

+			testee.removeFromConfiguredSites();  // Make sure we don't leave Eclipse in a wierd state

+		}

+	}

+

+	private void assertUpdateSiteHasIdenticalFeaturesAsDownloadSite(

+			UpdateManagerSite testee) throws CoreException, InstallError {

+		URL url = testee.getConfiguredSite().getSite().getURL();

+		IFeatureReference[] featureReferences = SiteManager.getSite(url, false, new NullProgressMonitor()).getFeatureReferences();

+		

+		List<IFeatureReference> featureReferencesList = Arrays.asList(featureReferences);

+		

+		assertTrue("Update site should have identical Features as download site", 

+				testee.hasIdenticalFeatures(featureReferencesList));

+	}

+

+	private UpdateManagerSite createTemporaryDownloadSiteWithDownloadedContents() throws IOException,

+			CoreException, MalformedURLException, InvocationTargetException 

+	{

+		File tempDir = createTempDir("1BenchTest-");	// start w/ numeral so that it sorts to the top

+		System.out.println("Temp update site dir = " + tempDir.getAbsolutePath()); // for debugging purposes

+		

+		InstallationSiteManager siteBuilder = new InstallationSiteManager(tempDir);

+		UpdateManagerSite temporaryDownloadSite = (UpdateManagerSite) siteBuilder.create();

+		temporaryDownloadSite.addToConfiguredSites();

+		

+		ISiteFeatureReference[] remoteFeatures = SiteManager.getSite(

+				new URL(SITE400_FIXTURE), false, new NullProgressMonitor())

+					.getFeatureReferences();

+		temporaryDownloadSite.install(remoteFeatures, new NullProgressMonitor());

+		

+		return temporaryDownloadSite;

+	}

+	

+	// computeUpdateSiteFeatureData--------------------------------------------------------------------------------

+

+	public void testComputeUpdateSiteFeatureData_emptyInput_resultsInEmptyOutput() throws Exception {

+		UpdateSiteFeatureXML[] result = testee.computeUpdateSiteFeatureData(

+				new IFeatureReference[] {});

+		assertEquals(0, result.length);

+	}

+	

+	public void testComputeUpdateSiteFeatureData_indexesMatch() throws Exception {

+		IFeatureReference[] input = new IFeatureReference[] {

+				newFeatureRef("file:///c:/path/to/features/featurefolder/",

+						"com.foo.feature.id", "1.0.0"),

+				newFeatureRef("file:///c:/path/to/features/featurefolder/",

+						"com.foo.feature.id", "1.0.0"),

+		};

+

+		UpdateSiteFeatureXML[] result = testee.computeUpdateSiteFeatureData(input);

+		

+		assertEquals(2, result.length);

+	}

+	

+	// computeFeatureXMLData---------------------------------------------------------------------------------------

+

+	public void testComputeFeatureXMLData_dataMatches() throws Exception {

+		IFeatureReference input = newFeatureRef(

+				"file:///c:/path/to/features/featurefolder/",

+				"com.foo.feature.id", "1.0.0");

+

+		UpdateSiteFeatureXML result = testee.computeFeatureXMLData(input);

+		

+		assertEquals("features/featurefolder.jar", result.jarRelativePath);

+		assertEquals("com.foo.feature.id", result.id);

+		assertEquals("1.0.0", result.version);

+	}

+	

+	// areFeaturesDifferent?---------------------------------------------------------------------------------------

+	

+	public void testAreFeaturesDifferent_catchesListsInDifferentOrders(){

+		List<String> list1 = new ArrayList<String>();

+		List<String> list2 = new LinkedList<String>();

+		

+		list1.add("thing 1");

+		list1.add("thing 2");

+		list1.add("thing 3");

+

+		list2.add("thing 3");

+		list2.add("thing 1");

+		list2.add("thing 2");

+		

+		assertFalse(testee.areFeaturesDifferent(list1, list2));

+	}		

+	

+	public void testAreFeaturesDifferent_matchesSimpleDuplicate(){

+		List<String> list1 = new ArrayList<String>();

+		List<String> list2 = new LinkedList<String>();

+		

+		list1.add("the same thing");

+		list2.add("the same thing");

+		

+		assertFalse(testee.areFeaturesDifferent(list1, list2));

+	}		

+

+	public void testAreFeaturesDifferent_catchesDifferentNoEmptyLists(){

+		List<String> list1 = new ArrayList<String>();

+		List<String> list2 = new LinkedList<String>();

+		

+		list1.add("something");

+		list1.add("somethingelse");

+		

+		assertTrue(testee.areFeaturesDifferent(list1, list2));

+	}		

+

+	public void testAreFeaturesDifferent_catchesDifferentListAndEmptyList(){

+		List<String> list1 = new ArrayList<String>();

+		List<String> list2 = new LinkedList<String>();

+		

+		list1.add("something");

+		

+		assertTrue(testee.areFeaturesDifferent(list1, list2));

+	}		

+	

+	public void testAreFeaturesDifferent_matchesEmptyLists(){

+		List<String> empty1 = new ArrayList<String>();

+		List<String> empty2 = new LinkedList<String>();

+		

+		assertFalse(testee.areFeaturesDifferent(empty1, empty2));

+	}

+

+	//--------------------------------------------------------------------------------

+	

+	private IFeatureReference newFeatureRef(final String url, final String id, final String version) {

+		return new IFeatureReference() {

+

+			public IFeature getFeature() throws CoreException {

+				return null;

+			}

+

+			public IFeature getFeature(IProgressMonitor monitor)

+					throws CoreException {

+				return null;

+			}

+

+			public String getName() {

+				return null;

+			}

+

+			public ISite getSite() {

+				return null;

+			}

+

+			public URL getURL() {

+				URL result = null;

+				try {

+					result = new URL(url);

+				} catch (MalformedURLException e) {

+					fail();

+				}

+				return result;

+			}

+

+			public VersionedIdentifier getVersionedIdentifier()

+					throws CoreException {

+				return new VersionedIdentifier(id, version);

+			}

+

+			public boolean isPatch() {

+				return false;

+			}

+

+			public void setSite(ISite site) {

+			}

+

+			public void setURL(URL url) throws CoreException {

+			}

+

+			@SuppressWarnings("unchecked")

+			public Object getAdapter(Class adapter) {

+				return null;

+			}

+

+			public String getNL() {

+				return null;

+			}

+

+			public String getOS() {

+				return null;

+			}

+

+			public String getOSArch() {

+				return null;

+			}

+

+			public String getWS() {

+				return null;

+			}};

+	}

+

+

+}