Skip to content

Commit 7749feb

Browse files
committed
feat: add options pattern to BasicClient
- feature is required because tr1d1um requires the ability to add a custom transport to BasicClient's http client (`HTTPTransport`) - improve main fx test
1 parent 05ff363 commit 7749feb

File tree

4 files changed

+289
-74
lines changed

4 files changed

+289
-74
lines changed

anclafx/provide_test.go

+17-2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type out struct {
2020

2121
Factory *touchstone.Factory
2222
BasicClientConfig chrysom.BasicClientConfig
23+
Options chrysom.Options
2324
}
2425

2526
func provideDefaults() (out, error) {
@@ -38,25 +39,39 @@ func provideDefaults() (out, error) {
3839
Address: "example.com",
3940
Bucket: "bucket-name",
4041
},
42+
Options: chrysom.Options{
43+
chrysom.Address("example.com"),
44+
chrysom.Bucket("bucket-name"),
45+
},
4146
}, nil
4247
}
4348

4449
func TestProvide(t *testing.T) {
4550
t.Run("Test anclafx.Provide() defaults", func(t *testing.T) {
46-
var svc *ancla.ClientService
51+
var (
52+
svc *ancla.ClientService
53+
bc *chrysom.BasicClient
54+
l *chrysom.ListenerClient
55+
)
4756
app := fxtest.New(t,
4857
anclafx.Provide(),
4958
fx.Provide(
5059
provideDefaults,
5160
),
52-
fx.Populate(&svc),
61+
fx.Populate(
62+
&svc,
63+
&bc,
64+
&l,
65+
),
5366
)
5467

5568
require := require.New(t)
5669
require.NotNil(app)
5770
require.NoError(app.Err())
5871
app.RequireStart()
5972
require.NotNil(svc)
73+
require.NotNil(bc)
74+
require.NotNil(l)
6075
app.RequireStop()
6176
})
6277
}

chrysom/basicClient.go

+14-31
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@ import (
1616
"github.com/xmidt-org/ancla/model"
1717
"github.com/xmidt-org/arrange/arrangehttp"
1818
"github.com/xmidt-org/sallust"
19+
"go.uber.org/fx"
1920
"go.uber.org/zap"
2021
)
2122

