|
| 1 | +import aQute.bnd.gradle.Bundle |
| 2 | +import aQute.bnd.gradle.Resolve |
| 3 | +import aQute.bnd.gradle.TestOSGi |
| 4 | + |
| 5 | +plugins { |
| 6 | + id("otel.java-conventions") |
| 7 | +} |
| 8 | + |
| 9 | +description = "OpenTelemetry Semantic Conventions OSGi Integration Tests" |
| 10 | +otelJava.moduleName.set("io.opentelemetry.semconv.integration.tests.osgi") |
| 11 | +// This module runs OSGi tests against the published semconv bundles; it does not publish an OSGi |
| 12 | +// bundle itself. |
| 13 | +otelJava.osgiEnabled.set(false) |
| 14 | + |
| 15 | +// The semconv bundles Import-Package io.opentelemetry.api.common, so resolution needs an |
| 16 | +// opentelemetry-api that is itself a proper OSGi bundle. OSGi metadata was added to the core |
| 17 | +// artifacts in opentelemetry-java#8417, well after the 1.33.0 compileOnly baseline pinned in |
| 18 | +// :dependencyManagement, so we force a recent version on this test module's classpath only. |
| 19 | +val osgiOtelApiVersion = "1.63.0" |
| 20 | + |
| 21 | +configurations.configureEach { |
| 22 | + resolutionStrategy { |
| 23 | + force("io.opentelemetry:opentelemetry-api:$osgiOtelApiVersion") |
| 24 | + } |
| 25 | +} |
| 26 | + |
| 27 | +dependencies { |
| 28 | + testImplementation(project(":semconv")) |
| 29 | + testImplementation(project(":semconv-incubating")) |
| 30 | + // Provides the io.opentelemetry.api.* packages the semconv bundles import, as an OSGi bundle. |
| 31 | + testImplementation("io.opentelemetry:opentelemetry-api:$osgiOtelApiVersion") |
| 32 | + |
| 33 | + testImplementation("org.osgi:org.osgi.test.junit5:1.3.0") |
| 34 | + // Provided by the OSGi framework at runtime. |
| 35 | + testCompileOnly("org.osgi:osgi.core:8.0.0") |
| 36 | + |
| 37 | + testRuntimeOnly("org.junit.platform:junit-platform-launcher") |
| 38 | + testRuntimeOnly("org.apache.felix:org.apache.felix.framework:7.0.5") |
| 39 | + // opentelemetry-common (pulled in transitively by opentelemetry-api) declares |
| 40 | + // Require-Capability: osgi.extender=osgi.serviceloader.processor, so the container needs Aries |
| 41 | + // SPI Fly to resolve even though semconv itself has no ServiceLoader providers. |
| 42 | + testRuntimeOnly("org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle:1.3.7") |
| 43 | +} |
| 44 | + |
| 45 | +// The testing bundle (our JUnit tests + Test-Cases header) is booted inside a real Felix container |
| 46 | +// via bnd's Bundle -> Resolve -> TestOSGi task chain, modeled on opentelemetry-java's |
| 47 | +// integration-tests/osgi module. |
| 48 | +val bsn = "opentelemetry-semconv-osgi-testing" |
| 49 | +val runee = "JavaSE-${java.toolchain.languageVersion.get()}" |
| 50 | +val testRuntimeClasspath = sourceSets.test.get().runtimeClasspath |
| 51 | + |
| 52 | +val testingBundle = tasks.register<Bundle>("testingBundle") { |
| 53 | + archiveClassifier.set("testing") |
| 54 | + from(sourceSets.test.get().output) |
| 55 | + bundle { |
| 56 | + // BND analyses compileClasspath by default; use the runtime classpath so testImplementation |
| 57 | + // deps (junit-jupiter, assertj) are visible and Test-Cases gets populated. |
| 58 | + classpath(testRuntimeClasspath) |
| 59 | + bnd( |
| 60 | + "Bundle-SymbolicName: $bsn", |
| 61 | + "Test-Cases: \${classes;HIERARCHY_INDIRECTLY_ANNOTATED;org.junit.platform.commons.annotation.Testable;CONCRETE}", |
| 62 | + ) |
| 63 | + } |
| 64 | +} |
| 65 | + |
| 66 | +val inputBndrun = layout.buildDirectory.file("bndrun/test.bndrun") |
| 67 | +val generateBndrun = tasks.register("generateBndrun") { |
| 68 | + // Local copies so the doLast closure captures only serializable values (String, Provider), not |
| 69 | + // the enclosing Kotlin build-script object (required by the configuration cache). |
| 70 | + val bndrunFile = inputBndrun |
| 71 | + val bndrunContent = |
| 72 | + """ |
| 73 | + |-tester: biz.aQute.tester.junit-platform |
| 74 | + |-runfw: org.apache.felix.framework |
| 75 | + |-runee: $runee |
| 76 | + | |
| 77 | + |-runrequires: \ |
| 78 | + | bnd.identity;id='$bsn',\ |
| 79 | + | bnd.identity;id='junit-jupiter-engine',\ |
| 80 | + | bnd.identity;id='junit-platform-launcher' |
| 81 | + """.trimMargin() |
| 82 | + inputs.property("content", bndrunContent) |
| 83 | + outputs.file(bndrunFile) |
| 84 | + doLast { |
| 85 | + bndrunFile.get().asFile.apply { parentFile.mkdirs() }.writeText(bndrunContent) |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +val resolvedBndrun = layout.buildDirectory.file("test.bndrun") |
| 90 | +val resolve = tasks.register<Resolve>("resolve") { |
| 91 | + dependsOn(testingBundle, generateBndrun) |
| 92 | + description = "Resolve the semconv OSGi test suite" |
| 93 | + group = JavaBasePlugin.VERIFICATION_GROUP |
| 94 | + bndrun = inputBndrun.get().asFile |
| 95 | + outputBndrun = resolvedBndrun |
| 96 | + bundles = files(testRuntimeClasspath, testingBundle.get().archiveFile) |
| 97 | + // The resolved bndrun embeds an absolute path to the input, so it is not safe to share via cache. |
| 98 | + outputs.cacheIf { false } |
| 99 | +} |
| 100 | + |
| 101 | +tasks.register<TestOSGi>("testOsgi") { |
| 102 | + dependsOn(resolve) |
| 103 | + description = "Run the semconv OSGi test suite inside an Apache Felix container" |
| 104 | + group = JavaBasePlugin.VERIFICATION_GROUP |
| 105 | + bndrun = resolvedBndrun |
| 106 | + bundles = files(testRuntimeClasspath, testingBundle.get().archiveFile) |
| 107 | + // BND reports success when zero tests ran (e.g. if bundles failed to start). Fail explicitly. |
| 108 | + val testResultsDir = layout.buildDirectory.dir("test-results/$name") |
| 109 | + doLast { |
| 110 | + check(testResultsDir.get().asFile.listFiles()?.isNotEmpty() == true) { |
| 111 | + "No OSGi test results found — bundles may have failed to start. Check the output above." |
| 112 | + } |
| 113 | + } |
| 114 | +} |
| 115 | + |
| 116 | +tasks { |
| 117 | + named<Jar>("jar") { |
| 118 | + enabled = false |
| 119 | + } |
| 120 | + named<Test>("test") { |
| 121 | + // Replace plain JUnit execution with the in-container OSGi test. |
| 122 | + actions.clear() |
| 123 | + dependsOn("testOsgi") |
| 124 | + } |
| 125 | +} |
0 commit comments