Skip to content

Commit

Permalink
Merge pull request #5 from szkiba/feature/modules
Browse files Browse the repository at this point in the history
Feature/modules
  • Loading branch information
szkiba authored Jun 12, 2023
2 parents 02afac7 + 80ad15f commit a5fdaa8
Show file tree
Hide file tree
Showing 28 changed files with 958 additions and 174 deletions.
1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ linters:
- gochecknoglobals
- lll
- wrapcheck
- gochecknoinits
# deprecated
- deadcode
- nosnakecase
Expand Down
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ In addition to the go standard library, the following third-party packages can b
- https://github.com/sirupsen/logrus
- https://github.com/stretchr/testify
- https://github.com/PuerkitoBio/goquery
- https://github.com/tidwall/gjson
- https://github.com/PaesslerAG/jsonpath
- https://github.com/santhosh-tekuri/jsonschema/v5
- https://github.com/brianvoe/gofakeit/v6


### Checks
Expand Down Expand Up @@ -281,6 +285,62 @@ func Default() error {
}
```

### JSON

The [gjson](https://github.com/tidwall/gjson) and [jsonpath](github.com/PaesslerAG/jsonpath) packages can be used to query JSON documents.

**gjson**
```go
package main

import (
"net/http"

"github.com/go-resty/resty/v2"
"github.com/stretchr/testify/require"
"github.com/tidwall/gjson"
)

func Default(require *require.Assertions) {
res, err := resty.New().R().Get("https://httpbin.test.k6.io/get")

require.NoError(err, "request success")
require.Equal(http.StatusOK, res.StatusCode(), "status code 200")

body := res.Body()

val := gjson.GetBytes(body, "headers.Host").Str

require.Equal("httpbin.test.k6.io", val, "headers.Host value OK")
}
```

**jsonpath**
```go
package main

import (
"net/http"

"github.com/PaesslerAG/jsonpath"
"github.com/go-resty/resty/v2"
"github.com/stretchr/testify/require"
)

