Skip to content

Commit

Permalink
Per VU module instance support for the http module
Browse files Browse the repository at this point in the history
part of #1858
  • Loading branch information
mstoykov committed Mar 2, 2021
1 parent 82cab8b commit 7e81f66
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 41 deletions.
13 changes: 12 additions & 1 deletion js/internal/modules/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,18 @@ var (
func Get(name string) interface{} {
mx.RLock()
defer mx.RUnlock()
return modules[name]
mod := modules[name]
if i, ok := mod.(HasModuleInstancePerVU); ok {
return i.NewModuleInstancePerVU()
}
return mod
}

// HasModuleInstancePerVU should be implemented by all native Golang modules that
// would require per-VU state. k6 will call their NewModuleInstancePerVU() methods
// every time a VU imports the module and use its result as the returned object.
type HasModuleInstancePerVU interface {
NewModuleInstancePerVU() interface{}
}

// Register the given mod as a JavaScript module, available
Expand Down
2 changes: 1 addition & 1 deletion js/modules/k6/http/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func TestHTTPFile(t *testing.T) {
assert.Equal(t, tc.expErr, fmt.Sprintf("%s", val["value"]))
}()
}
h := New()
h := new(GlobalHTTP).NewModuleInstancePerVU().(*HTTP)
ctx := common.WithRuntime(context.Background(), rt)
out := h.File(ctx, tc.input, tc.args...)
assert.Equal(t, tc.expected, out)
Expand Down
57 changes: 31 additions & 26 deletions js/modules/k6/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
)

func init() {
modules.Register("k6/http", New())
modules.Register("k6/http", new(GlobalHTTP))
}

