diff --git a/load_input.go b/load_input.go index 885c084..29b1a31 100644 --- a/load_input.go +++ b/load_input.go @@ -184,6 +184,35 @@ func ReadInput(data []byte, testDefinitions *TestDefinitions) { // Create a normal string map for all the body key-value pairs thisTestCase.Header = OrderedToStringMap(val.(orderedmap.OrderedMap)) } + // Form + if val, ok := thisTestCaseMap.Get("form"); ok { + // Turn the original string into json + bytes, err := json.Marshal(val) + if err != nil { + error := fmt.Sprintf("Error mnarshalling request form 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 form for test case : '%s'\n", err) + panic(error) + } + + // Search for any keys in the body that we need to replace with a dynamic random value + results := findRandom(nil, jsonData) + + // store the results back into the body + newBytes, err := json.Marshal(results) + if err != nil { + error := fmt.Sprintf("Error turning form interface back into json for test case : '%s'\n", err) + panic(error) + } + thisTestCase.Form = newBytes + //fmt.Printf("Form marshalled:\n%v\n", string(newBytes)) + } // Expect - this is more tricky since it is yet another json fragment if val, ok := thisTestCaseMap.Get("expect"); ok { @@ -205,6 +234,7 @@ func ReadInput(data []byte, testDefinitions *TestDefinitions) { thisTestCase.Expect = *expectOptions } } + testDefinitions.TestCases = append(testDefinitions.TestCases, *thisTestCase) } } diff --git a/main.go b/main.go index bebe620..64fa7fb 100644 --- a/main.go +++ b/main.go @@ -1,12 +1,15 @@ package main import ( + "encoding/json" "flag" "fmt" "os" "reflect" + "runtime" "strconv" "strings" + "time" "github.com/iancoleman/orderedmap" ) @@ -154,3 +157,31 @@ func OrderedToStringSlice(input []interface{}) []string { return result } + +// prettyPrint comes from https://gist.github.com/sfate/9d45f6c5405dc4c9bf63bf95fe6d1a7c +func prettyPrint(args ...interface{}) { + var caller string + + timeNow := time.Now().Format("01-02-2006 15:04:05") + prefix := fmt.Sprintf("[%s] %s -- ", "PrettyPrint", timeNow) + _, fileName, fileLine, ok := runtime.Caller(1) + + if ok { + caller = fmt.Sprintf("%s:%d", fileName, fileLine) + } else { + caller = "" + } + + fmt.Printf("\n%s%s\n", prefix, caller) + + if len(args) == 2 { + label := args[0] + value := args[1] + + s, _ := json.MarshalIndent(value, "", "\t") + fmt.Printf("%s%s: %s\n", prefix, label, string(s)) + } else { + s, _ := json.MarshalIndent(args, "", "\t") + fmt.Printf("%s%s\n", prefix, string(s)) + } +} diff --git a/run_tests.go b/run_tests.go index 3d8dbbf..7193a2d 100644 --- a/run_tests.go +++ b/run_tests.go @@ -7,8 +7,10 @@ import ( "errors" "fmt" "io" + "mime/multipart" "net/http" "net/url" + "os" "reflect" "strconv" "strings" @@ -96,8 +98,56 @@ func RunTest(testCase *TestCase) error { errMessage := fmt.Sprintf("error submitting request : '%s'\n", err) return errors.New(errMessage) } + } else if len(testCase.Form) > 0 { + fmt.Printf("Sending a form request\n") + //prettyPrint(testCase) + // Create buffer and multipart writer + var requestBody bytes.Buffer + writer := multipart.NewWriter(&requestBody) + + // unmarshal testCase.Form so we can search for replacements + var jsonBody map[string]interface{} + err = json.Unmarshal(testCase.Form, &jsonBody) + if err != nil { + error := fmt.Sprintf("Error processing request form for test case : '%s'\n", err) + panic(error) + } + + // TODO replacement searching + + for k, v := range jsonBody { + if k == "file" { + // Open file + file, err := os.Open(v.(string)) + if err != nil { + return fmt.Errorf("open file error: %w", err) + } + defer file.Close() + + // Add file + part, err := writer.CreateFormFile("file", file.Name()) + if err != nil { + return fmt.Errorf("create form file error: %w", err) + } + if _, err := io.Copy(part, file); err != nil { + return fmt.Errorf("copy file error: %w", err) + } + } else { + _ = writer.WriteField(k, v.(string)) + } + } + + // Finalize multipart writer + if err := writer.Close(); err != nil { + return fmt.Errorf("close writer error: %w", err) + } + + req, err = http.NewRequest(requestType, requestUrl, &requestBody) + req.Header.Set("Content-Type", writer.FormDataContentType()) } else { + fmt.Printf("Sending neither a body nor a form request\n") + //prettyPrint(testCase) req, err = http.NewRequest(requestType, requestUrl, nil) } @@ -115,7 +165,7 @@ func RunTest(testCase *TestCase) error { key := HeaderReplaceCaptures(k) val := HeaderReplaceCaptures(v) - //fmt.Printf("Add global header %s = %s\n", key, val) + fmt.Printf("Add global header %s = %s\n", key, val) req.Header.Add(key, val) } } @@ -126,7 +176,7 @@ func RunTest(testCase *TestCase) error { key := HeaderReplaceCaptures(k) val := HeaderReplaceCaptures(v) - //fmt.Printf("Add header %s = %s\n", key, val) + fmt.Printf("Add header %s = %s\n", key, val) req.Header.Add(key, val) } diff --git a/structs.go b/structs.go index 7588725..e028ee1 100644 --- a/structs.go +++ b/structs.go @@ -20,6 +20,7 @@ type TestCase struct { Header map[string]string //Body map[string]string Body []byte + Form []byte // Something to store results in ResultStatusCode int