Skip to content

Commit 7618df3

Browse files
committed
wip: configio converters
- More declarative syntax - Better reusability & maintainability: no more single complex parsing function
1 parent 0dea530 commit 7618df3

2 files changed

Lines changed: 137 additions & 81 deletions

File tree

configio/converters.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package configio
2+
3+
import (
4+
"bytes"
5+
"errors"
6+
"fmt"
7+
"io"
8+
"net/http"
9+
"time"
10+
11+
"github.com/benchttp/engine/benchttp"
12+
)
13+
14+
type (
15+
converter func(representation, *benchttp.Runner) error
16+
requestConverter func(representation, *http.Request) error
17+
)
18+
19+
var fieldConverters = []converter{
20+
func(repr representation, dst *benchttp.Runner) error {
21+
req := dst.Request
22+
if req == nil {
23+
req = &http.Request{}
24+
}
25+
for _, p := range requestConverters {
26+
if err := p(repr, req); err != nil {
27+
return err
28+
}
29+
}
30+
dst.Request = req
31+
return nil
32+
},
33+
func(repr representation, dst *benchttp.Runner) error {
34+
for _, p := range runnerParsers {
35+
if err := p(repr, dst); err != nil {
36+
return err
37+
}
38+
}
39+
return nil
40+
},
41+
}
42+
43+
var requestParser = func(repr representation, dst *benchttp.Runner) error {
44+
req := &http.Request{}
45+
for _, fieldParser := range requestConverters {
46+
if err := fieldParser(repr, req); err != nil {
47+
return err
48+
}
49+
}
50+
dst.Request = req
51+
return nil
52+
}
53+
54+
var requestConverters = []requestConverter{
55+
func(repr representation, dst *http.Request) error {
56+
return setString(repr.Request.Method, &dst.Method)
57+
},
58+
func(repr representation, dst *http.Request) error {
59+
if rawURL := repr.Request.URL; rawURL != nil {
60+
parsedURL, err := parseAndBuildURL(*rawURL, repr.Request.QueryParams)
61+
if err != nil {
62+
return fmt.Errorf(`configio: invalid url: %q`, *rawURL)
63+
}
64+
dst.URL = parsedURL
65+
}
66+
return nil
67+
},
68+
func(repr representation, dst *http.Request) error {
69+
if header := repr.Request.Header; len(header) != 0 {
70+
httpHeader := http.Header{}
71+
for key, val := range header {
72+
httpHeader[key] = val
73+
}
74+
dst.Header = httpHeader
75+
}
76+
return nil
77+
},
78+
func(repr representation, dst *http.Request) error {
79+
if body := repr.Request.Body; body != nil {
80+
switch body.Type {
81+
case "raw":
82+
dst.Body = io.NopCloser(bytes.NewReader([]byte(body.Content)))
83+
default:
84+
return errors.New(`configio: request.body.type: only "raw" accepted`)
85+
}
86+
}
87+
return nil
88+
},
89+
}
90+
91+
var runnerParsers = map[string]converter{
92+
"requests": func(repr representation, dst *benchttp.Runner) error {
93+
return setInt(repr.Runner.Requests, &dst.Requests)
94+
},
95+
"concurrency": func(repr representation, dst *benchttp.Runner) error {
96+
return setInt(repr.Runner.Concurrency, &dst.Concurrency)
97+
},
98+
"interval": func(repr representation, dst *benchttp.Runner) error {
99+
return setOptionalDuration(repr.Runner.Interval, &dst.Interval)
100+
},
101+
"requestTimeout": func(repr representation, dst *benchttp.Runner) error {
102+
return setOptionalDuration(repr.Runner.RequestTimeout, &dst.RequestTimeout)
103+
},
104+
"globalTimeout": func(repr representation, dst *benchttp.Runner) error {
105+
return setOptionalDuration(repr.Runner.GlobalTimeout, &dst.GlobalTimeout)
106+
},
107+
}
108+
109+
func setInt(src, dst *int) error {
110+
if src != nil {
111+
*dst = *src
112+
}
113+
return nil
114+
}
115+
116+
func setString(src, dst *string) error {
117+
if src != nil {
118+
*dst = *src
119+
}
120+
return nil
121+
}
122+
123+
func setOptionalDuration(src *string, dst *time.Duration) error {
124+
if src == nil {
125+
return nil
126+
}
127+
parsed, err := parseOptionalDuration(*src)
128+
if err != nil {
129+
return err
130+
}
131+
*dst = parsed
132+
return nil
133+
}

