Skip to content

Commit

Permalink
Equalize k6 js objects' fields names returned by setup
Browse files Browse the repository at this point in the history
When goja bridges go objects it makes all Public fields to be case snake
as is the js standard. But because of lack of json tags when we marshall
and then unmarshall them due to them being returned by setup, the names
were becoming the go struct ones.
This was obviosly confusing and not intentional so now all objects that
are bridged by goja have json tags added to them to fix it.
  • Loading branch information
mstoykov committed Oct 11, 2018
1 parent bb6e975 commit b1d4f20
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 39 deletions.
6 changes: 3 additions & 3 deletions js/modules/k6/html/element.go
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion js/modules/k6/html/html.go
Expand Up @@ -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 {
Expand Down
10 changes: 5 additions & 5 deletions js/modules/k6/http/http_request.go
Expand Up @@ -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) {
Expand Down
46 changes: 24 additions & 22 deletions js/modules/k6/http/response.go
Expand Up @@ -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
Expand Down
146 changes: 146 additions & 0 deletions 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 <http://www.gnu.org/licenses/>.
*
*/

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)
}
}
10 changes: 5 additions & 5 deletions js/modules/k6/ws/ws.go
Expand Up @@ -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
Expand Down
9 changes: 6 additions & 3 deletions lib/netext/tls.go
Expand Up @@ -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) {
Expand Down

0 comments on commit b1d4f20

Please sign in to comment.