This is an automated email from the ASF dual-hosted git repository.

royteeuwen pushed a commit to branch SLING-13233
in repository https://gitbox.apache.org/repos/asf/sling-whiteboard.git

commit f25a3e2a46f150c266c8202904439e1f94dc38aa
Author: Roy Teeuwen <[email protected]>
AuthorDate: Mon Jun 8 22:03:01 2026 +0200

    SLING-13233: add feature-launcher IT example showcasing build-local cp2fm 
aggregation
    
    A minimal content-package + bundle + all + it.tests example that converts 
the
    content package to a feature, aggregates it with the Sling Starter, and 
launches
    it - resolving the converted artifacts from the build's own 
target/cp-conversion
    directory, so nothing is installed into ~/.m2.
    
    Demonstrates:
    - slingfeature-maven-plugin: <additionalFeatureFiles> + 
<osgiBsnCollisionDetection>
    - feature-launcher-maven-plugin: <additionalRepositoryUrls> (extends, not 
replaces, the defaults)
    - sling-feature-converter-maven-plugin: installConvertedCP=false to stay 
build-local
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
---
 feature-launcher-it-example/README.md              |  59 ++++++
 feature-launcher-it-example/all/pom.xml            |  75 +++++++
 .../all/src/main/content/META-INF/vault/filter.xml |   4 +
 feature-launcher-it-example/bundle/pom.xml         |  62 ++++++
 .../apache/sling/fmexample/ExampleComponent.java   |  37 ++++
 feature-launcher-it-example/content/pom.xml        |  48 +++++
 .../src/main/content/META-INF/vault/filter.xml     |   4 +
 .../jcr_root/content/fmexample/.content.xml        |   5 +
 feature-launcher-it-example/it.tests/pom.xml       | 216 +++++++++++++++++++++
 .../apache/sling/fmexample/it/ExampleBundleIT.java |  83 ++++++++
 feature-launcher-it-example/pom.xml                |  96 +++++++++
 11 files changed, 689 insertions(+)