2223
var (
23-
ErrAddressEmpty = errors.New("argus address is required")
24-
ErrBucketEmpty = errors.New("bucket name is required")
2524
ErrItemIDEmpty = errors.New("item ID is required")
2625
ErrItemDataEmpty = errors.New("data field in item is required")
2726
ErrUndefinedIntervalTicker = errors.New("interval ticker is nil. Can't listen for updates")
@@ -91,9 +90,15 @@ const (
9190
// Items is a slice of model.Item(s) .
9291
type Items []model.Item
9392

93+
type BasicClientIn struct {
94+
fx.In
95+
96+
Options Options `optional:"true" `
97+
}
98+
9499
// ProvideBasicClient provides a new BasicClient.
95-
func ProvideBasicClient(config BasicClientConfig) (*BasicClient, error) {
96-
client, err := NewBasicClient(config)
100+
func ProvideBasicClient(in BasicClientIn) (*BasicClient, error) {
101+
client, err := NewBasicClient(in.Options)
97102
if err != nil {
98103
return nil, errors.Join(errFailedConfig, err)
99104
}
@@ -103,23 +108,13 @@ func ProvideBasicClient(config BasicClientConfig) (*BasicClient, error) {
103108

104109
// NewBasicClient creates a new BasicClient that can be used to
105110
// make requests to Argus.
106-
func NewBasicClient(config BasicClientConfig) (*BasicClient, error) {
107-
err := validateBasicConfig(&config)
108-
if err != nil {
109-
return nil, err
110-
}
111+
func NewBasicClient(opts Options) (*BasicClient, error) {
112+
var client BasicClient
111113

112-
client, err := config.HTTPClient.NewClient()
113-
if err != nil {
114-
return nil, err
115-
}
114+
opts = append(defaultOptions, opts)
115+
opts = append(opts, defaultValidateOptions)
116116

117-
return &BasicClient{
118-
client: client,
119-
auth: config.Auth,
120-
bucket: config.Bucket,
121-
storeBaseURL: config.Address + storeAPIPath,
122-
}, nil
117+
return &client, opts.apply(&client)
123118
}
124119

125120
// GetItems fetches all items that belong to a given owner.
@@ -263,15 +258,3 @@ func translateNonSuccessStatusCode(code int) error {
263258
return errNonSuccessResponse
264259
}
265260
}
266-
267-
func validateBasicConfig(config *BasicClientConfig) error {
268-
if config.Address == "" {
269-
return ErrAddressEmpty
270-
}
271-
272-
if config.Bucket == "" {
273-
return ErrBucketEmpty
274-
}
275-
276-
return nil
277-
}

chrysom/basicClient_test.go

+118-41
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import (
1818
"github.com/stretchr/testify/assert"
1919
"github.com/stretchr/testify/require"
2020
"github.com/xmidt-org/ancla/model"
21+
"github.com/xmidt-org/arrange/arrangehttp"
22+
"github.com/xmidt-org/arrange/arrangetls"
2123
)
2224

2325
const failingURL = "nowhere://"
@@ -28,65 +30,132 @@ var (
2830
errFails = errors.New("fails")
2931
)
3032

31-
func TestValidateBasicConfig(t *testing.T) {
33+
func TestValidateOptions(t *testing.T) {
3234
type testCase struct {
3335
Description string
34-
Input *BasicClientConfig
35-
Client *http.Client
36+
ValidateOption Option
37+
Client BasicClient
3638
ExpectedErr error
37-
ExpectedConfig *BasicClientConfig
3839
}
3940

40-
allDefaultsCaseConfig := &BasicClientConfig{
41-
Address: "example.com",
42-
Bucket: "bucket-name",
41+
tcs := []testCase{
42+
{
43+
Description: "Nil http client",
44+
ValidateOption: validateHTTPClient(),
45+
Client: BasicClient{},
46+
ExpectedErr: ErrHttpClient,
47+
},
48+
{
49+
Description: "Empty bucket",
50+
ValidateOption: validateBucket(),
51+
Client: BasicClient{},
52+
ExpectedErr: ErrBucketEmpty,
53+
},
54+
{
55+
Description: "Empty store base url",
56+
ValidateOption: validateStoreBaseURL(),
57+
Client: BasicClient{},
58+
ExpectedErr: ErrStoreBaseURLEmpty,
59+
},
60+
}
61+
62+
for _, tc := range tcs {
63+
t.Run(tc.Description, func(t *testing.T) {
64+
assert := assert.New(t)
65+
err := tc.ValidateOption.apply(&tc.Client)
66+
assert.ErrorIs(err, tc.ExpectedErr)
67+
})
4368
}
44-
allDefinedCaseConfig := &BasicClientConfig{
45-
Address: "example.com",
46-
Bucket: "amazing-bucket",
69+
}
70+
71+
func TestValidateBasicConfig(t *testing.T) {
72+
type testCase struct {
73+
Description string
74+
Input BasicClientConfig
75+
Transport http.RoundTripper
76+
Client *http.Client
77+
ExpectedErr error
4778
}
4879

4980
tcs := []testCase{
5081
{
5182
Description: "No address",
52-
Input: &BasicClientConfig{
53-
Bucket: "bucket-name",
83+
Input: BasicClientConfig{
84+
Bucket: "bucket-name",
85+
HTTPClient: arrangehttp.ClientConfig{},
5486
},
87+
Transport: http.DefaultTransport,
5588
ExpectedErr: ErrAddressEmpty,
5689
},
5790
{
5891
Description: "No bucket",
59-
Input: &BasicClientConfig{
60-
Address: "example.com",
92+
Input: BasicClientConfig{
93+
Address: "example.com",
94+
HTTPClient: arrangehttp.ClientConfig{},
6195
},
96+
Transport: http.DefaultTransport,
6297
ExpectedErr: ErrBucketEmpty,
6398
},
6499
{
65-
Description: "All default values",
66-
Input: &BasicClientConfig{
100+
Description: "Nil http transport",
101+
Input: BasicClientConfig{
102+
Address: "example.com",
103+
Bucket: "bucket-name",
104+
HTTPClient: arrangehttp.ClientConfig{},
105+
},
106+
Transport: nil,
107+
ExpectedErr: ErrHttpTransport,
108+
},
109+
{
110+
Description: "Bad http client config",
111+
Input: BasicClientConfig{
67112
Address: "example.com",
68113
Bucket: "bucket-name",
114+
HTTPClient: arrangehttp.ClientConfig{
115+
TLS: &arrangetls.Config{
116+
Certificates: arrangetls.ExternalCertificates{arrangetls.ExternalCertificate{CertificateFile: "junk-crt"}},
117+
},
118+
},
69119
},
70-
ExpectedConfig: allDefaultsCaseConfig,
120+
Transport: http.DefaultTransport,
121+
ExpectedErr: ErrHttpClientConfig,
71122
},
72123
{
73124
Description: "All defined",
74-
Input: &BasicClientConfig{
75-
Address: "example.com",
76-
Bucket: "amazing-bucket",
125+
Input: BasicClientConfig{
126+
Address: "example.com",
127+
Bucket: "amazing-bucket",
128+
HTTPClient: arrangehttp.ClientConfig{},
77129
},
78-
ExpectedConfig: allDefinedCaseConfig,
130+
Transport: http.DefaultTransport,
79131
},
80132
}
81133

82134
for _, tc := range tcs {
83135
t.Run(tc.Description, func(t *testing.T) {
136+
opts := append(
137+
defaultOptions,
138+
Address(tc.Input.Address),
139+
Bucket(tc.Input.Bucket),
140+
HTTPClient(tc.Input.HTTPClient),
141+
HTTPTransport(tc.Transport),
142+
defaultValidateOptions,
143+
)
144+
84145
assert := assert.New(t)
85-
err := validateBasicConfig(tc.Input)
86-
assert.Equal(tc.ExpectedErr, err)
87-
if tc.ExpectedErr == nil {
88-
assert.Equal(tc.ExpectedConfig, tc.Input)
146+
client := BasicClient{}
147+
errs := opts.apply(&client)
148+
if tc.ExpectedErr != nil {
149+
assert.ErrorIs(errs, tc.ExpectedErr)
150+
151+
return
89152
}
153+
154+
assert.NoError(errs)
155+
assert.Equal(tc.Input.Address+storeAPIPath, client.storeBaseURL)
156+
assert.Equal(tc.Input.Bucket, client.bucket)
157+
assert.Equal(tc.Transport, client.client.Transport)
158+
assert.NotNil(client.client)
90159
})
91160
}
92161
}
@@ -174,10 +243,12 @@ func TestSendRequest(t *testing.T) {
174243
server := httptest.NewServer(echoHandler)
175244
defer server.Close()
176245

177-
client, err := NewBasicClient(BasicClientConfig{
178-
Address: "example.com",
179-
Bucket: "bucket-name",
180-
})
246+
opts := Options{
247+
Address("example.com"),
248+
Bucket("bucket-name"),
249+
HTTPClient(arrangehttp.ClientConfig{}),
250+
}
251+
client, err := NewBasicClient(opts)
181252

182253
acquirer.On("Acquire").Return(tc.MockAuth, tc.MockError)
183254
client.auth = acquirer
@@ -285,10 +356,12 @@ func TestGetItems(t *testing.T) {
285356
rw.Write(tc.ResponsePayload)
286357
}))
287358

288-
client, err := NewBasicClient(BasicClientConfig{
289-
Address: server.URL,
290-
Bucket: bucket,
291-
})
359+
opts := Options{
360+
Address(server.URL),
361+
Bucket(bucket),
362+
HTTPClient(arrangehttp.ClientConfig{}),
363+
}
364+
client, err := NewBasicClient(opts)
292365

293366
require.Nil(err)
294367

@@ -440,10 +513,12 @@ func TestPushItem(t *testing.T) {
440513
}
441514
}))
442515

443-
client, err := NewBasicClient(BasicClientConfig{
444-
Address: server.URL,
445-
Bucket: bucket,
446-
})
516+
opts := Options{
517+
Address(server.URL),
518+
Bucket(bucket),
519+
HTTPClient(arrangehttp.ClientConfig{}),
520+
}
521+
client, err := NewBasicClient(opts)
447522

448523
acquirer.On("Acquire").Return(tc.MockAuth, tc.MockError)
449524
client.auth = acquirer
@@ -552,10 +627,12 @@ func TestRemoveItem(t *testing.T) {
552627
rw.Write(tc.ResponsePayload)
553628
}))
554629

555-
client, err := NewBasicClient(BasicClientConfig{
556-
Address: server.URL,
557-
Bucket: bucket,
558-
})
630+
opts := Options{
631+
Address(server.URL),
632+
Bucket(bucket),
633+
HTTPClient(arrangehttp.ClientConfig{}),
634+
}
635+
client, err := NewBasicClient(opts)
559636

560637
acquirer.On("Acquire").Return(tc.MockAuth, tc.MockError)
561638
client.auth = acquirer

0 commit comments

Comments
 (0)