func Default(require *require.Assertions) {
body := make(map[string]interface{})
res, err := resty.New().R().SetResult(&body).Get("https://httpbin.test.k6.io/get")

require.NoError(err, "request success")
require.Equal(http.StatusOK, res.StatusCode(), "status code 200")

val, err := jsonpath.Get("$.headers.Host", body)

require.NoError(err, "$.headers.Host no error")
require.Equal("httpbin.test.k6.io", val, "$.headers.Host value OK")
}
```

### Logging

The https://github.com/sirupsen/logrus package can be used for logging in the test script.
Expand Down
16 changes: 13 additions & 3 deletions g0/assert.go → g0/addon/assert.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
//
// SPDX-License-Identifier: MIT

package g0
package addon

import (
"errors"
Expand All @@ -18,11 +18,22 @@ import (
"go.k6.io/k6/metrics"
)

type TestingT interface {
assert.TestingT
require.TestingT

Check(string, bool)
}

type checker struct {
vu modules.VU
fail bool
}

func NewTestingT(vu modules.VU, fail bool) TestingT {
return &checker{vu: vu, fail: fail}
}

func (c *checker) Errorf(format string, args ...interface{}) {
state := c.vu.State()
if state == nil {
Expand Down Expand Up @@ -97,8 +108,7 @@ func (c *checker) FailNow() {
}

var (
_ assert.TestingT = (*checker)(nil)
_ require.TestingT = (*checker)(nil)
_ TestingT = (*checker)(nil)

errAssertionFailed = errors.New("assertion failed")
)
128 changes: 128 additions & 0 deletions g0/addon/transport.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
// SPDX-FileCopyrightText: 2023 Iván Szkiba
//
// SPDX-License-Identifier: MIT

package addon

import (
"bytes"
"io"
"net/http"
"strconv"
"strings"
"time"

"go.k6.io/k6/js/modules"
khttp "go.k6.io/k6/js/modules/k6/http"
"go.k6.io/k6/lib/netext/httpext"
)

type tripware struct {
vu modules.VU
}

var _ http.RoundTripper = (*tripware)(nil)

func NewTransport(vu modules.VU) http.RoundTripper {
return &tripware{vu: vu}
}

const (
httpTimeout = 60 * time.Second
protoFields = 2
)

func (t *tripware) toParsedRequest(req *http.Request) (*httpext.ParsedHTTPRequest, error) {
state := t.vu.State()
if state == nil {
return nil, khttp.ErrHTTPForbiddenInInitContext
}

u := req.URL.String()

url, err := httpext.NewURL(u, u)
if err != nil {
return nil, err
}

preq := &httpext.ParsedHTTPRequest{ // nolint:exhaustruct
URL: &url,
Req: req,
Timeout: httpTimeout,
Throw: state.Options.Throw.Bool,
Redirects: state.Options.MaxRedirects,
Cookies: make(map[string]*httpext.HTTPRequestCookie),
TagsAndMeta: t.vu.State().Tags.GetCurrentValues(),
}

if state.Options.DiscardResponseBodies.Bool {
preq.ResponseType = httpext.ResponseTypeNone
} else {
preq.ResponseType = httpext.ResponseTypeBinary
}

if req.Body != nil {
data, err := io.ReadAll(req.Body)
if err != nil {
return nil, err
}

preq.Body = bytes.NewBuffer(data)

req.Body.Close()
}

preq.Req.Header.Set("User-Agent", state.Options.UserAgent.String)

return preq, nil
}

func (t *tripware) toResponse(req *http.Request, eresp *httpext.Response) (*http.Response, error) {
resp := new(http.Response)

resp.Request = req

resp.Header = http.Header{}

for k, v := range eresp.Headers {
resp.Header.Set(k, v)
}

resp.Proto = eresp.Proto
fields := strings.SplitN(resp.Proto, "/", protoFields)

if major, err := strconv.Atoi(fields[0]); err == nil {
resp.ProtoMajor = major
}

if len(fields) > 0 {
if minor, err := strconv.Atoi(fields[1]); err == nil {
resp.ProtoMinor = minor
}
}

if eresp.Body != nil {
if data, ok := eresp.Body.([]byte); ok {
resp.Body = io.NopCloser(bytes.NewBuffer(data))
}
}

resp.Status = eresp.StatusText
resp.StatusCode = eresp.Status

return resp, nil
}

func (t *tripware) RoundTrip(req *http.Request) (*http.Response, error) {
preq, err := t.toParsedRequest(req)
if err != nil {
return nil, err
}

resp, err := httpext.MakeRequest(t.vu.Context(), t.vu.State(), preq)
if err != nil {
return nil, err
}

return t.toResponse(req, resp)
}
41 changes: 41 additions & 0 deletions g0/bootstrap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2023 Iván Szkiba
//
// SPDX-License-Identifier: MIT

package g0

import (
"github.com/szkiba/xk6-g0/internal/builtin/gjson"
"github.com/szkiba/xk6-g0/internal/builtin/gofakeit"
"github.com/szkiba/xk6-g0/internal/builtin/goquery"
"github.com/szkiba/xk6-g0/internal/builtin/jsonpath"
"github.com/szkiba/xk6-g0/internal/builtin/jsonschema"
"github.com/szkiba/xk6-g0/internal/builtin/logrus"
"github.com/szkiba/xk6-g0/internal/builtin/resty"
"github.com/szkiba/xk6-g0/internal/builtin/stdlib"
"github.com/szkiba/xk6-g0/internal/builtin/testify"
"go.k6.io/k6/js/modules"
)

func registerBuiltins() {
registerExports(stdlib.Exports)
registerExports(logrus.Exports)
registerExports(resty.Exports)
registerExports(testify.Exports)
registerExports(goquery.Exports)
registerExports(gjson.Exports)
registerExports(jsonpath.Exports)
registerExports(jsonschema.Exports)
registerExports(gofakeit.Exports)
}

func registerExtension() {
modules.Register("k6/x/g0", New())
}

func Bootstrap(addons ...ExportsFunc) {
registerBuiltins()
registerExports(addons...)
redirectStdin()
registerExtension()
}
2 changes: 1 addition & 1 deletion g0/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func isRunCommand(args []string) (bool, int) {
return true, scriptIndex
}

func RedirectStdin() {
func redirectStdin() {
isRun, scriptIndex := isRunCommand(os.Args)
if !isRun {
return
Expand Down
4 changes: 4 additions & 0 deletions g0/context.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
// SPDX-FileCopyrightText: 2023 Iván Szkiba
//
// SPDX-License-Identifier: MIT

package g0

import (
Expand Down
21 changes: 4 additions & 17 deletions g0/exports.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,14 @@ import (
"sync"

"github.com/imdario/mergo"
"github.com/szkiba/xk6-g0/internal/builtin/goquery"
"github.com/szkiba/xk6-g0/internal/builtin/logrus"
"github.com/szkiba/xk6-g0/internal/builtin/resty"
"github.com/szkiba/xk6-g0/internal/builtin/stdlib"
"github.com/szkiba/xk6-g0/internal/builtin/testify"
"github.com/traefik/yaegi/interp"
"go.k6.io/k6/js/modules"
)

type ExportsFunc func(modules.VU) interp.Exports

func RegisterExports(fn ExportsFunc) {
registry.register(fn)
func registerExports(fn ...ExportsFunc) {
registry.register(fn...)
}

type exportsRegistry struct {
Expand All @@ -30,11 +25,11 @@ type exportsRegistry struct {

var registry exportsRegistry

func (r *exportsRegistry) register(fn ExportsFunc) {
func (r *exportsRegistry) register(fn ...ExportsFunc) {
r.mu.Lock()
defer r.mu.Unlock()

r.exports = append(r.exports, fn)
r.exports = append(r.exports, fn...)
}

func (r *exportsRegistry) merge(vu modules.VU) (interp.Exports, error) { //nolint:varnamelen
Expand All @@ -51,11 +46,3 @@ func (r *exportsRegistry) merge(vu modules.VU) (interp.Exports, error) { //nolin

return symbols, nil
}

func init() {
RegisterExports(stdlib.Exports)
RegisterExports(logrus.Exports)
RegisterExports(resty.Exports)
RegisterExports(testify.Exports)
RegisterExports(goquery.Exports)
}
5 changes: 3 additions & 2 deletions g0/module.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package g0
import (
"os"

"github.com/szkiba/xk6-g0/g0/addon"
"github.com/szkiba/xk6-g0/internal/builtin/testify/assertions"
"github.com/szkiba/xk6-g0/internal/builtin/testify/requirements"
"github.com/traefik/yaegi/interp"
Expand All @@ -27,8 +28,8 @@ func (root *RootModule) NewModuleInstance(vu modules.VU) modules.Instance { // n
mod := &Module{ //nolint:exhaustruct
vu: vu,
yaegi: yaegi,
assert: assertions.New(&checker{fail: false, vu: vu}),
require: requirements.New(&checker{fail: true, vu: vu}),
assert: assertions.New(addon.NewTestingT(vu, false)),
require: requirements.New(addon.NewTestingT(vu, true)),
}

if err := mod.init(os.Getenv(envScript)); err != nil {
Expand Down
Loading

0 comments on commit a5fdaa8

Please sign in to comment.