import groovy.mock.interceptor.MockFor
|
|
import static groovy.test.GroovyAssert.*
|
|
import groovy.util.GroovyTestCase
|
|
|
|
import org.wikimedia.integration.Pipeline
|
|
import org.wikimedia.integration.PipelineRunner
|
|
import org.wikimedia.integration.PipelineStage
|
|
import org.wikimedia.integration.ExecutionGraph
|
|
import org.wikimedia.integration.ExecutionContext
|
|
|
|
class PipelineStageTest extends GroovyTestCase {
|
|
private class WorkflowScript {} // Mock for Jenkins Pipeline workflow context
|
|
|
|
void testDefaultConfig_shortHand() {
|
|
// shorthand with just name is: build and run a variant
|
|
def cfg = [name: "foo"]
|
|
|
|
assert PipelineStage.defaultConfig(cfg) == [
|
|
name: "foo",
|
|
build: '${.stage}',
|
|
run: [
|
|
image: '${.imageID}',
|
|
arguments: [],
|
|
],
|
|
]
|
|
}
|
|
|
|
void testDefaultConfig_run() {
|
|
def cfg = [
|
|
name: "foo",
|
|
build: "foo",
|
|
run: true,
|
|
]
|
|
|
|
assert PipelineStage.defaultConfig(cfg) == [
|
|
name: "foo",
|
|
build: "foo",
|
|
|
|
// run: true means run the built image
|
|
run: [
|
|
image: '${.imageID}',
|
|
arguments: [],
|
|
],
|
|
]
|
|
}
|
|
|
|
void testDefaultConfig_publish() {
|
|
def cfg = [
|
|
publish: [
|
|
image: true,
|
|
],
|
|
]
|
|
|
|
assert PipelineStage.defaultConfig(cfg) == [
|
|
publish: [
|
|
image: [
|
|
// defaults to the previously built image
|
|
id: '${.imageID}',
|
|
|
|
// defaults to the project name
|
|
name: '${setup.project}',
|
|
|
|
// defaults to the pipeline start timestamp and this stage name
|
|
tag: '${setup.timestamp}-${.stage}',
|
|
|
|
// defaults to []
|
|
tags: [],
|
|
],
|
|
],
|
|
]
|
|
}
|
|
|
|
void testDefaultConfig_deploy() {
|
|
def cfg = [
|
|
deploy: [
|
|
chart: "chart.tar.gz",
|
|
],
|
|
]
|
|
|
|
assert PipelineStage.defaultConfig(cfg) == [
|
|
deploy: [
|
|
chart: "chart.tar.gz",
|
|
|
|
// defaults to the previously published image
|
|
image: '${.publishedImage}',
|
|
|
|
// defaults to "ci"
|
|
cluster: "ci",
|
|
|
|
// defaults to true
|
|
test: true,
|
|
],
|
|
]
|
|
|
|
cfg = [
|
|
deploy: [
|
|
chart: "chart.tar.gz",
|
|
image: "fooimage",
|
|
cluster: "foocluster",
|
|
test: true,
|
|
],
|
|
]
|
|
|
|
assert PipelineStage.defaultConfig(cfg) == [
|
|
deploy: [
|
|
chart: "chart.tar.gz",
|
|
image: "fooimage",
|
|
cluster: "foocluster",
|
|
test: true,
|
|
],
|
|
]
|
|
}
|
|
|
|
void testBuild() {
|
|
def pipeline = new Pipeline("foo", [
|
|
stages: [
|
|
[
|
|
name: "foo",
|
|
build: "foovariant",
|
|
],
|
|
]
|
|
])
|
|
|
|
def mockRunner = new MockFor(PipelineRunner)
|
|
def stack = pipeline.stack()
|
|
def stage = stack[1][0]
|
|
|
|
stubStageContexts(stack, [
|
|
setup: { ctx ->
|
|
ctx["imageLabels"] = [foo: "foolabel", bar: "barlabel"]
|
|
},
|
|
])
|
|
|
|
mockRunner.demand.build { variant, labels ->
|
|
assert variant == "foovariant"
|
|
assert labels == [foo: "foolabel", bar: "barlabel"]
|
|
|
|
"foo-image-id"
|
|
}
|
|
|
|
mockRunner.use {
|
|
def ws = new WorkflowScript()
|
|
def runner = new PipelineRunner(ws)
|
|
|
|
stage.build(ws, runner)
|
|
}
|
|
|
|
assert stage.context["imageID"] == "foo-image-id"
|
|
}
|
|
|
|
void testDeploy_withTest() {
|
|
def pipeline = new Pipeline("foo", [
|
|
stages: [
|
|
[
|
|
name: "foo",
|
|
build: "foovariant",
|
|
publish: [
|
|
image: true,
|
|
],
|
|
],
|
|
[
|
|
name: "bar",
|
|
deploy: [
|
|
image: '${foo.publishedImage}',
|
|
chart: 'https://an.example/chart/foo-${.stage}.tar.gz',
|
|
tag: '${.stage}-tag',
|
|
test: true,
|
|
],
|
|
],
|
|
]
|
|
])
|
|
|
|
def mockRunner = new MockFor(PipelineRunner)
|
|
def stack = pipeline.stack()
|
|
def stage = stack[2][0]
|
|
|
|
stubStageContexts(stack, [
|
|
foo: { ctx ->
|
|
ctx["imageID"] = "foo-image-id"
|
|
|
|
ctx["imageName"] = "foo-project"
|
|
ctx["imageFullName"] = "registry.example/bar/foo-project"
|
|
ctx["imageTag"] = "0000-00-00-000000-foo"
|
|
ctx["imageTags"] = ["0000-00-00-000000-foo"]
|
|
ctx["publishedImage"] = "registry.example/bar/foo-project:0000-00-00-000000-foo"
|
|
},
|
|
])
|
|
|
|
mockRunner.demand.deployWithChart { chart, image, tag ->
|
|
assert chart == "https://an.example/chart/foo-bar.tar.gz"
|
|
assert image == "registry.example/bar/foo-project:0000-00-00-000000-foo"
|
|
assert tag == "bar-tag"
|
|
|
|
"bar-release-name"
|
|
}
|
|
|
|
mockRunner.demand.testRelease { releaseName ->
|
|
assert releaseName == "bar-release-name"
|
|
}
|
|
|
|
mockRunner.use {
|
|
def ws = new WorkflowScript()
|
|
def runner = new PipelineRunner(ws)
|
|
|
|
stage.deploy(ws, runner)
|
|
}
|
|
|
|
assert stage.context["releaseName"] == "bar-release-name"
|
|
}
|
|
|
|
void testDeploy_withoutTest() {
|
|
def pipeline = new Pipeline("foo", [
|
|
stages: [
|
|
[
|
|
name: "foo",
|
|
build: "foovariant",
|
|
publish: [
|
|
image: true,
|
|
],
|
|
],
|
|
[
|
|
name: "bar",
|
|
deploy: [
|
|
image: '${foo.publishedImage}',
|
|
chart: 'https://an.example/chart/foo-${.stage}.tar.gz',
|
|
tag: '${.stage}-tag',
|
|
test: false,
|
|
],
|
|
],
|
|
]
|
|
])
|
|
|
|
def mockRunner = new MockFor(PipelineRunner)
|
|
def stack = pipeline.stack()
|
|
def stage = stack[2][0]
|
|
|
|
stubStageContexts(stack, [
|
|
foo: { ctx ->
|
|
ctx["imageID"] = "foo-image-id"
|
|
|
|
ctx["imageName"] = "foo-project"
|
|
ctx["imageFullName"] = "registry.example/bar/foo-project"
|
|
ctx["imageTag"] = "0000-00-00-000000-foo"
|
|
ctx["imageTags"] = ["0000-00-00-000000-foo"]
|
|
ctx["publishedImage"] = "registry.example/bar/foo-project:0000-00-00-000000-foo"
|
|
},
|
|
])
|
|
|
|
mockRunner.demand.deployWithChart { chart, image, tag ->
|
|
assert chart == "https://an.example/chart/foo-bar.tar.gz"
|
|
assert image == "registry.example/bar/foo-project:0000-00-00-000000-foo"
|
|
assert tag == "bar-tag"
|
|
|
|
"bar-release-name"
|
|
}
|
|
|
|
mockRunner.use {
|
|
def ws = new WorkflowScript()
|
|
def runner = new PipelineRunner(ws)
|
|
|
|
stage.deploy(ws, runner)
|
|
}
|
|
|
|
assert stage.context["releaseName"] == "bar-release-name"
|
|
}
|
|
|
|
void testExports() {
|
|
def pipeline = new Pipeline("foo", [
|
|
stages: [
|
|
[
|
|
name: "foo",
|
|
build: "foovariant",
|
|
exports: [
|
|
thing: '${.imageID}-${setup.timestamp}',
|
|
],
|
|
],
|
|
]
|
|
])
|
|
|
|
def mockRunner = new MockFor(PipelineRunner)
|
|
def mockWS = new MockFor(WorkflowScript)
|
|
def stack = pipeline.stack()
|
|
def stage = stack[1][0]
|
|
|
|
stubStageContexts(stack, [
|
|
setup: { ctx ->
|
|
ctx["timestamp"] = "0000-00-00-000000"
|
|
},
|
|
foo: { ctx ->
|
|
ctx["imageID"] = "foo-image-id"
|
|
},
|
|
])
|
|
|
|
mockWS.demand.echo { msg ->
|
|
assert msg == "exported foo.thing='foo-image-id-0000-00-00-000000'"
|
|
}
|
|
|
|
mockWS.use {
|
|
mockRunner.use {
|
|
def ws = new WorkflowScript()
|
|
def runner = new PipelineRunner(ws)
|
|
|
|
stage.exports(ws, runner)
|
|
}
|
|
}
|
|
|
|
assert stage.context["thing"] == "foo-image-id-0000-00-00-000000"
|
|
}
|
|
|
|
void testPublish() {
|
|
def pipeline = new Pipeline("foopipeline", [
|
|
stages: [
|
|
[
|
|
name: "built",
|
|
build: "foovariant",
|
|
],
|
|
[
|
|
name: "published",
|
|
publish: [
|
|
image: [
|
|
id: '${built.imageID}',
|
|
],
|
|
],
|
|
]
|
|
]
|
|
])
|
|
|
|
def mockRunner = new MockFor(PipelineRunner)
|
|
def stack = pipeline.stack()
|
|
def stage = stack[2][0]
|
|
|
|
stubStageContexts(stack, [
|
|
setup: { ctx ->
|
|
ctx["project"] = "foo-project"
|
|
ctx["timestamp"] = "0000-00-00-000000"
|
|
ctx["imageLabels"] = []
|
|
},
|
|
built: { ctx ->
|
|
ctx["imageID"] = "foo-image-id"
|
|
},
|
|
])
|
|
|
|
mockRunner.demand.registerAs { imageID, imageName, tag ->
|
|
assert imageID == "foo-image-id"
|
|
assert imageName == "foo-project"
|
|
assert tag == "0000-00-00-000000-published"
|
|
}
|
|
|
|
mockRunner.demand.qualifyRegistryPath { imageName ->
|
|
assert imageName == "foo-project"
|
|
|
|
"registry.example/bar/foo-project"
|
|
}
|
|
|
|
mockRunner.use {
|
|
def ws = new WorkflowScript()
|
|
def runner = new PipelineRunner(ws)
|
|
|
|
stage.publish(ws, runner)
|
|
}
|
|
|
|
assert stage.context["imageName"] == "foo-project"
|
|
assert stage.context["imageFullName"] == "registry.example/bar/foo-project"
|
|
assert stage.context["imageTag"] == "0000-00-00-000000-published"
|
|
assert stage.context["imageTags"] == ["0000-00-00-000000-published"]
|
|
assert stage.context["publishedImage"] == "registry.example/bar/foo-project:0000-00-00-000000-published"
|
|
}
|
|
|
|
void testRun() {
|
|
def pipeline = new Pipeline("foo", [
|
|
stages: [
|
|
[
|
|
name: "foo",
|
|
build: "foovariant",
|
|
],
|
|
[
|
|
name: "bar",
|
|
run: [
|
|
image: '${foo.imageID}',
|
|
arguments: ['${.stage}arg'],
|
|
],
|
|
],
|
|
]
|
|
])
|
|
|
|
def mockRunner = new MockFor(PipelineRunner)
|
|
def stack = pipeline.stack()
|
|
def stage = stack[2][0]
|
|
|
|
stubStageContexts(stack, [
|
|
foo: { ctx ->
|
|
ctx["imageID"] = "foo-image-id"
|
|
},
|
|
])
|
|
|
|
mockRunner.demand.run { image, args ->
|
|
assert image == "foo-image-id"
|
|
assert args == ["bararg"]
|
|
}
|
|
|
|
mockRunner.use {
|
|
def ws = new WorkflowScript()
|
|
def runner = new PipelineRunner(ws)
|
|
|
|
stage.run(ws, runner)
|
|
}
|
|
}
|
|
|
|
private void stubStageContexts(stack, stubs) {
|
|
stack.each { stages ->
|
|
stages.each { stage ->
|
|
stage.context["stage"] = stage.name
|
|
|
|
stubs.each { stageName, stub ->
|
|
if (stage.name == stageName) {
|
|
stub(stage.context)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|