diff --git a/feature-launcher-it-example/README.md 
b/feature-launcher-it-example/README.md
new file mode 100644
index 00000000..d0129b66
--- /dev/null
+++ b/feature-launcher-it-example/README.md
@@ -0,0 +1,59 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+# Feature Launcher IT Example (SLING-13233)
+
+A minimal, **fully build-local** integration-test setup: a content package 
that embeds a bundle is
+converted to a feature model, aggregated with the Sling Starter, and launched 
— with all converted
+artifacts resolved from the build's own `target/` directory, so nothing is 
installed into `~/.m2`.
+
+## Modules
+
+| Module | Packaging | Purpose |
+|--------|-----------|---------|
+| `bundle` | `bundle` | A trivial OSGi DS component (proof that "something" 
reaches `ACTIVE`). |
+| `content` | `content-package` | Some dummy JCR content under 
`/content/fmexample`. |
+| `all` | `content-package` | Container package embedding the bundle and the 
content package. |
+| `it.tests` | `jar` | Converts → aggregates → launches → tests. |
+
+## The pipeline (all in `it.tests`)
+
+1. **`sling-feature-converter-maven-plugin:convert-cp`** (`initialize`) 
converts the `all` package into a
+   feature model under `target/cp-conversion/fm.out/` and writes the converted 
bundles + residual
+   `*-cp2fm-converted.zip` content packages under `target/cp-conversion/`. 
**`installConvertedCP=false`** keeps
+   them build-local (nothing is copied to `~/.m2`).
+2. **`slingfeature-maven-plugin:aggregate-features`** (`generate-resources`) 
aggregates the Sling Starter
+   (`<includeArtifact>`) with the converted feature, read at goal time via 
**`<additionalFeatureFiles>`**.
+   **`<osgiBsnCollisionDetection>`** enforces OSGi `Bundle-SymbolicName` 
uniqueness (collisions resolved by
+   the `*:*:HIGHEST` override).
+3. **`feature-launcher-maven-plugin`** launches the aggregated feature. 
**`<additionalRepositoryUrls>`**
+   points at `target/cp-conversion`, which is consulted *before* the 
local/remote repositories, so the
+   build-local converted artifacts resolve without remote lookups (and without 
an `~/.m2` install).
+4. **`maven-failsafe-plugin`** runs `ExampleBundleIT`, which asserts the 
example bundle is `ACTIVE` on the
+   launched instance.
+
+## Plugin features demonstrated (SLING-13233)
+
+- `slingfeature-maven-plugin`: `<additionalFeatureFiles>` and 
`<osgiBsnCollisionDetection>`.
+- `feature-launcher-maven-plugin`: `<additionalRepositoryUrls>` (extends, 
rather than replaces, the default
+  repository list).
+- `sling-feature-converter-maven-plugin`: `installConvertedCP=false` to stay 
build-local.
+
+## Run it
+
+```
+mvn clean verify
+```
diff --git a/feature-launcher-it-example/all/pom.xml 
b/feature-launcher-it-example/all/pom.xml
new file mode 100644
index 00000000..e6b97ca5
--- /dev/null
+++ b/feature-launcher-it-example/all/pom.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>org.apache.sling.fmexample</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.apache.sling.fmexample.all</artifactId>
+    <packaging>content-package</packaging>
+    <name>Apache Sling - Feature Launcher IT Example - All</name>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.jackrabbit</groupId>
+                <artifactId>filevault-package-maven-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <group>org.apache.sling.fmexample</group>
+                    <packageType>container</packageType>
+                    <!-- example package: skip the strict filevault content 
checks -->
+                    <skipValidation>true</skipValidation>
+                    <embeddeds>
+                        <embedded>
+                            <groupId>org.apache.sling</groupId>
+                            
<artifactId>org.apache.sling.fmexample.bundle</artifactId>
+                            
<target>/apps/fmexample-packages/application/install</target>
+                        </embedded>
+                        <embedded>
+                            <groupId>org.apache.sling</groupId>
+                            
<artifactId>org.apache.sling.fmexample.content</artifactId>
+                            <type>zip</type>
+                            
<target>/apps/fmexample-packages/application/install</target>
+                        </embedded>
+                    </embeddeds>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.fmexample.bundle</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.fmexample.content</artifactId>
+            <version>${project.version}</version>
+            <type>zip</type>
+        </dependency>
+    </dependencies>
+</project>
diff --git 
a/feature-launcher-it-example/all/src/main/content/META-INF/vault/filter.xml 
b/feature-launcher-it-example/all/src/main/content/META-INF/vault/filter.xml
new file mode 100644
index 00000000..4c63b13a
--- /dev/null
+++ b/feature-launcher-it-example/all/src/main/content/META-INF/vault/filter.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<workspaceFilter version="1.0">
+    <filter root="/apps/fmexample-packages"/>
+</workspaceFilter>
diff --git a/feature-launcher-it-example/bundle/pom.xml 
b/feature-launcher-it-example/bundle/pom.xml
new file mode 100644
index 00000000..a3b3251d
--- /dev/null
+++ b/feature-launcher-it-example/bundle/pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>org.apache.sling.fmexample</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.apache.sling.fmexample.bundle</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Sling - Feature Launcher IT Example - Bundle</name>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.service.component.annotations</artifactId>
+            <version>1.5.1</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <version>1.7.36</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git 
a/feature-launcher-it-example/bundle/src/main/java/org/apache/sling/fmexample/ExampleComponent.java
 
