Skip to content

Commit 7344500

Browse files
committed
Rewrite list database API to support pagination
Also refactor all API models: * `s/[Ii]d/ID/` * Add a basic `String` func to all model structs to aid debugging and logging - currently using a basic JSON format * Change all attributes in JSON structs to pointers with `omitempty` set * Add utility functions to covert between pointers and non-pointers
1 parent cac15fb commit 7344500

20 files changed

+656
-217
lines changed

account_test.go

+8-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"net/http/httptest"
66
"testing"
77

8+
"github.com/RedisLabs/rediscloud-go-api/redis"
89
"github.com/RedisLabs/rediscloud-go-api/service/account"
910
"github.com/stretchr/testify/assert"
1011
"github.com/stretchr/testify/require"
@@ -45,16 +46,16 @@ func TestAccount_ListPayments(t *testing.T) {
4546
actual, err := subject.Account.ListPaymentMethods(context.TODO())
4647
require.NoError(t, err)
4748

48-
assert.ElementsMatch(t, []account.PaymentMethod{
49+
assert.ElementsMatch(t, []*account.PaymentMethod{
4950
{
50-
Id: 123,
51-
Type: "Visa",
52-
CreditCardEndsWith: 9876,
51+
ID: redis.Int(123),
52+
Type: redis.String("Visa"),
53+
CreditCardEndsWith: redis.Int(9876),
5354
},
5455
{
55-
Id: 654,
56-
Type: "Mastercard",
57-
CreditCardEndsWith: 4567,
56+
ID: redis.Int(654),
57+
Type: redis.String("Mastercard"),
58+
CreditCardEndsWith: redis.Int(4567),
5859
},
5960
}, actual)
6061
}

cloud_account_test.go

+18-17
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"net/http/httptest"
77
"testing"
88

9+
"github.com/RedisLabs/rediscloud-go-api/redis"
910
"github.com/RedisLabs/rediscloud-go-api/service/cloud_accounts"
1011
"github.com/stretchr/testify/assert"
1112
"github.com/stretchr/testify/require"
@@ -54,13 +55,13 @@ func TestCloudAccount_Create(t *testing.T) {
5455
require.NoError(t, err)
5556

5657
actual, err := subject.CloudAccount.Create(context.TODO(), cloud_accounts.CreateCloudAccount{
57-
AccessKeyId: "123456",
58-
AccessSecretKey: "765432",
59-
ConsoleUsername: "foo",
60-
ConsolePassword: "bar",
61-
Name: "cumulus nimbus",
62-
Provider: "AWS",
63-
SignInLoginUrl: "http://example.org/foo",
58+
AccessKeyID: redis.String("123456"),
59+
AccessSecretKey: redis.String("765432"),
60+
ConsoleUsername: redis.String("foo"),
61+
ConsolePassword: redis.String("bar"),
62+
Name: redis.String("cumulus nimbus"),
63+
Provider: redis.String("AWS"),
64+
SignInLoginUrl: redis.String("http://example.org/foo"),
6465
})
6566
require.NoError(t, err)
6667
assert.Equal(t, expected, actual)
@@ -106,12 +107,12 @@ func TestCloudAccount_Update(t *testing.T) {
106107
require.NoError(t, err)
107108

108109
err = subject.CloudAccount.Update(context.TODO(), 642, cloud_accounts.UpdateCloudAccount{
109-
AccessKeyId: "tfvbjuyg",
110-
AccessSecretKey: "gyujmnbvgy",
111-
ConsoleUsername: "baz",
112-
ConsolePassword: "bar",
113-
Name: "stratocumulus",
114-
SignInLoginUrl: "http://example.org/foo",
110+
AccessKeyID: redis.String("tfvbjuyg"),
111+
AccessSecretKey: redis.String("gyujmnbvgy"),
112+
ConsoleUsername: redis.String("baz"),
113+
ConsolePassword: redis.String("bar"),
114+
Name: redis.String("stratocumulus"),
115+
SignInLoginUrl: redis.String("http://example.org/foo"),
115116
})
116117
require.NoError(t, err)
117118
}
@@ -138,10 +139,10 @@ func TestCloudAccount_Get(t *testing.T) {
138139
require.NoError(t, err)
139140

140141
assert.Equal(t, &cloud_accounts.CloudAccount{
141-
Name: "Frank",
142-
Provider: "GCP",
143-
Status: "active",
144-
AccessKeyId: "keyId",
142+
Name: redis.String("Frank"),
143+
Provider: redis.String("GCP"),
144+
Status: redis.String("active"),
145+
AccessKeyID: redis.String("keyId"),
145146
}, actual)
146147
}
147148

database_test.go

+48-32
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import (
66
"testing"
77
"time"
88

9+
"github.com/RedisLabs/rediscloud-go-api/redis"
910
"github.com/RedisLabs/rediscloud-go-api/service/databases"
1011
"github.com/stretchr/testify/assert"
1112
"github.com/stretchr/testify/require"
1213
)
1314

1415
func TestDatabase_List(t *testing.T) {
15-
s := httptest.NewServer(testServer("apiKey", "secret", getRequest(t, "/subscriptions/23456/databases", `{
16+
s := httptest.NewServer(testServer("apiKey", "secret", getRequest(t, "/subscriptions/23456/databases?limit=100&offset=0", `{
1617
"accountId": 2,
1718
"subscription": [
1819
{
@@ -46,25 +47,26 @@ func TestDatabase_List(t *testing.T) {
4647
subject, err := NewClient(BaseUrl(s.URL), Auth("apiKey", "secret"), Transporter(s.Client().Transport))
4748
require.NoError(t, err)
4849

49-
actual, err := subject.Database.List(context.TODO(), 23456)
50-
require.NoError(t, err)
50+
actual := subject.Database.List(context.TODO(), 23456)
5151

52+
assert.True(t, actual.Next())
53+
assert.NoError(t, actual.Err())
5254
assert.ElementsMatch(t, []*databases.Database{
5355
{
54-
ID: 42,
55-
Name: "first-example",
56-
Protocol: "redis",
57-
Provider: "AWS",
58-
Region: "eu-west-1",
56+
ID: redis.Int(42),
57+
Name: redis.String("first-example"),
58+
Protocol: redis.String("redis"),
59+
Provider: redis.String("AWS"),
60+
Region: redis.String("eu-west-1"),
5961
},
6062
{
61-
ID: 43,
62-
Name: "second-example",
63-
Protocol: "redis",
64-
Provider: "AWS",
65-
Region: "eu-west-1",
63+
ID: redis.Int(43),
64+
Name: redis.String("second-example"),
65+
Protocol: redis.String("redis"),
66+
Provider: redis.String("AWS"),
67+
Region: redis.String("eu-west-1"),
6668
},
67-
}, actual)
69+
}, actual.Value())
6870
}
6971

7072
func TestDatabase_Get(t *testing.T) {
@@ -130,24 +132,38 @@ func TestDatabase_Get(t *testing.T) {
130132
require.NoError(t, err)
131133

132134
assert.Equal(t, &databases.Database{
133-
ID: 98765,
134-
Name: "Example",
135-
Protocol: "redis",
136-
Provider: "AWS",
137-
Region: "eu-west-1",
138-
Status: "active",
139-
MemoryLimitInGb: 7,
140-
MemoryUsedInMb: 5,
141-
SupportOSSClusterApi: true,
142-
DataPersistence: "none",
143-
Replication: false,
144-
DataEvictionPolicy: "volatile-random",
145-
ActivatedOn: time.Date(2020, 11, 3, 9, 3, 30, 0, time.UTC),
146-
LastModified: time.Date(2020, 11, 3, 9, 3, 30, 0, time.UTC),
147-
MemoryStorage: "ram",
148-
PrivateEndpoint: "example.net:16668",
149-
PublicEndpoint: "example.com:16668",
150-
RedisVersionCompliance: "6.0.5",
135+
ID: redis.Int(98765),
136+
Name: redis.String("Example"),
137+
Protocol: redis.String("redis"),
138+
Provider: redis.String("AWS"),
139+
Region: redis.String("eu-west-1"),
140+
Status: redis.String("active"),
141+
MemoryLimitInGb: redis.Float64(7),
142+
MemoryUsedInMb: redis.Float64(5),
143+
SupportOSSClusterApi: redis.Bool(true),
144+
DataPersistence: redis.String("none"),
145+
Replication: redis.Bool(false),
146+
DataEvictionPolicy: redis.String("volatile-random"),
147+
ActivatedOn: redis.Time(time.Date(2020, 11, 3, 9, 3, 30, 0, time.UTC)),
148+
LastModified: redis.Time(time.Date(2020, 11, 3, 9, 3, 30, 0, time.UTC)),
149+
MemoryStorage: redis.String("ram"),
150+
PrivateEndpoint: redis.String("example.net:16668"),
151+
PublicEndpoint: redis.String("example.com:16668"),
152+
RedisVersionCompliance: redis.String("6.0.5"),
153+
ThroughputMeasurement: &databases.Throughput{
154+
By: redis.String("operations-per-second"),
155+
Value: redis.Int(10_000),
156+
},
157+
Clustering: &databases.Clustering{
158+
NumberOfShards: redis.Int(1),
159+
},
160+
Security: &databases.Security{
161+
SslClientAuthentication: redis.Bool(false),
162+
SourceIps: redis.StringSlice("0.0.0.0/0"),
163+
Password: redis.String("test"),
164+
},
165+
Modules: []*databases.Module{},
166+
Alerts: []*databases.Alert{},
151167
}, actual)
152168
}
153169

internal/http_client.go

+22-2
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,11 @@ func (c *HttpClient) withoutRequestBody(ctx context.Context, method, name, path
6161

6262
if response.StatusCode > 299 {
6363
body, _ := ioutil.ReadAll(response.Body)
64-
return fmt.Errorf("failed to %s: %d - %s", name, response.StatusCode, body)
64+
return &HttpError{
65+
Name: name,
66+
StatusCode: response.StatusCode,
67+
Body: body,
68+
}
6569
}
6670

6771
if err := json.NewDecoder(response.Body).Decode(&responseBody); err != nil {
@@ -98,7 +102,11 @@ func (c *HttpClient) withRequestBody(ctx context.Context, method, name, path str
98102

99103
if response.StatusCode > 299 {
100104
body, _ := ioutil.ReadAll(response.Body)
101-
return fmt.Errorf("failed to %s: %d - %s", name, response.StatusCode, body)
105+
return &HttpError{
106+
Name: name,
107+
StatusCode: response.StatusCode,
108+
Body: body,
109+
}
102110
}
103111

104112
if err := json.NewDecoder(response.Body).Decode(&responseBody); err != nil {
@@ -107,3 +115,15 @@ func (c *HttpClient) withRequestBody(ctx context.Context, method, name, path str
107115

108116
return nil
109117
}
118+
119+
type HttpError struct {
120+
Name string
121+
StatusCode int
122+
Body []byte
123+
}
124+
125+
func (h *HttpError) Error() string {
126+
return fmt.Sprintf("failed to %s: %d - %s", h.Name, h.StatusCode, h.Body)
127+
}
128+
129+
var _ error = &HttpError{}

internal/to_string.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package internal
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
)
7+
8+
func ToString(o interface{}) string {
9+
output, err := json.Marshal(o)
10+
if err != nil {
11+
return fmt.Sprintf("%#v", o)
12+
}
13+
return string(output)
14+
}

redis/type_coversion.go

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package redis
2+
3+
import "time"
4+
5+
func Int(i int) *int {
6+
return &i
7+
}
8+
9+
func IntValue(i *int) int {
10+
if i == nil {
11+
return 0
12+
}
13+
return *i
14+
}
15+
16+
func String(s string) *string {
17+
return &s
18+
}
19+
20+
func StringValue(s *string) string {
21+
if s == nil {
22+
return ""
23+
}
24+
return *s
25+
}
26+
27+
func Float64(f float64) *float64 {
28+
return &f
29+
}
30+
31+
func Float64Value(f *float64) float64 {
32+
if f == nil {
33+
return 0
34+
}
35+
return *f
36+
}
37+
38+
func Bool(b bool) *bool {
39+
return &b
40+
}
41+
42+
func BoolValue(b *bool) bool {
43+
if b == nil {
44+
return false
45+
}
46+
return *b
47+
}
48+
49+
func Time(d time.Time) *time.Time {
50+
return &d
51+
}
52+
53+
func TimeValue(d *time.Time) time.Time {
54+
if d == nil {
55+
return time.Time{}
56+
}
57+
return *d
58+
}
59+
60+
func StringSlice(ss ...string) []*string {
61+
var ret []*string
62+
for _, s := range ss {
63+
ret = append(ret, String(s))
64+
}
65+
return ret
66+
}
67+
68+
func StringSliceValue(ss ...*string) []string {
69+
var ret []string
70+
for _, s := range ss {
71+
if s != nil {
72+
ret = append(ret, StringValue(s))
73+
}
74+
}
75+
return ret
76+
}

service/account/model.go

+14-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,21 @@
11
package account
22

3+
import "github.com/RedisLabs/rediscloud-go-api/internal"
4+
35
type paymentMethods struct {
4-
PaymentMethods []PaymentMethod `json:"paymentMethods"`
6+
PaymentMethods []*PaymentMethod `json:"paymentMethods,omitempty"`
7+
}
8+
9+
func (o paymentMethods) String() string {
10+
return internal.ToString(o)
511
}
612

713
type PaymentMethod struct {
8-
Id int `json:"id"`
9-
Type string `json:"type"`
10-
CreditCardEndsWith int `json:"creditCardEndsWith"`
14+
ID *int `json:"id,omitempty"`
15+
Type *string `json:"type,omitempty"`
16+
CreditCardEndsWith *int `json:"creditCardEndsWith,omitempty"`
17+
}
18+
19+
func (o PaymentMethod) String() string {
20+
return internal.ToString(o)
1121
}

service/account/service.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func NewApi(client HttpClient) *Api {
1717
}
1818

1919
// ListPaymentMethods will return the list of available payment methods.
20-
func (a *Api) ListPaymentMethods(ctx context.Context) ([]PaymentMethod, error) {
20+
func (a *Api) ListPaymentMethods(ctx context.Context) ([]*PaymentMethod, error) {
2121
var body paymentMethods
2222
if err := a.client.Get(ctx, "list payment methods", "/payment-methods", &body); err != nil {
2323
return nil, err

0 commit comments

Comments
 (0)