From 9f83553f22f2c21ecd15012791ec4e3f43f7a8f3 Mon Sep 17 00:00:00 2001 From: John Sharpe Date: Wed, 28 Aug 2024 11:47:37 +0100 Subject: [PATCH] Added tags to the client and testing (#179) --- .gitignore | 2 +- client.go | 3 + service/regions/service.go | 1 - service/tags/model.go | 21 ++ service/tags/service.go | 83 ++++++++ tags_test.go | 410 +++++++++++++++++++++++++++++++++++++ 6 files changed, 518 insertions(+), 2 deletions(-) create mode 100644 service/tags/model.go create mode 100644 service/tags/service.go create mode 100644 tags_test.go diff --git a/.gitignore b/.gitignore index 197c610..8095ca7 100644 --- a/.gitignore +++ b/.gitignore @@ -226,7 +226,7 @@ Sessionx.vim # Temporary .netrwhist # Auto-generated tag files -tags +# tags # Persistent undo [._]*.un~ diff --git a/client.go b/client.go index 71347c4..edf5599 100644 --- a/client.go +++ b/client.go @@ -28,6 +28,7 @@ import ( "github.com/RedisLabs/rediscloud-go-api/service/pricing" "github.com/RedisLabs/rediscloud-go-api/service/regions" "github.com/RedisLabs/rediscloud-go-api/service/subscriptions" + "github.com/RedisLabs/rediscloud-go-api/service/tags" "github.com/RedisLabs/rediscloud-go-api/service/transit_gateway/attachments" ) @@ -42,6 +43,7 @@ type Client struct { Maintenance *maintenance.API Pricing *pricing.API TransitGatewayAttachments *attachments.API + Tags *tags.API // fixed FixedPlans *plans.API FixedSubscriptions *fixedSubscriptions.API @@ -89,6 +91,7 @@ func NewClient(configs ...Option) (*Client, error) { Maintenance: maintenance.NewAPI(client, t, config.logger), Pricing: pricing.NewAPI(client), TransitGatewayAttachments: attachments.NewAPI(client, t, config.logger), + Tags: tags.NewAPI(client), // fixed FixedPlans: plans.NewAPI(client, config.logger), FixedPlanSubscriptions: plan_subscriptions.NewAPI(client, config.logger), diff --git a/service/regions/service.go b/service/regions/service.go index 21e35e1..0c5c3b5 100644 --- a/service/regions/service.go +++ b/service/regions/service.go @@ -17,7 +17,6 @@ type Log interface { type HttpClient interface { Get(ctx context.Context, name, path string, responseBody interface{}) error Post(ctx context.Context, name, path string, requestBody interface{}, responseBody interface{}) error - Put(ctx context.Context, name, path string, requestBody interface{}, responseBody interface{}) error DeleteWithQuery(ctx context.Context, name, path string, requestBody interface{}, responseBody interface{}) error } diff --git a/service/tags/model.go b/service/tags/model.go new file mode 100644 index 0000000..4634497 --- /dev/null +++ b/service/tags/model.go @@ -0,0 +1,21 @@ +package tags + +import "fmt" + +type AllTags struct { + Tags *[]*Tag `json:"tags,omitempty"` +} + +type Tag struct { + Key *string `json:"key,omitempty"` + Value *string `json:"value,omitempty"` +} + +type NotFound struct { + subId int + dbId int +} + +func (f *NotFound) Error() string { + return fmt.Sprintf("database %d in subscription %d not found", f.dbId, f.subId) +} diff --git a/service/tags/service.go b/service/tags/service.go new file mode 100644 index 0000000..db00276 --- /dev/null +++ b/service/tags/service.go @@ -0,0 +1,83 @@ +package tags + +import ( + "context" + "fmt" + "net/http" + + "github.com/RedisLabs/rediscloud-go-api/internal" +) + +type HttpClient interface { + Get(ctx context.Context, name, path string, responseBody interface{}) error + Put(ctx context.Context, name, path string, requestBody interface{}, responseBody interface{}) error +} + +type API struct { + client HttpClient +} + +func NewAPI(client HttpClient) *API { + return &API{client: client} +} + +func (a *API) Get(ctx context.Context, subscription int, database int) (*AllTags, error) { + message := fmt.Sprintf("get tags for database %d in subscription %d", subscription, database) + address := fmt.Sprintf("/subscriptions/%d/databases/%d/tags", subscription, database) + tags, err := a.get(ctx, message, address) + if err != nil { + return nil, wrap404Error(subscription, database, err) + } + return tags, nil +} + +func (a *API) GetFixed(ctx context.Context, subscription int, database int) (*AllTags, error) { + message := fmt.Sprintf("get tags for fixed database %d in subscription %d", subscription, database) + address := fmt.Sprintf("fixed/subscriptions/%d/databases/%d/tags", subscription, database) + tags, err := a.get(ctx, message, address) + if err != nil { + return nil, wrap404Error(subscription, database, err) + } + return tags, nil +} + +func (a *API) Put(ctx context.Context, subscription int, database int, tags AllTags) error { + message := fmt.Sprintf("update tags for database %d in subscription %d", subscription, database) + address := fmt.Sprintf("/subscriptions/%d/databases/%d/tags", subscription, database) + err := a.put(ctx, message, address, tags) + if err != nil { + return wrap404Error(subscription, database, err) + } + return nil +} + +func (a *API) PutFixed(ctx context.Context, subscription int, database int, tags AllTags) error { + message := fmt.Sprintf("update tags for fixed database %d in subscription %d", subscription, database) + address := fmt.Sprintf("fixed/subscriptions/%d/databases/%d/tags", subscription, database) + err := a.put(ctx, message, address, tags) + if err != nil { + return wrap404Error(subscription, database, err) + } + return nil +} + +func (a *API) get(ctx context.Context, message string, address string) (*AllTags, error) { + var tags AllTags + err := a.client.Get(ctx, message, address, &tags) + if err != nil { + return nil, err + } + return &tags, nil +} + +func (a *API) put(ctx context.Context, message string, address string, tags AllTags) error { + var tagsResponse AllTags + return a.client.Put(ctx, message, address, tags, &tagsResponse) +} + +func wrap404Error(subId int, dbId int, err error) error { + if v, ok := err.(*internal.HTTPError); ok && v.StatusCode == http.StatusNotFound { + return &NotFound{subId: subId, dbId: dbId} + } + return err +} diff --git a/tags_test.go b/tags_test.go new file mode 100644 index 0000000..a2b9711 --- /dev/null +++ b/tags_test.go @@ -0,0 +1,410 @@ +package rediscloud_api + +import ( + "context" + "net/http/httptest" + "testing" + + "github.com/RedisLabs/rediscloud-go-api/redis" + "github.com/RedisLabs/rediscloud-go-api/service/tags" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// Pro/Active-Active + +// When you first create a database, the tags block is mostly empty +func TestGetTagsNonExistent(t *testing.T) { + server := httptest.NewServer( + testServer( + "key", + "secret", + getRequest( + t, + "/subscriptions/115251/databases/51068559/tags", + `{ + "links": [ + { + "href": "https://api-staging.qa.redislabs.com/v1/subscriptions/115251/databases/51068559/tags", + "type": "GET", + "rel": "self" + } + ] + }`, + ), + ), + ) + + subject, err := clientFromTestServer(server, "key", "secret") + require.NoError(t, err) + + actual, err := subject.Tags.Get(context.TODO(), 115251, 51068559) + require.NoError(t, err) + + assert.Equal(t, &tags.AllTags{}, actual) +} + +func TestGetTagsEmpty(t *testing.T) { + server := httptest.NewServer( + testServer( + "key", + "secret", + getRequest( + t, + "/subscriptions/115251/databases/51068559/tags", + `{ + "tags": [], + "links": [ + { + "href": "https://api-staging.qa.redislabs.com/v1/subscriptions/115251/databases/51068559/tags", + "type": "GET", + "rel": "self" + } + ], + "accountId": 69369 + }`, + ), + ), + ) + + subject, err := clientFromTestServer(server, "key", "secret") + require.NoError(t, err) + + actual, err := subject.Tags.Get(context.TODO(), 115251, 51068559) + require.NoError(t, err) + + assert.Equal(t, &tags.AllTags{ + Tags: &[]*tags.Tag{}, + }, actual) +} + +func TestGetTags(t *testing.T) { + server := httptest.NewServer( + testServer( + "key", + "secret", + getRequest( + t, + "/subscriptions/115251/databases/51068559/tags", + `{ + "tags": [ + { + "links": [], + "key": "environment", + "value": "production", + "createdAt": "2024-08-28T08:59:31.966Z", + "updatedAt": "2024-08-28T08:59:31.966Z" + }, + { + "links": [], + "key": "department", + "value": "finance", + "createdAt": "2024-08-28T08:59:31.966Z", + "updatedAt": "2024-08-28T08:59:31.966Z" + } + ], + "links": [ + { + "href": "https://api-staging.qa.redislabs.com/v1/subscriptions/115251/databases/51068559/tags", + "type": "GET", + "rel": "self" + } + ], + "accountId": 69369 + }`, + ), + ), + ) + + subject, err := clientFromTestServer(server, "key", "secret") + require.NoError(t, err) + + actual, err := subject.Tags.Get(context.TODO(), 115251, 51068559) + require.NoError(t, err) + + assert.Equal(t, &tags.AllTags{ + Tags: &[]*tags.Tag{ + { + Key: redis.String("environment"), + Value: redis.String("production"), + }, + { + Key: redis.String("department"), + Value: redis.String("finance"), + }, + }, + }, actual) +} + +func TestPutTags(t *testing.T) { + server := httptest.NewServer( + testServer( + "key", + "secret", + putRequest( + t, + "/subscriptions/115251/databases/51068559/tags", + `{ + "tags": [ + { + "key": "environment", + "value": "production" + }, + { + "key": "department", + "value": "finance" + } + ] + }`, + `{ + "tags": [ + { + "links": [], + "key": "environment", + "value": "production", + "createdAt": "2024-08-28T08:59:31.966Z", + "updatedAt": "2024-08-28T08:59:31.966Z" + }, + { + "links": [], + "key": "department", + "value": "finance", + "createdAt": "2024-08-28T08:59:31.966Z", + "updatedAt": "2024-08-28T08:59:31.966Z" + } + ], + "links": [ + { + "href": "https://api-staging.qa.redislabs.com/v1/subscriptions/115251/databases/51068559/tags", + "type": "PUT", + "rel": "self" + } + ], + "accountId": 69369 + }`, + ), + ), + ) + + subject, err := clientFromTestServer(server, "key", "secret") + require.NoError(t, err) + + err = subject.Tags.Put( + context.TODO(), + 115251, + 51068559, + tags.AllTags{ + Tags: &[]*tags.Tag{ + { + Key: redis.String("environment"), + Value: redis.String("production"), + }, + { + Key: redis.String("department"), + Value: redis.String("finance"), + }, + }, + }, + ) + + require.NoError(t, err) +} + +// Fixed + +// When you first create a database, the tags block is mostly empty +func TestFixedGetTagsNonExistent(t *testing.T) { + server := httptest.NewServer( + testServer( + "key", + "secret", + getRequest( + t, + "/fixed/subscriptions/115229/databases/51068525/tags", + `{ + "links": [ + { + "href": "https://api-staging.qa.redislabs.com/v1/fixed/subscriptions/115229/databases/51068525/tags", + "type": "GET", + "rel": "self" + } + ] + }`, + ), + ), + ) + + subject, err := clientFromTestServer(server, "key", "secret") + require.NoError(t, err) + + actual, err := subject.Tags.GetFixed(context.TODO(), 115229, 51068525) + require.NoError(t, err) + + assert.Equal(t, &tags.AllTags{}, actual) +} + +func TestFixedGetTagsEmpty(t *testing.T) { + server := httptest.NewServer( + testServer( + "key", + "secret", + getRequest( + t, + "/fixed/subscriptions/115229/databases/51068525/tags", + `{ + "tags": [], + "links": [ + { + "href": "https://api-staging.qa.redislabs.com/v1/fixed/subscriptions/115229/databases/51068525/tags", + "type": "GET", + "rel": "self" + } + ], + "accountId": 69369 + }`, + ), + ), + ) + + subject, err := clientFromTestServer(server, "key", "secret") + require.NoError(t, err) + + actual, err := subject.Tags.GetFixed(context.TODO(), 115229, 51068525) + require.NoError(t, err) + + assert.Equal(t, &tags.AllTags{ + Tags: &[]*tags.Tag{}, + }, actual) +} + +func TestFixedGetTags(t *testing.T) { + server := httptest.NewServer( + testServer( + "key", + "secret", + getRequest( + t, + "/fixed/subscriptions/115229/databases/51068525/tags", + `{ + "tags": [ + { + "links": [], + "key": "environment", + "value": "production", + "createdAt": "2024-08-27T10:34:19.395Z", + "updatedAt": "2024-08-27T10:34:19.395Z" + }, + { + "links": [], + "key": "costcenter", + "value": "0700", + "createdAt": "2024-08-27T10:34:19.395Z", + "updatedAt": "2024-08-27T10:34:19.395Z" + } + ], + "links": [ + { + "href": "https://api-staging.qa.redislabs.com/v1/fixed/subscriptions/115229/databases/51068525/tags", + "type": "GET", + "rel": "self" + } + ], + "accountId": 69369 + }`, + ), + ), + ) + + subject, err := clientFromTestServer(server, "key", "secret") + require.NoError(t, err) + + actual, err := subject.Tags.GetFixed(context.TODO(), 115229, 51068525) + require.NoError(t, err) + + assert.Equal(t, &tags.AllTags{ + Tags: &[]*tags.Tag{ + { + Key: redis.String("environment"), + Value: redis.String("production"), + }, + { + Key: redis.String("costcenter"), + Value: redis.String("0700"), + }, + }, + }, actual) +} + +func TestFixedPutTags(t *testing.T) { + server := httptest.NewServer( + testServer( + "key", + "secret", + putRequest( + t, + "/fixed/subscriptions/115229/databases/51068525/tags", + `{ + "tags": [ + { + "key": "environment", + "value": "production" + }, + { + "key": "costCenter", + "value": "0700" + } + ] + }`, + `{ + "tags": [ + { + "links": [], + "key": "environment", + "value": "production", + "createdAt": "2024-08-27T10:34:19.395Z", + "updatedAt": "2024-08-27T10:34:19.395Z" + }, + { + "links": [], + "key": "costcenter", + "value": "0700", + "createdAt": "2024-08-27T10:34:19.395Z", + "updatedAt": "2024-08-27T10:34:19.395Z" + } + ], + "links": [ + { + "href": "https://api-staging.qa.redislabs.com/v1/fixed/subscriptions/115229/databases/51068525/tags", + "type": "PUT", + "rel": "self" + } + ], + "accountId": 69369 + }`, + ), + ), + ) + + subject, err := clientFromTestServer(server, "key", "secret") + require.NoError(t, err) + + err = subject.Tags.PutFixed( + context.TODO(), + 115229, + 51068525, + tags.AllTags{ + Tags: &[]*tags.Tag{ + { + Key: redis.String("environment"), + Value: redis.String("production"), + }, + { + Key: redis.String("costCenter"), + Value: redis.String("0700"), + }, + }, + }, + ) + + require.NoError(t, err) +}