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
master
Dan Duvall 2 years ago
parent
commit
00ed534468
16 changed files with 328 additions and 2 deletions
  1. +2
    -0
      .dockerignore
  2. +58
    -2
      Makefile
  3. +58
    -0
      systemtests/jenkins/Dockerfile
  4. +14
    -0
      systemtests/jenkins/init.groovy.d/01-password.groovy
  5. +7
    -0
      systemtests/jenkins/init.groovy.d/02-nodes.groovy
  6. +13
    -0
      systemtests/jenkins/init.groovy.d/03-job.groovy
  7. +4
    -0
      systemtests/jenkins/init.groovy.d/04-script-approval.groovy
  8. +96
    -0
      systemtests/jenkins/plugins.txt
  9. +22
    -0
      systemtests/jenkins/ref/org.jenkinsci.plugins.workflow.libs.GlobalLibraries.xml.override
  10. +18
    -0
      systemtests/repo1/.pipeline/config.yaml
  11. +12
    -0
      systemtests/repo1/.pipeline/service1/blubber.yaml
  12. +7
    -0
      systemtests/repo1/.pipeline/service2/blubber.yaml
  13. +4
    -0
      systemtests/repo1/Jenkinsfile
  14. +4
    -0
      systemtests/repo1/src/service1/Makefile
  15. +7
    -0
      systemtests/repo1/src/service1/server.sh
  16. +2
    -0
      systemtests/repo1/src/service2/Makefile

+ 2
- 0
.dockerignore View File

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

+ 58
- 2
Makefile View File