b/feature-launcher-it-example/bundle/src/main/java/org/apache/sling/fmexample/ExampleComponent.java
new file mode 100644
index 00000000..0e378174
--- /dev/null
+++ 
b/feature-launcher-it-example/bundle/src/main/java/org/apache/sling/fmexample/ExampleComponent.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.fmexample;
+
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Trivial immediate component. Its only purpose is to give the example bundle 
something to do, so the
+ * integration test can verify the bundle reaches the ACTIVE state once the 
launched instance is up.
+ */
+@Component(immediate = true, service = ExampleComponent.class)
+public class ExampleComponent {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(ExampleComponent.class);
+
+    @Activate
+    public void activate() {
+        LOG.info("Apache Sling Feature Launcher IT example bundle activated");
+    }
+}
diff --git a/feature-launcher-it-example/content/pom.xml 
b/feature-launcher-it-example/content/pom.xml
new file mode 100644
index 00000000..d1207665
--- /dev/null
+++ b/feature-launcher-it-example/content/pom.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>org.apache.sling.fmexample</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.apache.sling.fmexample.content</artifactId>
+    <packaging>content-package</packaging>
+    <name>Apache Sling - Feature Launcher IT Example - Content Package</name>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.jackrabbit</groupId>
+                <artifactId>filevault-package-maven-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <group>org.apache.sling.fmexample</group>
+                    <packageType>content</packageType>
+                    <!-- example package: skip the strict filevault content 
checks -->
+                    <skipValidation>true</skipValidation>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git 
a/feature-launcher-it-example/content/src/main/content/META-INF/vault/filter.xml
 
b/feature-launcher-it-example/content/src/main/content/META-INF/vault/filter.xml
new file mode 100644
index 00000000..940eb192
--- /dev/null
+++ 
b/feature-launcher-it-example/content/src/main/content/META-INF/vault/filter.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<workspaceFilter version="1.0">
+    <filter root="/content/fmexample"/>
+</workspaceFilter>
diff --git 
a/feature-launcher-it-example/content/src/main/content/jcr_root/content/fmexample/.content.xml
 
