A practical way to automate testing Oauth 2.0 Service — Part 2

DevOps Integration

Angela T.T.
5 min readSep 19, 2018

In the previous article, we have introduced how to use Restbird task to automate testing OAuth 2.0 service, now we’re going to step forward to discuss how to integrate Restbird test cases into Continuous Integration (CI) system. And show you how Restbird can take an important part in DevOps.

Let’s continue with the Box test project, since we already have a valid access token in hand and a task to refresh it periodically, we can now freely play with the APIs.

In the following example, we’ll create a simple test case in Restbird to implement the logic of “Get id of the specific folder name under root directory, if the folder doesn’t exist, then create a new one”, the test case will be marked as success if the logic completed without error, otherwise the case failed.

We will then integrate this test case into Jenkins, the most popular CI tool being used in DevOps teams.

> All Restbird code used in this example have been uploaded into Github Repo [restbird/example-Box-Oauth2](https://github.com/restbird/example-Box-Oauth2)

Create Test Case for API endpoints

Two BOX File related APIs will be used in this example, we create a new Rest case in Box project and include these 2 APIs

Create API to retrieve id of specific folder

Here is the API definition of Box to get infomation of a folder.

Method: GET

Url: https://api.box.com/2.0/folders/{folder_id}

The root folder of a Box account is always represented by the ID “0”.

This is how the request looks in [Restbird](https://restbird.org)

Then impletement the logic to retrive folder_id of folder_name and save folder_id in environment variable in [Response Check Scripts](https://restbird.org/docs/rest.html#response-validation-script), here we use GoLang as sample language:

package api
import "callapi"
import "net/http"
import "io/ioutil"
import "encoding/json"
import "fmt"

type MyEntry struct {
Id string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
}

type MyCollection struct{
Entries []MyEntry `json:"entries,omitempty"`
}

type MyDATA struct {
Item_collection MyCollection `json:"item_collection,omitempty"`
}

func (c CallBack) ResponseValidate(resp *http.Response, ctx *callapi.RestBirdCtx) bool {
var body []byte
var err error
var data MyDATA

if resp.StatusCode == 200 {
if body, err = ioutil.ReadAll(resp.Body); err != nil {
fmt.Println("read body failed.")
return false
}

if err = json.Unmarshal(body, &data); err != nil {
fmt.Println("conver body to json failed")
return false
}

for i, v := range data.Item_collection.Entries {
if v.Name == ctx.GetVars("folder_name") {
ctx.SetVars("folder_id", v.Id)
fmt.Println("Found folder: ")
fmt.Println("i, folder_id, folder_name: " , i, ",", ctx.GetVars("folder_id"), ",", ctx.GetVars("folder_name"))
return true
}
}

fmt.Println("Can't find folder: ", ctx.GetVars("folder_name"))
return true
}
return false
}

Create API to create specific folder

Here is the API definition of Box to create a folder.

Method: POST
Url: https://api.box.com/2.0/folders

Req Body (Raw): {“name”:”{{folder_name}}”, “parent”: {“id”: “0”}}

Here is how the request looks in [Restbird](https://restbird.org)

In [Response Check Scripts](https://restbird.org/docs/rest.html#response-validation-script) we’ll check the response code and retrieve the folder_id of the new folder and save it into environment variable.

package api
import "callapi"
import "net/http"
import "fmt"
import "io/ioutil"
import "encoding/json"
type MyDATA struct {
Id string `json:"id, omitempty"`
}

func (c CallBack) ResponseValidate(resp *http.Response, ctx *callapi.RestBirdCtx) bool {
if resp.StatusCode == 201 {
var body []byte
var err error
var data MyDATA

if body, err = ioutil.ReadAll(resp.Body); err != nil {
fmt.Println("read body failed.")
return false
}

if err = json.Unmarshal(body, &data); err != nil {
fmt.Println("conver body to json failed:", err.Error())
return false
}

ctx.SetVars("folder_id", data.Id)
fmt.Println("folder_id", ctx.GetVars("folder_id"))

return true
}
return false
}

> All Rest APIs need to add OAuth Authorization header with access token
> Authorization : Bearer {{box\_access\_token}}

Create Test script to implement logic

Beside Http(s) request, Restbird also supports creating pure script in rest project to organize multiple single APIs into complex test cases.
Here we’re going to create a script for our first test case:

Case 0: Get Id of folder_name, if folder doesn’t exist, create a new one

In the script, we call the 2 APIs we just created in previous steps.

package api
import "callapi"
import "fmt"
import api0 "restbird/Box/File/api0"
import api1 "restbird/Box/File/api1"

type CallBack struct {}

func (c CallBack) GoScripts(ctx *callapi.RestBirdCtx) bool{

var folder_id = ""
ctx.SetVars("folder_name", "Demo6")
ctx.SetVars("folder_id", "")

reterr, retbool,retMsg := callapi.DoHttpRequest("Box/File", "api0", api0.CallBack{}, ctx)

fmt.Println(reterr, retbool,retMsg)

if !retbool {
fmt.Println("callapi failed", retMsg)
return false
}

folder_id = ctx.GetVars("folder_id")

if folder_id == ""{
fmt.Println("Folder doesn't exist, create a new one: ", ctx.GetVars("folder_name"))
reterr, retbool,retMsg := callapi.DoHttpRequest("Box/File", "api1", api1.CallBack{}, ctx)
fmt.Println(reterr, retbool,retMsg)

if(!retbool){
fmt.Println("callapi failed", retMsg)
return false
}

folder_id = ctx.GetVars("folder_id")
}

fmt.Println(folder_id)

return true
}

We can always run API or script directly in Restbird to check logic, e.g. now after click “Run Test” we can check “console log” to verify that everything runs properly.

Integrate with Jenkins

Now we have everything ready on Restbird side, the final step is to integrate Restbird into Jenkins to complete our CI system.

Well, this is truely as easy as breeze, with Http Request plugin, Jenkins is able to call [Restbird API]

Install Http Request plugin in Jenkins

Manage Jenkins -> Manage Plugin -> Search “Http Request” then install

Install Pipeline Utility Steps plugin in Jenkins

Manage Jenkins -> Manage Plugin -> Search “Pipeline Utility Steps” then install

This plugin provide lib for Json parser

Add new pipeline task

Here we create a typical CI work flow including 3 steps: build -> deploy -> run auto test, Restbird is used in auto test step.
This code can be used to define pipeline sript:

node {
def payload

stage('Build') {
//...
}
stage('Deploy') {
//..
}
stage('Run test') {
def host = 'http://192.168.1.178:10000'
def basicAuth = 'Basic YWRtaW46YWRtaW4='

println('Call Restbird API to run test:')
def reqBody = '{"casepath":"Box/TestScripts","apis":["api0"]}'
def response = httpRequest httpMode:'POST', customHeaders: [[name: 'Authorization', value: basicAuth]], requestBody: reqBody, url:host+"/v1/rest/run"
println('Status: '+response.status)
println('Response: '+response.content)
payload = readJSON text: response.content
def historyId = payload.his.id
println('History_id: '+ historyId)

def historyReqBody = '{"project":"Box/TestScripts","id":"' + payload.his.id + '", "immediatereturn": true}'

for(int i=0;i<10;i++){
println('Call Restbird API to get result: ' + i)

def historyResponse = httpRequest httpMode:'POST', customHeaders: [[name: 'Authorization', value: basicAuth]], requestBody: historyReqBody, url:host+"/v1/rest/runresult"
println('Status: '+historyResponse.status)
println('Response: '+historyResponse.content)


if(historyResponse.status == 200){

printConsoleLog(host, basicAuth, historyId)

payload = readJSON text: historyResponse.content
if(payload.code == 0){
if(payload.his.responseval.result == true){
currentBuild.result = 'SUCCESS'
}else{
currentBuild.result = 'FAILURE'
}
return
}else if(payload.code == -1){
println("Test unfinshed, check back in 10 seconds")
sleep 10
}else{
println("Test error" + payload.code + ", " + payload.info)
currentBuild.result = 'FAILURE'
return
}
}else{
currentBuild.result = 'FAILURE'
return
}

}

//return timeout
currentBuild.result = 'FAILURE'
return
}
}
def printConsoleLog(host, basicAuth, historyId){
println('--Call Restbird API to get console log:')
def consoleResponse = httpRequest httpMode:'GET', customHeaders: [[name: 'Authorization', value: basicAuth]], url:host+"/v1/rest/his/console?project=Box/TestScripts&id=" + historyId
println('--Console Status: '+consoleResponse.status)
println('--Console Response: '+consoleResponse.content)
}

> checkout [Restbird API definition]

> Download the example project from [github](https://github.com/restbird/example-Box-Oauth2)

--

--