Skip to content

Commit

Permalink
Merge pull request #1 from Nhattd97/master
Browse files Browse the repository at this point in the history
init project and add code logic for v1.0.0
  • Loading branch information
duchnguyen authored Feb 10, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
2 parents ec85056 + 97f18f1 commit d0e6389
Showing 14 changed files with 609 additions and 2 deletions.
Binary file added .DS_Store
Binary file not shown.
124 changes: 122 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,122 @@
# kobiton-execute-test-buildkite-plugin
A Buildkite plugin to (synchronously) execute an automated test script on Kobiton service
# Kobiton Execute Test Buildkite Plugin

A Buildkite Plugin to (synchronously) execute an automated test script on Kobiton service.

## Example

Add the following to your `pipeline.yml`:

```yml
steps:
- label: "Kobiton Execute Test"
plugins:
- kobiton/kobiton-execute-test#v1.0.0:
kobi-username: 'your kobiton username'
kobi-api-key: "your kobiton api key"
executor-url: 'https://executor-demo.kobiton.com'
executor-username: 'your kobiton executor server username'
executor-password: "your kobiton executor server password"
git-repo-url: 'https://github.com/Nhattd97/azure-devops-sample-java-prod.git'
git-repo-branch: 'master'
git-repo-ssh-key: ''
app-id: 'kobiton-store:91041'
root-directory: "/"
command: 'mvn test'
device-name: 'Galaxy S10'
device-platform-version: '10'
use-custom-device: 'false'
device-platform: 'android'
wait-for-execution: 'true'
log-type: 'combined'
```
## Configuration
### `kobiton-username` (Required, string)

Kobiton Username to upload to Kobiton, for example `"kobitonadmin"`.

### `kobi-api-key` (Required, string)

API key to access Kobiton API, for example `"2c8n41e4-b30d-4f19-ba63-6596016c9e58"`.

### `executor-url` (Required, string)

Kobiton Automation Test Executor URL, please contact our Support Team to get this.

### `executor-username` (Required, string)

The Username for Kobiton Automation Test Executor, please contact our Support Team to get this.

### `executor-password` (Required, string)

The Password Kobiton Automation Test Executor, please contact our Support Team to get this.

### `git-repo-url` (Required, string)

Link to your Git repository.

### `git-repo-branch` (Required, string)

The branch of your Git repository you want to execute automation test with.

### `git-repo-ssh-key` (Optional, string)

This is required if your Git Repository is private.

### `kobiton-app-id` (Optional, string)

The App ID or App URL to use in your test script, for example `"kobiton-store:91041"`.

### `root-directory` (Required, string)

Input the root directory of your Git repository, for example `"\"`.

### `command` (Required, string)

Command lines to install dependencies and execute your automation test script. These commands will run from the root directory of your Git repository. For example `"mvn test"`.

### `use-custom-device` (Optional, boolean)

Check if you want to execute one or some test cases with a specific Kobiton Cloud Device. If you already set your device information in your test script, leave this field `false`.

### `device-name` (Optional, string)

This value will be consumed by the `KOBITON_DEVICE_NAME` environment variable in your test script.

### `device-platform` (Optional, string)

This value will be consumed by the `KOBITON_DEVICE_PLATFORM_NAME` environment variable in your test script.

### `device-platform-version` (Optional, string)

This value will be consumed by the `KOBITON_SESSION_PLATFORM_VERSION` environment variable in your test script.

### `wait-for-execution` (Optional, boolean)

Check if your want the release pipeline to wait until your automation testing is completed or failed, then print out the console log and test result.

### `log-type` (Optional, string)

Your desired log type to be showed. Choose `"combined"` to show logs in chronological order, or Separated for single type of log (`"ouput"` or `"error"`).

## Developing

To run the tests:

```shell
docker-compose run --rm tests
```

To validate the `plugin.yml`:
```shell
docker-compose run --rm lint
```

## Contributing

1. Fork the repo
2. Make the changes
3. Run the tests
4. Commit and push your changes
5. Send a pull request
108 changes: 108 additions & 0 deletions app/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package main

import (
"encoding/json"
"log"
"os"
"strings"
"time"

"github.com/Nhattd97/kobiton-execute-test-buildkite-plugin/app/model"
"github.com/Nhattd97/kobiton-execute-test-buildkite-plugin/app/utils"
)

const MAX_MS_WAIT_FOR_EXECUTION = 1 * 3600 * 1000 // 1 hour in miliseconds

var jobId = ""
var reportUrl = ""