b/feature-launcher-it-example/content/src/main/content/jcr_root/content/fmexample/.content.xml
new file mode 100644
index 00000000..25672958
--- /dev/null
+++ 
b/feature-launcher-it-example/content/src/main/content/jcr_root/content/fmexample/.content.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jcr:root xmlns:jcr="http://www.jcp.org/jcr/1.0";
+          xmlns:sling="http://sling.apache.org/jcr/sling/1.0";
+          jcr:primaryType="sling:Folder"
+          jcr:title="Feature Launcher IT Example"/>
diff --git a/feature-launcher-it-example/it.tests/pom.xml 
b/feature-launcher-it-example/it.tests/pom.xml
new file mode 100644
index 00000000..64e4cadf
--- /dev/null
+++ b/feature-launcher-it-example/it.tests/pom.xml
@@ -0,0 +1,216 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.sling</groupId>
+        <artifactId>org.apache.sling.fmexample</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>org.apache.sling.fmexample.it.tests</artifactId>
+    <name>Apache Sling - Feature Launcher IT Example - IT Tests</name>
+
+    <properties>
+        <maven.deploy.skip>true</maven.deploy.skip>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>reserve-network-port</id>
+                        <goals>
+                            <goal>reserve-network-port</goal>
+                        </goals>
+                        <phase>process-resources</phase>
+                        <configuration>
+                            <portNames>
+                                <portName>http.port</portName>
+                            </portNames>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- 1. Convert the 'all' content package into a feature model. 
installConvertedCP=false keeps the
+                    converted bundles + cp2fm content packages build-local 
under target/cp-conversion. -->
+            <plugin>
+                <groupId>org.apache.sling</groupId>
+                <artifactId>sling-feature-converter-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>convert-cp-to-fm</id>
+                        <phase>initialize</phase>
+                        <goals>
+                            <goal>convert-cp</goal>
+                        </goals>
+                        <configuration>
+                            <contentPackages>
+                                <contentPackage>
+                                    <groupId>org.apache.sling</groupId>
+                                    
<artifactId>org.apache.sling.fmexample.all</artifactId>
+                                </contentPackage>
+                            </contentPackages>
+                            <!-- false (default is true): do NOT install the 
converted bundles + cp2fm
+                                 content packages into the local Maven repo 
(~/.m2). They stay under
+                                 target/cp-conversion and the launcher reads 
them from there via
+                                 <additionalRepositoryUrls>, so this build 
never writes to ~/.m2. -->
+                            <installConvertedCP>false</installConvertedCP>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- 2. Aggregate Sling Starter + the converted feature into one 
launchable feature. The converted
+                    feature is read at goal time via additionalFeatureFiles; 
osgiBsnCollisionDetection enforces
+                    OSGi Bundle-SymbolicName uniqueness (collisions resolved 
by the *:*:HIGHEST rule). -->
+            <plugin>
+                <groupId>org.apache.sling</groupId>
+                <artifactId>slingfeature-maven-plugin</artifactId>
+                <extensions>true</extensions>
+                <executions>
+                    <execution>
+                        <id>aggregate-it-feature</id>
+                        <phase>generate-resources</phase>
+                        <goals>
+                            <goal>aggregate-features</goal>
+                        </goals>
+                        <configuration>
+                            <aggregates>
+                                <aggregate>
+                                    <classifier>it</classifier>
+                                    <attach>false</attach>
+                                    <includeArtifact>
+                                        <groupId>org.apache.sling</groupId>
+                                        
<artifactId>org.apache.sling.starter</artifactId>
+                                        
<version>${sling.starter.version}</version>
+                                        <classifier>oak_tar</classifier>
+                                        <type>slingosgifeature</type>
+                                    </includeArtifact>
+                                    <additionalFeatureFiles>
+                                        
<additionalFeatureFile>${project.build.directory}/cp-conversion/fm.out/org.apache.sling.fmexample.all.json</additionalFeatureFile>
+                                    </additionalFeatureFiles>
+                                    <artifactsOverrides>
+                                        
<artifactsOverride>*:*:HIGHEST</artifactsOverride>
+                                    </artifactsOverrides>
+                                    
<osgiBsnCollisionDetection>true</osgiBsnCollisionDetection>
+                                </aggregate>
+                            </aggregates>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- 3. Launch the aggregated feature. additionalRepositoryUrls 
resolves the build-local converted
+                    artifacts from target/cp-conversion first, so nothing has 
to be installed into ~/.m2. -->
+            <plugin>
+                <groupId>org.apache.sling</groupId>
+                <artifactId>feature-launcher-maven-plugin</artifactId>
+                <configuration>
+                    <featureLauncherVersion>1.3.6</featureLauncherVersion>
+                    <launches>
+                        <launch>
+                            <id>model</id>
+                            <skip>${skipTests}</skip>
+                            
<featureFile>${project.build.directory}/slingfeature-tmp/feature-it.json</featureFile>
+                            <additionalRepositoryUrls>
+                                
<additionalRepositoryUrl>file://${project.build.directory}/cp-conversion</additionalRepositoryUrl>
+                            </additionalRepositoryUrls>
+                            <launcherArguments>
+                                <frameworkProperties>
+                                    
<org.osgi.service.http.port>${http.port}</org.osgi.service.http.port>
+                                </frameworkProperties>
+                            </launcherArguments>
+                            <startTimeoutSeconds>180</startTimeoutSeconds>
+                        </launch>
+                    </launches>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>start</goal>
+                            <goal>stop</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- 4. Run the integration tests against the launched instance. 
-->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-failsafe-plugin</artifactId>
+                <configuration>
+                    <systemPropertyVariables>
+                        <HTTP_PORT>${http.port}</HTTP_PORT>
+                    </systemPropertyVariables>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>integration-test</goal>
+                            <goal>verify</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <!-- Reactor ordering: the 'all' package is built (and converted 
above) before this module. -->
+        <dependency>
+            <groupId>org.apache.sling</groupId>
+            <artifactId>org.apache.sling.fmexample.all</artifactId>
+            <version>${project.version}</version>
+            <type>zip</type>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter</artifactId>
+            <version>5.10.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <version>4.2.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.5.14</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.11.0</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git 
a/feature-launcher-it-example/it.tests/src/test/java/org/apache/sling/fmexample/it/ExampleBundleIT.java
 
