From b7094fd83da401c5b2a8a348c509a6b2d9d51f23 Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Fri, 29 Dec 2023 13:11:55 +1100 Subject: [PATCH] initial work --- go.mod | 5 ++ go.sum | 2 + main.go | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests.json | 56 +++++++++++++++++ 4 files changed, 241 insertions(+) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 tests.json diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a5ab58f --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module apitester + +go 1.21.0 + +require github.com/iancoleman/orderedmap v0.3.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..3300bf6 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= +github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= diff --git a/main.go b/main.go new file mode 100644 index 0000000..35e74ba --- /dev/null +++ b/main.go @@ -0,0 +1,178 @@ +package main + +import ( + "encoding/json" + "flag" + "fmt" + "os" + + "github.com/iancoleman/orderedmap" +) + +type CommonTestSettings struct { + RootUrl string + Name string + Headers map[string]string // Need to initialise with make +} + +type InputData struct { + Name string `json:"name"` + TestCases []TestCases `json:"testCases"` + URL string `json:"url"` + Header HeaderOptions `json:"header"` +} + +type TestCases struct { + Path string `json:"path"` + Method string `json:"method"` + Description string `json:"description"` + Expect ExpectOptions `json:"expect"` +} + +type ExpectOptions struct { + Header HeaderOptions `json:"header"` + Body BodyOptions `json:"body"` +} + +type HeaderOptions struct { + Contains ContainsTest `json:"contains"` + Equals EqualsTest `json:"equals"` +} + +type BodyOptions struct { + Contains ContainsTest `json:"contains"` + Equals EqualsTest `json:"equals"` + HasKeys HasKeysTest `json:"hasKeys"` + PathEq PathEqTest `json:"pathEq"` + PathContains PathContainsTest `json:"pathContains"` +} + +// Test types +type ContainsTest struct { + // dynamically specified key value pairs +} + +type EqualsTest struct { + // dynamically specified key value pairs +} + +type HasKeysTest struct { + // dynamically specified key value pairs +} + +type PathEqTest struct { + // dynamically specified key value pairs +} + +type PathContainsTest struct { + // dynamically specified key value pairs +} + +// fileExists returns true if the specified file exists and is not a directory +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} + +func PerformGet() { + +} + +func PerformPost() { + +} + +func TestOutput() { + +} + +func main() { + var s []byte + var err error + + // Prepare struct to store settings common to all tests + testSettings := new(CommonTestSettings) + testSettings.Headers = make(map[string]string) + + //testCaseDefinition := new(InputData) + + // Command line arguments + var inputJson string + + // Process command line arguments + flag.StringVar(&inputJson, "input", "./tests.json", "Full path to input json test definition file") + + // Read the json input file + if fileExists(inputJson) { + s, err = os.ReadFile(inputJson) + if err != nil { + panic(err) + } + } else { + fmt.Printf("Input JSON file '%s' does not exist.\n", inputJson) + os.Exit(1) + } + + // Unmarshal the json into an orderedmap to preserve the ordering of json structure + o := orderedmap.New() + err = json.Unmarshal([]byte(s), &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)) + for i, key := range topLevel { + fmt.Printf("[%d] : %s\n", i, key) + } + + // TODO : Check required top level keys are present + if len(topLevel) <= 1 { + error := "Missing required keys in input json" + panic(error) + } + + // Get a reference to the node containing all our test cases + testsInterface, ok := o.Get("testCases") + if !ok { + fmt.Printf("No key defining test cases found\n") + } + + // Test Cases is an array, need to go one level down before we start looking at key/values + vs := testsInterface.([]interface{}) + fmt.Printf("Listing %d test definitions\n", len(vs)) + for i, vInterface := range vs { + v := vInterface.(orderedmap.OrderedMap) + keys := v.Keys() + fmt.Printf("Test %d\n", i) + for j := range keys { + fmt.Printf("[%d] : %s\n", j, keys[j]) + } + } + + return + + // 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 + for i, key := range testCasesKeys { + /* + if strings.EqualFold(key, "path") { + fmt.Printf("Found config element for path\n") + e, _ := configMap.Get(key) + for i, e := range strings.Split(e.(string), ",") { + config.keyOrder[i] = e + } + } + */ + fmt.Printf("[%d] : %s\n", i, key) + } +} diff --git a/tests.json b/tests.json new file mode 100644 index 0000000..e2e203e --- /dev/null +++ b/tests.json @@ -0,0 +1,56 @@ +{ + "name": "CBS test cases", + "testCases": [ + { + "path": "/hosts", + "method": "GET", + "description": "Check database query is working", + "expect": { + "header": { + "contains": { + "http_status": "200" + } + }, + "body": { + "contains": { + "Cluster":"Cluster2" + } + } + } + }, + { + "path": "/protected/hosts?key=e36689911ed0e9cba50c436b66d664cf9ee4f555e182a48021c21d9f7c640868", + "method": "POST", + "description": "Create new host", + "body": { + "Hostname":"host999.cdc.home", + "IP":"10.63.39.5", + "Subnet":"255.255.255.0", + "Gateway":"10.63.39.1", + "Vcenter":"avcp06.cdc.home", + "Datacenter":"CDC", + "Cluster":"Cluster", + "MAC":"b8:2a:72:cf:84:99", + "PerformReinstall":false, + "BootWWN":"naa.70000970000297600333533030314130", + "Vlan":"1000", + "DNS":"10.63.39.1", + "DNS2":"10.45.39.1", + "NTP1":"10.63.39.1", + "NTP2":"10.45.39.1", + "BootTypeUefi":true + }, + "expect": { + "header": { + "contains": { + "http_status": "201" + } + } + } + } + ], + "url": "https://10.63.39.130:443", + "header": { + "Content-Type": "application/json" + } +} \ No newline at end of file