diff --git a/agent/pkg/oas/specgen.go b/agent/pkg/oas/specgen.go index a63e3aaaf..36b20b11b 100644 --- a/agent/pkg/oas/specgen.go +++ b/agent/pkg/oas/specgen.go @@ -350,20 +350,25 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool) e } handleNameVals(hdrGW, &opObj.Parameters) - if req.PostData.Text != "" && isSuccess { - reqBody, err := getRequestBody(req, opObj, isSuccess) + if isSuccess { + reqBody, err := getRequestBody(req, opObj) if err != nil { return err } if reqBody != nil { - reqCtype, _ := getReqCtype(req) - reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype) - if err != nil { - return err - } + if req.PostData.Text == "" { + reqBody.Required = false + } else { - _ = reqMedia + reqCtype, _ := getReqCtype(req) + reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype) + if err != nil { + return err + } + + _ = reqMedia + } } } return nil @@ -537,9 +542,11 @@ func handleFormData(content *openapi.MediaType, parts []PartWithBody) { for name := range seenNames { content.Schema.Required = append(content.Schema.Required, name) } + sort.Strings(content.Schema.Required) } // else it's a known schema with no required fields } else { content.Schema.Required = intersectSliceWithMap(content.Schema.Required, seenNames) + sort.Strings(content.Schema.Required) } } @@ -603,6 +610,10 @@ func getReqCtype(req *har.Request) (ctype string, params map[string]string) { } } + if ctype == "" { + return "", map[string]string{} + } + mediaType, params, err := mime.ParseMediaType(ctype) if err != nil { logger.Log.Errorf("Cannot parse Content-Type header %q: %v", ctype, err) @@ -638,9 +649,14 @@ func getResponseObj(resp *har.Response, opObj *openapi.Operation, isSuccess bool return resResponse, nil } -func getRequestBody(req *har.Request, opObj *openapi.Operation, isSuccess bool) (*openapi.RequestBodyObj, error) { +func getRequestBody(req *har.Request, opObj *openapi.Operation) (*openapi.RequestBodyObj, error) { if opObj.RequestBody == nil { - opObj.RequestBody = &openapi.RequestBodyObj{Description: "Generic request body", Required: true, Content: map[string]*openapi.MediaType{}} + // create if there is body in request + if req.PostData.Text != "" { + opObj.RequestBody = &openapi.RequestBodyObj{Description: "Generic request body", Required: true, Content: map[string]*openapi.MediaType{}} + } else { + return nil, nil + } } reqBody, err := opObj.RequestBody.ResolveRequestBody(reqBodyResolver) @@ -648,9 +664,6 @@ func getRequestBody(req *har.Request, opObj *openapi.Operation, isSuccess bool) return nil, err } - // TODO: maintain required flag for it, but only consider successful responses - //reqBody.Content[] - return reqBody, nil } diff --git a/agent/pkg/oas/test_artifacts/params.har b/agent/pkg/oas/test_artifacts/params.har index 551f4db73..226f0839f 100644 --- a/agent/pkg/oas/test_artifacts/params.har +++ b/agent/pkg/oas/test_artifacts/params.har @@ -370,6 +370,174 @@ "wait": -1, "receive": 1 } + }, + { + "startedDateTime": "2019-09-06T06:16:21.757122+00:00", + "time": 1, + "request": { + "method": "POST", + "url": "https://httpbin.org/body-optional", + "httpVersion": "", + "cookies": [], + "headers": [ + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1, + "postData": { + "mimeType": "", + "text": "" + } + }, + "response": { + "status": 200, + "statusText": "OK", + "httpVersion": "", + "cookies": [], + "headers": [ + ], + "content": { + "size": 0, + "mimeType": "", + "text": "" + }, + "redirectURL": "", + "headersSize": -1, + "bodySize": 0 + }, + "cache": {}, + "timings": { + "send": -1, + "wait": -1, + "receive": 1 + } + }, + { + "startedDateTime": "2019-09-06T06:16:21.747122+00:00", + "time": 1, + "request": { + "method": "POST", + "url": "https://httpbin.org/body-optional", + "httpVersion": "", + "cookies": [], + "headers": [ + { + "name": "Content-Type", + "value": "application/json" + } + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1, + "postData": { + "mimeType": "", + "text": "{\"key\", \"val\"}" + } + }, + "response": { + "status": 200, + "statusText": "OK", + "httpVersion": "", + "cookies": [], + "headers": [ + ], + "content": { + "size": 0, + "mimeType": "", + "text": "" + }, + "redirectURL": "", + "headersSize": -1, + "bodySize": 0 + }, + "cache": {}, + "timings": { + "send": -1, + "wait": -1, + "receive": 1 + } + }, + { + "startedDateTime": "2019-09-06T06:16:21.757122+00:00", + "time": 1, + "request": { + "method": "POST", + "url": "https://httpbin.org/body-optional", + "httpVersion": "", + "cookies": [], + "headers": [ + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1, + "postData": { + "mimeType": "", + "text": "" + } + }, + "response": { + "status": 200, + "statusText": "OK", + "httpVersion": "", + "cookies": [], + "headers": [ + ], + "content": { + "size": 0, + "mimeType": "", + "text": "" + }, + "redirectURL": "", + "headersSize": -1, + "bodySize": 0 + }, + "cache": {}, + "timings": { + "send": -1, + "wait": -1, + "receive": 1 + } + }, + { + "startedDateTime": "2019-09-06T06:16:21.757122+00:00", + "time": 1, + "request": { + "method": "POST", + "url": "https://httpbin.org/body-required", + "httpVersion": "", + "cookies": [], + "headers": [ + ], + "queryString": [], + "headersSize": -1, + "bodySize": -1, + "postData": { + "mimeType": "", + "text": "body exists" + } + }, + "response": { + "status": 200, + "statusText": "OK", + "httpVersion": "", + "cookies": [], + "headers": [ + ], + "content": { + "size": 0, + "mimeType": "", + "text": "" + }, + "redirectURL": "", + "headersSize": -1, + "bodySize": 0 + }, + "cache": {}, + "timings": { + "send": -1, + "wait": -1, + "receive": 1 + } } ] } diff --git a/agent/pkg/oas/test_artifacts/params.har.spec.json b/agent/pkg/oas/test_artifacts/params.har.spec.json index 28cb200ba..c53a4f846 100644 --- a/agent/pkg/oas/test_artifacts/params.har.spec.json +++ b/agent/pkg/oas/test_artifacts/params.har.spec.json @@ -2,7 +2,7 @@ "openapi": "3.1.0", "info": { "title": "https://httpbin.org", - "description": "Mizu observed 9 entries (0 failed), at 0.222 hits/s, average response time is 0.363 seconds", + "description": "Mizu observed 13 entries (0 failed), at 0.154 hits/s, average response time is 0.251 seconds", "version": "1.0" }, "servers": [ @@ -15,7 +15,7 @@ "get": { "summary": "/appears-once", "description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.630 seconds", - "operationId": "ebf78fe8-6ebe-40bb-ad88-eab0dce05e91", + "operationId": "8dfc5a75-5f9b-4b57-ad88-77154a016201", "responses": { "200": { "description": "Successful call with status 200", @@ -26,15 +26,6 @@ } } }, - "x-last-seen-ts": 1567750580.0471218, - "x-counters-total": { - "entries": 1, - "failures": 0, - "firstSeen": 1567750580.0471218, - "lastSeen": 1567750580.0471218, - "sumRT": 0.63, - "sumDuration": 0 - }, "x-counters-per-source": { "": { "entries": 1, @@ -44,6 +35,15 @@ "sumRT": 0.63, "sumDuration": 0 } + }, + "x-last-seen-ts": 1567750580.0471218, + "x-counters-total": { + "entries": 1, + "failures": 0, + "firstSeen": 1567750580.0471218, + "lastSeen": 1567750580.0471218, + "sumRT": 0.63, + "sumDuration": 0 } } }, @@ -51,7 +51,7 @@ "get": { "summary": "/appears-twice", "description": "Mizu observed 2 entries (0 failed), at 0.500 hits/s, average response time is 0.630 seconds", - "operationId": "67e6640a-8cb2-4e31-ae4d-b066b397ee93", + "operationId": "844ae464-fcee-4bd7-97cf-aaa096196c02", "responses": { "200": { "description": "Successful call with status 200", @@ -62,15 +62,6 @@ } } }, - "x-last-seen-ts": 1567750581.7471218, - "x-counters-total": { - "entries": 2, - "failures": 0, - "firstSeen": 1567750580.7471218, - "lastSeen": 1567750581.7471218, - "sumRT": 1.26, - "sumDuration": 1 - }, "x-counters-per-source": { "": { "entries": 2, @@ -80,6 +71,100 @@ "sumRT": 1.26, "sumDuration": 1 } + }, + "x-last-seen-ts": 1567750581.7471218, + "x-counters-total": { + "entries": 2, + "failures": 0, + "firstSeen": 1567750580.7471218, + "lastSeen": 1567750581.7471218, + "sumRT": 1.26, + "sumDuration": 1 + } + } + }, + "/body-optional": { + "post": { + "summary": "/body-optional", + "description": "Mizu observed 3 entries (0 failed), at 0.000 hits/s, average response time is 0.001 seconds", + "operationId": "6e78e253-1f15-4ecd-9147-ba407c6fbeac", + "responses": { + "200": { + "description": "Successful call with status 200", + "content": { + "": {} + } + } + }, + "x-last-seen-ts": 1567750581.757122, + "x-counters-total": { + "entries": 3, + "failures": 0, + "firstSeen": 1567750581.7471218, + "lastSeen": 1567750581.757122, + "sumRT": 0.003, + "sumDuration": 0 + }, + "x-counters-per-source": { + "": { + "entries": 3, + "failures": 0, + "firstSeen": 1567750581.7471218, + "lastSeen": 1567750581.757122, + "sumRT": 0.003, + "sumDuration": 0 + } + }, + "requestBody": { + "description": "Generic request body", + "content": { + "application/json": { + "example": "{\"key\", \"val\"}" + } + } + } + } + }, + "/body-required": { + "post": { + "summary": "/body-required", + "description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.001 seconds", + "operationId": "1eefebc8-28c0-43d8-877f-4c5f67ff479d", + "responses": { + "200": { + "description": "Successful call with status 200", + "content": { + "": {} + } + } + }, + "x-last-seen-ts": 1567750581.757122, + "x-counters-total": { + "entries": 1, + "failures": 0, + "firstSeen": 1567750581.757122, + "lastSeen": 1567750581.757122, + "sumRT": 0.001, + "sumDuration": 0 + }, + "x-counters-per-source": { + "": { + "entries": 1, + "failures": 0, + "firstSeen": 1567750581.757122, + "lastSeen": 1567750581.757122, + "sumRT": 0.001, + "sumDuration": 0 + } + }, + "requestBody": { + "description": "Generic request body", + "content": { + "": { + "example": "body exists" + } + }, + "required": true } } }, @@ -87,7 +172,7 @@ "post": { "summary": "/form-multipart", "description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.001 seconds", - "operationId": "a8e0380e-3ade-4150-af6b-9edb7f24d9dc", + "operationId": "fc1eb6a3-3d55-4b4a-bfd0-c2ae85d590d5", "responses": { "200": { "description": "Successful call with status 200", @@ -98,14 +183,6 @@ } } }, - "x-counters-total": { - "entries": 1, - "failures": 0, - "firstSeen": 1567750582.7471218, - "lastSeen": 1567750582.7471218, - "sumRT": 0.001, - "sumDuration": 0 - }, "x-counters-per-source": { "": { "entries": 1, @@ -117,6 +194,14 @@ } }, "x-last-seen-ts": 1567750582.7471218, + "x-counters-total": { + "entries": 1, + "failures": 0, + "firstSeen": 1567750582.7471218, + "lastSeen": 1567750582.7471218, + "sumRT": 0.001, + "sumDuration": 0 + }, "requestBody": { "description": "Generic request body", "content": { @@ -154,7 +239,7 @@ "post": { "summary": "/form-urlencoded", "description": "Mizu observed 2 entries (0 failed), at 0.500 hits/s, average response time is 0.001 seconds", - "operationId": "dd251f61-2636-4c38-ad9d-d4b654464eba", + "operationId": "b416c98b-4ba8-4739-bd2a-6c3e31478bc9", "responses": { "200": { "description": "Successful call with status 200", @@ -163,7 +248,6 @@ } } }, - "x-last-seen-ts": 1567750581.7471218, "x-counters-total": { "entries": 2, "failures": 0, @@ -182,6 +266,7 @@ "sumDuration": 1 } }, + "x-last-seen-ts": 1567750581.7471218, "requestBody": { "description": "Generic request body", "content": { @@ -232,7 +317,7 @@ "get": { "summary": "/{Id}", "description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.630 seconds", - "operationId": "095b3932-c824-4054-a6da-bc872f279743", + "operationId": "d8b4de17-4c0e-401c-891b-36a7cee390bf", "responses": { "200": { "description": "Successful call with status 200", @@ -287,7 +372,7 @@ "get": { "summary": "/{Id}/sub1", "description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.111 seconds", - "operationId": "6f168b6d-9b67-490e-9895-903b078de4c5", + "operationId": "edacc275-1761-4011-af9b-3a3ed7c3d2b8", "responses": { "200": { "description": "Successful call with status 200", @@ -296,7 +381,6 @@ } } }, - "x-last-seen-ts": 1567750483.864529, "x-counters-total": { "entries": 1, "failures": 0, @@ -314,7 +398,8 @@ "sumRT": 0.111, "sumDuration": 0 } - } + }, + "x-last-seen-ts": 1567750483.864529 }, "parameters": [ { @@ -340,7 +425,7 @@ "get": { "summary": "/{Id}/sub2", "description": "Mizu observed 1 entries (0 failed), at 0.000 hits/s, average response time is 0.630 seconds", - "operationId": "d1e7900f-01dc-4d79-912e-5ca79ecd73e3", + "operationId": "61702da5-e4e7-4d95-8071-a6208f3d19d4", "responses": { "200": { "description": "Successful call with status 200", @@ -351,6 +436,15 @@ } } }, + "x-last-seen-ts": 1567750578.7471218, + "x-counters-total": { + "entries": 1, + "failures": 0, + "firstSeen": 1567750578.7471218, + "lastSeen": 1567750578.7471218, + "sumRT": 0.63, + "sumDuration": 0 + }, "x-counters-per-source": { "": { "entries": 1, @@ -360,15 +454,6 @@ "sumRT": 0.63, "sumDuration": 0 } - }, - "x-last-seen-ts": 1567750578.7471218, - "x-counters-total": { - "entries": 1, - "failures": 0, - "firstSeen": 1567750578.7471218, - "lastSeen": 1567750578.7471218, - "sumRT": 0.63, - "sumDuration": 0 } }, "parameters": [ @@ -392,22 +477,22 @@ ] } }, - "x-counters-total": { - "entries": 9, - "failures": 0, - "firstSeen": 1567750483.864529, - "lastSeen": 1567750582.7471218, - "sumRT": 3.2639999999999993, - "sumDuration": 2 - }, "x-counters-per-source": { "": { - "entries": 9, + "entries": 13, "failures": 0, "firstSeen": 1567750483.864529, "lastSeen": 1567750582.7471218, - "sumRT": 3.2639999999999993, + "sumRT": 3.268, "sumDuration": 2 } + }, + "x-counters-total": { + "entries": 13, + "failures": 0, + "firstSeen": 1567750483.864529, + "lastSeen": 1567750582.7471218, + "sumRT": 3.268, + "sumDuration": 2 } } \ No newline at end of file