implement feature to generate random test data
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -9,8 +9,8 @@ export CGO_ENABLED=0
|
||||
commit=$(git rev-parse HEAD)
|
||||
#tag=$(git describe --tags --abbrev=0)
|
||||
buildtime=$(TZ=Australia/Sydney date +%Y-%m-%dT%T%z)
|
||||
#git_version=$(git describe --tags --always --long --dirty)
|
||||
package_name=api-tester
|
||||
git_version=$(git describe --tags --always --long --dirty)
|
||||
package_name=apitester
|
||||
|
||||
#echo "Current directory:"
|
||||
#pwd
|
||||
@@ -35,7 +35,7 @@ do
|
||||
exit 1
|
||||
fi
|
||||
echo "build complete : $output_name"
|
||||
sha256sum build/$output_name > build/${output_name}_checksum.txt
|
||||
#sha256sum build/$output_name > build/${output_name}_checksum.txt
|
||||
#ls -lah ./build/
|
||||
done
|
||||
|
||||
|
@@ -38,7 +38,58 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"test3": {
|
||||
"path": "/api/admin/group/add",
|
||||
"disabled": true,
|
||||
"method": "POST",
|
||||
"description": "add new local group",
|
||||
"body": {
|
||||
"groupName": "test local group",
|
||||
"ldapGroup": false
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"test4": {
|
||||
"path": "/api/admin/groups",
|
||||
"method": "GET",
|
||||
"description": "get group listing again",
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"hasKeys": ["groupName"],
|
||||
"contains": {
|
||||
"message": "success"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"test5": {
|
||||
"path": "/api/admin/group/delete",
|
||||
"method": "POST",
|
||||
"description": "remove new local group",
|
||||
"body": {
|
||||
"groupName": "test local group",
|
||||
"ldapGroup": false
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://10.63.39.130:8443",
|
||||
"insecure": true,
|
||||
|
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
|
||||
"github.com/iancoleman/orderedmap"
|
||||
@@ -145,20 +146,36 @@ func ReadInput(data []byte, testDefinitions *TestDefinitions) {
|
||||
}
|
||||
// Body
|
||||
if val, ok := thisTestCaseMap.Get("body"); ok {
|
||||
// Create a normal string map for all the body key-value pairs
|
||||
|
||||
// TODO : Support nested json instead of single level flat request
|
||||
|
||||
//thisTestCase.Body = OrderedToStringMap(val.(orderedmap.OrderedMap))
|
||||
|
||||
// Turn the original string into json
|
||||
bytes, err := json.Marshal(val)
|
||||
if err != nil {
|
||||
error := fmt.Sprintf("Error mnarshalling request body for test case : '%s'\n", err)
|
||||
panic(error)
|
||||
}
|
||||
|
||||
// Now that we have json, convert it to an interface that we can play with
|
||||
var jsonData interface{}
|
||||
err = json.Unmarshal(bytes, &jsonData)
|
||||
if err != nil {
|
||||
error := fmt.Sprintf("Error processing request body for test case : '%s'\n", err)
|
||||
panic(error)
|
||||
} else {
|
||||
thisTestCase.Body = bytes
|
||||
//fmt.Printf("Body marshalled:\n%v\n", string(bytes))
|
||||
}
|
||||
|
||||
// Search for any keys in the body that we need to replace with a dynamic random value
|
||||
results := findRandom(nil, jsonData)
|
||||
|
||||
// for debugging
|
||||
//resultJSON, _ := json.MarshalIndent(results, "", " ")
|
||||
//fmt.Println(string(resultJSON))
|
||||
|
||||
// store the results back into the body
|
||||
newBytes, err := json.Marshal(results)
|
||||
if err != nil {
|
||||
error := fmt.Sprintf("Error turning body interface back into json for test case : '%s'\n", err)
|
||||
panic(error)
|
||||
}
|
||||
thisTestCase.Body = newBytes
|
||||
//fmt.Printf("Body marshalled:\n%v\n", string(newBytes))
|
||||
}
|
||||
// Header
|
||||
if val, ok := thisTestCaseMap.Get("header"); ok {
|
||||
@@ -190,6 +207,47 @@ func ReadInput(data []byte, testDefinitions *TestDefinitions) {
|
||||
}
|
||||
}
|
||||
|
||||
// Use this function to find and generate any random values we want to use during testing
|
||||
func findRandom(key interface{}, data interface{}) interface{} {
|
||||
switch v := data.(type) {
|
||||
case map[string]interface{}:
|
||||
if randomValue, ok := v["random"]; ok {
|
||||
if randomObj, ok := randomValue.(map[string]interface{}); ok {
|
||||
if isString, isStringOk := randomObj["isString"].(bool); isStringOk && isString {
|
||||
if length, lengthOk := randomObj["length"].(float64); lengthOk {
|
||||
newString := generateRandomString(int(length))
|
||||
fmt.Printf("Generated random string '%s' to insert into JSON body for key '%s'\n", newString, key.(string))
|
||||
return newString
|
||||
}
|
||||
} else if isInt, isIntOk := randomObj["isInt"].(bool); isIntOk && isInt {
|
||||
newInt := rand.Int()
|
||||
fmt.Printf("Generated random number '%d' to insert into JSON body\n", newInt)
|
||||
return newInt
|
||||
}
|
||||
}
|
||||
}
|
||||
for key, value := range v {
|
||||
v[key] = findRandom(key, value)
|
||||
}
|
||||
case []interface{}:
|
||||
for i, value := range v {
|
||||
v[i] = findRandom(i, value)
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
func generateRandomString(length int) string {
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
result := make([]byte, length)
|
||||
for i := range result {
|
||||
result[i] = charset[rand.Intn(len(charset))]
|
||||
}
|
||||
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func ReadHeaderTestCases(input orderedmap.OrderedMap, result *HeaderTests) {
|
||||
result.Contains = make(map[string]string)
|
||||
result.Equals = make(map[string]string)
|
||||
|
36
main.go
36
main.go
@@ -4,7 +4,9 @@ import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/iancoleman/orderedmap"
|
||||
)
|
||||
@@ -12,6 +14,36 @@ import (
|
||||
var testDefinitions *TestDefinitions
|
||||
var captureValues *CaptureValues
|
||||
|
||||
func PrintStructContents(s interface{}, indentLevel int) string {
|
||||
var result strings.Builder
|
||||
|
||||
val := reflect.ValueOf(s)
|
||||
|
||||
if val.Kind() == reflect.Ptr {
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
typ := val.Type()
|
||||
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
field := val.Field(i)
|
||||
fieldType := typ.Field(i)
|
||||
|
||||
indent := strings.Repeat("\t", indentLevel)
|
||||
result.WriteString(fmt.Sprintf("%s%s: ", indent, fieldType.Name))
|
||||
|
||||
switch field.Kind() {
|
||||
case reflect.Struct:
|
||||
result.WriteString("\n")
|
||||
result.WriteString(PrintStructContents(field.Interface(), indentLevel+1))
|
||||
default:
|
||||
result.WriteString(fmt.Sprintf("%v\n", field.Interface()))
|
||||
}
|
||||
}
|
||||
|
||||
return result.String()
|
||||
}
|
||||
|
||||
func main() {
|
||||
var s []byte
|
||||
var err error
|
||||
@@ -43,6 +75,8 @@ func main() {
|
||||
// Process the input json
|
||||
ReadInput(s, testDefinitions)
|
||||
|
||||
//fmt.Println(PrintStructContents(testDefinitions.TestCases[1], 0))
|
||||
|
||||
// Perform specified test cases
|
||||
for i := range testDefinitions.TestCases {
|
||||
|
||||
@@ -52,6 +86,7 @@ func main() {
|
||||
}
|
||||
|
||||
RunTest(&testDefinitions.TestCases[i])
|
||||
|
||||
fmt.Printf("\nRunning checks on output\n")
|
||||
success, err := CheckResults(&testDefinitions.TestCases[i])
|
||||
if err != nil {
|
||||
@@ -71,6 +106,7 @@ func main() {
|
||||
|
||||
// For debugging, just dump the output
|
||||
//fmt.Printf("%+v\n", testDefinitions)
|
||||
//fmt.Println(PrintStructContents(testDefinitions, 0))
|
||||
}
|
||||
|
||||
// fileExists returns true if the specified file exists and is not a directory
|
||||
|
75
permissions-test.json
Normal file
75
permissions-test.json
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"name": "CBS permissions testing",
|
||||
"testCases": {
|
||||
"test1": {
|
||||
"path": "/api/login",
|
||||
"method": "POST",
|
||||
"description": "Perform login",
|
||||
"body": {
|
||||
"username": "Administrator",
|
||||
"password": "Password123"
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"hasKeys": ["access_token"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"test2": {
|
||||
"path": "/api/admin/permissions",
|
||||
"method": "GET",
|
||||
"description": "get list of permissions",
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"hasKeys": ["permissionId"],
|
||||
"contains": {
|
||||
"message": "success"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"test3": {
|
||||
"path": "/api/admin/permission/add",
|
||||
"method": "POST",
|
||||
"description": "create new permission",
|
||||
"body": {
|
||||
"Description": "Readonly access to default safe",
|
||||
"safeId": 1,
|
||||
"userId": 2,
|
||||
"readOnly": true
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://10.63.39.130:8443",
|
||||
"insecure": true,
|
||||
"header": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer %ACCESS_TOKEN%"
|
||||
},
|
||||
"capture": {
|
||||
"test1": {
|
||||
"body": {
|
||||
"access_token": "%ACCESS_TOKEN%"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -128,12 +128,14 @@ func RunTest(testCase *TestCase) error {
|
||||
// If we found one, add the appropriate replacement to captureValues
|
||||
for i := range testDefinitions.CaptureCases {
|
||||
if testDefinitions.CaptureCases[i].TestCaseName == testCase.Name {
|
||||
fmt.Printf("\nProcessing capture(s) for test case '%s'\n", testCase.Name)
|
||||
captureData := testDefinitions.CaptureCases[i].CaptureData
|
||||
|
||||
for k, v := range captureData.Body.Data {
|
||||
//fmt.Printf("Body capture %s = %s\n", k, v)
|
||||
|
||||
if val, ok := testCase.ResultBodyMap[k]; ok {
|
||||
fmt.Printf("Found capture %s\n", k)
|
||||
// TODO handle values other than string using a switch
|
||||
//fmt.Printf("Found matching capture in body with value : '%v', storing replacement with key '%s'\n", val, v)
|
||||
captureValues.Data[v] = val.(string)
|
||||
|
120
safes-test.json
Normal file
120
safes-test.json
Normal file
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"name": "CBS safes testing",
|
||||
"testCases": {
|
||||
"test1": {
|
||||
"path": "/api/login",
|
||||
"method": "POST",
|
||||
"description": "Perform login",
|
||||
"body": {
|
||||
"username": "Administrator",
|
||||
"password": "Password123"
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"hasKeys": ["access_token"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"test2": {
|
||||
"path": "/api/safe/list",
|
||||
"method": "GET",
|
||||
"description": "get user allowed safe listing",
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"hasKeys": ["safeName"],
|
||||
"contains": {
|
||||
"message": "success"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"test3": {
|
||||
"path": "/api/admin/safe/add",
|
||||
"method": "POST",
|
||||
"description": "create new safe",
|
||||
"body": {
|
||||
"safeName": "API test created safe"
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"test4": {
|
||||
"path": "/api/admin/safe/add",
|
||||
"method": "POST",
|
||||
"description": "create new safe",
|
||||
"body": {
|
||||
"safeName": "API test created second safe"
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"test5": {
|
||||
"path": "/api/admin/safe/listall",
|
||||
"method": "GET",
|
||||
"description": "get all defined safe listing",
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"hasKeys": ["safeName"],
|
||||
"contains": {
|
||||
"message": "success"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"test6": {
|
||||
"path": "/api/admin/safe/delete",
|
||||
"method": "POST",
|
||||
"description": "get all defined safe listing",
|
||||
"body": {
|
||||
"safeName": "API test created safe"
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://10.63.39.130:8443",
|
||||
"insecure": true,
|
||||
"header": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer %ACCESS_TOKEN%"
|
||||
},
|
||||
"capture": {
|
||||
"test1": {
|
||||
"body": {
|
||||
"access_token": "%ACCESS_TOKEN%"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -28,6 +28,11 @@ type TestCase struct {
|
||||
ResultBodyMap map[string]interface{}
|
||||
}
|
||||
|
||||
type RandomBody struct {
|
||||
IsString bool `json:"isString"`
|
||||
Length int `json:"length"`
|
||||
}
|
||||
|
||||
type CaptureCase struct {
|
||||
TestCaseName string
|
||||
CaptureData CaptureCaseData
|
||||
|
67
test-random.json
Normal file
67
test-random.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "CBS test cases",
|
||||
"testCases": {
|
||||
"test1": {
|
||||
"path": "/api/login",
|
||||
"method": "POST",
|
||||
"description": "Perform login",
|
||||
"body": {
|
||||
"username": "Administrator",
|
||||
"password": "Password123"
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"hasKeys": ["access_token"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"test12": {
|
||||
"path": "/api/secret/store",
|
||||
"method": "POST",
|
||||
"description": "store first new secret",
|
||||
"body": {
|
||||
"safeId": 1,
|
||||
"deviceName": {
|
||||
"random": {
|
||||
"isString": true,
|
||||
"length": 12
|
||||
}
|
||||
},
|
||||
"deviceCategory": "appliance",
|
||||
"userName": "service@cdc.home",
|
||||
"secretValue": {
|
||||
"random": {
|
||||
"isString": true,
|
||||
"length": 20
|
||||
}
|
||||
}
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://10.63.39.130:8443",
|
||||
"insecure": true,
|
||||
"header": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer %ACCESS_TOKEN%"
|
||||
},
|
||||
"capture": {
|
||||
"test1": {
|
||||
"body": {
|
||||
"access_token": "%ACCESS_TOKEN%"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -22,7 +22,7 @@
|
||||
}
|
||||
},
|
||||
"test2": {
|
||||
"path": "/api/admin/user/register",
|
||||
"path": "/api/admin/user/add",
|
||||
"method": "POST",
|
||||
"description": "register user account",
|
||||
"header": {
|
||||
@@ -136,7 +136,12 @@
|
||||
"description": "store first new secret",
|
||||
"body": {
|
||||
"safeId": 1,
|
||||
"deviceName": "avcp01.cdc.home",
|
||||
"deviceName": {
|
||||
"random": {
|
||||
"isString": true,
|
||||
"length": 12
|
||||
}
|
||||
},
|
||||
"deviceCategory": "appliance",
|
||||
"userName": "service@cdc.home",
|
||||
"secretValue": "TheWiggles"
|
||||
|
66
user-test.json
Normal file
66
user-test.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"name": "CBS normal user testing",
|
||||
"testCases": {
|
||||
"test1": {
|
||||
"path": "/api/login",
|
||||
"method": "POST",
|
||||
"description": "Perform login",
|
||||
"body": {
|
||||
"username": "nathtest",
|
||||
"password": "VMware1!"
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200",
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"hasKeys": ["access_token"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"test20": {
|
||||
"path": "/api/secret/list",
|
||||
"disabled": false,
|
||||
"method": "GET",
|
||||
"description": "List secrets",
|
||||
"header": {
|
||||
"Authorization": "Bearer %ACCESS_TOKEN%"
|
||||
},
|
||||
"expect": {
|
||||
"header": {
|
||||
"contains": {
|
||||
"http_status": "200"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"test22": {
|
||||
"path": "/api/secret/update",
|
||||
"method": "POST",
|
||||
"description": "try update existing secret",
|
||||
"body": {
|
||||
"deviceName": "adcp01.cdc.home",
|
||||
"deviceCategory": "windows-server",
|
||||
"userName": "dummy@cdc.home",
|
||||
"secretValue": "TheWiggles"
|
||||
}
|
||||
}
|
||||
},
|
||||
"url": "https://10.63.39.130:8443",
|
||||
"insecure": true,
|
||||
"header": {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer %ACCESS_TOKEN%"
|
||||
},
|
||||
"capture": {
|
||||
"test1": {
|
||||
"body": {
|
||||
"access_token": "%ACCESS_TOKEN%"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user