b/feature-launcher-it-example/it.tests/src/test/java/org/apache/sling/fmexample/it/ExampleBundleIT.java
new file mode 100644
index 00000000..fbc97474
--- /dev/null
+++ 
b/feature-launcher-it-example/it.tests/src/test/java/org/apache/sling/fmexample/it/ExampleBundleIT.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.fmexample.it;
+
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+import java.util.Base64;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.junit.jupiter.api.Test;
+
+import static org.awaitility.Awaitility.await;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Verifies that the example bundle - which travelled content-package -&gt; 
cp2fm feature -&gt; aggregate -&gt;
+ * launcher - is installed and ACTIVE on the launched Sling instance.
+ */
+class ExampleBundleIT {
+
+    private static final String BUNDLE_SYMBOLIC_NAME = 
"org.apache.sling.fmexample.bundle";
+    private static final String AUTH =
+            "Basic " + 
Base64.getEncoder().encodeToString("admin:admin".getBytes(StandardCharsets.UTF_8));
+
+    private final int port = Integer.getInteger("HTTP_PORT", 8080);
+    private final String consoleUrl = "http://localhost:"; + port + 
"/system/console/bundles.json";
+
+    @Test
+    void exampleBundleIsActive() {
+        try (CloseableHttpClient client = HttpClients.createDefault()) {
+            await().atMost(Duration.ofMinutes(2))
+                    .pollInterval(Duration.ofSeconds(3))
+                    .ignoreExceptions()
+                    .untilAsserted(() -> assertEquals("Active", 
bundleState(client)));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private String bundleState(CloseableHttpClient client) throws Exception {
+        HttpGet get = new HttpGet(consoleUrl);
+        get.setHeader("Authorization", AUTH); // preemptive basic auth for the 
Felix web console
+        try (CloseableHttpResponse response = client.execute(get)) {
+            int status = response.getStatusLine().getStatusCode();
+            String body = EntityUtils.toString(response.getEntity());
+            String snippet = body.substring(0, Math.min(200, body.length()));
+            assertEquals(200, status, "unexpected status, body=" + snippet);
+            assertTrue(body.trim().startsWith("{"), "expected JSON, got: " + 
snippet);
+
+            JsonArray bundles =
+                    
JsonParser.parseString(body).getAsJsonObject().getAsJsonArray("data");
+            for (int i = 0; i < bundles.size(); i++) {
+                JsonObject bundle = bundles.get(i).getAsJsonObject();
+                if 
(BUNDLE_SYMBOLIC_NAME.equals(bundle.get("symbolicName").getAsString())) {
+                    return bundle.get("state").getAsString();
+                }
+            }
+            return "NOT_PRESENT";
+        }
+    }
+}
diff --git a/feature-launcher-it-example/pom.xml 
b/feature-launcher-it-example/pom.xml
new file mode 100644
index 00000000..c0f00078
--- /dev/null
+++ b/feature-launcher-it-example/pom.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.sling</groupId>
+    <artifactId>org.apache.sling.fmexample</artifactId>
+    <version>1.0.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>Apache Sling - Feature Launcher IT Example (SLING-13233)</name>
+    <description>
+        Showcases a fully build-local integration-test setup: a content 
package embedding a bundle is
+        converted to a feature model, aggregated with the Sling Starter, and 
launched - resolving the
+        converted artifacts from the build's own target/cp-conversion 
directory (no ~/.m2 install).
+    </description>
+
+    <modules>
+        <module>bundle</module>
+        <module>content</module>
+        <module>all</module>
+        <module>it.tests</module>
+    </modules>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.release>17</maven.compiler.release>
+        <sling.starter.version>14</sling.starter.version>
+    </properties>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <version>3.13.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.felix</groupId>
+                    <artifactId>maven-bundle-plugin</artifactId>
+                    <version>5.1.9</version>
+                    <extensions>true</extensions>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.jackrabbit</groupId>
+                    <artifactId>filevault-package-maven-plugin</artifactId>
+                    <version>1.3.6</version>
+                    <extensions>true</extensions>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.sling</groupId>
+                    
<artifactId>sling-feature-converter-maven-plugin</artifactId>
+                    <version>1.0.14</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.sling</groupId>
+                    <artifactId>slingfeature-maven-plugin</artifactId>
+                    <version>1.9.5-SNAPSHOT</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.sling</groupId>
+                    <artifactId>feature-launcher-maven-plugin</artifactId>
+                    <version>1.0.5-SNAPSHOT</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.codehaus.mojo</groupId>
+                    <artifactId>build-helper-maven-plugin</artifactId>
+                    <version>3.2.0</version>
+                </plugin>
+                <plugin>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-failsafe-plugin</artifactId>
+                    <version>3.3.1</version>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+</project>


Reply via email to