configio/representation.go

Lines changed: 4 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
package configio
22

33
import (
4-
"bytes"
5-
"errors"
64
"fmt"
7-
"io"
8-
"net/http"
95
"net/url"
106
"strconv"
117
"time"
@@ -57,86 +53,13 @@ func (repr representation) validate() error {
5753
// and stores any non-nil field value into the corresponding field
5854
// of dst.
5955
func (repr representation) parseAndMutate(dst *benchttp.Runner) error {
60-
if err := repr.parseRequestInto(dst); err != nil {
61-
return err
62-
}
63-
if err := repr.parseRunnerInto(dst); err != nil {
64-
return err
65-
}
66-
return repr.parseTestsInto(dst)
67-
}
68-
69-
func (repr representation) parseRequestInto(dst *benchttp.Runner) error {
70-
if dst.Request == nil {
71-
dst.Request = &http.Request{}
72-
}
73-
74-
if method := repr.Request.Method; method != nil {
75-
dst.Request.Method = *method
76-
}
77-
78-
if rawURL := repr.Request.URL; rawURL != nil {
79-
parsedURL, err := parseAndBuildURL(*rawURL, repr.Request.QueryParams)
80-
if err != nil {
81-
return fmt.Errorf(`configio: invalid url: %q`, *rawURL)
82-
}
83-
dst.Request.URL = parsedURL
84-
}
85-
86-
if header := repr.Request.Header; len(header) != 0 {
87-
httpHeader := http.Header{}
88-
for key, val := range header {
89-
httpHeader[key] = val
90-
}
91-
dst.Request.Header = httpHeader
92-
}
93-
94-
if body := repr.Request.Body; body != nil {
95-
switch body.Type {
96-
case "raw":
97-
dst.Request.Body = io.NopCloser(bytes.NewReader([]byte(body.Content)))
98-
default:
99-
return errors.New(`configio: request.body.type: only "raw" accepted`)
100-
}
101-
}
102-
103-
return nil
104-
}
105-
106-
func (repr representation) parseRunnerInto(dst *benchttp.Runner) error {
107-
if requests := repr.Runner.Requests; requests != nil {
108-
dst.Requests = *requests
109-
}
110-
111-
if concurrency := repr.Runner.Concurrency; concurrency != nil {
112-
dst.Concurrency = *concurrency
113-
}
114-
115-
if interval := repr.Runner.Interval; interval != nil {
116-
parsedInterval, err := parseOptionalDuration(*interval)
117-
if err != nil {
118-
return err
119-
}
120-
dst.Interval = parsedInterval
121-
}
122-
123-
if requestTimeout := repr.Runner.RequestTimeout; requestTimeout != nil {
124-
parsedTimeout, err := parseOptionalDuration(*requestTimeout)
125-
if err != nil {
126-
return err
127-
}
128-
dst.RequestTimeout = parsedTimeout
129-
}
130-
131-
if globalTimeout := repr.Runner.GlobalTimeout; globalTimeout != nil {
132-
parsedGlobalTimeout, err := parseOptionalDuration(*globalTimeout)
133-
if err != nil {
56+
for _, converter := range fieldConverters {
57+
if err := converter(repr, dst); err != nil {
13458
return err
13559
}
136-
dst.GlobalTimeout = parsedGlobalTimeout
13760
}
138-
139-
return nil
61+
// TODO: use converter for tests
62+
return repr.parseTestsInto(dst)
14063
}
14164

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

0 commit comments

Comments
 (0)