Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add secrets field to define credential variables #414

Merged
merged 5 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ $(GOCREDITS): | $(BIN_DIR)
@$(GO) install github.com/Songmu/gocredits/cmd/[email protected]

GOLANGCI_LINT := $(BIN_DIR)/golangci-lint
GOLANGCI_LINT_VERSION := 1.52.2
GOLANGCI_LINT_VERSION := 1.57.2
GOLANGCI_LINT_OS_ARCH := $(shell echo golangci-lint-$(GOLANGCI_LINT_VERSION)-$(GOOS)-$(GOARCH))
GOLANGCI_LINT_GZIP := $(GOLANGCI_LINT_OS_ARCH).tar.gz
$(GOLANGCI_LINT): | $(BIN_DIR)
Expand Down
83 changes: 83 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,89 @@ steps:
text: '{{request.body.text}}'
```

You can also define global variables in the `scenarigo.yaml`. The defined variables can be used from all test scenarios.

```yaml
schemaVersion: config/v1
vars:
name: zoncoen
```

### Secrets

The `secrets` field allows defining variables like the `vars` field. Besides, the values defined by the `secrets` field are masked in the outputs.

```yaml
schemaVersion: scenario/v1
plugins:
plugin: plugin.so
vars:
clientId: abcdef
secrets:
clientSecret: XXXXX
title: get user profile
steps:
- title: get access token
protocol: http
request:
method: POST
url: 'http://example.com/oauth/token'
header:
Content-Type: application/x-www-form-urlencoded
body:
grant_type: client_credentials
client_id: '{{vars.clientId}}'
client_secret: '{{secrets.clientSecret}}'
expect:
code: OK
body:
access_token: '{{$ != ""}}'
token_type: Bearer
bind:
secrets:
accessToken: '{{response.body.access_token}}'
- title: get user profile
protocol: http
request:
method: GET
url: 'http://example.com/users/zoncoen'
header:
Authorization: 'Bearer {{secrets.accessToken}}'
expect:
code: OK
body:
name: zoncoen
```

```shell
...
--- PASS: scenarios/get-profile.yaml/get_user_profile/get_access_token (0.00s)
request:
method: POST
url: http://example.com/oauth/token
header:
Content-Type:
- application/x-www-form-urlencoded
body:
client_id: abcdef
client_secret: {{secrets.clientSecret}}
grant_type: client_credentials
response:
...
body:
access_token: {{secrets.accessToken}}
token_type: Bearer
elapsed time: 0.001743 sec
--- PASS: scenarios/get-profile.yaml/get_user_profile/get_user_profile (0.00s)
request:
method: GET
url: http://example.com/users/zoncoen
header:
Authorization:
- Bearer {{secrets.accessToken}}
...
```

### Timeout/Retry

You can set timeout and retry policy for each step.
Expand Down
2 changes: 1 addition & 1 deletion assert/assertion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
- go
- '{{$ == "test"}}'`
var in interface{}
if err := yaml.NewDecoder(strings.NewReader(str), yaml.UseOrderedMap()).Decode(&in); err != nil {

Check failure on line 24 in assert/assertion_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

undefined: yaml (typecheck)
t.Fatalf("unexpected error: %s", err)
}
qs := []string{
Expand Down Expand Up @@ -340,7 +340,7 @@
}
if err := assertion.Assert("foo"); err == nil {
t.Error("no error")
} else if got, expect := err.Error(), ".'{{call <-}}': expected FOO but got foo"; got != expect {
} else if got, expect := err.Error(), `.'{{call <-}}': expected "FOO" but got "foo"`; got != expect {
t.Errorf("expect %q but got %q", expect, got)
}
})
Expand Down
2 changes: 2 additions & 0 deletions assert/equal.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ func Equal(expected interface{}, customEqs ...Equaler) Assertion {
}
}
return errors.Errorf("expected %T (%+v) but got %T (%+v)", expected, expected, v, v)
} else if t.Kind() == reflect.String {
return errors.Errorf("expected %q but got %q", expected, v)
}
return errors.Errorf("expected %+v but got %+v", expected, v)
})
Expand Down
18 changes: 10 additions & 8 deletions assert/operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func TestAnd(t *testing.T) {
},
ok: "one",
ng: "1",
expectError: "[0]: expected one but got 1",
expectError: `[0]: expected "one" but got "1"`,
},
"two": {
assertions: []Assertion{
Expand All @@ -35,16 +35,17 @@ func TestAnd(t *testing.T) {
},
ok: "one",
ng: "1",
expectError: "[0]: expected one but got 1",
expectError: `[0]: expected "one" but got "1"`,
},
"multi error": {
assertions: []Assertion{
Equal("one"),
Equal("un"),
NotZero(),
},
ng: "1",
expectError: "2 errors occurred: [0]: expected one but got 1\n[1]: expected un but got 1",
ng: "1",
expectError: `2 errors occurred: [0]: expected "one" but got "1"
[1]: expected "un" but got "1"`,
},
}
for _, test := range tests {
Expand Down Expand Up @@ -85,16 +86,17 @@ func TestOr(t *testing.T) {
},
ok: "two",
ng: "2",
expectError: "[0]: all assertions failed: expected two but got 2",
expectError: `[0]: all assertions failed: expected "two" but got "2"`,
},
"two": {
assertions: []Assertion{
Equal("one"),
Equal("two"),
},
ok: "two",
ng: "2",
expectError: "2 errors occurred: [0]: all assertions failed: expected one but got 2\n[1]: all assertions failed: expected two but got 2",
ok: "two",
ng: "2",
expectError: `2 errors occurred: [0]: all assertions failed: expected "one" but got "2"
[1]: all assertions failed: expected "two" but got "2"`,
},
}
for _, test := range tests {
Expand Down
7 changes: 7 additions & 0 deletions cmd/scenarigo/cmd/plugin/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,13 @@ func executeWithEnvs(ctx context.Context, envs []string, wd, name string, args .
}

func updateGoMod(cmd *cobra.Command, goCmd, name, gomodPath string, overrideKeys []string, overrides map[string]*overrideModule) error {
if err := editGoMod(cmd, goCmd, gomodPath, func(gomod *modfile.File) error {
gomod.DropToolchainStmt()
return nil
}); err != nil {
return fmt.Errorf("failed to edit toolchain directive: %w", err)
}

initialRequires, initialReplaces, err := updateRequireDirectives(cmd, goCmd, gomodPath, overrides)
if err != nil {
return err
Expand Down
17 changes: 8 additions & 9 deletions cmd/scenarigo/cmd/plugin/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1287,8 +1287,7 @@ replace github.com/zoncoen/scenarigo v0.11.2 => github.com/zoncoen/scenarigo v0.

go 1.21
`,
expectStdout: `WARN: test.so: remove require github.com/zoncoen/scenarigo v0.11.2
WARN: test.so: remove replace github.com/zoncoen/scenarigo v0.11.2 => github.com/zoncoen/scenarigo v0.11.0
expectStdout: `WARN: test.so: remove replace github.com/zoncoen/scenarigo v0.11.2 => github.com/zoncoen/scenarigo v0.11.0
`,
},
"add require": {
Expand Down Expand Up @@ -1320,15 +1319,15 @@ go 1.21
require google.golang.org/grpc v1.37.1

require (
github.com/golang/protobuf v1.4.2 // indirect
golang.org/x/net v0.0.0-20190311183353-d8887717615a // indirect
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a // indirect
golang.org/x/text v0.3.0 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/protobuf v1.25.0 // indirect
github.com/golang/protobuf v1.5.0 // indirect
golang.org/x/net v0.21.0 // indirect
golang.org/x/sys v0.17.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect
google.golang.org/protobuf v1.33.0 // indirect
)
`,
expectStdout: `WARN: test.so: add require google.golang.org/grpc v1.37.1 by test
expectStdout: `WARN: test.so: change require google.golang.org/grpc v1.63.2 ==> v1.37.1 by test
`,
},
"overwrite require by require": {
Expand Down
19 changes: 6 additions & 13 deletions cmd/scenarigo/cmd/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ package cmd
import (
"bytes"
"errors"
"fmt"
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"

Expand All @@ -33,11 +31,6 @@ func TestRun(t *testing.T) {

t.Setenv("TEST_ADDR", srv.URL)

wd, err := os.Getwd()
if err != nil {
t.Fatalf("failed to get current directory: %s", err)
}

tests := map[string]struct {
args []string
config string
Expand Down Expand Up @@ -80,7 +73,7 @@ ok testdata/scenarios/pass.yaml 0.000s
body:
message: request
elapsed time: 0.000000 sec
expected response but got request
expected "response" but got "request"
12 | expect:
13 | code: 200
14 | body:
Expand All @@ -103,14 +96,14 @@ ok scenarios/pass.yaml 0.000s
config: "./testdata/scenarigo-plugin-not-found.yaml",
args: []string{"testdata/scenarios/pass.yaml"},
expectError: ErrTestFailed.Error(),
expectOutput: strings.TrimPrefix(fmt.Sprintf(`
expectOutput: strings.TrimPrefix(`
--- FAIL: setup (0.00s)
--- FAIL: setup/plugin.so (0.00s)
failed to open plugin: plugin.Open("%s"): realpath failed
failed to open plugin: plugin.Open("/go/src/github.com/zoncoen/scenarigo/cmd/testdata/plugin.so"): realpath failed
FAIL
FAIL setup 0.000s
FAIL
`, filepath.Join(wd, "testdata", "plugin.so")), "\n"),
`, "\n"),
},
"print summary": {
args: []string{},
Expand Down Expand Up @@ -141,7 +134,7 @@ FAIL
body:
message: request
elapsed time: 0.000000 sec
expected response but got request
expected "response" but got "request"
12 | expect:
13 | code: 200
14 | body:
Expand Down Expand Up @@ -188,7 +181,7 @@ Failed tests:
body:
message: request
elapsed time: 0.000000 sec
expected response but got request
expected "response" but got "request"
12 | expect:
13 | code: 200
14 | body:
Expand Down
28 changes: 28 additions & 0 deletions context/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type (
keyPluginDir struct{}
keyPlugins struct{}
keyVars struct{}
keySecrets struct{}
keySteps struct{}
keyRequest struct{}
keyResponse struct{}
Expand Down Expand Up @@ -64,6 +65,9 @@ func (c *Context) RequestContext() context.Context {

// WithReporter returns a copy of c with new test reporter.
func (c *Context) WithReporter(r reporter.Reporter) *Context {
if s := c.Secrets(); s != nil {
reporter.SetLogReplacer(c.reporter, s)
}
return newContext(c.ctx, c.reqCtx, r)
}

Expand Down Expand Up @@ -158,6 +162,30 @@ func (c *Context) Vars() Vars {
return nil
}

// WithSecrets returns a copy of c with v.
func (c *Context) WithSecrets(s any) *Context {
if s == nil {
return c
}
secrets, _ := c.ctx.Value(keySecrets{}).(*Secrets)
secrets = secrets.Append(s)
reporter.SetLogReplacer(c.reporter, secrets)
return newContext(
context.WithValue(c.ctx, keySecrets{}, secrets),
c.reqCtx,
c.reporter,
)
}

// Secrets returns the context secrets.
func (c *Context) Secrets() *Secrets {
secrets, ok := c.ctx.Value(keySecrets{}).(*Secrets)
if ok {
return secrets
}
return nil
}

// WithSteps returns a copy of c with steps.
func (c *Context) WithSteps(steps *Steps) *Context {
if steps == nil {
Expand Down
6 changes: 6 additions & 0 deletions context/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const (
nameContext = "ctx"
namePlugins = "plugins"
nameVars = "vars"
nameSecrets = "secrets"
nameSteps = "steps"
nameRequest = "request"
nameResponse = "response"
Expand All @@ -26,6 +27,11 @@ func (c *Context) ExtractByKey(key string) (interface{}, bool) {
if v != nil {
return v, true
}
case nameSecrets:
v := c.Secrets()
if v != nil {
return v, true
}
case nameSteps:
v := c.Steps()
if v != nil {
Expand Down
7 changes: 7 additions & 0 deletions context/extract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ func TestContext_ExtractKey(t *testing.T) {
query: "vars.foo",
expect: "bar",
},
"secrets": {
ctx: func(ctx *Context) *Context {
return ctx.WithSecrets(vars)
},
query: "secrets.foo",
expect: "bar",
},
"steps": {
ctx: func(ctx *Context) *Context {
steps := NewSteps()
Expand Down
Loading
Loading