@ -2,7 +2,14 @@ SHELL := /bin/bash
GRADLE := $(shell command -v gradle)
BLUBBER := $(shell command -v blubber)
DOCKER := $(shell command -v docker)
DOCKER_TAG := piplinelib-tests-$(shell date -I)
DOCKER_TAG := piplinelib-tests-$(shell date -u +%Y%m%d-%H%M%S)
DOCKER_LABEL := wmf.gc=pipelinelib-tests
DOCKER_BUILD := docker build --label $(DOCKER_LABEL) --tag $(DOCKER_TAG)
DOCKER_RUN := docker run --rm --label $(DOCKER_LABEL) --name $(DOCKER_TAG)
DOCKER_STOP := docker stop "$(DOCKER_TAG)"
DOCKER_STOP_ALL = docker stop $(shell docker ps -qf label=$(DOCKER_LABEL))
DOCKER_RMI = docker rmi $(shell docker images -qf label=$(DOCKER_LABEL))
.PHONY: test
@ -26,9 +33,58 @@ ifneq (,$(GRADLE))
else ifneq (,$(and $(BLUBBER), $(DOCKER)))
blubber .pipeline/blubber.yaml test | docker build -t "$(DOCKER_TAG)" -f - .
docker run --rm -it "$(DOCKER_TAG)"
docker rmi "$(DOCKER_TAG)"
@exit 0
else
@echo "Can't find Gradle or Blubber/Docker. Install one to run tests."
@exit 1
endif
systemtest:
ifneq (,$(and $(DOCKER), $(DOCKER_HOST)))
$(eval JENKINS_HOST := $(patsubst tcp://%,%,$(DOCKER_HOST)))
$(eval JENKINS_HOST := $(word 1, $(subst :, ,$(JENKINS_HOST))))
$(eval JENKINS_URL := http://docker:docker@$(JENKINS_HOST):8080)
$(eval JENKINS_BLUE_URL := $(JENKINS_URL)/blue/organizations/jenkins)
$(eval BUILD_OUTPUT := $(shell mktemp))
$(DOCKER_BUILD) -f systemtests/jenkins/Dockerfile .
$(DOCKER_RUN) -d \
-p 8080:8080 \
-v /var/run/docker.sock:/var/run/docker.sock \
$(DOCKER_TAG)
@while ! curl -s http://$(JENKINS_HOST):8080/ > /dev/null; do \
echo "waiting for jenkins..."; \
sleep 1; \
done
@while curl -s http://$(JENKINS_HOST):8080/ | grep -q "is getting ready to work"; do \
echo "waiting for jenkins..."; \
sleep 1; \
done
curl -X POST $(JENKINS_URL)/job/repo1/build
@echo "Build $(JENKINS_URL)/job/repo1/1 created"
@while curl -sw %%{http_code} $(JENKINS_URL)/job/repo1/1/api/json | grep -q '404'; do \
echo "waiting for build to start..."; \
sleep 1; \
done
@while curl -s $(JENKINS_URL)/job/repo1/1/api/json | grep -q '"building":true'; do \
sleep 1; \
curl -s $(JENKINS_URL)/job/repo1/1/consoleText | \
tail -n +$$(wc -l $(BUILD_OUTPUT) | awk '{ print $$1 }') | \
tee -a $(BUILD_OUTPUT); \
done
ifeq (1,$(DEBUG))
@echo "DEBUG: Build $(JENKINS_URL)/job/repo1/1 completed"
@echo -n "DEBUG: Press <enter> to continue: "
@read
endif
$(DOCKER_STOP)
else
@echo "Can't find Docker and your DOCKER_HOST. Set up both to run system tests."
@exit 1
endif

+ 58
- 0
systemtests/jenkins/Dockerfile View File

@ -0,0 +1,58 @@
ARG VERSION=2.169
FROM jenkins/jenkins:${VERSION}-slim
ARG VERSION
USER root
RUN groupadd -g 1001 docker && usermod -G docker jenkins
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
software-properties-common && \
( curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - ) && \
add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" && \
apt-get update && \
apt-get install -y docker-ce-cli && \
rm -rf /var/lib/apt/lists/*
USER jenkins
RUN echo $VERSION > /usr/share/jenkins/ref/jenkins.install.UpgradeWizard.state
RUN echo $VERSION > /usr/share/jenkins/ref/jenkins.install.InstallUtil.lastExecVersion
COPY systemtests/jenkins/plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt
COPY systemtests/jenkins/ref/* /usr/share/jenkins/ref/
COPY systemtests/jenkins/init.groovy.d/*.groovy /usr/share/jenkins/ref/init.groovy.d/
USER root
RUN git config --global user.name docker && \
git config --global user.email docker@docker.invalid
COPY systemtests/repo1 /var/lib/git/repo1
RUN cd /var/lib/git/repo1 && \
git init . && \
git add --all && \
git commit -m repo1
COPY . /var/lib/git/pipelinelib
RUN cd /var/lib/git/pipelinelib && \
git checkout -b test-in-docker-$VERSION && \
test -z "$(git status -s)" || ( \
git add --all && \
git commit -m wip \
) && \
git checkout master && \
git merge -s octopus test-in-docker-$VERSION
USER jenkins

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

@ -0,0 +1,14 @@
import jenkins.model.Jenkins
import hudson.security.HudsonPrivateSecurityRealm
import hudson.security.GlobalMatrixAuthorizationStrategy
def instance = Jenkins.getInstance()
def hudsonRealm = new HudsonPrivateSecurityRealm(false)
hudsonRealm.createAccount("docker","docker")
instance.setSecurityRealm(hudsonRealm)
instance.save()
def strategy = new GlobalMatrixAuthorizationStrategy()
strategy.add(Jenkins.ADMINISTER, "docker")
instance.setAuthorizationStrategy(strategy)

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

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

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

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

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

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

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

@ -0,0 +1,96 @@
ace-editor:1.1
ant:1.9
antisamy-markup-formatter:1.5
apache-httpcomponents-client-4-api:4.5.5-3.0
authentication-tokens:1.3
blueocean-autofavorite:1.2.2
blueocean-bitbucket-pipeline:1.10.2
blueocean-commons:1.10.2
blueocean-config:1.10.2
blueocean-core-js:1.10.2
blueocean-dashboard:1.10.2
blueocean-display-url:2.2.0
blueocean-events:1.10.2
blueocean-git-pipeline:1.10.2
blueocean-github-pipeline:1.10.2
blueocean-i18n:1.10.2
blueocean-jira:1.10.2
blueocean-jwt:1.10.2
blueocean-personalization:1.10.2
blueocean-pipeline-api-impl:1.10.2
blueocean-pipeline-editor:1.10.2
blueocean-pipeline-scm-api:1.10.2
blueocean-rest-impl:1.10.2
blueocean-rest:1.10.2
blueocean-web:1.10.2
blueocean:1.10.2
bouncycastle-api:2.17
branch-api:2.2.0
build-timeout:1.19
cloudbees-folder:6.7
command-launcher:1.3
credentials-binding:1.18
credentials:2.1.18
display-url-api:2.3.1
docker-commons:1.13
docker-workflow:1.17
durable-task:1.29
email-ext:2.66
git-client:2.7.6
git-server:1.7
git:3.9.3
github-api:1.95
github-branch-source:2.4.5
github:1.29.4
gradle:1.31
handlebars:1.1.1
http_request:1.8.22
jackson2-api:2.9.8
jdk-tool:1.2
jquery-detached:1.2.1
jsch:0.1.55
junit:1.27
ldap:1.20
lockable-resources:2.5
mailer:1.23
mapdb-api:1.0.9.0
matrix-auth:2.3
matrix-project:1.14
momentjs:1.1.1
pam-auth:1.4
pipeline-build-step:2.8
pipeline-github-lib:1.0
pipeline-graph-analysis:1.9
pipeline-input-step:2.10
pipeline-milestone-step:1.3.1
pipeline-model-api:1.3.7
pipeline-model-declarative-agent:1.1.1
pipeline-model-definition:1.3.7
pipeline-model-extensions:1.3.7
pipeline-rest-api:2.10
pipeline-stage-step:2.3
pipeline-stage-tags-metadata:1.3.7
pipeline-stage-view:2.10
pipeline-utility-steps:2.2.0
plain-credentials:1.5
resource-disposer:0.12
scm-api:2.4.0
script-security:1.56
ssh-credentials:1.15
ssh-slaves:1.29.4
structs:1.17
subversion:2.12.1
timestamper:1.9
token-macro:2.7
workflow-aggregator:2.6
workflow-api:2.33
workflow-basic-steps:2.15
workflow-cps-global-lib:2.13
workflow-cps:2.65
workflow-durable-task-step:2.29
workflow-job:2.32
workflow-multibranch:2.21
workflow-scm-step:2.7
workflow-step-api:2.19
workflow-support:3.2
ws-cleanup:0.37

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

@ -0,0 +1,22 @@
<?xml version='1.1' encoding='UTF-8'?>
<org.jenkinsci.plugins.workflow.libs.GlobalLibraries plugin="workflow-cps-global-lib@2.13">
<libraries>
<org.jenkinsci.plugins.workflow.libs.LibraryConfiguration>
<name>pipelinelib</name>
<retriever class="org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever">
<scm class="jenkins.plugins.git.GitSCMSource" plugin="git@3.9.3">
<id>b0369997-9747-4089-9333-67a046d3ffb2</id>
<remote>/var/lib/git/pipelinelib</remote>
<credentialsId></credentialsId>
<traits>
<jenkins.plugins.git.traits.BranchDiscoveryTrait/>
</traits>
</scm>
</retriever>
<defaultVersion>master</defaultVersion>
<implicit>false</implicit>
<allowVersionOverride>true</allowVersionOverride>
<includeInChangesets>true</includeInChangesets>
</org.jenkinsci.plugins.workflow.libs.LibraryConfiguration>
</libraries>
</org.jenkinsci.plugins.workflow.libs.GlobalLibraries>

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

@ -0,0 +1,18 @@
pipelines:
service1:
directory: src/service1
stages:
- name: unit
build: test
run: true
- name: lint
- name: candidate
build: production
run: false
execution:
- [unit, candidate]
- [lint, candidate]
service2:
directory: src/service2
stages:
- name: test

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

@ -0,0 +1,12 @@
version: v3
base: docker-registry.wikimedia.org/wikimedia-stretch
apt: { packages: [make] }
variants:
test:
entrypoint: [make, unit]
lint:
entrypoint: [make, lint]
production:
apt: { packages: [netcat] }
entrypoint: [./server.sh]

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

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

+ 4
- 0
systemtests/repo1/Jenkinsfile View File

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

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

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

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

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

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

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

Loading…
Cancel
Save