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 dff189be622ba47d4c3145ca41811aebb9a239a6 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 | 215 +++++++++++++++++++++ .../apache/sling/fmexample/it/ExampleBundleIT.java | 83 ++++++++ feature-launcher-it-example/pom.xml | 96 +++++++++ 11 files changed, 688 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..bec2e4e3 --- /dev/null +++ b/feature-launcher-it-example/it.tests/pom.xml @@ -0,0 +1,215 @@ +<?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> + <fmOutput>${project.build.directory}/cp-conversion/fm.out</fmOutput> + <bundleStartOrder>20</bundleStartOrder> + <installConvertedCP>false</installConvertedCP> + <mergeConfigurations>true</mergeConfigurations> + </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 -> cp2fm feature -> aggregate -> + * 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>
