Plugin Compatibility Testing
A plugin can be executed inside of a Spinnaker version that is
different than the version it was compiled against. For example, a plugin
compiled against Spinnaker 1.20
might be compatible with Spinnaker versions up
to 1.23
.
This range is important for plugin developers so that they can support users across Spinnaker versions; it’s important for plugin consumers so that they can safely install and upgrade plugins. Fortunately, testing can resolve this compatibility range automatically.
Integration testing
To start, you should write Spring Boot-style integration tests using service test fixtures .
The Spinnaker plugin example repositories have examples of these kinds of tests.
These integration tests have good properties. They execute a service’s main
and
demonstrate that a plugin can be loaded into the service at runtime. You can inject
Spring’s ApplicationContext
into your test class and attempt to retrieve the beans defined by your
plugin.
You can also use these tests to verify the end-to-end behavior of your plugin. For example, if you’re writing a new stage as
a plugin, you can ask Orca’s /orchestrate
endpoint to execute a pipeline that
includes your new stage type.
Automated compatibility testing
These integration tests demonstrate that a compiled plugin can execute inside of a service at runtime. By executing a test multiple times but changing the underlying service version, we can resolve which versions of Spinnaker a plugin is compatible with.
Spinnaker’s Gradle compatibility-test-runner
plugin does exactly this: you
provide a list of Spinnaker versions; it runs your integration tests
against those versions.
Before using this Gradle plugin, check that your integration tests
depend on Spinnaker’s exported Gradle platforms, which take the form <service>-bom
.
For example, if your test relies on orca-api-tck
, your plugin’s subproject build file should look something like this:
dependencies {
// ...
testImplementation("com.netflix.spinnaker.orca:orca-bom:<orca-version>")
testImplementation("com.netflix.spinnaker.orca:orca-api-tck") // Don't specify a version here - it will be resolved by `orca-bom` above.
}
To use the test runner, configure your plugin’s build files:
// Inside root project
plugins {
id("io.spinnaker.plugin.bundler").version("8.6.0") // Must be 8.6.0 or later.
}
spinnakerBundle {
// ...
compatibility {
spinnaker = ["1.21.1", "1.22.0"] // Set of Spinnaker versions to test against.
}
}
// Inside service extension subproject
apply plugin: "io.spinnaker.plugin.compatibility-test-runner"
The plugin will create a set of tasks: a set of compatibilityTest-<subproject-name>-<spinnaker-version>
tasks, and a top-level compatibilityTest
task that will run all of the compatibility test subtasks.
How does it work?
The test runner dynamically creates Gradle source sets for each top-level Spinnaker version you declare
and re-writes your test dependencies to depend on the service Gradle platform version (e.g., com.spinnaker.netflix.orca:orca-bom
)
that corresponds to those Spinnaker versions. It does not alter your plugin’s compile or runtime classpaths.
Your plugin compiles against version X
; the test runner runs your plugin inside Spinnaker Y
and Z
.