From 6c48219c0cb001a57b5462cfb3079a843d26e466 Mon Sep 17 00:00:00 2001 From: wagslane Date: Sun, 29 Dec 2024 12:41:43 -0700 Subject: [PATCH] render the variables that are being used in http tests --- checks/http.go | 23 ++++++----- client/lessons.go | 36 +++++++++-------- render/common.go | 16 +++++++- render/http.go | 98 ++++++++++++++++++++++++++++++++--------------- 4 files changed, 112 insertions(+), 61 deletions(-) diff --git a/checks/http.go b/checks/http.go index 202a36a..b23a106 100644 --- a/checks/http.go +++ b/checks/http.go @@ -17,12 +17,12 @@ import ( ) type HttpTestResult struct { - Err string `json:"-"` - RequestHeaders http.Header `json:"-"` - StatusCode int - Headers map[string]string - BodyString string - Variables map[string]string + Err string `json:"-"` + StatusCode int + ResponseHeaders map[string]string + BodyString string + Variables map[string]string + Request api.LessonDataHTTPTestsRequest } func HttpTest( @@ -101,11 +101,11 @@ func HttpTest( } parseVariables(body, request.ResponseVariables, variables) responses[i] = HttpTestResult{ - RequestHeaders: r.Header, - StatusCode: resp.StatusCode, - Headers: headers, - BodyString: truncateAndStringifyBody(body), - Variables: variables, + StatusCode: resp.StatusCode, + ResponseHeaders: headers, + BodyString: truncateAndStringifyBody(body), + Variables: variables, + Request: request, } } return responses, finalBaseURL @@ -118,7 +118,6 @@ func truncateAndStringifyBody(body []byte) string { bodyString := string(body) const maxBodyLength = 100000 if len(bodyString) > maxBodyLength { - fmt.Printf("truncating from %v to %v", len(bodyString), maxBodyLength) bodyString = bodyString[:maxBodyLength] } return bodyString diff --git a/client/lessons.go b/client/lessons.go index 667904b..2df2522 100644 --- a/client/lessons.go +++ b/client/lessons.go @@ -45,23 +45,25 @@ type LessonDataHTTPTests struct { HttpTests struct { BaseURL *string ContainsCompleteDir bool - Requests []struct { - ResponseVariables []ResponseVariable - Tests []HTTPTest - Request struct { - FullURL string // overrides BaseURL and Path if set - Path string - BasicAuth *struct { - Username string - Password string - } - Headers map[string]string - BodyJSON map[string]interface{} - Method string - Actions struct { - DelayRequestByMs *int32 - } - } + Requests []LessonDataHTTPTestsRequest + } +} + +type LessonDataHTTPTestsRequest struct { + ResponseVariables []ResponseVariable + Tests []HTTPTest + Request struct { + FullURL string // overrides BaseURL and Path if set + Path string + BasicAuth *struct { + Username string + Password string + } + Headers map[string]string + BodyJSON map[string]interface{} + Method string + Actions struct { + DelayRequestByMs *int32 } } } diff --git a/render/common.go b/render/common.go index ffede3d..622c38f 100644 --- a/render/common.go +++ b/render/common.go @@ -4,6 +4,7 @@ import ( "fmt" "strings" + api "github.com/bootdotdev/bootdev/client" "github.com/charmbracelet/bubbles/spinner" "github.com/charmbracelet/lipgloss" ) @@ -36,6 +37,20 @@ func renderTestHeader(header string, spinner spinner.Model, isFinished bool, isS return strings.Join(sliced, "\n") + "\n" } +func renderTestResponseVars(respVars []api.ResponseVariable) string { + var str string + for _, respVar := range respVars { + varStr := gray.Render(fmt.Sprintf(" * Saving `%s` from `%s`", respVar.Name, respVar.Path)) + edges := " ├─" + for i := 0; i < lipgloss.Height(varStr)-1; i++ { + edges += "\n │ " + } + str += lipgloss.JoinHorizontal(lipgloss.Top, edges, varStr) + str += "\n" + } + return str +} + func renderTests(tests []testModel, spinner string) string { var str string for _, test := range tests { @@ -49,7 +64,6 @@ func renderTests(tests []testModel, spinner string) string { str += lipgloss.JoinHorizontal(lipgloss.Top, edges, testStr) str += "\n" } - str += "\n" return str } diff --git a/render/http.go b/render/http.go index 3ef06d6..a013d82 100644 --- a/render/http.go +++ b/render/http.go @@ -23,8 +23,9 @@ type doneHttpMsg struct { } type startHttpMsg struct { - url string - method string + url string + method string + responseVariables []api.ResponseVariable } type resolveHttpMsg struct { @@ -33,11 +34,12 @@ type resolveHttpMsg struct { results *checks.HttpTestResult } type httpReqModel struct { - request string - passed *bool - results *checks.HttpTestResult - finished bool - tests []testModel + responseVariables []api.ResponseVariable + request string + passed *bool + results *checks.HttpTestResult + finished bool + tests []testModel } type httpRootModel struct { @@ -78,7 +80,11 @@ func (m httpRootModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, tea.Quit case startHttpMsg: - m.reqs = append(m.reqs, httpReqModel{request: fmt.Sprintf("%s %s", msg.method, msg.url), tests: []testModel{}}) + m.reqs = append(m.reqs, httpReqModel{ + request: fmt.Sprintf("%s %s", msg.method, msg.url), + tests: []testModel{}, + responseVariables: msg.responseVariables, + }) return m, nil case resolveHttpMsg: @@ -115,6 +121,7 @@ func (m httpRootModel) View() string { for _, req := range m.reqs { str += renderTestHeader(req.request, m.spinner, req.finished, m.isSubmit, req.passed) str += renderTests(req.tests, s) + str += renderTestResponseVars(req.responseVariables) if req.results != nil && m.finalized { str += printHTTPResult(*req.results) } @@ -129,37 +136,63 @@ func (m httpRootModel) View() string { } func printHTTPResult(result checks.HttpTestResult) string { - str := "" if result.Err != "" { - str += fmt.Sprintf(" Err: %v\n", result.Err) - } else { - if len(result.RequestHeaders) > 0 { - str += " Request Headers: \n" - for k, v := range result.RequestHeaders { - str += fmt.Sprintf(" - %v: %v\n", k, v[0]) + return fmt.Sprintf(" Err: %v\n\n", result.Err) + } + + str := "" + + str += fmt.Sprintf(" Response Status Code: %v\n", result.StatusCode) + + filteredHeaders := make(map[string]string) + for respK, respV := range result.ResponseHeaders { + for reqK := range result.Request.Request.Headers { + if strings.ToLower(respK) == strings.ToLower(reqK) { + filteredHeaders[respK] = respV } } - str += fmt.Sprintf(" Response Status Code: %v\n", result.StatusCode) - str += " Response Body: \n" - unmarshalled := map[string]interface{}{} - bytes := []byte(result.BodyString) + } + + if len(filteredHeaders) > 0 { + str += " Response Headers: \n" + for k, v := range filteredHeaders { + str += fmt.Sprintf(" - %v: %v\n", k, v) + } + } - contentType := http.DetectContentType(bytes) - if contentType == "application/json" || strings.HasPrefix(contentType, "text/") { - err := json.Unmarshal([]byte(result.BodyString), &unmarshalled) + str += " Response Body: \n" + bytes := []byte(result.BodyString) + contentType := http.DetectContentType(bytes) + if contentType == "application/json" || strings.HasPrefix(contentType, "text/") { + var unmarshalled interface{} + err := json.Unmarshal([]byte(result.BodyString), &unmarshalled) + if err == nil { + pretty, err := json.MarshalIndent(unmarshalled, "", " ") if err == nil { - pretty, err := json.MarshalIndent(unmarshalled, "", " ") - if err == nil { - str += string(pretty) - } + str += string(pretty) } else { str += result.BodyString } } else { - str += fmt.Sprintf("Binary %s file", contentType) + str += result.BodyString + } + } else { + str += fmt.Sprintf("Binary %s file", contentType) + } + str += "\n" + + if len(result.Variables) > 0 { + str += " Variables available: \n" + for k, v := range result.Variables { + if v != "" { + str += fmt.Sprintf(" - %v: %v\n", k, v) + } else { + str += fmt.Sprintf(" - %v: [not found]\n", k) + } } } str += "\n" + return str } @@ -215,11 +248,14 @@ func httpRenderer( url = req.Request.FullURL } ch <- startHttpMsg{ - url: checks.InterpolateVariables(url, results[i].Variables), - method: req.Request.Method, + url: checks.InterpolateVariables(url, results[i].Variables), + method: req.Request.Method, + responseVariables: req.ResponseVariables, } for _, test := range req.Tests { - ch <- startTestMsg{text: prettyPrintHTTPTest(test, results[i].Variables)} + ch <- startTestMsg{ + text: prettyPrintHTTPTest(test, results[i].Variables), + } } time.Sleep(500 * time.Millisecond) for j := range req.Tests { @@ -267,7 +303,7 @@ func prettyPrintHTTPTest(test api.HTTPTest, variables map[string]string) string if test.HeadersContain != nil { interpolatedKey := checks.InterpolateVariables(test.HeadersContain.Key, variables) interpolatedValue := checks.InterpolateVariables(test.HeadersContain.Value, variables) - return fmt.Sprintf("Expecting header to contain: '%s: %v'", interpolatedKey, interpolatedValue) + return fmt.Sprintf("Expecting headers to contain: '%s: %v'", interpolatedKey, interpolatedValue) } if test.JSONValue != nil { var val any