Skip to content

Commit db729d4

Browse files
authored
Added test cases (#116)
1 parent 008823f commit db729d4

File tree

3 files changed

+369
-96
lines changed

3 files changed

+369
-96
lines changed

clients/options.go

+3-9
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,6 @@ import (
77
"oss.nandlabs.io/golly/config"
88
)
99

10-
var EmptyClientOptions = &ClientOptions{
11-
Attributes: config.NewMapAttributes(),
12-
CircuitBreaker: nil,
13-
Auth: nil,
14-
RetryPolicy: nil,
15-
}
16-
1710
type RetryPolicy struct {
1811
MaxRetries int
1912
BackoffInterval time.Duration
@@ -24,7 +17,8 @@ type RetryPolicy struct {
2417
func (r *RetryPolicy) WaitTime(retryCount int) time.Duration {
2518
backoff := r.BackoffInterval
2619
if r.Exponential {
27-
backoff = time.Duration(int64(math.Pow(2, float64(retryCount)))*backoff.Milliseconds()) * time.Millisecond
20+
multiple := math.Pow(2, float64(retryCount))
21+
backoff = time.Duration(multiple) * r.BackoffInterval
2822
backoff = min(backoff, r.MaxBackoff)
2923
}
3024
return backoff
@@ -114,7 +108,7 @@ func (b *OptionsBuilder) RetryPolicy(maxRetries int, backoffIntervalMs int, expo
114108
MaxRetries: maxRetries,
115109
BackoffInterval: time.Duration(backoffIntervalMs) * time.Millisecond,
116110
Exponential: exponential,
117-
MaxBackoff: time.Duration(backoffIntervalMs) * time.Millisecond,
111+
MaxBackoff: time.Duration(maxBackoffInMs) * time.Millisecond,
118112
}
119113
return b
120114
}

rest/client.go

+79-72
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ var basicAuthHandlerFunc = func(client *Client, req *http.Request) error {
3737
}
3838

3939
var bearerAuthHandlerFunc = func(client *Client, req *http.Request) error {
40-
if client.options.Auth == nil || client.options.Auth.Type() != clients.AuthTypeBasic {
40+
if client.options.Auth == nil || client.options.Auth.Type() != clients.AuthTypeBearer {
4141
return fmt.Errorf("invalid auth type")
4242
}
4343
req.Header.Set("Authorization", "Bearer "+client.options.Auth.Token())
@@ -66,127 +66,127 @@ type ClientOpts struct {
6666

6767
type ClientOptsBuilder struct {
6868
*clients.OptionsBuilder
69-
opts *ClientOpts
69+
restOptions *ClientOpts
7070
}
7171

72-
func ClientOptBuilder() *ClientOptsBuilder {
72+
func CliOptsBuilder() *ClientOptsBuilder {
7373
return &ClientOptsBuilder{
7474
OptionsBuilder: clients.NewOptionsBuilder(),
75-
opts: &ClientOpts{
76-
ClientOptions: clients.EmptyClientOptions,
77-
tlsConfig: &tls.Config{},
75+
restOptions: &ClientOpts{
76+
tlsConfig: &tls.Config{},
7877
},
7978
}
8079
}
8180

8281
func (co *ClientOptsBuilder) EnvProxy(proxyBasicAuth string) *ClientOptsBuilder {
83-
co.opts.proxyBasicAuth = proxyBasicAuth
82+
co.restOptions.proxyBasicAuth = proxyBasicAuth
8483
return co
8584
}
8685

8786
func (co *ClientOptsBuilder) CodecOpts(options map[string]any) *ClientOptsBuilder {
88-
co.opts.codecOptions = options
87+
co.restOptions.codecOptions = options
8988
return co
9089
}
9190

9291
func (co *ClientOptsBuilder) MaxIdlePerHost(maxIdleConnPerHost int) *ClientOptsBuilder {
93-
co.opts.maxIdlePerHost = maxIdleConnPerHost
92+
co.restOptions.maxIdlePerHost = maxIdleConnPerHost
9493
return co
9594
}
9695

9796
func (co *ClientOptsBuilder) ProxyAuth(user, password, bypass string) *ClientOptsBuilder {
98-
co.opts.proxyBasicAuth = "Basic " + base64.StdEncoding.EncodeToString([]byte(user+":"+password))
97+
co.restOptions.proxyBasicAuth = "Basic " + base64.StdEncoding.EncodeToString([]byte(user+":"+password))
9998
return co
10099
}
101100

102101
func (co *ClientOptsBuilder) BaseUrl(baseurl string) (err error) {
103102
if baseurl == textutils.EmptyStr {
104103
return errors.New("invalid base url")
105104
}
106-
co.opts.baseUrl, err = url.Parse(baseurl)
107-
if err == nil && co.opts.baseUrl.Scheme == textutils.EmptyStr && co.opts.baseUrl.Host == textutils.EmptyStr {
105+
co.restOptions.baseUrl, err = url.Parse(baseurl)
106+
if err == nil && co.restOptions.baseUrl.Scheme == textutils.EmptyStr && co.restOptions.baseUrl.Host == textutils.EmptyStr {
108107
err = errors.New("invalid base url")
109108
} else {
110-
if !strings.HasSuffix(co.opts.baseUrl.Path, textutils.ForwardSlashStr) {
111-
co.opts.baseUrl.Path = co.opts.baseUrl.Path + textutils.ForwardSlashStr
109+
if !strings.HasSuffix(co.restOptions.baseUrl.Path, textutils.ForwardSlashStr) {
110+
co.restOptions.baseUrl.Path = co.restOptions.baseUrl.Path + textutils.ForwardSlashStr
112111
}
113112
}
114113

115114
return
116115
}
117116

118117
func (co *ClientOptsBuilder) ErrOnStatus(httpStatusCodes ...int) *ClientOptsBuilder {
119-
if co.opts.errorOnMap == nil {
120-
co.opts.errorOnMap = make(map[int]int)
118+
if co.restOptions.errorOnMap == nil {
119+
co.restOptions.errorOnMap = make(map[int]int)
121120
}
122121
for _, code := range httpStatusCodes {
123-
co.opts.errorOnMap[code] = code
122+
co.restOptions.errorOnMap[code] = code
124123
}
125124
return co
126125
}
127126

128127
func (co *ClientOptsBuilder) SSLVerify(verify bool) *ClientOptsBuilder {
129-
if co.opts.tlsConfig == nil {
130-
co.opts.tlsConfig = &tls.Config{}
128+
if co.restOptions.tlsConfig == nil {
129+
co.restOptions.tlsConfig = &tls.Config{}
131130
}
132-
co.opts.tlsConfig.InsecureSkipVerify = verify
133-
co.opts.useCustomTLSConfig = true
131+
co.restOptions.tlsConfig.InsecureSkipVerify = verify
132+
co.restOptions.useCustomTLSConfig = true
134133
return co
135134
}
136135

137136
func (co *ClientOptsBuilder) CaCerts(caFilePath ...string) *ClientOptsBuilder {
138-
co.opts.useCustomTLSConfig = true
139-
if co.opts.tlsConfig == nil {
140-
co.opts.tlsConfig = &tls.Config{}
137+
co.restOptions.useCustomTLSConfig = true
138+
if co.restOptions.tlsConfig == nil {
139+
co.restOptions.tlsConfig = &tls.Config{}
141140
}
142-
if co.opts.tlsConfig.RootCAs == nil {
143-
co.opts.tlsConfig.RootCAs = x509.NewCertPool()
141+
if co.restOptions.tlsConfig.RootCAs == nil {
142+
co.restOptions.tlsConfig.RootCAs = x509.NewCertPool()
144143
}
145144
for _, v := range caFilePath {
146145
caCert, err := os.ReadFile(v)
147146
if err != nil {
148147
logger.Error("error reading ca cert file", err)
149148
continue
150149
}
151-
co.opts.tlsConfig.RootCAs.AppendCertsFromPEM(caCert)
150+
co.restOptions.tlsConfig.RootCAs.AppendCertsFromPEM(caCert)
152151
}
153152
return co
154153
}
155154

156155
func (co *ClientOptsBuilder) TlsCerts(certs ...tls.Certificate) *ClientOptsBuilder {
157-
if co.opts.tlsConfig == nil {
158-
co.opts.tlsConfig = &tls.Config{}
156+
if co.restOptions.tlsConfig == nil {
157+
co.restOptions.tlsConfig = &tls.Config{}
159158
}
160-
co.opts.useCustomTLSConfig = true
161-
co.opts.tlsConfig.Certificates = append(co.opts.tlsConfig.Certificates, certs...)
159+
co.restOptions.useCustomTLSConfig = true
160+
co.restOptions.tlsConfig.Certificates = append(co.restOptions.tlsConfig.Certificates, certs...)
162161
return co
163162
}
164163

165164
func (co *ClientOptsBuilder) IdleTimeoutMs(t int) *ClientOptsBuilder {
166-
co.opts.idleTimeout = time.Duration(t) * time.Millisecond
165+
co.restOptions.idleTimeout = time.Duration(t) * time.Millisecond
167166
return co
168167
}
169168

170169
func (co *ClientOptsBuilder) RequestTimeoutMs(t int) *ClientOptsBuilder {
171-
co.opts.requestTimeout = time.Duration(t) * time.Millisecond
170+
co.restOptions.requestTimeout = time.Duration(t) * time.Millisecond
172171
return co
173172
}
174173
func (co *ClientOptsBuilder) TlsHandShakeTimeoutMs(t int) *ClientOptsBuilder {
175-
co.opts.tlsHandShakeTimeout = time.Duration(t) * time.Millisecond
174+
co.restOptions.tlsHandShakeTimeout = time.Duration(t) * time.Millisecond
176175
return co
177176
}
178177

179178
func (co *ClientOptsBuilder) ExpectContinueTimeoutMs(t int) *ClientOptsBuilder {
180-
co.opts.expectContinueTimeout = time.Duration(t) * time.Millisecond
179+
co.restOptions.expectContinueTimeout = time.Duration(t) * time.Millisecond
181180
return co
182181
}
183182
func (co *ClientOptsBuilder) CookieJar(jar http.CookieJar) *ClientOptsBuilder {
184-
co.opts.jar = jar
183+
co.restOptions.jar = jar
185184
return co
186185
}
187186

188187
func (co *ClientOptsBuilder) Build() *ClientOpts {
189-
return co.opts
188+
co.restOptions.ClientOptions = co.OptionsBuilder.Build()
189+
return co.restOptions
190190
}
191191

192192
// Client represents a REST client.
@@ -228,7 +228,7 @@ func NewClientWithOptions(options *ClientOpts) *Client {
228228
// NewClient creates a new REST client with default values.
229229
func NewClient() *Client {
230230
return NewClientWithOptions(&ClientOpts{
231-
ClientOptions: clients.EmptyClientOptions,
231+
ClientOptions: clients.NewOptionsBuilder().Build(),
232232
tlsConfig: &tls.Config{
233233
InsecureSkipVerify: false,
234234
},
@@ -269,50 +269,57 @@ func (c *Client) Execute(req *Request) (res *Response, err error) {
269269
if c.options.proxyBasicAuth != textutils.EmptyStr {
270270
httpReq.Header.Set(proxyAuthHdr, c.options.proxyBasicAuth)
271271
}
272-
if err == nil {
273-
if c.options.Auth != nil {
274-
if handlerFunc, ok := c.options.AuthHandlers[c.options.Auth.Type()]; ok {
275-
err = handlerFunc(c, httpReq)
276-
} else {
277-
err = fmt.Errorf("invalid auth type or no handlerfunc found for auth type %v", c.options.Auth.Type())
278-
return
279-
}
280-
}
281-
// Check if the circuit breaker is open
282-
if c.options.CircuitBreaker != nil {
283-
err = c.options.CircuitBreaker.CanExecute()
284-
// If the circuit breaker is open, return an error
272+
if err != nil {
273+
return
274+
}
275+
// Check if the request has an auth type and if so, execute the auth handler
276+
if c.options.Auth != nil {
277+
if handlerFunc, ok := c.options.AuthHandlers[c.options.Auth.Type()]; ok {
278+
err = handlerFunc(c, httpReq)
285279
if err != nil {
286280
return
287281
}
282+
} else {
283+
err = fmt.Errorf("invalid auth type or no handlerfunc found for auth type %v", c.options.Auth.Type())
284+
return
288285
}
289-
// Execute the request
290-
httpRes, err = c.httpClient.Do(httpReq)
291-
// Check if the response is an error
292-
isErr := c.isError(err, httpRes)
293-
if c.options.CircuitBreaker != nil {
294-
c.options.CircuitBreaker.OnExecution(!isErr)
286+
}
287+
// Check if the circuit breaker is open
288+
if c.options.CircuitBreaker != nil {
289+
err = c.options.CircuitBreaker.CanExecute()
290+
// If the circuit breaker is open, return an error
291+
if err != nil {
292+
return
295293
}
296-
if isErr && c.options.RetryPolicy != nil {
297-
retryCount := 0
298-
// For each retry, sleep for the backoff interval and retry the request
299-
for isErr && retryCount < c.options.RetryPolicy.MaxRetries {
300-
time.Sleep(c.options.RetryPolicy.WaitTime(retryCount))
301-
retryCount++
302-
httpRes, err = c.httpClient.Do(httpReq)
303-
isErr = c.isError(err, httpRes)
304-
if c.options.CircuitBreaker != nil {
305-
c.options.CircuitBreaker.OnExecution(!isErr)
306-
}
294+
}
295+
// Execute the request
296+
httpRes, err = c.httpClient.Do(httpReq)
297+
// Check if the response is an error
298+
isErr := c.isError(err, httpRes)
299+
if c.options.CircuitBreaker != nil {
300+
c.options.CircuitBreaker.OnExecution(!isErr)
301+
}
302+
if isErr && c.options.RetryPolicy != nil {
303+
retryCount := 0
304+
// For each retry, sleep for the backoff interval and retry the request
305+
for isErr && retryCount < c.options.RetryPolicy.MaxRetries {
306+
sleepFor := c.options.RetryPolicy.WaitTime(retryCount)
307+
time.Sleep(sleepFor)
308+
retryCount++
309+
httpRes, err = c.httpClient.Do(httpReq)
310+
isErr = c.isError(err, httpRes)
311+
if c.options.CircuitBreaker != nil {
312+
c.options.CircuitBreaker.OnExecution(!isErr)
307313
}
308314
}
315+
}
309316

310-
httpRes, err = c.httpClient.Do(httpReq)
317+
httpRes, err = c.httpClient.Do(httpReq)
311318

312-
if err == nil {
313-
res = &Response{raw: httpRes, client: c}
314-
}
319+
if err == nil {
320+
res = &Response{raw: httpRes, client: c}
315321
}
322+
316323
return
317324
}
318325

0 commit comments

Comments
 (0)