diff --git a/js/modules/k6/html/element.go b/js/modules/k6/html/element.go
index e115aa8e98e..96770512a7c 100644
--- a/js/modules/k6/html/element.go
+++ b/js/modules/k6/html/element.go
@@ -25,10 +25,10 @@ type Element struct {
}
type Attribute struct {
- OwnerElement *Element
- Name string
+ OwnerElement *Element `json:"owner_element"`
+ Name string `json:"name"`
nsPrefix string
- Value string
+ Value string `json:"value"`
}
func (e Element) attrAsString(name string) string {
diff --git a/js/modules/k6/html/html.go b/js/modules/k6/html/html.go
index 980bd3232ec..d71f283e4b3 100644
--- a/js/modules/k6/html/html.go
+++ b/js/modules/k6/html/html.go
@@ -49,7 +49,7 @@ func (HTML) ParseHTML(ctx context.Context, src string) (Selection, error) {
type Selection struct {
rt *goja.Runtime
sel *goquery.Selection
- URL string
+ URL string `json:"url"`
}
func (s Selection) emptySelection() Selection {
diff --git a/js/modules/k6/http/http_request.go b/js/modules/k6/http/http_request.go
index 51855df6d86..ab703901311 100644
--- a/js/modules/k6/http/http_request.go
+++ b/js/modules/k6/http/http_request.go
@@ -51,11 +51,11 @@ import (
)
type HTTPRequest struct {
- Method string
- URL string
- Headers map[string][]string
- Body string
- Cookies map[string][]*HTTPRequestCookie
+ Method string `json:"method"`
+ URL string `json:"url"`
+ Headers map[string][]string `json:"headers"`
+ Body string `json:"body"`
+ Cookies map[string][]*HTTPRequestCookie `json:"cookies"`
}
func (h *HTTP) Get(ctx context.Context, url goja.Value, args ...goja.Value) (*HTTPResponse, error) {
diff --git a/js/modules/k6/http/response.go b/js/modules/k6/http/response.go
index 9c0344e264f..bb8a518a678 100644
--- a/js/modules/k6/http/response.go
+++ b/js/modules/k6/http/response.go
@@ -26,43 +26,45 @@ import (
"encoding/json"
"errors"
"fmt"
- "github.com/tidwall/gjson"
"net/url"
"strings"
+ "github.com/tidwall/gjson"
+
"github.com/dop251/goja"
"github.com/loadimpact/k6/js/common"
"github.com/loadimpact/k6/js/modules/k6/html"
"github.com/loadimpact/k6/lib/netext"
)
-type OCSP struct {
- ProducedAt, ThisUpdate, NextUpdate, RevokedAt int64
- RevocationReason string
- Status string
-}
-
type HTTPResponseTimings struct {
- Duration, Blocked, LookingUp, Connecting, TLSHandshaking, Sending, Waiting, Receiving float64
+ Duration float64 `json:"duration"`
+ Blocked float64 `json:"blocked"`
+ LookingUp float64 `json:"looking_up"`
+ Connecting float64 `json:"connecting"`
+ TLSHandshaking float64 `json:"tls_handshaking"`
+ Sending float64 `json:"sending"`
+ Waiting float64 `json:"waiting"`
+ Receiving float64 `json:"receiving"`
}
type HTTPResponse struct {
ctx context.Context
- RemoteIP string
- RemotePort int
- URL string
- Status int
- Proto string
- Headers map[string]string
- Cookies map[string][]*HTTPCookie
- Body interface{}
- Timings HTTPResponseTimings
- TLSVersion string
- TLSCipherSuite string
- OCSP netext.OCSP `js:"ocsp"`
- Error string
- Request HTTPRequest
+ RemoteIP string `json:"remote_ip"`
+ RemotePort int `json:"remote_port"`
+ URL string `json:"url"`
+ Status int `json:"status"`
+ Proto string `json:"proto"`
+ Headers map[string]string `json:"headers"`
+ Cookies map[string][]*HTTPCookie `json:"cookies"`
+ Body interface{} `json:"body"`
+ Timings HTTPResponseTimings `json:"timings"`
+ TLSVersion string `json:"tls_version"`
+ TLSCipherSuite string `json:"tls_cipher_suite"`
+ OCSP netext.OCSP `js:"ocsp" json:"ocsp"`
+ Error string `json:"error"`
+ Request HTTPRequest `json:"request"`
cachedJSON goja.Value
validatedJSON bool
diff --git a/js/modules/k6/marshalling_test.go b/js/modules/k6/marshalling_test.go
new file mode 100644
index 00000000000..cc66f13c54d
--- /dev/null
+++ b/js/modules/k6/marshalling_test.go
@@ -0,0 +1,146 @@
+/*
+ *
+ * k6 - a next-generation load testing tool
+ * Copyright (C) 2016 Load Impact
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package k6_test
+
+import (
+ "context"
+ "net"
+ "testing"
+ "time"
+
+ "github.com/loadimpact/k6/js"
+ "github.com/loadimpact/k6/lib"
+ "github.com/loadimpact/k6/lib/testutils"
+ "github.com/loadimpact/k6/lib/types"
+ "github.com/loadimpact/k6/stats"
+ "github.com/spf13/afero"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+ null "gopkg.in/guregu/null.v3"
+)
+
+func TestSetupDataMarshalling(t *testing.T) {
+ tb := testutils.NewHTTPMultiBin(t)
+ defer tb.Cleanup()
+
+ script := []byte(tb.Replacer.Replace(`
+ import http from "k6/http";
+ import html from "k6/html";
+ import ws from "k6/ws";
+ export let options = { setupTimeout: "10s" };
+
+
+ function make_jar() {
+ let jar = http.cookieJar();
+ jar.set("test", "something")
+ return jar;
+ }
+
+ export function setup() {
+ let res = http.get("http://test.loadimpact.com:HTTPBIN_PORT");
+ let html_selection = html.parseHTML(res.body);
+ let ws_res = ws.connect("ws://test.loadimpact.com:HTTPBIN_PORT/ws-echo", function(socket){
+ socket.on("open", function() {
+ socket.send("test")
+ })
+ socket.on("message", function (data){
+ if (!data=="test") {
+ throw new Error ("echo'd data doesn't match our message!");
+ }
+ socket.close()
+ });
+ });
+
+ return {
+ http_response: res,
+ html_selection: html_selection,
+ html_element: html_selection.find('html'),
+ html_attribute: html_selection.find('html').children('body').get(0).attributes(),
+ jar: make_jar(),
+ ws_res: ws_res,
+ };
+ }
+
+ function get_non_function_properties(object) {
+ return Object.keys(object).filter(element =>
+ typeof(object[element]) !== "function");
+ }
+
+ function arrays_are_equal(first, second) {
+ if (first.length != second.length) {
+ return false
+ }
+ return first.every(element => second.includes(element))
+ }
+
+ function diff_object_properties(name, first, second) {
+ let first_properties = get_non_function_properties(first).sort();
+ let second_properties = get_non_function_properties(second).sort();
+ if (!(arrays_are_equal(first_properties, second_properties))) {
+ console.error("for " + name + ":\n" +
+ "first_properties : " + JSON.stringify(first_properties) + "\n" +
+ "second_properties: " + JSON.stringify(second_properties) + "\n" +
+ "are not the same");
+ throw new Error("not matching " + name);
+ }
+ first_properties.
+ filter(element => typeof(first[element]) === "object").
+ forEach(function(element) {
+ diff_object_properties(name+"."+element,
+ first[element],
+ second[element]);
+ });
+ }
+
+ export default function (data) {
+ let first_properties = get_non_function_properties(data).sort();
+ diff_object_properties("setupdata", data, setup());
+ }
+ `))
+
+ runner, err := js.New(
+ &lib.SourceData{Filename: "/script.js", Data: script},
+ afero.NewMemMapFs(),
+ lib.RuntimeOptions{Env: map[string]string{"setupTimeout": "10s"}},
+ )
+
+ runner.SetOptions(lib.Options{
+ SetupTimeout: types.NullDurationFrom(1 * time.Second),
+ MaxRedirects: null.IntFrom(10),
+ Throw: null.BoolFrom(true),
+ Hosts: map[string]net.IP{
+ "test.loadimpact.com": net.ParseIP("127.0.0.1"),
+ },
+ })
+
+ require.NoError(t, err)
+
+ samples := make(chan stats.SampleContainer, 100)
+
+ if !assert.NoError(t, runner.Setup(context.Background(), samples)) {
+ return
+ }
+ vu, err := runner.NewVU(samples)
+ if assert.NoError(t, err) {
+ err := vu.RunOnce(context.Background())
+ assert.NoError(t, err)
+ }
+}
diff --git a/js/modules/k6/ws/ws.go b/js/modules/k6/ws/ws.go
index 5e698c2bca6..52178d7ab8d 100644
--- a/js/modules/k6/ws/ws.go
+++ b/js/modules/k6/ws/ws.go
@@ -63,11 +63,11 @@ type Socket struct {
}
type WSHTTPResponse struct {
- URL string
- Status int
- Headers map[string]string
- Body string
- Error string
+ URL string `json:"url"`
+ Status int `json:"status"`
+ Headers map[string]string `json:"headers"`
+ Body string `json:"body"`
+ Error string `json:"error"`
}
const writeWait = 10 * time.Second
diff --git a/lib/netext/tls.go b/lib/netext/tls.go
index 813ec3ccfc3..75584ee1419 100644
--- a/lib/netext/tls.go
+++ b/lib/netext/tls.go
@@ -33,9 +33,12 @@ type TLSInfo struct {
CipherSuite string
}
type OCSP struct {
- ProducedAt, ThisUpdate, NextUpdate, RevokedAt int64
- RevocationReason string
- Status string
+ ProducedAt int64 `json:"produced_at"`
+ ThisUpdate int64 `json:"this_update"`
+ NextUpdate int64 `json:"next_update"`
+ RevokedAt int64 `json:"revoked_at"`
+ RevocationReason string `json:"revocation_reason"`
+ Status string `json:"status"`
}
func ParseTLSConnState(tlsState *tls.ConnectionState) (TLSInfo, OCSP) {