Browse Source

pipeline: Provide a rickety but useful system test

Unit testing this library does not give adequate confidence in the
working state of the overall system. The provided `systemtest` Makefile
target can be used to run a very broad system-level test using Jenkins
running in a local Docker context. It's not safe to run in CI (requires
bind mounting the Docker socket within the Jenkins container so that it
can actual perform builds) but it's useful for local development.

Change-Id: Ib9645afa993fa7d247321f3307de30bcab627c20
Dan Duvall 7 months ago
parent
commit
00ed534468

+ 2
- 0
.dockerignore View File

@@ -1 +1,3 @@
1
+**/.*.sw[po]
2
+
1 3
 .gradle

+ 58
- 2
Makefile View File

@@ -2,7 +2,14 @@ SHELL := /bin/bash
2 2
 GRADLE := $(shell command -v gradle)
3 3
 BLUBBER := $(shell command -v blubber)
4 4
 DOCKER := $(shell command -v docker)
5
-DOCKER_TAG := piplinelib-tests-$(shell date -I)
5
+
6
+DOCKER_TAG := piplinelib-tests-$(shell date -u +%Y%m%d-%H%M%S)
7
+DOCKER_LABEL := wmf.gc=pipelinelib-tests
8
+DOCKER_BUILD := docker build --label $(DOCKER_LABEL) --tag $(DOCKER_TAG)
9
+DOCKER_RUN := docker run --rm --label $(DOCKER_LABEL) --name $(DOCKER_TAG)
10
+DOCKER_STOP := docker stop "$(DOCKER_TAG)"
11
+DOCKER_STOP_ALL = docker stop $(shell docker ps -qf label=$(DOCKER_LABEL))
12
+DOCKER_RMI = docker rmi $(shell docker images -qf label=$(DOCKER_LABEL))
6 13
 
7 14
 
8 15
 .PHONY: test
@@ -26,9 +33,58 @@ ifneq (,$(GRADLE))
26 33
 else ifneq (,$(and $(BLUBBER), $(DOCKER)))
27 34
 	blubber .pipeline/blubber.yaml test | docker build -t "$(DOCKER_TAG)" -f - .
28 35
 	docker run --rm -it "$(DOCKER_TAG)"
29
-	docker rmi "$(DOCKER_TAG)"
30 36
 	@exit 0
31 37
 else
32 38
 	@echo "Can't find Gradle or Blubber/Docker. Install one to run tests."
33 39
 	@exit 1
34 40
 endif