const (
Expand All @@ -46,32 +46,14 @@ const (
// ErrJarForbiddenInInitContext is used when a cookie jar was made in the init context
var ErrJarForbiddenInInitContext = common.NewInitContextError("Making cookie jars in the init context is not supported")

//nolint: golint
type HTTP struct {
SSL_3_0 string `js:"SSL_3_0"`
TLS_1_0 string `js:"TLS_1_0"`
TLS_1_1 string `js:"TLS_1_1"`
TLS_1_2 string `js:"TLS_1_2"`
TLS_1_3 string `js:"TLS_1_3"`
OCSP_STATUS_GOOD string `js:"OCSP_STATUS_GOOD"`
OCSP_STATUS_REVOKED string `js:"OCSP_STATUS_REVOKED"`
OCSP_STATUS_SERVER_FAILED string `js:"OCSP_STATUS_SERVER_FAILED"`
OCSP_STATUS_UNKNOWN string `js:"OCSP_STATUS_UNKNOWN"`
OCSP_REASON_UNSPECIFIED string `js:"OCSP_REASON_UNSPECIFIED"`
OCSP_REASON_KEY_COMPROMISE string `js:"OCSP_REASON_KEY_COMPROMISE"`
OCSP_REASON_CA_COMPROMISE string `js:"OCSP_REASON_CA_COMPROMISE"`
OCSP_REASON_AFFILIATION_CHANGED string `js:"OCSP_REASON_AFFILIATION_CHANGED"`
OCSP_REASON_SUPERSEDED string `js:"OCSP_REASON_SUPERSEDED"`
OCSP_REASON_CESSATION_OF_OPERATION string `js:"OCSP_REASON_CESSATION_OF_OPERATION"`
OCSP_REASON_CERTIFICATE_HOLD string `js:"OCSP_REASON_CERTIFICATE_HOLD"`
OCSP_REASON_REMOVE_FROM_CRL string `js:"OCSP_REASON_REMOVE_FROM_CRL"`
OCSP_REASON_PRIVILEGE_WITHDRAWN string `js:"OCSP_REASON_PRIVILEGE_WITHDRAWN"`
OCSP_REASON_AA_COMPROMISE string `js:"OCSP_REASON_AA_COMPROMISE"`
}
// GlobalHTTP is a global HTTP module for a k6 instance/test run
type GlobalHTTP struct{}

var _ modules.HasModuleInstancePerVU = new(GlobalHTTP)

func New() *HTTP {
//TODO: move this as an anonymous struct somewhere...
return &HTTP{
// NewModuleInstancePerVU returns an HTTP instance for each VU
func (g *GlobalHTTP) NewModuleInstancePerVU() interface{} { // this here needs to return interface{}
return &HTTP{ // change the below fields to be not writable or not fields
SSL_3_0: netext.SSL_3_0,
TLS_1_0: netext.TLS_1_0,
TLS_1_1: netext.TLS_1_1,
Expand All @@ -94,6 +76,29 @@ func New() *HTTP {
}
}

//nolint: golint
type HTTP struct {
SSL_3_0 string `js:"SSL_3_0"`
TLS_1_0 string `js:"TLS_1_0"`
TLS_1_1 string `js:"TLS_1_1"`
TLS_1_2 string `js:"TLS_1_2"`
TLS_1_3 string `js:"TLS_1_3"`
OCSP_STATUS_GOOD string `js:"OCSP_STATUS_GOOD"`
OCSP_STATUS_REVOKED string `js:"OCSP_STATUS_REVOKED"`
OCSP_STATUS_SERVER_FAILED string `js:"OCSP_STATUS_SERVER_FAILED"`
OCSP_STATUS_UNKNOWN string `js:"OCSP_STATUS_UNKNOWN"`
OCSP_REASON_UNSPECIFIED string `js:"OCSP_REASON_UNSPECIFIED"`
OCSP_REASON_KEY_COMPROMISE string `js:"OCSP_REASON_KEY_COMPROMISE"`
OCSP_REASON_CA_COMPROMISE string `js:"OCSP_REASON_CA_COMPROMISE"`
OCSP_REASON_AFFILIATION_CHANGED string `js:"OCSP_REASON_AFFILIATION_CHANGED"`
OCSP_REASON_SUPERSEDED string `js:"OCSP_REASON_SUPERSEDED"`
OCSP_REASON_CESSATION_OF_OPERATION string `js:"OCSP_REASON_CESSATION_OF_OPERATION"`
OCSP_REASON_CERTIFICATE_HOLD string `js:"OCSP_REASON_CERTIFICATE_HOLD"`
OCSP_REASON_REMOVE_FROM_CRL string `js:"OCSP_REASON_REMOVE_FROM_CRL"`
OCSP_REASON_PRIVILEGE_WITHDRAWN string `js:"OCSP_REASON_PRIVILEGE_WITHDRAWN"`
OCSP_REASON_AA_COMPROMISE string `js:"OCSP_REASON_AA_COMPROMISE"`
}

func (*HTTP) XCookieJar(ctx *context.Context) *HTTPCookieJar {
return newCookieJar(ctx)
}
Expand Down
2 changes: 1 addition & 1 deletion js/modules/k6/http/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
func TestTagURL(t *testing.T) {
rt := goja.New()
rt.SetFieldNameMapper(common.FieldNameMapper{})
rt.Set("http", common.Bind(rt, New(), nil))
rt.Set("http", common.Bind(rt, new(GlobalHTTP).NewModuleInstancePerVU(), nil))

testdata := map[string]struct{ u, n string }{
`http://localhost/anything/`: {"http://localhost/anything/", "http://localhost/anything/"},
Expand Down
6 changes: 3 additions & 3 deletions js/modules/k6/http/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func (h *HTTP) Request(ctx context.Context, method string, url goja.Value, args
if err != nil {
return nil, err
}
return responseFromHttpext(resp), nil
return h.responseFromHttpext(resp), nil
}

//TODO break this function up
Expand Down Expand Up @@ -377,7 +377,7 @@ func (h *HTTP) prepareBatchArray(
ParsedHTTPRequest: parsedReq,
Response: response,
}
results[i] = &Response{response}
results[i] = h.responseFromHttpext(response)
}

return batchReqs, results, nil
Expand All @@ -401,7 +401,7 @@ func (h *HTTP) prepareBatchObject(
ParsedHTTPRequest: parsedReq,
Response: response,
}
results[key] = &Response{response}
results[key] = h.responseFromHttpext(response)
i++
}

Expand Down
2 changes: 1 addition & 1 deletion js/modules/k6/http/request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func newRuntime(
ctx := new(context.Context)
*ctx = lib.WithState(tb.Context, state)
*ctx = common.WithRuntime(*ctx, rt)
rt.Set("http", common.Bind(rt, New(), ctx))
rt.Set("http", common.Bind(rt, new(GlobalHTTP).NewModuleInstancePerVU(), ctx))

return tb, state, samples, rt, ctx
}
Expand Down
12 changes: 6 additions & 6 deletions js/modules/k6/http/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ import (
// Response is a representation of an HTTP response to be returned to the goja VM
type Response struct {
*httpext.Response `js:"-"`
h *HTTP
}

func responseFromHttpext(resp *httpext.Response) *Response {
res := Response{resp}
return &res
func (h *HTTP) responseFromHttpext(resp *httpext.Response) *Response {
return &Response{Response: resp, h: h}
}

// JSON parses the body of a response as json and returns it to the goja VM
Expand Down Expand Up @@ -159,9 +159,9 @@ func (res *Response) SubmitForm(args ...goja.Value) (*Response, error) {
q.Add(k, v.String())
}
requestURL.RawQuery = q.Encode()
return New().Request(res.GetCtx(), requestMethod, rt.ToValue(requestURL.String()), goja.Null(), requestParams)
return res.h.Request(res.GetCtx(), requestMethod, rt.ToValue(requestURL.String()), goja.Null(), requestParams)
}
return New().Request(res.GetCtx(), requestMethod, rt.ToValue(requestURL.String()), rt.ToValue(values), requestParams)
return res.h.Request(res.GetCtx(), requestMethod, rt.ToValue(requestURL.String()), rt.ToValue(values), requestParams)
}

// ClickLink parses the body as an html, looks for a link and than makes a request as if the link was
Expand Down Expand Up @@ -202,5 +202,5 @@ func (res *Response) ClickLink(args ...goja.Value) (*Response, error) {
}
requestURL := responseURL.ResolveReference(hrefURL)

return New().Get(res.GetCtx(), rt.ToValue(requestURL.String()), requestParams)
return res.h.Get(res.GetCtx(), rt.ToValue(requestURL.String()), requestParams)
}
4 changes: 2 additions & 2 deletions js/modules/k6/http/response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,15 +413,15 @@ func BenchmarkResponseJson(b *testing.B) {
tc := tc
b.Run(fmt.Sprintf("Selector %s ", tc.selector), func(b *testing.B) {
for n := 0; n < b.N; n++ {
resp := responseFromHttpext(&httpext.Response{Body: jsonData})
resp := new(HTTP).responseFromHttpext(&httpext.Response{Body: jsonData})
resp.JSON(tc.selector)
}
})
}

b.Run("Without selector", func(b *testing.B) {
for n := 0; n < b.N; n++ {
resp := responseFromHttpext(&httpext.Response{Body: jsonData})
resp := new(HTTP).responseFromHttpext(&httpext.Response{Body: jsonData})
resp.JSON()
}
})
Expand Down

0 comments on commit 7e81f66

Please sign in to comment.