func main() {

stepConfig := new(model.StepConfig)
stepConfig.Init()

var executorBasicAuth = strings.Join([]string{stepConfig.GetExecutorUsername(), stepConfig.GetExecutorPassword()}, ":")
var executorBasicAuthEncoded = utils.Base64Encode(executorBasicAuth)

var headers = map[string]string{}
headers["x-kobiton-credential-username"] = stepConfig.GetKobiUsername()
headers["x-kobiton-credential-api-key"] = stepConfig.GetKobiPassword()
headers["authorization"] = "Basic " + executorBasicAuthEncoded
headers["content-type"] = "application/json"
headers["accept"] = "application/json"

executorPayload := new(model.ExecutorRequestPayload)
model.BuildExecutorRequestPayload(executorPayload, stepConfig)
executorJsonPayload, _ := json.MarshalIndent(executorPayload, "", " ")
client := utils.HttpClient()

var executorUrl = stepConfig.GetExecutorUrl() + "/submit"

var response = utils.SendRequest(client, "POST", executorUrl, headers, executorJsonPayload)

jobId = string(response)

if stepConfig.IsWaitForExecution() {

log.Printf("Requesting to get logs for job %s", jobId)

var getJobInfoUrl = stepConfig.GetExecutorUrl() + "/jobs/" + jobId
var getJobLogUrl = getJobInfoUrl + "/logs?type=" + stepConfig.GetLogType()
var getReportUrl = getJobInfoUrl + "/report"
var isTimeout = false

ticker := time.NewTicker(30 * time.Second)
var authHeader = map[string]string{"authorization": "Basic " + executorBasicAuthEncoded}
var jobResponse model.JobResponse
var waitingBeginAt = time.Now().UnixMilli()

for range ticker.C {
var response = utils.SendRequest(client, "GET", getJobInfoUrl, authHeader, nil)
json.Unmarshal(response, &jobResponse)
log.Println("Job Status: ", jobResponse.Status)

if jobResponse.Status == "COMPLETED" || jobResponse.Status == "FAILED" {
log.Printf("Job ID %s is finish with status: %s", jobId, jobResponse.Status)
break
} else {
var currentTime = time.Now().UnixMilli()

if currentTime-waitingBeginAt >= MAX_MS_WAIT_FOR_EXECUTION {
isTimeout = true
break
}
}
}
defer ticker.Stop()

if isTimeout {
log.Println("==============================================================================")
log.Println("Execution has reached maximum waiting time")
} else {
var logResponse = utils.SendRequest(client, "GET", getJobLogUrl, authHeader, nil)

log.Println("==============================================================================")
log.Println(string(logResponse))

var reportResponse = utils.SendRequest(client, "GET", getReportUrl, authHeader, nil)
reportUrl = string(reportResponse)
}
}

log.Println("==============================================================================")

if jobId != "" {
log.Println("Job ID: ", jobId)
}

if reportUrl != "" {
log.Println("Report URL: ", reportUrl)
}

//
// --- Exit codes:
// The exit code of your Step is very important. If you return
// with a 0 exit code `bitrise` will register your Step as "successful".
// Any non zero exit code will be registered as "failed" by `bitrise`.
os.Exit(0)
}
53 changes: 53 additions & 0 deletions app/model/executorrequestpayload.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package model

import "strings"

type DesiredCaps struct {
DeviceName string `json:"deviceName,omitempty"`
PlatformVersion string `json:"platformVersion,omitempty"`
PlatformName string `json:"platformName,omitempty"`
AppId string `json:"appId,omitempty"`
}

type TestConfig struct {
Git string `json:"git"`
Ssh string `json:"ssh"`
Branch string `json:"branch"`
RootDirectory string `json:"rootDirectory,omitempty`
Commands []string `json:"commands"`
}

type BitriseConfig struct {
ReleaseId string `json:"releaseId"`
}

type ExecutorRequestPayload struct {
DesiredCaps DesiredCaps `json:"desiredCaps,omitempty"`
TestConfig TestConfig `json:"testConfig"`
AzureConfig BitriseConfig `json:"azureConfig"`
}

type JobResponse struct {
ID string `json:"id"`
Status string `json:"status"`
}

func BuildExecutorRequestPayload(e *ExecutorRequestPayload, s *StepConfig) {
// TestConfig
e.TestConfig.Git = s.gitRepoUrl
e.TestConfig.Branch = s.gitRepoBranch
e.TestConfig.Ssh = s.gitSSHKey
e.TestConfig.Commands = strings.Split(s.commands, "\n")
e.TestConfig.RootDirectory = s.rootDirectory

// DesiredCaps
if s.useCustomDevice {
e.DesiredCaps.DeviceName = s.deviceName
e.DesiredCaps.PlatformName = s.devicePlatformName
e.DesiredCaps.PlatformVersion = s.devicePlatformVersion
e.DesiredCaps.AppId = s.kobiAppId
}

// BitriseConfig
e.AzureConfig.ReleaseId = "123"
}
Loading

0 comments on commit d0e6389

Please sign in to comment.