41
+
42
+systemtest:
43
+ifneq (,$(and $(DOCKER), $(DOCKER_HOST)))
44
+	$(eval JENKINS_HOST := $(patsubst tcp://%,%,$(DOCKER_HOST)))
45
+	$(eval JENKINS_HOST := $(word 1, $(subst :, ,$(JENKINS_HOST))))
46
+	$(eval JENKINS_URL := http://docker:docker@$(JENKINS_HOST):8080)
47
+	$(eval JENKINS_BLUE_URL := $(JENKINS_URL)/blue/organizations/jenkins)
48
+	$(eval BUILD_OUTPUT := $(shell mktemp))
49
+
50
+	$(DOCKER_BUILD) -f systemtests/jenkins/Dockerfile .
51
+	$(DOCKER_RUN) -d \
52
+	  -p 8080:8080 \
53
+	  -v /var/run/docker.sock:/var/run/docker.sock \
54
+	  $(DOCKER_TAG)
55
+
56
+	@while ! curl -s http://$(JENKINS_HOST):8080/ > /dev/null; do \
57
+	  echo "waiting for jenkins..."; \
58
+	  sleep 1; \
59
+	done
60
+	@while curl -s http://$(JENKINS_HOST):8080/ | grep -q "is getting ready to work"; do \
61
+	  echo "waiting for jenkins..."; \
62
+	  sleep 1; \
63
+	done
64
+
65
+	curl -X POST $(JENKINS_URL)/job/repo1/build
66
+
67
+	@echo "Build $(JENKINS_URL)/job/repo1/1 created"
68
+	@while curl -sw %%{http_code} $(JENKINS_URL)/job/repo1/1/api/json | grep -q '404'; do \
69
+	  echo "waiting for build to start..."; \
70
+	  sleep 1; \
71
+	done
72
+
73
+	@while curl -s $(JENKINS_URL)/job/repo1/1/api/json | grep -q '"building":true'; do \
74
+	  sleep 1; \
75
+	  curl -s $(JENKINS_URL)/job/repo1/1/consoleText | \
76
+	    tail -n +$$(wc -l $(BUILD_OUTPUT) | awk '{ print $$1 }') | \
77
+	    tee -a $(BUILD_OUTPUT); \
78
+	done
79
+
80
+ifeq (1,$(DEBUG))
81
+	@echo "DEBUG: Build $(JENKINS_URL)/job/repo1/1 completed"
82
+	@echo -n "DEBUG: Press <enter> to continue: "
83
+	@read
84
+endif
85
+
86
+	$(DOCKER_STOP)
87
+else
88
+	@echo "Can't find Docker and your DOCKER_HOST. Set up both to run system tests."
89
+	@exit 1
90
+endif

+ 58
- 0
systemtests/jenkins/Dockerfile View File

@@ -0,0 +1,58 @@
1
+ARG VERSION=2.169
2
+
3
+FROM jenkins/jenkins:${VERSION}-slim
4
+
5
+ARG VERSION
6
+
7
+USER root
8
+
9
+RUN groupadd -g 1001 docker && usermod -G docker jenkins
10
+
11
+ENV DEBIAN_FRONTEND=noninteractive
12
+RUN apt-get update && \
13
+    apt-get install -y \
14
+      apt-transport-https \
15
+      ca-certificates \
16
+      curl \
17
+      gnupg2 \
18
+      software-properties-common && \
19
+    ( curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - ) && \
20
+    add-apt-repository \
21
+      "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" && \
22
+    apt-get update && \
23
+    apt-get install -y docker-ce-cli && \
24
+    rm -rf /var/lib/apt/lists/*
25
+
26
+USER jenkins
27
+
28
+RUN echo $VERSION > /usr/share/jenkins/ref/jenkins.install.UpgradeWizard.state
29
+RUN echo $VERSION > /usr/share/jenkins/ref/jenkins.install.InstallUtil.lastExecVersion
30
+
31
+COPY systemtests/jenkins/plugins.txt /usr/share/jenkins/ref/plugins.txt
32
+RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt
33
+
34
+COPY systemtests/jenkins/ref/* /usr/share/jenkins/ref/
35
+COPY systemtests/jenkins/init.groovy.d/*.groovy /usr/share/jenkins/ref/init.groovy.d/
36
+
37
+USER root
38
+
39
+RUN git config --global user.name docker && \
40
+    git config --global user.email docker@docker.invalid
41
+
42
+COPY systemtests/repo1 /var/lib/git/repo1
43
+RUN cd /var/lib/git/repo1 && \
44
+    git init . && \
45
+    git add --all && \
46
+    git commit -m repo1
47
+
48
+COPY . /var/lib/git/pipelinelib
49
+RUN cd /var/lib/git/pipelinelib && \
50
+    git checkout -b test-in-docker-$VERSION && \
51
+    test -z "$(git status -s)" || ( \
52
+      git add --all && \
53
+      git commit -m wip \
54
+    ) && \
55
+    git checkout master && \
56
+    git merge -s octopus test-in-docker-$VERSION
57
+
58
+USER jenkins

+ 14
- 0
systemtests/jenkins/init.groovy.d/01-password.groovy View File

@@ -0,0 +1,14 @@
1
+import jenkins.model.Jenkins
2
+import hudson.security.HudsonPrivateSecurityRealm
3
+import hudson.security.GlobalMatrixAuthorizationStrategy
4
+
5
+def instance = Jenkins.getInstance()
6
+
7
+def hudsonRealm = new HudsonPrivateSecurityRealm(false)
8
+hudsonRealm.createAccount("docker","docker")
9
+instance.setSecurityRealm(hudsonRealm)
10
+instance.save()
11
+
12
+def strategy = new GlobalMatrixAuthorizationStrategy()
13
+strategy.add(Jenkins.ADMINISTER, "docker")
14
+instance.setAuthorizationStrategy(strategy)

+ 7
- 0
systemtests/jenkins/init.groovy.d/02-nodes.groovy View File

@@ -0,0 +1,7 @@
1
+import jenkins.model.Jenkins
2
+
3
+Jenkins.instance.computers.each { c ->
4
+  c.node.labelString += "blubber"
5
+}
6
+
7
+Jenkins.instance.save()

+ 13
- 0
systemtests/jenkins/init.groovy.d/03-job.groovy View File

@@ -0,0 +1,13 @@
1
+import hudson.plugins.git.*
2
+import jenkins.model.Jenkins
3
+
4
+import org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition
5
+import org.jenkinsci.plugins.workflow.job.WorkflowJob
6
+
7
+def scm = new GitSCM("/var/lib/git/repo1")
8
+scm.branches = [new BranchSpec("master")]
9
+
10
+def job = new WorkflowJob(Jenkins.instance, "repo1")
11
+job.definition = new CpsScmFlowDefinition(scm, "Jenkinsfile")
12
+
13
+Jenkins.instance.reload()

+ 4
- 0
systemtests/jenkins/init.groovy.d/04-script-approval.groovy View File

@@ -0,0 +1,4 @@
1
+import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApproval
2
+
3
+ScriptApproval.get().approveSignature('staticMethod java.net.URI create java.lang.String')
4
+ScriptApproval.get().approveSignature('method java.net.URI resolve java.net.URI')

+ 96
- 0
systemtests/jenkins/plugins.txt View File

@@ -0,0 +1,96 @@
1
+ace-editor:1.1
2
+ant:1.9
3
+antisamy-markup-formatter:1.5
4
+apache-httpcomponents-client-4-api:4.5.5-3.0
5
+authentication-tokens:1.3
6
+blueocean-autofavorite:1.2.2
7
+blueocean-bitbucket-pipeline:1.10.2
8
+blueocean-commons:1.10.2
9
+blueocean-config:1.10.2
10
+blueocean-core-js:1.10.2
11
+blueocean-dashboard:1.10.2
12
+blueocean-display-url:2.2.0
13
+blueocean-events:1.10.2
14
+blueocean-git-pipeline:1.10.2
15
+blueocean-github-pipeline:1.10.2
16
+blueocean-i18n:1.10.2
17
+blueocean-jira:1.10.2
18
+blueocean-jwt:1.10.2
19
+blueocean-personalization:1.10.2
20
+blueocean-pipeline-api-impl:1.10.2
21
+blueocean-pipeline-editor:1.10.2
22
+blueocean-pipeline-scm-api:1.10.2
23
+blueocean-rest-impl:1.10.2
24
+blueocean-rest:1.10.2
25
+blueocean-web:1.10.2
26
+blueocean:1.10.2
27
+bouncycastle-api:2.17
28
+branch-api:2.2.0
29
+build-timeout:1.19
30
+cloudbees-folder:6.7
31
+command-launcher:1.3
32
+credentials-binding:1.18
33
+credentials:2.1.18
34
+display-url-api:2.3.1
35
+docker-commons:1.13
36
+docker-workflow:1.17
37
+durable-task:1.29
38
+email-ext:2.66
39
+git-client:2.7.6
40
+git-server:1.7
41
+git:3.9.3
42
+github-api:1.95
43
+github-branch-source:2.4.5
44
+github:1.29.4
45
+gradle:1.31
46
+handlebars:1.1.1
47
+http_request:1.8.22
48
+jackson2-api:2.9.8
49
+jdk-tool:1.2
50
+jquery-detached:1.2.1
51
+jsch:0.1.55
52
+junit:1.27
53
+ldap:1.20
54
+lockable-resources:2.5
55
+mailer:1.23
56
+mapdb-api:1.0.9.0
57
+matrix-auth:2.3
58
+matrix-project:1.14
59
+momentjs:1.1.1
60
+pam-auth:1.4
61
+pipeline-build-step:2.8
62
+pipeline-github-lib:1.0
63
+pipeline-graph-analysis:1.9
64
+pipeline-input-step:2.10
65
+pipeline-milestone-step:1.3.1
66
+pipeline-model-api:1.3.7
67
+pipeline-model-declarative-agent:1.1.1
68
+pipeline-model-definition:1.3.7
69
+pipeline-model-extensions:1.3.7
70
+pipeline-rest-api:2.10
71
+pipeline-stage-step:2.3
72
+pipeline-stage-tags-metadata:1.3.7
73
+pipeline-stage-view:2.10
74
+pipeline-utility-steps:2.2.0
75
+plain-credentials:1.5
76
+resource-disposer:0.12
77
+scm-api:2.4.0
78
+script-security:1.56
79
+ssh-credentials:1.15
80
+ssh-slaves:1.29.4
81
+structs:1.17
82
+subversion:2.12.1
83
+timestamper:1.9
84
+token-macro:2.7
85
+workflow-aggregator:2.6
86
+workflow-api:2.33
87
+workflow-basic-steps:2.15
88
+workflow-cps-global-lib:2.13
89
+workflow-cps:2.65
90
+workflow-durable-task-step:2.29
91
+workflow-job:2.32
92
+workflow-multibranch:2.21
93
+workflow-scm-step:2.7
94
+workflow-step-api:2.19
95
+workflow-support:3.2
96
+ws-cleanup:0.37

+ 22
- 0
systemtests/jenkins/ref/org.jenkinsci.plugins.workflow.libs.GlobalLibraries.xml.override View File

@@ -0,0 +1,22 @@
1
+<?xml version='1.1' encoding='UTF-8'?>
2
+<org.jenkinsci.plugins.workflow.libs.GlobalLibraries plugin="workflow-cps-global-lib@2.13">
3
+  <libraries>
4
+    <org.jenkinsci.plugins.workflow.libs.LibraryConfiguration>
5
+      <name>pipelinelib</name>
6
+      <retriever class="org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever">
7
+        <scm class="jenkins.plugins.git.GitSCMSource" plugin="git@3.9.3">
8
+          <id>b0369997-9747-4089-9333-67a046d3ffb2</id>
9
+					<remote>/var/lib/git/pipelinelib</remote>
10
+          <credentialsId></credentialsId>
11
+          <traits>
12
+            <jenkins.plugins.git.traits.BranchDiscoveryTrait/>
13
+          </traits>
14
+        </scm>
15
+      </retriever>
16
+      <defaultVersion>master</defaultVersion>
17
+      <implicit>false</implicit>
18
+      <allowVersionOverride>true</allowVersionOverride>
19
+      <includeInChangesets>true</includeInChangesets>
20
+    </org.jenkinsci.plugins.workflow.libs.LibraryConfiguration>
21
+  </libraries>
22
+</org.jenkinsci.plugins.workflow.libs.GlobalLibraries>

+ 18
- 0
systemtests/repo1/.pipeline/config.yaml View File

@@ -0,0 +1,18 @@
1
+pipelines:
2
+  service1:
3
+    directory: src/service1
4
+    stages:
5
+      - name: unit
6
+        build: test
7
+        run: true
8
+      - name: lint
9
+      - name: candidate
10
+        build: production
11
+        run: false
12
+    execution:
13
+      - [unit, candidate]
14
+      - [lint, candidate]
15
+  service2:
16
+    directory: src/service2
17
+    stages:
18
+      - name: test

+ 12
- 0
systemtests/repo1/.pipeline/service1/blubber.yaml View File

@@ -0,0 +1,12 @@
1
+version: v3
2
+base: docker-registry.wikimedia.org/wikimedia-stretch
3
+apt: { packages: [make] }
4
+
5
+variants:
6
+  test:
7
+    entrypoint: [make, unit]
8
+  lint:
9
+    entrypoint: [make, lint]
10
+  production:
11
+    apt: { packages: [netcat] }
12
+    entrypoint: [./server.sh]

+ 7
- 0
systemtests/repo1/.pipeline/service2/blubber.yaml View File

@@ -0,0 +1,7 @@
1
+version: v3
2
+base: docker-registry.wikimedia.org/wikimedia-jessie
3
+apt: { packages: [make] }
4
+
5
+variants:
6
+  test:
7
+    entrypoint: [make, test]

+ 4
- 0
systemtests/repo1/Jenkinsfile View File

@@ -0,0 +1,4 @@
1
+@Library('pipelinelib') import org.wikimedia.integration.*
2
+
3
+def builder = new PipelineBuilder(".pipeline/config.yaml")
4
+builder.build(this)

+ 4
- 0
systemtests/repo1/src/service1/Makefile View File

@@ -0,0 +1,4 @@
1
+unit:
2
+	echo service1 unit tests
3
+lint:
4
+	echo service2 linters

+ 7
- 0
systemtests/repo1/src/service1/server.sh View File

@@ -0,0 +1,7 @@
1
+#!/bin/bash
2
+
3
+while true; do
4
+cat <<-end | nc -l 0.0.0.0 7530
5
+HTTP/1.1 200 OK\r\n\r\nfoo
6
+end
7
+done

+ 2
- 0
systemtests/repo1/src/service2/Makefile View File

@@ -0,0 +1,2 @@
1
+test:
2
+	echo service2 test

Loading…
Cancel
Save