From 2a96752cc28041bccb8dd47a2f6f7b9057d5bafc Mon Sep 17 00:00:00 2001 From: Ye Chen Date: Fri, 11 Aug 2023 16:27:28 -0400 Subject: [PATCH 1/8] add betas --- betas.go | 99 +++++++++++++++++++ go.mod | 2 +- go.sum | 2 + test/integration/betas_test.go | 24 +++++ .../fixtures/TestBetaPrograms_List.yaml | 60 +++++++++++ 5 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 betas.go create mode 100644 test/integration/betas_test.go create mode 100644 test/integration/fixtures/TestBetaPrograms_List.yaml diff --git a/betas.go b/betas.go new file mode 100644 index 000000000..04cd89f8b --- /dev/null +++ b/betas.go @@ -0,0 +1,99 @@ +package linodego + +import ( + "context" + "encoding/json" + "fmt" + "net/url" + "time" + + "github.com/go-resty/resty/v2" + "github.com/linode/linodego/internal/parseabletime" +) + +// Beta Program is a new product or service that is not generally available to all Akamai customers. +// Users must enroll into a beta in order to access the functionality. +type BetaProgram struct { + Label string `json:"label"` + ID string `json:"id"` + Description string `json:"description"` + + // Start date of the beta program. + StartDT *time.Time `json"-"` + + // End date of the beta program. + EndDT *time.Time `json"-"` + + // Greenlight is a program that allows customers to gain access to + // certain beta programs and to collect direct feedback from those customers. + GreenlightOnly bool `json:"greenlight_only"` + + // Link to product marketing page for the beta program. + MoreInfo string `json:"more_info"` +} + +// BetasPagedResponse represents a paginated Beta Programs API response +type BetasPagedResponse struct { + *PageOptions + Data []BetaProgram `json:"data"` +} + +// endpoint gets the endpoint URL for BetaProgram +func (BetasPagedResponse) endpoint(_ ...any) string { + return "/betas" +} + +// UnmarshalJSON implements the json.Unmarshaler interface +func (beta *BetaProgram) UnmarshalJSON(b []byte) error { + type Mask BetaProgram + + p := struct { + *Mask + StartDT *parseabletime.ParseableTime `json:"start_dt"` + EndDT *parseabletime.ParseableTime `json:"end_dt"` + }{ + Mask: (*Mask)(beta), + } + + if err := json.Unmarshal(b, &p); err != nil { + return err + } + + beta.StartDT = (*time.Time)(p.StartDT) + beta.EndDT = (*time.Time)(p.EndDT) + + return nil +} + +func (resp *BetasPagedResponse) castResult(r *resty.Request, e string) (int, int, error) { + res, err := coupleAPIErrors(r.SetResult(BetasPagedResponse{}).Get(e)) + if err != nil { + return 0, 0, err + } + castedRes := res.Result().(*BetasPagedResponse) + resp.Data = append(resp.Data, castedRes.Data...) + return castedRes.Pages, castedRes.Results, nil +} + +// ListBetaPrograms lists active beta programs +func (c *Client) ListBetaPrograms(ctx context.Context, opts *ListOptions) ([]BetaProgram, error) { + response := BetasPagedResponse{} + err := c.listHelper(ctx, &response, opts) + if err != nil { + return nil, err + } + return response.Data, nil +} + +// GetBetaProgram gets the beta program's detail with the ID +func (c *Client) GetBetaProgram(ctx context.Context, betaID string) (*BetaProgram, error) { + req := c.R(ctx).SetResult(&BetaProgram{}) + betaID = url.PathEscape(betaID) + e := fmt.Sprintf("betas/%s", betaID) + r, err := coupleAPIErrors(req.Get(e)) + if err != nil { + return nil, err + } + + return r.Result().(*BetaProgram), nil +} diff --git a/go.mod b/go.mod index 3613cf9f5..95e8d3a1e 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/linode/linodego require ( github.com/go-resty/resty/v2 v2.7.0 - github.com/google/go-cmp v0.5.7 + github.com/google/go-cmp v0.5.9 github.com/stretchr/testify v1.7.1 // indirect gopkg.in/ini.v1 v1.66.6 ) diff --git a/go.sum b/go.sum index 9a6afd76f..9bd988426 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPr github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= diff --git a/test/integration/betas_test.go b/test/integration/betas_test.go new file mode 100644 index 000000000..14ac920ea --- /dev/null +++ b/test/integration/betas_test.go @@ -0,0 +1,24 @@ +package integration + +import ( + "context" + "testing" + + "github.com/linode/linodego" +) + +func TestBetaPrograms_List(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestBetaPrograms_List") + defer teardown() + + betas, err := client.ListBetaPrograms(context.Background(), &linodego.ListOptions{}) + if err != nil { + t.Errorf("Error getting Events, expected struct, got error %v", err) + } + + // TODO: assert data after actual data can be retrieved from API. + // No data is expected to be returned temporarily. + if len(betas) != 0 { + t.Errorf("Expected to see none beta program returned.") + } +} diff --git a/test/integration/fixtures/TestBetaPrograms_List.yaml b/test/integration/fixtures/TestBetaPrograms_List.yaml new file mode 100644 index 000000000..a7bc4297a --- /dev/null +++ b/test/integration/fixtures/TestBetaPrograms_List.yaml @@ -0,0 +1,60 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.linode.com/v4beta/betas + method: GET + response: + body: '{"data": [], "page": 1, "pages": 1, "results": 0}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=0, s-maxage=0, no-cache, no-store + - private, max-age=60, s-maxage=60 + Content-Length: + - "49" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - '*' + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "800" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" From a07b9415ba6429df8385d0c085b37cb6ebe3ce08 Mon Sep 17 00:00:00 2001 From: Ye Chen Date: Fri, 11 Aug 2023 16:33:10 -0400 Subject: [PATCH 2/8] fix typo --- betas.go | 4 ++-- test/integration/betas_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/betas.go b/betas.go index 04cd89f8b..c72a0cc84 100644 --- a/betas.go +++ b/betas.go @@ -89,8 +89,8 @@ func (c *Client) ListBetaPrograms(ctx context.Context, opts *ListOptions) ([]Bet func (c *Client) GetBetaProgram(ctx context.Context, betaID string) (*BetaProgram, error) { req := c.R(ctx).SetResult(&BetaProgram{}) betaID = url.PathEscape(betaID) - e := fmt.Sprintf("betas/%s", betaID) - r, err := coupleAPIErrors(req.Get(e)) + b := fmt.Sprintf("betas/%s", betaID) + r, err := coupleAPIErrors(req.Get(b)) if err != nil { return nil, err } diff --git a/test/integration/betas_test.go b/test/integration/betas_test.go index 14ac920ea..696dcbb07 100644 --- a/test/integration/betas_test.go +++ b/test/integration/betas_test.go @@ -13,7 +13,7 @@ func TestBetaPrograms_List(t *testing.T) { betas, err := client.ListBetaPrograms(context.Background(), &linodego.ListOptions{}) if err != nil { - t.Errorf("Error getting Events, expected struct, got error %v", err) + t.Errorf("Error getting Beta programs, expected struct, got error %v", err) } // TODO: assert data after actual data can be retrieved from API. From 12dd8df6f298a407e80b2337da9b33d43e9bf3ae Mon Sep 17 00:00:00 2001 From: Ye Chen Date: Fri, 11 Aug 2023 17:06:03 -0400 Subject: [PATCH 3/8] revert go mod change --- go.mod | 2 +- go.sum | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 95e8d3a1e..3613cf9f5 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,7 @@ module github.com/linode/linodego require ( github.com/go-resty/resty/v2 v2.7.0 - github.com/google/go-cmp v0.5.9 + github.com/google/go-cmp v0.5.7 github.com/stretchr/testify v1.7.1 // indirect gopkg.in/ini.v1 v1.66.6 ) diff --git a/go.sum b/go.sum index 9bd988426..9a6afd76f 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPr github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= From 3ada482ccd164b43d67e2657aa8f5c9f36700f83 Mon Sep 17 00:00:00 2001 From: Ye Chen Date: Mon, 14 Aug 2023 11:33:53 -0400 Subject: [PATCH 4/8] typo --- betas.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/betas.go b/betas.go index c72a0cc84..e6f0f7345 100644 --- a/betas.go +++ b/betas.go @@ -19,10 +19,10 @@ type BetaProgram struct { Description string `json:"description"` // Start date of the beta program. - StartDT *time.Time `json"-"` + StartDT *time.Time `json:"-"` // End date of the beta program. - EndDT *time.Time `json"-"` + EndDT *time.Time `json:"-"` // Greenlight is a program that allows customers to gain access to // certain beta programs and to collect direct feedback from those customers. From 711fc04341c07498f76c54ad4a9f9b845ee746a3 Mon Sep 17 00:00:00 2001 From: Ye Chen Date: Mon, 14 Aug 2023 12:03:25 -0400 Subject: [PATCH 5/8] fix linter --- .golangci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.golangci.yml b/.golangci.yml index abdc2337b..093ed1f79 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -36,6 +36,9 @@ linters: - nosnakecase #################### + # workaround to avoid linter failures of getting malformed json + - musttag + - bodyclose - contextcheck - nilerr From 35648707da377f0a11fb3a685831c189b4f2c4e9 Mon Sep 17 00:00:00 2001 From: Ye Chen Date: Tue, 15 Aug 2023 12:32:03 -0400 Subject: [PATCH 6/8] use started, ended --- betas.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/betas.go b/betas.go index e6f0f7345..9cd84ad57 100644 --- a/betas.go +++ b/betas.go @@ -19,10 +19,10 @@ type BetaProgram struct { Description string `json:"description"` // Start date of the beta program. - StartDT *time.Time `json:"-"` + Started *time.Time `json:"-"` // End date of the beta program. - EndDT *time.Time `json:"-"` + Ended *time.Time `json:"-"` // Greenlight is a program that allows customers to gain access to // certain beta programs and to collect direct feedback from those customers. @@ -49,8 +49,8 @@ func (beta *BetaProgram) UnmarshalJSON(b []byte) error { p := struct { *Mask - StartDT *parseabletime.ParseableTime `json:"start_dt"` - EndDT *parseabletime.ParseableTime `json:"end_dt"` + Started *parseabletime.ParseableTime `json:"started"` + Ended *parseabletime.ParseableTime `json:"ended"` }{ Mask: (*Mask)(beta), } @@ -59,8 +59,8 @@ func (beta *BetaProgram) UnmarshalJSON(b []byte) error { return err } - beta.StartDT = (*time.Time)(p.StartDT) - beta.EndDT = (*time.Time)(p.EndDT) + beta.Started = (*time.Time)(p.Started) + beta.Ended = (*time.Time)(p.Ended) return nil } From d22fb85643e7c257079a7cde7c51c084f8227e5f Mon Sep 17 00:00:00 2001 From: Ye Chen Date: Thu, 17 Aug 2023 10:20:59 -0400 Subject: [PATCH 7/8] add test fixtures --- test/integration/betas_test.go | 25 ++++++-- .../fixtures/TestBetaProgram_Get.yaml | 62 +++++++++++++++++++ .../fixtures/TestBetaPrograms_List.yaml | 14 +++-- 3 files changed, 92 insertions(+), 9 deletions(-) create mode 100644 test/integration/fixtures/TestBetaProgram_Get.yaml diff --git a/test/integration/betas_test.go b/test/integration/betas_test.go index 696dcbb07..dbea28b07 100644 --- a/test/integration/betas_test.go +++ b/test/integration/betas_test.go @@ -16,9 +16,26 @@ func TestBetaPrograms_List(t *testing.T) { t.Errorf("Error getting Beta programs, expected struct, got error %v", err) } - // TODO: assert data after actual data can be retrieved from API. - // No data is expected to be returned temporarily. - if len(betas) != 0 { - t.Errorf("Expected to see none beta program returned.") + if len(betas) == 0 { + t.Errorf("Expected to see beta program returned.") + } else { + assertDateSet(t, betas[0].Started) } } + +func TestBetaProgram_Get(t *testing.T) { + client, teardown := createTestClient(t, "fixtures/TestBetaProgram_Get") + defer teardown() + + betaID := "active_closed" + beta, err := client.GetBetaProgram(context.Background(), betaID) + + if err != nil { + t.Errorf("Error getting Beta program, expected struct, got error %v", err) + } + + if beta.ID != betaID { + t.Errorf("expected beta ID to be %s; got %s", betaID, beta.ID) + } + +} diff --git a/test/integration/fixtures/TestBetaProgram_Get.yaml b/test/integration/fixtures/TestBetaProgram_Get.yaml new file mode 100644 index 000000000..f198f09ec --- /dev/null +++ b/test/integration/fixtures/TestBetaProgram_Get.yaml @@ -0,0 +1,62 @@ +--- +version: 1 +interactions: +- request: + body: "" + form: {} + headers: + Accept: + - application/json + Content-Type: + - application/json + User-Agent: + - linodego/dev https://github.com/linode/linodego + url: https://api.dev.linode.com/v4beta/betas/active_closed + method: GET + response: + body: '{"id": "active_closed", "label": "active closed beta", "description": "An + active closed beta", "started": "2018-01-02T03:04:05", "ended": null, "greenlight_only": + true, "more_info": "a link with even more info"}' + headers: + Access-Control-Allow-Credentials: + - "true" + Access-Control-Allow-Headers: + - Authorization, Origin, X-Requested-With, Content-Type, Accept, X-Filter + Access-Control-Allow-Methods: + - HEAD, GET, OPTIONS, POST, PUT, DELETE + Access-Control-Allow-Origin: + - '*' + Access-Control-Expose-Headers: + - X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Status + Cache-Control: + - private, max-age=0, s-maxage=0, no-cache, no-store + - private, max-age=60, s-maxage=60 + Content-Length: + - "211" + Content-Security-Policy: + - default-src 'none' + Content-Type: + - application/json + Server: + - nginx + Strict-Transport-Security: + - max-age=31536000 + Vary: + - Authorization, X-Filter + - Authorization, X-Filter + X-Accepted-Oauth-Scopes: + - '*' + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + - DENY + X-Oauth-Scopes: + - '*' + X-Ratelimit-Limit: + - "1200" + X-Xss-Protection: + - 1; mode=block + status: 200 OK + code: 200 + duration: "" diff --git a/test/integration/fixtures/TestBetaPrograms_List.yaml b/test/integration/fixtures/TestBetaPrograms_List.yaml index a7bc4297a..b161ee8b1 100644 --- a/test/integration/fixtures/TestBetaPrograms_List.yaml +++ b/test/integration/fixtures/TestBetaPrograms_List.yaml @@ -11,10 +11,15 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.linode.com/v4beta/betas + url: https://api.dev.linode.com/v4beta/betas method: GET response: - body: '{"data": [], "page": 1, "pages": 1, "results": 0}' + body: '{"data": [{"id": "active_closed", "label": "active closed beta", + "description": "An active closed beta", "started": "2023-07-19T15:23:43", + "ended": null, "greenlight_only": true, "more_info": "a link with even more info"}, + {"id": "limited", "label": "limited beta", "description": "An active limited beta", + "started": "2023-07-19T15:23:43", "ended": null, "greenlight_only": false, + "more_info": "a link with even more info"}], "page": 1, "pages": 1, "results": 2}' headers: Access-Control-Allow-Credentials: - "true" @@ -29,8 +34,6 @@ interactions: Cache-Control: - private, max-age=0, s-maxage=0, no-cache, no-store - private, max-age=60, s-maxage=60 - Content-Length: - - "49" Content-Security-Policy: - default-src 'none' Content-Type: @@ -40,6 +43,7 @@ interactions: Strict-Transport-Security: - max-age=31536000 Vary: + - Accept-Encoding - Authorization, X-Filter - Authorization, X-Filter X-Accepted-Oauth-Scopes: @@ -52,7 +56,7 @@ interactions: X-Oauth-Scopes: - '*' X-Ratelimit-Limit: - - "800" + - "1200" X-Xss-Protection: - 1; mode=block status: 200 OK From 61cecd4baff64ef7920b33874b3ededa03b2fa6b Mon Sep 17 00:00:00 2001 From: Ye Chen Date: Thu, 17 Aug 2023 10:33:18 -0400 Subject: [PATCH 8/8] fix fixtures --- test/integration/fixtures/TestBetaProgram_Get.yaml | 2 +- test/integration/fixtures/TestBetaPrograms_List.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/integration/fixtures/TestBetaProgram_Get.yaml b/test/integration/fixtures/TestBetaProgram_Get.yaml index f198f09ec..7bfaa9231 100644 --- a/test/integration/fixtures/TestBetaProgram_Get.yaml +++ b/test/integration/fixtures/TestBetaProgram_Get.yaml @@ -11,7 +11,7 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.dev.linode.com/v4beta/betas/active_closed + url: https://api.linode.com/v4beta/betas/active_closed method: GET response: body: '{"id": "active_closed", "label": "active closed beta", "description": "An diff --git a/test/integration/fixtures/TestBetaPrograms_List.yaml b/test/integration/fixtures/TestBetaPrograms_List.yaml index b161ee8b1..a69b44fb0 100644 --- a/test/integration/fixtures/TestBetaPrograms_List.yaml +++ b/test/integration/fixtures/TestBetaPrograms_List.yaml @@ -11,7 +11,7 @@ interactions: - application/json User-Agent: - linodego/dev https://github.com/linode/linodego - url: https://api.dev.linode.com/v4beta/betas + url: https://api.linode.com/v4beta/betas method: GET response: body: '{"data": [{"id": "active_closed", "label": "active closed beta",