You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

422 lines
9.7 KiB

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)
}
}
}
}
}
}