12
.
6
.
2018

Testbare Jenkins Shared Pipelines

Unit- und Integration Tests für Pipeline Code

Einleitung

Wir nutzen Jenkins in mehreren Projekten und haben uns eine Shared Jenkins Pipeline aufgebaut. Bisher konnten wir unseren Pipeline Code nie wirklich lokal testen, es hat immer erst im eigentlichen Jenkins Job geknallt. Diesen Umstand wollten wir schleunigst ändern und haben uns damit beschäftigt, wie man testbaren Pipeline Code produzieren kann. Dieser BlogPost gibt dabei die Grundzüge unseres Ansatzes wieder.

 

Who wrote the Pipeline Code? Why do we see the error on Mars?
Who wrote the Pipeline Code? Why do we see the error on Mars?

 

UnitTests für Pipeline Code

Wir wollten folgendes erreichen:

  • Jenkins Befehle mocken (sh, withCredentials, echo …)
  • Ein Helper ruft keine anderen Helper auf (Separation of Concerns)
  • Jeder Helper hat einen UnitTest
  • Ein UnitTest mocked Jenkins und prüft (assert) die vom Helper produzierten shell-calls.

Unser Shared Pipeline Setup sieht dabei wie folgt aus:

Struktur der Shared Pipeline
Struktur der Shared Pipeline

 

Demo: Shared Pipeline mit GitHelper

Wir wollen zur Demonstration einen simplen GitHelper programmieren, der uns die Arbeit mit GIT erleichtert.

Das ganze Demo-Projekt seht ihr auf GitHub:

Wir binden die Demo Shared Pipeline in Jenkins als Globale Pipeline Library ein. Globale Pipelines laufen außerhalb der Sandbox und ermöglichen so einiges mehr an Funktionen als ge-sandboxte Pipelines.

Wir wollen unsere Library später unter der ID “comsysto” abrufen können und konfigurieren sie wie folgt:

Jenkins Verwalten - System Konfigurieren
Jenkins Verwalten - System Konfigurieren

 

Konfiguriere Globale Pipeline Library
Konfiguriere Globale Pipeline Library

 

Somit können wir unsere Library wie folgt in einem Jenkinsfile eines Pipeline-Jobs nutzen:

github:cb2087993b88083bef768284470fefba

 

Credentials in Jenkins einrichten

Wir wollen mit unserem GitHelper und mithilfe von GitHub Personal Access Tokens private GitHub Repositories clonen können. Dafür legen wir uns ein UsernameAndPassword Credential mit dem Token als Passwort an.

Zugangsdaten
Zugangsdaten

 

Zugangsdaten hinzufügen
Zugangsdaten hinzufügen

 

Zugangsdaten mit Personal Access Token anlegen
Zugangsdaten mit Personal Access Token anlegen

 

Wir haben später in der Pipeline Zugriff auf die Zugangsdaten über die ID github-credentials-1. Credentials können wie folgt genutzt werden, was aber der GitHelper für uns übernehmen wird:

github:d87b080864e88123d87204ebbfa6c189

 

Einen Pipeline Job einrichten

Wir richten einen Pipeline Job ein, um unsere Pipeline zu testen. Als Randnotiz sei gesagt, dass wir neben den UnitTests auch für jeden Helper einen eigenen Integration-Test-Pipeline-Job haben.

Neuer Job - Typ Pipeline Job
Neuer Job - Typ Pipeline Job

Wir tragen folgenden Pipeline Code ein:

github:c8957be89be04a530076636b2f71c6b0

Dieser nutzt unsere globale comsysto-Library und den GitHelper. Man sieht, dass wir die credentials anhand der ID übergeben sowie Repository-Owner und Repository-name. Es wird also das private Repository https://github.com/comsysto/test-jenkins-private-repository gecloned.

 

Lässt man den Job laufen, sieht das Ergebnis so aus:

Erfolgreicher Job Run mit Shared Pipeline
Erfolgreicher Job Run mit Shared Pipeline

 

GitHelper und cloneGitHubRepository()

Unser GitHelper sieht wie folgt aus:

github:196dd91e17fdb9adee8e1dda2c3ffd98

 

Der Dazugehörige Unit Test instanziiert den GitHelper sowie einen Jenkins Mock welcher alle Jenkins API Calls mocked.

github:1f4de8e8d0157bb0b68f67390f88a774

 

Der Jenkins Mock ist dabei recht simpel aufgebaut. Aktuell mockt er nur envsh() und withCredentials().

github:0071f5dea7c1bc377471babc396edd76

Die Unit Tests können wir wie folgt ausführen:

shell:groovy -cp src/ src/com/comsysto/pipeline/test/GitHelperTest.groovy

Natürlich muss die Groovy SDK installiert sein. Wenn man alles richtig gemacht hat, laufen alle Tests sauber durch. Das @Grab() sorgt ggf. für eine etwas längere Wartezeit, da erst das JAR heruntergeladen werden muss.

Erfolgreicher Unit Test Run eines Helpers
Erfolgreicher Unit Test Run eines Helpers

 

Fazit

Wir können unsere Jenkins Library lokal testen. Und wissen daher früh, wenn etwas nicht funktioniert. Durch weitere Integration Test Pipeline Jobs pro Helper kann man die Testabdeckung noch weiter erhöhen. Wir sind mit unserem Ansatz sehr zufrieden und werden immer weiter daran feilen.

Bernhard
Software Engineer - Java, JVM