- import groovy.mock.interceptor.MockFor
- import static groovy.test.GroovyAssert.*
- import groovy.util.GroovyTestCase
-
- import java.io.FileNotFoundException
-
- import org.wikimedia.integration.Blubber
- import org.wikimedia.integration.PipelineRunner
- import org.wikimedia.integration.Utility
-
- class PipelineRunnerTest extends GroovyTestCase {
- private class WorkflowScript {} // Mock for Jenkins Pipeline workflow context
-
- void setUp() {
- // Mock all static calls to Utility.randomAlphanum
- Utility.metaClass.static.randomAlphanum = { "randomfoo" }
- }
-
- void tearDown() {
- // Reset static mocks
- Utility.metaClass = null
- }
-
- void testConstructor_workflowScript() {
- new PipelineRunner(new WorkflowScript())
- }
-
- void testConstructor_workflowScriptAndProperties() {
- new PipelineRunner(new WorkflowScript(), configPath: "foo")
- }
-
- void testGetConfigFile() {
- def pipeline = new PipelineRunner(new WorkflowScript(), configPath: "foo")
-
- assert pipeline.getConfigFile("bar") == "foo/bar"
- }
-
- void testGetTempFile() {
- def pipeline = new PipelineRunner(new WorkflowScript(), configPath: "foo")
-
- assert pipeline.getTempFile("bar") ==~ /^foo\/bar[a-z0-9]+$/
- }
-
- void testQualifyRegistryPath() {
- def pipeline = new PipelineRunner(new WorkflowScript())
-
- def url = pipeline.qualifyRegistryPath("foo")
-
- assert url == "docker-registry.wikimedia.org/wikimedia/foo"
- }
-
- void testQualifyRegistryPath_disallowsSlashes() {
- def pipeline = new PipelineRunner(new WorkflowScript())
-
- shouldFail(AssertionError) {
- pipeline.qualifyRegistryPath("foo/bar")
- }
- }
-
- void testBuild_checksWhetherConfigExists() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.demand.fileExists { path ->
- assert path == ".pipeline/nonexistent.yaml"
-
- false
- }
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript(),
- configPath: ".pipeline",
- blubberConfig: "nonexistent.yaml")
-
- shouldFail(FileNotFoundException) {
- runner.build("foo", [bar: "baz"])
- }
- }
- }
-
- void testBuild_generatesDockerfileAndBuilds() {
- def mockWorkflow = new MockFor(WorkflowScript)
- def mockBlubber = new MockFor(Blubber)
-
- mockWorkflow.demand.fileExists { true }
-
- mockBlubber.demand.generateDockerfile { variant ->
- assert variant == "foo"
-
- "BASE: foo\n"
- }
-
- mockWorkflow.demand.writeFile { args ->
- assert args.text == "BASE: foo\n"
- assert args.file ==~ /^\.pipeline\/Dockerfile\.[a-z0-9]+$/
- }
-
- mockWorkflow.demand.sh { args ->
- assert args.returnStdout
- assert args.script ==~ (/^docker build --pull --label 'foo=a' --label 'bar=b' / +
- /--file '\.pipeline\/Dockerfile\.[a-z0-9]+' \.$/)
-
- // Mock `docker build` output to test that we correctly parse the image ID
- return "Removing intermediate container foo\n" +
- " ---> bf1e86190382\n" +
- "Successfully built bf1e86190382\n"
- }
-
- mockWorkflow.use {
- mockBlubber.use {
- def runner = new PipelineRunner(new WorkflowScript())
-
- assert runner.build("foo", [foo: "a", bar: "b"]) == "bf1e86190382"
- }
- }
- }
-
- void testDeploy_checksConfigForChart() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.demand.readYaml { Map args ->
- assert args.file == ".foo/bar.yaml"
-
- [chart: null]
- }
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript(),
- configPath: ".foo",
- helmConfig: "bar.yaml")
-
- shouldFail(AssertionError) {
- runner.deploy("foo/name", "footag")
- }
- }
- }
-
- void testDeploy_executesHelm() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.demand.readYaml {
- [chart: "http://an.example/chart.tgz"]
- }
-
- mockWorkflow.demand.sh { cmd ->
- def expectedCmd = "helm --tiller-namespace='ci' install " +
- "--namespace='ci' --set " +
- "'docker.registry=docker-registry.wikimedia.org'," +
- "'docker.pull_policy=IfNotPresent'," +
- "'main_app.image=wikimedia/foo/name'," +
- "'main_app.version=footag' " +
- "-n 'foo/name-randomfoo' " +
- "--debug --wait --timeout 120 " +
- "'http://an.example/chart.tgz'"
-
- assert cmd == expectedCmd
- }
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript())
-
- runner.deploy("foo/name", "footag")
- }
- }
-
- void testDeploy_executesHelmWithKubeConfig() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.demand.readYaml {
- [chart: "http://an.example/chart.tgz"]
- }
-
- mockWorkflow.demand.sh { cmd ->
- def expectedCmd = "KUBECONFIG='/etc/kubernetes/foo.config' " +
- "helm --tiller-namespace='ci' install " +
- "--namespace='ci' --set " +
- "'docker.registry=docker-registry.wikimedia.org'," +
- "'docker.pull_policy=IfNotPresent'," +
- "'main_app.image=wikimedia/foo/name'," +
- "'main_app.version=footag' " +
- "-n 'foo/name-randomfoo' " +
- "--debug --wait --timeout 120 " +
- "'http://an.example/chart.tgz'"
-
- assert cmd == expectedCmd
- }
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript(),
- kubeConfig: "/etc/kubernetes/foo.config")
-
- runner.deploy("foo/name", "footag")
- }
- }
-
- void testPurgeRelease_executesHelm() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.demand.sh { cmd ->
- def expectedCmd = "helm --tiller-namespace='ci' delete --purge 'foorelease'"
-
- assert cmd == expectedCmd
- }
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript())
-
- runner.purgeRelease("foorelease")
- }
- }
-
- void testPurgeRelease_executesHelmWithKubeConfig() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.demand.sh { cmd ->
- def expectedCmd = "KUBECONFIG='/etc/kubernetes/foo.config' " +
- "helm --tiller-namespace='ci' delete --purge 'foorelease'"
-
- assert cmd == expectedCmd
- }
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript(),
- kubeConfig: "/etc/kubernetes/foo.config")
-
- runner.purgeRelease("foorelease")
- }
- }
-
- void testTestRelease_executesHelm() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.demand.sh { cmd ->
- def expectedCmd = "helm --tiller-namespace='ci' test --cleanup 'foorelease'"
-
- assert cmd == expectedCmd
- }
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript())
-
- runner.testRelease("foorelease")
- }
- }
-
- void testTestRelease_executesHelmWithKubeConfig() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.demand.sh { cmd ->
- def expectedCmd = "KUBECONFIG='/etc/kubernetes/foo.config' " +
- "helm --tiller-namespace='ci' test --cleanup 'foorelease'"
-
- assert cmd == expectedCmd
- }
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript(),
- kubeConfig: "/etc/kubernetes/foo.config")
-
- runner.testRelease("foorelease")
- }
- }
-
- void testRegisterAs() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.demand.sh { cmd ->
- assert cmd == "docker tag 'fooID' 'internal.example/foorepo/fooname:footag' && " +
- "sudo /usr/local/bin/docker-pusher 'internal.example/foorepo/fooname:footag'"
- }
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript(),
- registryInternal: 'internal.example',
- repository: 'foorepo')
-
- runner.registerAs("fooID", "fooname", "footag")
- }
- }
-
- void testRegisterAs_bailsOnSlashes() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript())
-
- shouldFail(AssertionError) {
- runner.registerAs("fooID", "foo/name", "footag")
- }
- }
- }
-
- void testRemoveImage() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.demand.sh { cmd ->
- assert cmd == "docker rmi --force 'fooID'"
- }
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript())
-
- runner.removeImage("fooID")
- }
- }
-
- void testRun() {
- def mockWorkflow = new MockFor(WorkflowScript)
-
- mockWorkflow.demand.timeout { Map args, Closure c ->
- assert args.time == 20
- assert args.unit == "MINUTES"
-
- c()
- }
-
- mockWorkflow.demand.sh { cmd ->
- assert cmd == "exec docker run --rm 'foo'"
- }
-
- mockWorkflow.use {
- def runner = new PipelineRunner(new WorkflowScript())
-
- runner.run("foo")
- }
- }
- }
|