Skip to content
Draft
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
133 changes: 133 additions & 0 deletions configio/converters.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package configio

import (
"bytes"
"errors"
"fmt"
"io"
"net/http"
"time"

"github.com/benchttp/engine/benchttp"
)

type (
converter func(representation, *benchttp.Runner) error
requestConverter func(representation, *http.Request) error
)

var fieldConverters = []converter{
func(repr representation, dst *benchttp.Runner) error {
req := dst.Request
if req == nil {
req = &http.Request{}
}
for _, p := range requestConverters {
if err := p(repr, req); err != nil {
return err
}
}
dst.Request = req
return nil
},
func(repr representation, dst *benchttp.Runner) error {
for _, p := range runnerParsers {
if err := p(repr, dst); err != nil {
return err
}
}
return nil
},
}

var requestParser = func(repr representation, dst *benchttp.Runner) error {
req := &http.Request{}
for _, fieldParser := range requestConverters {
if err := fieldParser(repr, req); err != nil {
return err
}
}
dst.Request = req
return nil
}

var requestConverters = []requestConverter{
func(repr representation, dst *http.Request) error {
return setString(repr.Request.Method, &dst.Method)
},
func(repr representation, dst *http.Request) error {
if rawURL := repr.Request.URL; rawURL != nil {
parsedURL, err := parseAndBuildURL(*rawURL, repr.Request.QueryParams)
if err != nil {
return fmt.Errorf(`configio: invalid url: %q`, *rawURL)
}
dst.URL = parsedURL
}
return nil
},
func(repr representation, dst *http.Request) error {
if header := repr.Request.Header; len(header) != 0 {
httpHeader := http.Header{}
for key, val := range header {
httpHeader[key] = val
}
dst.Header = httpHeader
}
return nil
},
func(repr representation, dst *http.Request) error {
if body := repr.Request.Body; body != nil {
switch body.Type {
case "raw":
dst.Body = io.NopCloser(bytes.NewReader([]byte(body.Content)))
default:
return errors.New(`configio: request.body.type: only "raw" accepted`)
}
}
return nil
},
}

var runnerParsers = map[string]converter{
"requests": func(repr representation, dst *benchttp.Runner) error {
return setInt(repr.Runner.Requests, &dst.Requests)
},
"concurrency": func(repr representation, dst *benchttp.Runner) error {
return setInt(repr.Runner.Concurrency, &dst.Concurrency)
},
"interval": func(repr representation, dst *benchttp.Runner) error {
return setOptionalDuration(repr.Runner.Interval, &dst.Interval)
},
"requestTimeout": func(repr representation, dst *benchttp.Runner) error {
return setOptionalDuration(repr.Runner.RequestTimeout, &dst.RequestTimeout)
},
"globalTimeout": func(repr representation, dst *benchttp.Runner) error {
return setOptionalDuration(repr.Runner.GlobalTimeout, &dst.GlobalTimeout)
},
}

func setInt(src, dst *int) error {
if src != nil {
*dst = *src
}
return nil
}

func setString(src, dst *string) error {
if src != nil {
*dst = *src
}
return nil
}

func setOptionalDuration(src *string, dst *time.Duration) error {
if src == nil {
return nil
}
parsed, err := parseOptionalDuration(*src)
if err != nil {
return err
}
*dst = parsed
return nil
}
85 changes: 4 additions & 81 deletions configio/representation.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
package configio

import (
"bytes"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"time"
Expand Down Expand Up @@ -57,86 +53,13 @@ func (repr representation) validate() error {
// and stores any non-nil field value into the corresponding field
// of dst.
func (repr representation) parseAndMutate(dst *benchttp.Runner) error {
if err := repr.parseRequestInto(dst); err != nil {
return err
}
if err := repr.parseRunnerInto(dst); err != nil {
return err
}
return repr.parseTestsInto(dst)
}

func (repr representation) parseRequestInto(dst *benchttp.Runner) error {
if dst.Request == nil {
dst.Request = &http.Request{}
}

if method := repr.Request.Method; method != nil {
dst.Request.Method = *method
}

if rawURL := repr.Request.URL; rawURL != nil {
parsedURL, err := parseAndBuildURL(*rawURL, repr.Request.QueryParams)
if err != nil {
return fmt.Errorf(`configio: invalid url: %q`, *rawURL)
}
dst.Request.URL = parsedURL
}

if header := repr.Request.Header; len(header) != 0 {
httpHeader := http.Header{}
for key, val := range header {
httpHeader[key] = val
}
dst.Request.Header = httpHeader
}

if body := repr.Request.Body; body != nil {
switch body.Type {
case "raw":
dst.Request.Body = io.NopCloser(bytes.NewReader([]byte(body.Content)))
default:
return errors.New(`configio: request.body.type: only "raw" accepted`)
}
}

return nil
}

func (repr representation) parseRunnerInto(dst *benchttp.Runner) error {
if requests := repr.Runner.Requests; requests != nil {
dst.Requests = *requests
}

if concurrency := repr.Runner.Concurrency; concurrency != nil {
dst.Concurrency = *concurrency
}

if interval := repr.Runner.Interval; interval != nil {
parsedInterval, err := parseOptionalDuration(*interval)
if err != nil {
return err
}
dst.Interval = parsedInterval
}

if requestTimeout := repr.Runner.RequestTimeout; requestTimeout != nil {
parsedTimeout, err := parseOptionalDuration(*requestTimeout)
if err != nil {
return err
}
dst.RequestTimeout = parsedTimeout
}

if globalTimeout := repr.Runner.GlobalTimeout; globalTimeout != nil {
parsedGlobalTimeout, err := parseOptionalDuration(*globalTimeout)
if err != nil {
for _, converter := range fieldConverters {
if err := converter(repr, dst); err != nil {
return err
}
dst.GlobalTimeout = parsedGlobalTimeout
}

return nil
// TODO: use converter for tests
return repr.parseTestsInto(dst)
}

func (repr representation) parseTestsInto(dst *benchttp.Runner) error {
Expand Down