Skip to content
This repository has been archived by the owner on Feb 28, 2022. It is now read-only.

Commit

Permalink
Merge pull request #23 from stephendonner/servicebook
Browse files Browse the repository at this point in the history
[WIP] Add a Service Book class with a shared testProject method, for scripted pipelines
  • Loading branch information
stephendonner authored Sep 5, 2017
2 parents 32f6814 + 2191dbe commit 58c7efc
Show file tree
Hide file tree
Showing 3 changed files with 226 additions and 0 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This repository holds

[![Build Status](https://travis-ci.org/mozilla/fxtest-jenkins-pipeline.svg?branch=master)](https://travis-ci.org/mozilla/fxtest-jenkins-pipeline)

# Pipeline Steps
## ircNotification
Sends a notification to IRC with the specified `channel`, `nick`, and `server`.
By default it will connect to `irc.mozilla.org:6697` as `fxtest` and join the
Expand Down Expand Up @@ -155,9 +156,25 @@ writeCapabilities(
path: 'fx51win10.json'
)
```
# ServiceBook
## testProject
Queries the Service Book project API for the given project `name`, iterates over
its associated test repositories, checks them out from SCM, and executes their
```run``` file(s). Finally, it returns ```exit 0``` on successful/passing
tests, and ```exit 1``` in the event of failed builds.

## Examples
```groovy
@Library('fxtest') _
def sb = new org.mozilla.fxtest.ServiceBook()
sb.testProject('kinto')
```

## Version History

### 1.7 (2017-09-04)
* Introduced ```ServiceBook``` class, with ```testProject``` method to execute tests for all pipeline associated with the specified project name.
### 1.6 (2017-04-13)
* Changed TBPL log name to `buildbot_text` in Treeherder message for log parsing. ([#12](https://github.com/mozilla/fxtest-jenkins-pipeline/issues/12))
* Switched to YAML schema for Treeherder message validation. ([#2](https://github.com/mozilla/fxtest-jenkins-pipeline/issues/2))
Expand Down
168 changes: 168 additions & 0 deletions src/org/mozilla/fxtest/ServiceBook.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package org.mozilla.fxtest

import groovy.json.JsonSlurperClassic;


HttpResponse doGetHttpRequest(String requestUrl){
URL url = new URL(requestUrl);
HttpURLConnection connection = url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
HttpResponse resp = new HttpResponse(connection);

if(resp.isFailure()){
error("\nGET from URL: $requestUrl\n HTTP Status: $resp.statusCode\n Message: $resp.message\n Response Body: $resp.body");
}
return resp;
}

HttpResponse doPostHttpRequestWithJson(String json, String requestUrl){
return doHttpRequestWithJson(json, requestUrl, "POST");
}

HttpResponse doPutHttpRequestWithJson(String json, String requestUrl){
return doHttpRequestWithJson(json, requestUrl, "PUT");
}

HttpResponse doHttpRequestWithJson(String json, String requestUrl, String verb){
URL url = new URL(requestUrl);
HttpURLConnection connection = url.openConnection();

connection.setRequestMethod(verb);
connection.setRequestProperty("Content-Type", "application/json");
connection.doOutput = true;

def writer = new OutputStreamWriter(connection.outputStream);
writer.write(json);
writer.flush();
writer.close();

connection.connect();

//parse the response
HttpResponse resp = new HttpResponse(connection);

if(resp.isFailure()){
error("\n$verb to URL: $requestUrl\n JSON: $json\n HTTP Status: $resp.statusCode\n Message: $resp.message\n Response Body: $resp.body");
}

return resp;
}

class HttpResponse {
String body;
String message;
Integer statusCode;
boolean failure = false;

public HttpResponse(HttpURLConnection connection){
this.statusCode = connection.responseCode;
this.message = connection.responseMessage;

if(statusCode == 200 || statusCode == 201){
this.body = connection.content.text;//this would fail the pipeline if there was a 400
}else{
this.failure = true;
this.body = connection.getErrorStream().text;
}

connection = null; //set connection to null for good measure, since we are done with it
}
}


// Servicebook iterator to get operational tests for a given project
Object getProjectTests(String name) {
resp = doGetHttpRequest("http://servicebook.dev.mozaws.net/api/project").body;
def jsonSlurper = new JsonSlurperClassic();
def projects = jsonSlurper.parseText(resp);

for (project in projects.data) {
def projectName = name.toLowerCase();
if (project.name == projectName) {
echo "The project " + name + " was found!"

def jenkin_tests = [];
for (test in project.tests) {
if (test.jenkins_pipeline) {
echo "Adding one test " + test.name
jenkin_tests << test;
}
}
return jenkin_tests;
}
}
echo "The project " + name + " was not found"
return null;
}



def validURL(url) {
allowedOrgs = ['Kinto', 'mozilla', 'mozilla-services']

for (allowedOrg in allowedOrgs) {
if (url.startsWith('https://github.com/' + allowedOrg + '/')) {
return true
}
}
echo url + " is not a valid url"
return false
}


def runStage(test) {
stage(test.name) {
if (validURL(test.url)) {
echo "checking out " + test.url + ".git"
node {
checkout([$class: 'GitSCM',
branches: [[name: '*/master']],
doGenerateSubmoduleConfigurations: false,
extensions: [[$class: 'CleanCheckout']],
submoduleCfg: [],
userRemoteConfigs: [[url: test.url + '.git']]]
)
}
echo "checked out"
node {
sh "chmod +x run"
sh "${WORKSPACE}/run"
}
} else {
throw new IOException(test.url + " is not allowed")
}
}
}

def testProject(String name) {
echo "Testing project " + name
def failures = []
def tests = getProjectTests(name)

for (test in tests) {
stage(test) {
try {
echo "Running " + test
echo "URL is " + test.url
runStage(test)
} catch (exc) {
echo test.name + " failed"
echo "Caught: ${exc}"
failures.add(test.name)
}
}
stage('Ship it!') {
node {
if (failures.size == 0) {
sh 'exit 0'
} else {
sh 'exit 1'
}
}
}
}
}


return this;
41 changes: 41 additions & 0 deletions tests/serviceBookTests.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package tests

import org.junit.Before
import org.junit.Test

import com.lesfurets.jenkins.unit.BasePipelineTest

class ServiceBookTests extends BasePipelineTest {


@Override
@Before
void setUp() throws Exception {
super.setUp()
}

@Test
void allowedOrgs() {
def script = loadScript('src/org/mozilla/fxtest/ServiceBook.groovy')
for ( i in ['Kinto', 'mozilla', 'mozilla-services'] ) {
assert script.validURL("https://github.com/${i}/foo") == true
}
}

@Test
void disallowedOrgs() {
def script = loadScript('src/org/mozilla/fxtest/ServiceBook.groovy')
for ( i in ['kinto', 'Mozilla', 'davehunt'] ) {
assert script.validURL("https://github.com/${i}/foo") == false
}
}

// @Test
// void projectWithTests() {
// def resp = [body:'{"data": [{"foo": {"tests": [{"name": "bar", "jenkins_pipeline": true}]}}]}']
// def script = loadScript('src/org/mozilla/fxtest/ServiceBook.groovy')
// script.doGetHttpRequest = { String url -> [resp] }
// def tests = script.getProjectTests('foo')
// assert tests != null
// }
}

0 comments on commit 58c7efc

Please sign in to comment.