diff --git a/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/META-INF/MANIFEST.MF b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..6d33b22837
--- /dev/null
+++ b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/META-INF/MANIFEST.MF
@@ -0,0 +1,7 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: pvumb.bundle1
+Bundle-SymbolicName: pvumb.bundle1;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: TEST
+Bundle-RequiredExecutionEnvironment: JavaSE-17
diff --git a/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/META-INF/p2.inf b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/META-INF/p2.inf
new file mode 100644
index 0000000000..cd4d646153
--- /dev/null
+++ b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/META-INF/p2.inf
@@ -0,0 +1,11 @@
+# Create the virtual IU
+units.0.id=configure.pvumb.bundle1
+units.0.version=1.0.0
+units.0.provides.1.namespace=org.eclipse.equinox.p2.iu
+units.0.provides.1.name=configure.pvumb.bundle1
+units.0.provides.1.version=1.0.0
+
+# Require in this bundle the created virtual IU
+requires.0.namespace=org.eclipse.equinox.p2.iu
+requires.0.name=configure.pvumb.bundle1
+requires.0.range=0.0.0
diff --git a/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/build.properties b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/build.properties
new file mode 100644
index 0000000000..7594fab8d5
--- /dev/null
+++ b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/build.properties
@@ -0,0 +1,2 @@
+bin.includes = META-INF/,\
+ .
diff --git a/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/pom.xml b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/pom.xml
new file mode 100644
index 0000000000..7987cbc641
--- /dev/null
+++ b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle1/pom.xml
@@ -0,0 +1,16 @@
+
+
+ 4.0.0
+
+
+ tycho-its-project.p2Inf.virtualUnit.multiBundle
+ parent
+ 1.0.0-SNAPSHOT
+
+
+ pvumb.bundle1
+ eclipse-plugin
+
+
diff --git a/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle2/META-INF/MANIFEST.MF b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle2/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..7fa4a43de0
--- /dev/null
+++ b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle2/META-INF/MANIFEST.MF
@@ -0,0 +1,8 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: pvumb.bundle2
+Bundle-SymbolicName: pvumb.bundle2;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: TEST
+Bundle-RequiredExecutionEnvironment: JavaSE-17
+Require-Bundle: pvumb.bundle1
diff --git a/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle2/build.properties b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle2/build.properties
new file mode 100644
index 0000000000..7594fab8d5
--- /dev/null
+++ b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle2/build.properties
@@ -0,0 +1,2 @@
+bin.includes = META-INF/,\
+ .
diff --git a/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle2/pom.xml b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle2/pom.xml
new file mode 100644
index 0000000000..771c3be042
--- /dev/null
+++ b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/bundle2/pom.xml
@@ -0,0 +1,16 @@
+
+
+ 4.0.0
+
+
+ tycho-its-project.p2Inf.virtualUnit.multiBundle
+ parent
+ 1.0.0-SNAPSHOT
+
+
+ pvumb.bundle2
+ eclipse-plugin
+
+
diff --git a/tycho-its/projects/p2Inf.virtualUnit.multiBundle/pom.xml b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/pom.xml
new file mode 100644
index 0000000000..db8bcab7fb
--- /dev/null
+++ b/tycho-its/projects/p2Inf.virtualUnit.multiBundle/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+
+ tycho-its-project.p2Inf.virtualUnit.multiBundle
+ parent
+ 1.0.0-SNAPSHOT
+ pom
+
+
+ 4.0.4
+
+
+
+ bundle1
+ bundle2
+
+
+
+
+
+ org.eclipse.tycho
+ tycho-maven-plugin
+ ${tycho-version}
+ true
+
+
+ org.eclipse.tycho
+ target-platform-configuration
+ ${tycho-version}
+
+ consider
+
+
+
+
+
+
diff --git a/tycho-its/src/test/java/org/eclipse/tycho/test/p2Inf/VirtualUnitTest.java b/tycho-its/src/test/java/org/eclipse/tycho/test/p2Inf/VirtualUnitTest.java
index 6e748d411e..e6038c313d 100644
--- a/tycho-its/src/test/java/org/eclipse/tycho/test/p2Inf/VirtualUnitTest.java
+++ b/tycho-its/src/test/java/org/eclipse/tycho/test/p2Inf/VirtualUnitTest.java
@@ -13,6 +13,7 @@
import static org.junit.Assert.assertTrue;
import java.io.File;
+import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
@@ -54,10 +55,29 @@ public void testVirtualUnitRequirementDoesNotFailBuild() throws Exception {
String hostUnitId = "pvu.bundle";
String configureUnitId = "configure.pvu.bundle";
- File p2Content = new File(verifier.getBasedir(), "bundle/target/p2content.xml");
- Document doc = XMLParser.parse(p2Content);
+ List units = getUnits(verifier.getBasedir(), "bundle/target/p2content.xml");
+ Optional hostUnit = findUnit(units, hostUnitId);
+ Optional configureUnit = findUnit(units, configureUnitId);
+
+ Stream hostUnitRequirements = findRequirements(hostUnit);
+
+ assertTrue("Host IU " + hostUnitId + " not found", hostUnit.isPresent());
+ assertTrue("Configure IU " + configureUnitId + " not found", configureUnit.isPresent());
+ assertTrue("Requirement of IU " + configureUnitId + " not found in IU " + hostUnitId,
+ hostUnitRequirements.anyMatch(elem -> configureUnitId.equals(elem.getAttributeValue("name"))));
+ }
+
+ @Test
+ public void testVirtualUnitMultiBundleWithRequirementDoesNotFailBuild() throws Exception {
+ Verifier verifier = getVerifier("/p2Inf.virtualUnit.multiBundle", false);
+ verifier.executeGoals(asList("verify"));
+ verifier.verifyErrorFreeLog();
- List units = doc.getChild("units").getChildren("unit");
+ // Host bundle and virtual IU assertions
+ String hostUnitId = "pvumb.bundle1";
+ String configureUnitId = "configure.pvumb.bundle1";
+
+ List units = getUnits(verifier.getBasedir(), "bundle1/target/p2content.xml");
Optional hostUnit = findUnit(units, hostUnitId);
Optional configureUnit = findUnit(units, configureUnitId);
@@ -67,6 +87,25 @@ public void testVirtualUnitRequirementDoesNotFailBuild() throws Exception {
assertTrue("Configure IU " + configureUnitId + " not found", configureUnit.isPresent());
assertTrue("Requirement of IU " + configureUnitId + " not found in IU " + hostUnitId,
hostUnitRequirements.anyMatch(elem -> configureUnitId.equals(elem.getAttributeValue("name"))));
+
+ // Client bundle assertions
+ String clientUnitId = "pvumb.bundle2";
+
+ units = getUnits(verifier.getBasedir(), "bundle2/target/p2content.xml");
+ Optional clientUnit = findUnit(units, clientUnitId);
+
+ Stream clientUnitRequirements = findRequirements(clientUnit);
+
+ assertTrue("Client IU " + clientUnitId + " not found", clientUnit.isPresent());
+ assertTrue("Requirement of IU " + hostUnitId + " not found in IU " + clientUnitId,
+ clientUnitRequirements.anyMatch(elem -> hostUnitId.equals(elem.getAttributeValue("name"))));
+ }
+
+ private static List getUnits(String baseDir, String filePath) throws IOException {
+ File p2Content = new File(baseDir, filePath);
+ Document doc = XMLParser.parse(p2Content);
+
+ return doc.getChild("units").getChildren("unit");
}
private static Optional findUnit(List units, String hostUnitId) {