Files
apitester/load_input.go
Nathan Coad a31b01af4d
All checks were successful
continuous-integration/drone/push Build is passing
add feature to disable test case
2024-01-09 15:29:13 +11:00

244 lines
7.3 KiB
Go

package main
import (
"encoding/json"
"fmt"
"reflect"
"github.com/iancoleman/orderedmap"
)
func ReadInput(data []byte, testDefinitions *TestDefinitions) {
var err error
// Unmarshal the json into an orderedmap to preserve the ordering of json structure
o := orderedmap.New()
err = json.Unmarshal([]byte(data), &o)
if err != nil {
error := fmt.Sprintf("JSON Unmarshal error %s\n", err)
panic(error)
}
topLevel := o.Keys()
//fmt.Printf("Found %d top-level keys in json data\n", len(topLevel))
// TODO : Check required top level keys are present
if len(topLevel) <= 1 {
error := "Missing required keys in input json"
panic(error)
}
// Get the name of the group of tests
if data, ok := o.Get("name"); ok {
testDefinitions.Name = data.(string)
//fmt.Printf("test name: '%s'\n", testDefinitions.Name)
}
// Get the base url if defined
if data, ok := o.Get("url"); ok {
testDefinitions.BaseUrl = data.(string)
}
// Check for any headers to include with all requests
if data, ok := o.Get("header"); ok {
headerMap := data.(orderedmap.OrderedMap)
testDefinitions.Headers = OrderedToStringMap(headerMap)
}
// Check if we should ignore certificate errors
if data, ok := o.Get("insecure"); ok {
testDefinitions.Insecure = data.(bool)
}
// Get a reference to the node containing each of the test cases
testsInterface, ok := o.Get("testCases")
if !ok {
panic("No key defining test cases found\n")
}
// Process the "capture" settings that allow us to use values from one test case in subsequent test cases
// each capture node has a name that links it to the test case that captures that data
if capture, ok := o.Get("capture"); ok {
captureMap := capture.(orderedmap.OrderedMap)
captureKeys := captureMap.Keys()
for _, outerKey := range captureKeys {
// Define a new capture case object to record these details
thisCaptureCase := new(CaptureCase)
// Make sure we can access the capture defintiion
if captureCase, ok := captureMap.Get(outerKey); ok {
// Store the test case name that this capture will come from
thisCaptureCase.TestCaseName = outerKey
//fmt.Printf("[%d] : Capture from %s\n", i, outerKey)
// Get capture data from body
thisCaptureCaseMap := captureCase.(orderedmap.OrderedMap)
if body, ok := thisCaptureCaseMap.Get("body"); ok {
//fmt.Printf("This capture case has body defined\n")
bodyMap := body.(orderedmap.OrderedMap)
bodyMapKeys := bodyMap.Keys()
bodyData := make(map[string]string)
for _, bodyKey := range bodyMapKeys {
if bodyVal, ok := bodyMap.Get(bodyKey); ok {
switch vType := bodyVal.(type) {
case string:
//fmt.Printf("Capturing '%s' from test result and using '%s' for replacement token\n", bodyKey, bodyVal.(string))
// Store capture info
bodyData[bodyKey] = bodyVal.(string)
default:
fmt.Printf("received unexpected value type, %T\n", vType)
}
}
}
captureBody := new(CaptureBody)
captureBody.Data = bodyData
thisCaptureCase.CaptureData.Body = *captureBody
}
// TODO : header
}
testDefinitions.CaptureCases = append(testDefinitions.CaptureCases, *thisCaptureCase)
}
}
// Get the keys for the first test so we know what config options have been specified
testCasesMap := testsInterface.(orderedmap.OrderedMap)
testCasesKeys := testCasesMap.Keys()
// Parse json into our testCaseDefinition
// Parse each key into our config struct
fmt.Printf("Loading %d test cases\n", len(testCasesKeys))
for _, outerKey := range testCasesKeys {
//fmt.Printf("Test %d : %s\n", i, outerKey)
// Get the name of the test case
thisTestCase := new(TestCase)
thisTestCase.Name = outerKey
if testCase, ok := testCasesMap.Get(outerKey); ok {
// Get the details of the test case
thisTestCaseMap := testCase.(orderedmap.OrderedMap)
// Path
if val, ok := thisTestCaseMap.Get("path"); ok {
thisTestCase.Path = val.(string)
}
// Method
if val, ok := thisTestCaseMap.Get("method"); ok {
thisTestCase.Method = val.(string)
}
// Description
if val, ok := thisTestCaseMap.Get("description"); ok {
thisTestCase.Description = val.(string)
}
// Disabled
if val, ok := thisTestCaseMap.Get("disabled"); ok {
thisTestCase.Disabled = val.(bool)
}
// 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))
bytes, err := json.Marshal(val)
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))
}
}
// Header
if val, ok := thisTestCaseMap.Get("header"); ok {
// Create a normal string map for all the body key-value pairs
thisTestCase.Header = OrderedToStringMap(val.(orderedmap.OrderedMap))
}
// Expect - this is more tricky since it is yet another json fragment
if val, ok := thisTestCaseMap.Get("expect"); ok {
expectOptions := new(ExpectOptions)
// expect can have header and body definitions
expectMap := val.(orderedmap.OrderedMap)
// Handle the possible checks for a header
if expectVal, ok2 := expectMap.Get("header"); ok2 {
ReadHeaderTestCases(expectVal.(orderedmap.OrderedMap), &expectOptions.Header)
}
// Handle the possible checks for a body
if expectVal, ok2 := expectMap.Get("body"); ok2 {
ReadBodyTestCases(expectVal.(orderedmap.OrderedMap), &expectOptions.Body)
}
thisTestCase.Expect = *expectOptions
}
}
testDefinitions.TestCases = append(testDefinitions.TestCases, *thisTestCase)
}
}
func ReadHeaderTestCases(input orderedmap.OrderedMap, result *HeaderTests) {
result.Contains = make(map[string]string)
result.Equals = make(map[string]string)
// Contains check
if val, ok := input.Get("contains"); ok {
containsMap := val.(orderedmap.OrderedMap)
result.Contains = OrderedToStringMap(containsMap)
}
// Equals check
if val, ok := input.Get("equals"); ok {
equalsMap := val.(orderedmap.OrderedMap)
result.Equals = OrderedToStringMap(equalsMap)
}
}
func ReadBodyTestCases(input orderedmap.OrderedMap, result *BodyTests) {
result.Contains = make(map[string]string)
result.Equals = make(map[string]string)
// TODO : Use tags in struct rather than hard coding all the different check types
// using https://stackoverflow.com/a/23840419 as an idea
// Contains check
if val, ok := input.Get("contains"); ok {
// Confirm this is an ordered map
if _, ok := val.(orderedmap.OrderedMap); !ok {
error := fmt.Sprintf("Unexpected json definition for Body Contains check. Type is '%v' but expected Object.\n", reflect.TypeOf(val))
panic(error)
}
containsMap := val.(orderedmap.OrderedMap)
result.Contains = OrderedToStringMap(containsMap)
}
// Equals check
if val, ok := input.Get("equals"); ok {
equalsMap := val.(orderedmap.OrderedMap)
result.Equals = OrderedToStringMap(equalsMap)
}
// Has Keys check
if val, ok := input.Get("hasKeys"); ok {
// This is an array not a map
hasKeysArray := val.([]interface{})
result.HasKeys = OrderedToStringSlice(hasKeysArray)
}
// TODO : remaining tests
}