From 5a71d0ddd08b8ceecc60084b05033b6057cc1250 Mon Sep 17 00:00:00 2001 From: "Marcelo E. Magallon" Date: Wed, 30 Aug 2023 16:48:28 -0600 Subject: [PATCH] Fix: use double quotes with JS-escaped strings Signed-off-by: Marcelo E. Magallon --- internal/prober/multihttp/script.go | 67 ++++++++++++------------ internal/prober/multihttp/script_test.go | 56 ++++++++++---------- 2 files changed, 61 insertions(+), 62 deletions(-) diff --git a/internal/prober/multihttp/script.go b/internal/prober/multihttp/script.go index a3549ce0..90834ff5 100644 --- a/internal/prober/multihttp/script.go +++ b/internal/prober/multihttp/script.go @@ -72,18 +72,18 @@ func buildHeaders(headers []*sm.HttpHeader, body *sm.HttpRequestBody) string { if body != nil { if len(body.ContentType) > 0 { - buf.WriteString(`'Content-Type':'`) + buf.WriteString(`'Content-Type':"`) buf.WriteString(template.JSEscapeString(body.ContentType)) - buf.WriteRune('\'') + buf.WriteRune('"') comma = "," } if len(body.ContentEncoding) > 0 { buf.WriteString(comma) - buf.WriteString(`'Content-Encoding':'`) + buf.WriteString(`'Content-Encoding':"`) buf.WriteString(template.JSEscapeString(body.ContentEncoding)) - buf.WriteRune('\'') + buf.WriteRune('"') comma = "," } } @@ -91,11 +91,11 @@ func buildHeaders(headers []*sm.HttpHeader, body *sm.HttpRequestBody) string { for _, header := range headers { buf.WriteString(comma) - buf.WriteRune('\'') + buf.WriteRune('"') buf.WriteString(template.JSEscapeString(header.Name)) - buf.WriteString(`':'`) + buf.WriteString(`":"`) buf.WriteString(template.JSEscapeString(header.Value)) - buf.WriteRune('\'') + buf.WriteRune('"') comma = "," } @@ -128,10 +128,9 @@ func (c assertionCondition) Name(w *strings.Builder, subject, value string) { w.WriteString(`ends with`) } - w.WriteRune(' ') - w.WriteRune('"') + w.WriteString(` \"`) w.WriteString(template.JSEscapeString(value)) - w.WriteRune('"') + w.WriteString(`\"`) } func (c assertionCondition) Render(w *strings.Builder, subject, value string) { @@ -142,27 +141,27 @@ func (c assertionCondition) Render(w *strings.Builder, subject, value string) { case sm.MultiHttpEntryAssertionConditionVariant_CONTAINS, sm.MultiHttpEntryAssertionConditionVariant_DEFAULT_CONDITION: w.WriteString(subject) - w.WriteString(`.includes('`) + w.WriteString(`.includes("`) w.WriteString(template.JSEscapeString(value)) - w.WriteString(`')`) + w.WriteString(`")`) case sm.MultiHttpEntryAssertionConditionVariant_EQUALS: w.WriteString(subject) - w.WriteString(` === '`) + w.WriteString(` === "`) w.WriteString(template.JSEscapeString(value)) - w.WriteString(`'`) + w.WriteString(`"`) case sm.MultiHttpEntryAssertionConditionVariant_STARTS_WITH: w.WriteString(subject) - w.WriteString(`.startsWith('`) + w.WriteString(`.startsWith("`) w.WriteString(template.JSEscapeString(value)) - w.WriteString(`')`) + w.WriteString(`")`) case sm.MultiHttpEntryAssertionConditionVariant_ENDS_WITH: w.WriteString(subject) - w.WriteString(`.endsWith('`) + w.WriteString(`.endsWith("`) w.WriteString(template.JSEscapeString(value)) - w.WriteString(`')`) + w.WriteString(`")`) } } @@ -173,7 +172,7 @@ func (c assertionCondition) Render(w *strings.Builder, subject, value string) { func buildChecks(url, method string, assertion *sm.MultiHttpEntryAssertion) string { var b strings.Builder - b.WriteString(`check(response, { '`) + b.WriteString(`check(response, { "`) switch assertion.Type { case sm.MultiHttpEntryAssertionType_TEXT: @@ -182,12 +181,12 @@ func buildChecks(url, method string, assertion *sm.MultiHttpEntryAssertion) stri switch assertion.Subject { case sm.MultiHttpEntryAssertionSubjectVariant_RESPONSE_BODY, sm.MultiHttpEntryAssertionSubjectVariant_DEFAULT_SUBJECT: cond.Name(&b, "body", assertion.Value) - b.WriteString(`': response => `) + b.WriteString(`": response => `) cond.Render(&b, "response.body", assertion.Value) case sm.MultiHttpEntryAssertionSubjectVariant_RESPONSE_HEADERS: cond.Name(&b, "header", assertion.Value) - b.WriteString(`': response => { `) + b.WriteString(`": response => { `) b.WriteString(`const values = Object.entries(response.headers).map(header => header[0].toLowerCase() + ': ' + header[1]); `) b.WriteString(`return !!values.find(value => `) cond.Render(&b, "value", assertion.Value) @@ -195,50 +194,50 @@ func buildChecks(url, method string, assertion *sm.MultiHttpEntryAssertion) stri case sm.MultiHttpEntryAssertionSubjectVariant_HTTP_STATUS_CODE: cond.Name(&b, "status code", assertion.Value) - b.WriteString(`': response => `) + b.WriteString(`": response => `) cond.Render(&b, `response.status.toString()`, assertion.Value) } case sm.MultiHttpEntryAssertionType_JSON_PATH_VALUE: cond := assertionCondition(assertion.Condition) cond.Name(&b, assertion.Expression, assertion.Value) - b.WriteString(`': response => jsonpath.query(response.json(), '`) + b.WriteString(`": response => jsonpath.query(response.json(), "`) b.WriteString(template.JSEscapeString(assertion.Expression)) - b.WriteString(`').some(values => `) + b.WriteString(`").some(values => `) cond.Render(&b, `values`, assertion.Value) b.WriteString(`)`) case sm.MultiHttpEntryAssertionType_JSON_PATH_ASSERTION: - b.WriteString(assertion.Expression) - b.WriteString(` exists': response => jsonpath.query(response.json(), '`) - b.WriteString(assertion.Expression) - b.WriteString(`').length > 0`) + b.WriteString(template.JSEscapeString(assertion.Expression)) + b.WriteString(` exists": response => jsonpath.query(response.json(), "`) + b.WriteString(template.JSEscapeString(assertion.Expression)) + b.WriteString(`").length > 0`) case sm.MultiHttpEntryAssertionType_REGEX_ASSERTION: switch assertion.Subject { case sm.MultiHttpEntryAssertionSubjectVariant_RESPONSE_BODY, sm.MultiHttpEntryAssertionSubjectVariant_DEFAULT_SUBJECT: b.WriteString(`body matches /`) b.WriteString(template.JSEscapeString(assertion.Expression)) - b.WriteString(`/': response => { const expr = new RegExp('`) + b.WriteString(`/": response => { const expr = new RegExp("`) b.WriteString(template.JSEscapeString(assertion.Expression)) - b.WriteString(`'); `) + b.WriteString(`"); `) b.WriteString(`return expr.test(response.body); }`) case sm.MultiHttpEntryAssertionSubjectVariant_RESPONSE_HEADERS: b.WriteString(`headers matches /`) b.WriteString(template.JSEscapeString(assertion.Expression)) - b.WriteString(`/': response => { const expr = new RegExp('`) + b.WriteString(`/": response => { const expr = new RegExp("`) b.WriteString(template.JSEscapeString(assertion.Expression)) - b.WriteString(`'); `) + b.WriteString(`"); `) b.WriteString(`const values = Object.entries(response.headers).map(header => header[0].toLowerCase() + ': ' + header[1]); `) b.WriteString(`return !!values.find(value => expr.test(value)); }`) case sm.MultiHttpEntryAssertionSubjectVariant_HTTP_STATUS_CODE: b.WriteString(`status matches /`) b.WriteString(template.JSEscapeString(assertion.Expression)) - b.WriteString(`/': response => { const expr = new RegExp('`) + b.WriteString(`/": response => { const expr = new RegExp("`) b.WriteString(template.JSEscapeString(assertion.Expression)) - b.WriteString(`'); `) + b.WriteString(`"); `) b.WriteString(`return expr.test(response.status.toString()); }`) } } diff --git a/internal/prober/multihttp/script_test.go b/internal/prober/multihttp/script_test.go index e5226397..c2129a95 100644 --- a/internal/prober/multihttp/script_test.go +++ b/internal/prober/multihttp/script_test.go @@ -86,7 +86,7 @@ func TestBuildHeaders(t *testing.T) { }, }, }, - expected: `{'Content-Type':'application/json'}`, + expected: `{"Content-Type":"application/json"}`, }, "two headers": { input: input{ @@ -101,7 +101,7 @@ func TestBuildHeaders(t *testing.T) { }, }, }, - expected: `{'Content-Type':'application/json','Accept':'text/html'}`, + expected: `{"Content-Type":"application/json","Accept":"text/html"}`, }, "blank value": { input: input{ @@ -112,7 +112,7 @@ func TestBuildHeaders(t *testing.T) { }, }, }, - expected: `{'Content-Type':''}`, + expected: `{"Content-Type":""}`, }, "body-content-type+content-encoding": { input: input{ @@ -122,7 +122,7 @@ func TestBuildHeaders(t *testing.T) { Payload: []byte("test"), }, }, - expected: `{'Content-Type':'text/plain','Content-Encoding':'none'}`, + expected: `{'Content-Type':"text/plain",'Content-Encoding':"none"}`, }, "body-content-type": { input: input{ @@ -131,7 +131,7 @@ func TestBuildHeaders(t *testing.T) { Payload: []byte("test"), }, }, - expected: `{'Content-Type':'text/plain'}`, + expected: `{'Content-Type':"text/plain"}`, }, "body-content-encoding": { input: input{ @@ -140,7 +140,7 @@ func TestBuildHeaders(t *testing.T) { Payload: []byte("test"), }, }, - expected: `{'Content-Encoding':'none'}`, + expected: `{'Content-Encoding':"none"}`, }, "body-content-type+content-encoding+headers": { input: input{ @@ -156,7 +156,7 @@ func TestBuildHeaders(t *testing.T) { }, }, }, - expected: `{'Content-Type':'text/plain','Content-Encoding':'none','X-Some-Header':'some value'}`, + expected: `{'Content-Type':"text/plain",'Content-Encoding':"none","X-Some-Header":"some value"}`, }, "body-content-type+headers": { input: input{ @@ -171,7 +171,7 @@ func TestBuildHeaders(t *testing.T) { }, }, }, - expected: `{'Content-Type':'text/plain','X-Some-Header':'some value'}`, + expected: `{'Content-Type':"text/plain","X-Some-Header":"some value"}`, }, "body-content-encoding+headers": { input: input{ @@ -186,7 +186,7 @@ func TestBuildHeaders(t *testing.T) { }, }, }, - expected: `{'Content-Encoding':'none','X-Some-Header':'some value'}`, + expected: `{'Content-Encoding':"none","X-Some-Header":"some value"}`, }, "empty": { input: input{ @@ -209,7 +209,7 @@ func TestBuildHeaders(t *testing.T) { }, }, }, - expected: `{'Content-Type':'text/plain','Content-Encoding':'none','Content-Type':'application/json'}`, + expected: `{'Content-Type':"text/plain",'Content-Encoding':"none","Content-Type":"application/json"}`, }, } @@ -263,31 +263,31 @@ func TestAssertionConditionName(t *testing.T) { condition: sm.MultiHttpEntryAssertionConditionVariant_NOT_CONTAINS, subject: "subject", value: "value", - expected: "subject does not contain \"value\"", + expected: `subject does not contain \"value\"`, }, "TestAssertionConditionNameContains": { condition: sm.MultiHttpEntryAssertionConditionVariant_CONTAINS, subject: "subject", value: "value", - expected: "subject contains \"value\"", + expected: `subject contains \"value\"`, }, "TestAssertionConditionNameEquals": { condition: sm.MultiHttpEntryAssertionConditionVariant_EQUALS, subject: "subject", value: "value", - expected: "subject equals \"value\"", + expected: `subject equals \"value\"`, }, "TestAssertionConditionNameStartsWith": { condition: sm.MultiHttpEntryAssertionConditionVariant_STARTS_WITH, subject: "subject", value: "value", - expected: "subject starts with \"value\"", + expected: `subject starts with \"value\"`, }, "TestAssertionConditionNameEndsWith": { condition: sm.MultiHttpEntryAssertionConditionVariant_ENDS_WITH, subject: "subject", value: "value", - expected: "subject ends with \"value\"", + expected: `subject ends with \"value\"`, }, } @@ -312,31 +312,31 @@ func TestAssertionConditionRender(t *testing.T) { condition: sm.MultiHttpEntryAssertionConditionVariant_NOT_CONTAINS, subject: "subject", value: "val'ue", - expected: "!subject.includes('val\\'ue')", + expected: `!subject.includes("val\'ue")`, }, "TestAssertionConditionRenderContains": { condition: sm.MultiHttpEntryAssertionConditionVariant_CONTAINS, subject: "subject", value: "val'ue", - expected: "subject.includes('val\\'ue')", + expected: `subject.includes("val\'ue")`, }, "TestAssertionConditionRenderEquals": { condition: sm.MultiHttpEntryAssertionConditionVariant_EQUALS, subject: "subject", value: "val'ue", - expected: "subject === 'val\\'ue'", + expected: `subject === "val\'ue"`, }, "TestAssertionConditionRenderStartsWith": { condition: sm.MultiHttpEntryAssertionConditionVariant_STARTS_WITH, subject: "subject", value: "val'ue", - expected: "subject.startsWith('val\\'ue')", + expected: `subject.startsWith("val\'ue")`, }, "TestAssertionConditionRenderEndsWith": { condition: sm.MultiHttpEntryAssertionConditionVariant_ENDS_WITH, subject: "subject", value: "val'ue", - expected: "subject.endsWith('val\\'ue')", + expected: `subject.endsWith("val\'ue")`, }, } @@ -366,7 +366,7 @@ func TestBuildChecks(t *testing.T) { Subject: sm.MultiHttpEntryAssertionSubjectVariant_RESPONSE_BODY, Value: "value", }, - expected: `check(response, { 'body contains "value"': response => response.body.includes('value') }, {"url": "http://example.com", "method": "GET"});`, + expected: `check(response, { "body contains \"value\"": response => response.body.includes("value") }, {"url": "http://example.com", "method": "GET"});`, }, "TestBuildChecksTextAssertionWithHeadersSubject": { url: "http://example.com", @@ -377,7 +377,7 @@ func TestBuildChecks(t *testing.T) { Subject: sm.MultiHttpEntryAssertionSubjectVariant_RESPONSE_HEADERS, Value: "value", }, - expected: `check(response, { 'header contains "value"': response => { const values = Object.entries(response.headers).map(header => header[0].toLowerCase() + ': ' + header[1]); return !!values.find(value => value.includes('value')); } }, {"url": "http://example.com", "method": "GET"});`, + expected: `check(response, { "header contains \"value\"": response => { const values = Object.entries(response.headers).map(header => header[0].toLowerCase() + ': ' + header[1]); return !!values.find(value => value.includes("value")); } }, {"url": "http://example.com", "method": "GET"});`, }, "TestBuildChecksTextAssertionWithStatusCodeSubject": { url: "http://example.com", @@ -388,7 +388,7 @@ func TestBuildChecks(t *testing.T) { Subject: sm.MultiHttpEntryAssertionSubjectVariant_HTTP_STATUS_CODE, Value: "value", }, - expected: `check(response, { 'status code contains "value"': response => response.status.toString().includes('value') }, {"url": "http://example.com", "method": "GET"});`, + expected: `check(response, { "status code contains \"value\"": response => response.status.toString().includes("value") }, {"url": "http://example.com", "method": "GET"});`, }, "TestBuildChecksJsonPathValueAssertionWithBodySubject": { url: "http://example.com", @@ -400,7 +400,7 @@ func TestBuildChecks(t *testing.T) { Expression: "/path/to/value", Value: "value", }, - expected: `check(response, { '/path/to/value contains "value"': response => jsonpath.query(response.json(), '/path/to/value').some(values => values.includes('value')) }, {"url": "http://example.com", "method": "GET"});`, + expected: `check(response, { "/path/to/value contains \"value\"": response => jsonpath.query(response.json(), "/path/to/value").some(values => values.includes("value")) }, {"url": "http://example.com", "method": "GET"});`, }, "TestBuildChecksJsonPathAssertionWithBodySubject": { url: "http://example.com", @@ -410,7 +410,7 @@ func TestBuildChecks(t *testing.T) { Subject: sm.MultiHttpEntryAssertionSubjectVariant_RESPONSE_BODY, Expression: "/path/to/value", }, - expected: `check(response, { '/path/to/value exists': response => jsonpath.query(response.json(), '/path/to/value').length > 0 }, {"url": "http://example.com", "method": "GET"});`, + expected: `check(response, { "/path/to/value exists": response => jsonpath.query(response.json(), "/path/to/value").length > 0 }, {"url": "http://example.com", "method": "GET"});`, }, "TestBuildChecksRegexAssertionWithBodySubject": { url: "http://example.com", @@ -420,7 +420,7 @@ func TestBuildChecks(t *testing.T) { Subject: sm.MultiHttpEntryAssertionSubjectVariant_RESPONSE_BODY, Expression: "regex", }, - expected: `check(response, { 'body matches /regex/': response => { const expr = new RegExp('regex'); return expr.test(response.body); } }, {"url": "http://example.com", "method": "GET"});`, + expected: `check(response, { "body matches /regex/": response => { const expr = new RegExp("regex"); return expr.test(response.body); } }, {"url": "http://example.com", "method": "GET"});`, }, "TestBuildChecksRegexAssertionWithHeadersSubject": { url: "http://example.com", @@ -430,7 +430,7 @@ func TestBuildChecks(t *testing.T) { Subject: sm.MultiHttpEntryAssertionSubjectVariant_RESPONSE_HEADERS, Expression: "regex", }, - expected: `check(response, { 'headers matches /regex/': response => { const expr = new RegExp('regex'); const values = Object.entries(response.headers).map(header => header[0].toLowerCase() + ': ' + header[1]); return !!values.find(value => expr.test(value)); } }, {"url": "http://example.com", "method": "GET"});`, + expected: `check(response, { "headers matches /regex/": response => { const expr = new RegExp("regex"); const values = Object.entries(response.headers).map(header => header[0].toLowerCase() + ': ' + header[1]); return !!values.find(value => expr.test(value)); } }, {"url": "http://example.com", "method": "GET"});`, }, "TestBuildChecksRegexAssertionWithStatusCodeSubject": { url: "http://example.com", @@ -440,7 +440,7 @@ func TestBuildChecks(t *testing.T) { Subject: sm.MultiHttpEntryAssertionSubjectVariant_HTTP_STATUS_CODE, Expression: "regex", }, - expected: `check(response, { 'status matches /regex/': response => { const expr = new RegExp('regex'); return expr.test(response.status.toString()); } }, {"url": "http://example.com", "method": "GET"});`, + expected: `check(response, { "status matches /regex/": response => { const expr = new RegExp("regex"); return expr.test(response.status.toString()); } }, {"url": "http://example.com", "method": "GET"});`, }, }