Skip to content
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
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,15 @@ And I request "some-service" HTTP endpoint with headers
| X-Bar | 123 |
```

Or use a pipe-delimited `.table` or CSV `.csv` file.

```gherkin
And I request "some-service" HTTP endpoint with headers from file
"""
path/to/file.table
"""
```

An additional cookie can be supplied. For multiple cookies, call step multiple times.

```gherkin
Expand All @@ -74,6 +83,15 @@ And I request "some-service" HTTP endpoint with cookies
| cbar | 123 |
```

Or use a pipe-delimited `.table` or CSV `.csv` file.

```gherkin
And I request "some-service" HTTP endpoint with cookies from file
"""
path/to/file.csv
"""
```

Optionally request body can be configured. If body is a valid JSON5 payload, it will be converted to JSON before use.
Otherwise, body is used as is.

Expand Down Expand Up @@ -105,6 +123,15 @@ And I request "some-service" HTTP endpoint with urlencoded form data
| fbar | 456 |
```

Or use a pipe-delimited `.table` or CSV `.csv` file.

```gherkin
And I request "some-service" HTTP endpoint with urlencoded form data from file
"""
path/to/file.table
"""
```


By default, redirects are not followed. This behavior can be changed.

Expand Down
6 changes: 4 additions & 2 deletions _testdata/LocalClient.feature
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ Feature: HTTP Service
Scenario: Bad request
When I request HTTP endpoint with method "DELETE" and URI "/bad-request"
And I request HTTP endpoint with header "X-Foo: bar"
And I request HTTP endpoint with cookie "c1: v1"
And I request HTTP endpoint with cookie "c2: v2"
And I request HTTP endpoint with cookies from file
"""
_testdata/cookies.table
"""
Then I should have response with status "Bad Request"
And I should have response with body from file
"""
Expand Down
2 changes: 2 additions & 0 deletions _testdata/cookies.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
c1,v1
c2,v2
2 changes: 2 additions & 0 deletions _testdata/cookies.table
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
| c1 | v1 |
| c2 | v2 |
150 changes: 144 additions & 6 deletions local_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import (
"bytes"
"context"
"encoding/csv"
"encoding/json"
"errors"
"fmt"
Expand Down Expand Up @@ -200,6 +201,11 @@
s.Step(`^I request(.*) HTTP endpoint with query parameters$`, l.iRequestWithQueryParameters)
s.Step(`^I request(.*) HTTP endpoint with urlencoded form data$`, l.iRequestWithFormDataParameters)

s.Step(`^I request(.*) HTTP endpoint with cookies from file$`, l.iRequestWithCookiesFromFile)
s.Step(`^I request(.*) HTTP endpoint with headers from file$`, l.iRequestWithHeadersFromFile)
s.Step(`^I request(.*) HTTP endpoint with query parameters from file$`, l.iRequestWithQueryParametersFromFile)
s.Step(`^I request(.*) HTTP endpoint with urlencoded form data from file$`, l.iRequestWithFormDataParametersFromFile)

s.Step(`^I follow redirects from(.*) HTTP endpoint$`, l.iFollowRedirects)
s.Step(`^I retry(.*) HTTP request up to (\d+ time[s]?|.*)$`, l.iRetry)
s.Step(`^I concurrently request idempotent(.*) HTTP endpoint$`, l.iRequestWithConcurrency)
Expand Down Expand Up @@ -385,6 +391,76 @@
return ctx, nil
}

func mapOfCSVFile(fn string) (url.Values, error) {
d, err := os.ReadFile(fn)
if err != nil {
return nil, err
}

Check notice on line 398 in local_client.go

View workflow job for this annotation

GitHub Actions / test (stable)

3 statement(s) are not covered by tests.

r := csv.NewReader(bytes.NewReader(d))

rows, err := r.ReadAll()
if err != nil {
return nil, err
}

Check notice on line 405 in local_client.go

View workflow job for this annotation

GitHub Actions / test (stable)

4 statement(s) are not covered by tests.

res := make(url.Values, len(rows))

for _, l := range rows {
if len(l) != 2 {
return nil, fmt.Errorf("%w, 2 expected, %d received",
errInvalidNumberOfColumns, len(l))
}

Check notice on line 413 in local_client.go

View workflow job for this annotation

GitHub Actions / test (stable)

5 statement(s) are not covered by tests.

k := l[0]
v := l[1]

res[k] = append(res[k], v)

Check notice on line 418 in local_client.go

View workflow job for this annotation

GitHub Actions / test (stable)

3 statement(s) are not covered by tests.
}

return res, nil

Check notice on line 421 in local_client.go

View workflow job for this annotation

GitHub Actions / test (stable)

1 statement(s) are not covered by tests.
}

func mapOfTableFile(fn string) (url.Values, error) {
if strings.HasSuffix(fn, ".csv") {
return mapOfCSVFile(fn)
}

Check notice on line 427 in local_client.go

View workflow job for this annotation

GitHub Actions / test (stable)

1 statement(s) on lines 425:427 are not covered by tests.

if !strings.HasSuffix(fn, ".table") {
return nil, fmt.Errorf("unsupported file, *.table or *.csv expected: %s", fn)
}

Check notice on line 431 in local_client.go

View workflow job for this annotation

GitHub Actions / test (stable)

1 statement(s) on lines 429:431 are not covered by tests.

d, err := os.ReadFile(fn)
if err != nil {
return nil, err
}

Check notice on line 436 in local_client.go

View workflow job for this annotation

GitHub Actions / test (stable)

1 statement(s) on lines 434:436 are not covered by tests.

res := make(url.Values)

for _, l := range bytes.Split(d, []byte("\n")) {
l := strings.TrimSpace(string(l))

if len(l) == 0 {
continue
}

l = strings.Trim(l, `|`)
p := strings.Split(l, "|")

if len(p) != 2 {
return nil, fmt.Errorf("%w, 2 expected, %d received",
errInvalidNumberOfColumns, len(p))
}

Check notice on line 453 in local_client.go

View workflow job for this annotation

GitHub Actions / test (stable)

1 statement(s) on lines 450:453 are not covered by tests.

k := strings.TrimSpace(p[0])
v := strings.TrimSpace(p[1])

res[k] = append(res[k], v)
}

return res, nil
}

func mapOfData(data *godog.Table) (url.Values, error) {
if len(data.Rows[0].Cells) != 2 {
return nil, fmt.Errorf("%w, 2 expected, %d received",
Expand All @@ -402,7 +478,21 @@
return res, nil
}

func (l *LocalClient) tableSetup(
func (l *LocalClient) fileTableSetup(
ctx context.Context,
fn string,
receiverName string,
receiver func(name, value string) *httpmock.Client,
) (context.Context, error) {
m, err := mapOfTableFile(fn)
if err != nil {
return ctx, err
}

Check notice on line 490 in local_client.go

View workflow job for this annotation

GitHub Actions / test (stable)

1 statement(s) on lines 488:490 are not covered by tests.

return l.tableSetup(ctx, m, receiverName, receiver)
}

func (l *LocalClient) godogTableSetup(
ctx context.Context,
data *godog.Table,
receiverName string,
Expand All @@ -413,7 +503,19 @@
return ctx, err
}

var rv []byte
return l.tableSetup(ctx, m, receiverName, receiver)
}

func (l *LocalClient) tableSetup(
ctx context.Context,
m url.Values,
receiverName string,
receiver func(name, value string) *httpmock.Client,
) (context.Context, error) {
var (
err error
rv []byte
)

ctx = l.VS.PrepareContext(ctx)

Expand All @@ -437,7 +539,16 @@
return ctx, err
}

return l.tableSetup(ctx, data, "form data parameter", c.WithURLEncodedFormDataParam)
return l.godogTableSetup(ctx, data, "form data parameter", c.WithURLEncodedFormDataParam)
}

func (l *LocalClient) iRequestWithFormDataParametersFromFile(ctx context.Context, service string, filePath string) (context.Context, error) {
c, ctx, err := l.Service(ctx, service)
if err != nil {
return ctx, err
}

return l.fileTableSetup(ctx, filePath, "form data parameter", c.WithURLEncodedFormDataParam)
}

func (l *LocalClient) iRequestWithQueryParameters(ctx context.Context, service string, data *godog.Table) (context.Context, error) {
Expand All @@ -446,7 +557,16 @@
return ctx, err
}

return l.tableSetup(ctx, data, "query parameter", c.WithQueryParam)
return l.godogTableSetup(ctx, data, "query parameter", c.WithQueryParam)
}

func (l *LocalClient) iRequestWithQueryParametersFromFile(ctx context.Context, service string, filePath string) (context.Context, error) {
c, ctx, err := l.Service(ctx, service)
if err != nil {
return ctx, err
}

return l.fileTableSetup(ctx, filePath, "query parameter", c.WithQueryParam)
}

func (l *LocalClient) iRequestWithHeaders(ctx context.Context, service string, data *godog.Table) (context.Context, error) {
Expand All @@ -455,7 +575,16 @@
return ctx, err
}

return l.tableSetup(ctx, data, "header", c.WithHeader)
return l.godogTableSetup(ctx, data, "header", c.WithHeader)
}

func (l *LocalClient) iRequestWithHeadersFromFile(ctx context.Context, service string, filePath string) (context.Context, error) {
c, ctx, err := l.Service(ctx, service)
if err != nil {
return ctx, err
}

return l.fileTableSetup(ctx, filePath, "header", c.WithHeader)
}

func (l *LocalClient) iRequestWithCookie(ctx context.Context, service, name, value string) (context.Context, error) {
Expand All @@ -480,7 +609,16 @@
return ctx, err
}

return l.tableSetup(ctx, data, "cookie", c.WithCookie)
return l.godogTableSetup(ctx, data, "cookie", c.WithCookie)
}

func (l *LocalClient) iRequestWithCookiesFromFile(ctx context.Context, service string, filePath string) (context.Context, error) {
c, ctx, err := l.Service(ctx, service)
if err != nil {
return ctx, err
}

return l.fileTableSetup(ctx, filePath, "cookie", c.WithCookie)
}

func (l *LocalClient) iRequestWithAttachment(ctx context.Context, service, fieldName, fileName string, fileContent string) (context.Context, error) {
Expand Down
Loading