From a53db9edb72f4b3a8c3dcf225104b90fabbee94e Mon Sep 17 00:00:00 2001 From: Quentin Brosse Date: Thu, 14 Nov 2019 15:13:14 +0100 Subject: [PATCH 1/4] feat: client validation --- api/instance/v1/server_utils.go | 4 +- internal/uuid/uuid.go | 10 ----- internal/validation/is.go | 49 ++++++++++++++++++++++++ scw/client_option.go | 65 +++++++++++++++++++++++--------- scw/client_option_test.go | 67 +++++++++++++++++++++++++-------- scw/client_test.go | 2 +- scw/config_test.go | 16 +++++--- scw/errors.go | 19 ++++------ scw/locality.go | 15 +++----- scw/locality_test.go | 10 ++--- 10 files changed, 181 insertions(+), 76 deletions(-) delete mode 100644 internal/uuid/uuid.go create mode 100644 internal/validation/is.go diff --git a/api/instance/v1/server_utils.go b/api/instance/v1/server_utils.go index d93eec1c..7cba1f1e 100644 --- a/api/instance/v1/server_utils.go +++ b/api/instance/v1/server_utils.go @@ -10,7 +10,7 @@ import ( "github.com/scaleway/scaleway-sdk-go/api/marketplace/v1" "github.com/scaleway/scaleway-sdk-go/internal/async" "github.com/scaleway/scaleway-sdk-go/internal/errors" - "github.com/scaleway/scaleway-sdk-go/internal/uuid" + "github.com/scaleway/scaleway-sdk-go/internal/validation" "github.com/scaleway/scaleway-sdk-go/scw" ) @@ -18,7 +18,7 @@ import ( func (s *API) CreateServer(req *CreateServerRequest, opts ...scw.RequestOption) (*CreateServerResponse, error) { // If image is not a UUID we try to fetch it from marketplace. - if req.Image != "" && !uuid.IsUUID(req.Image) { + if req.Image != "" && !validation.IsUUID(req.Image) { apiMarketplace := marketplace.NewAPI(s.client) imageId, err := apiMarketplace.GetLocalImageIDByLabel(&marketplace.GetLocalImageIDByLabelRequest{ ImageLabel: req.Image, diff --git a/internal/uuid/uuid.go b/internal/uuid/uuid.go deleted file mode 100644 index bbd8ec95..00000000 --- a/internal/uuid/uuid.go +++ /dev/null @@ -1,10 +0,0 @@ -package uuid - -import "regexp" - -var isUUIDRegexp = regexp.MustCompile(`[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}`) - -// IsUUID returns true if the given string has a UUID format. -func IsUUID(s string) bool { - return isUUIDRegexp.MatchString(s) -} diff --git a/internal/validation/is.go b/internal/validation/is.go new file mode 100644 index 00000000..b9e0d168 --- /dev/null +++ b/internal/validation/is.go @@ -0,0 +1,49 @@ +package validation + +import ( + "net/url" + "regexp" +) + +var ( + isUUIDRegexp = regexp.MustCompile(`[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}`) + isRegionRegex = regexp.MustCompile("^[a-z]{2}-[a-z]{3}$") + isZoneRegex = regexp.MustCompile("^[a-z]{2}-[a-z]{3}-[1-9]$") + isAccessKey = regexp.MustCompile("^SCW[A-Z0-9]{17}$") +) + +// IsUUID returns true if the given string has a valid UUID format. +func IsUUID(s string) bool { + return isUUIDRegexp.MatchString(s) +} + +// IsAccessKey returns true if the given string has a valid Scaleway access key format. +func IsAccessKey(s string) bool { + return isAccessKey.MatchString(s) +} + +// IsSecretKey returns true if the given string has a valid Scaleway secret key format. +func IsSecretKey(s string) bool { + return IsUUID(s) +} + +// IsOrganizationID returns true if the given string has a valid Scaleway organization ID format. +func IsOrganizationID(s string) bool { + return IsUUID(s) +} + +// IsRegion returns true if the given string has a valid region format. +func IsRegion(s string) bool { + return isRegionRegex.MatchString(s) +} + +// IsZone returns true if the given string has a valid zone format. +func IsZone(s string) bool { + return isZoneRegex.MatchString(s) +} + +// IsURL returns true if the given string has a valid URL format. +func IsURL(s string) bool { + _, err := url.Parse(s) + return err == nil +} diff --git a/scw/client_option.go b/scw/client_option.go index 782238be..73b27a2e 100644 --- a/scw/client_option.go +++ b/scw/client_option.go @@ -2,10 +2,11 @@ package scw import ( "net/http" - "net/url" + "strings" "github.com/scaleway/scaleway-sdk-go/internal/auth" "github.com/scaleway/scaleway-sdk-go/internal/errors" + "github.com/scaleway/scaleway-sdk-go/internal/validation" ) // ClientOption is a function which applies options to a settings object. @@ -170,40 +171,70 @@ func (s *settings) apply(opts []ClientOption) { } func (s *settings) validate() error { - var err error + // Auth. if s.token == nil { // It should not happen, WithoutAuth option is used by default. panic(errors.New("no credential option provided")) } - if token, isToken := s.token.(*auth.Token); isToken { if token.AccessKey == "" { - return &ClientCredentialError{errorType: clientCredentialError_EmptyAccessKey} + return NewClientValidationError("access key cannot be empty") + } + if !validation.IsAccessKey(token.AccessKey) { + return NewClientValidationError("bad access key format") } if token.SecretKey == "" { - return &ClientCredentialError{errorType: clientCredentialError_EmptySecreyKey} + return NewClientValidationError("secret key cannot be empty") + } + if !validation.IsSecretKey(token.SecretKey) { + return NewClientValidationError("bad secret key format") } } - _, err = url.Parse(s.apiURL) - if err != nil { - return errors.Wrap(err, "invalid url %s", s.apiURL) + // Default Organization ID. + if s.defaultOrganizationID != nil { + if *s.defaultOrganizationID == "" { + return NewClientValidationError("default organization ID cannot be empty") + } + if !validation.IsOrganizationID(*s.defaultOrganizationID) { + return NewClientValidationError("default organization ID must be a valid UUID") + } } - // TODO: Check OrganizationID format - if s.defaultOrganizationID != nil && *s.defaultOrganizationID == "" { - return errors.New("default organization id cannot be empty") + // Default Region. + if s.defaultRegion != nil { + if *s.defaultRegion == "" { + return NewClientValidationError("default region cannot be empty") + } + if !validation.IsRegion(string(*s.defaultRegion)) { + regions := []string(nil) + for _, r := range AllRegions { + regions = append(regions, string(r)) + } + return NewClientValidationError("bad default region format, available regions are: %s", strings.Join(regions, ", ")) + } } - // TODO: Check Region format - if s.defaultRegion != nil && *s.defaultRegion == "" { - return errors.New("default region cannot be empty") + // Default Zone. + if s.defaultZone != nil { + if *s.defaultZone == "" { + return NewClientValidationError("default zone cannot be empty") + } + if !validation.IsZone(string(*s.defaultZone)) { + zones := []string(nil) + for _, z := range AllZones { + zones = append(zones, string(z)) + } + return NewClientValidationError("bad default zone format, available zones are: %s", strings.Join(zones, ", ")) + } } - // TODO: Check Zone format - if s.defaultZone != nil && *s.defaultZone == "" { - return errors.New("default zone cannot be empty") + // API URL. + if !validation.IsURL(s.apiURL) { + return NewClientValidationError("invalid url %s", s.apiURL) } + // TODO: check for max s.defaultPageSize + return nil } diff --git a/scw/client_option_test.go b/scw/client_option_test.go index 1299a535..24d4f451 100644 --- a/scw/client_option_test.go +++ b/scw/client_option_test.go @@ -29,45 +29,64 @@ func TestClientOptions(t *testing.T) { { name: "Create a valid client option", clientOption: func(s *settings) { - s.token = auth.NewToken(testAccessKey, testSecretKey) - s.apiURL = apiURL + s.token = auth.NewToken(v2ValidAccessKey, v2ValidSecretKey) + s.apiURL = v2ValidAPIURL s.defaultOrganizationID = &defaultOrganizationID s.defaultRegion = &defaultRegion s.defaultZone = &defaultZone }, }, { - name: "Should throw an access key error", + name: "Should throw an empty access key error", clientOption: func(s *settings) { - s.apiURL = apiURL - s.token = auth.NewToken("", testSecretKey) + s.token = auth.NewToken("", v2ValidSecretKey) }, errStr: "scaleway-sdk-go: access key cannot be empty", }, { - name: "Should throw a secret key error", + name: "Should throw a bad access key error", clientOption: func(s *settings) { - s.apiURL = apiURL - s.token = auth.NewToken(testSecretKey, "") + s.token = auth.NewToken(v2InvalidAccessKey, v2ValidSecretKey) + }, + errStr: "scaleway-sdk-go: bad access key format", + }, + { + name: "Should throw an empty secret key error", + clientOption: func(s *settings) { + s.token = auth.NewToken(v2ValidAccessKey, "") }, errStr: "scaleway-sdk-go: secret key cannot be empty", }, + { + name: "Should throw a bad secret key error", + clientOption: func(s *settings) { + s.token = auth.NewToken(v2ValidAccessKey, v2InvalidSecretKey) + }, + errStr: "scaleway-sdk-go: bad secret key format", + }, { name: "Should throw an url error", clientOption: func(s *settings) { s.apiURL = ":test" - s.token = auth.NewToken(testAccessKey, testSecretKey) + s.token = auth.NewToken(v2ValidAccessKey, v2ValidSecretKey) }, - errStr: "scaleway-sdk-go: invalid url :test: parse :test: missing protocol scheme", + errStr: "scaleway-sdk-go: invalid url :test", }, { - name: "Should throw a organization id error", + name: "Should throw an empty organization ID error", clientOption: func(s *settings) { - v := "" - s.token = auth.NewToken(testAccessKey, testSecretKey) - s.defaultOrganizationID = &v + s.token = auth.NewToken(v2ValidAccessKey, v2ValidSecretKey) + s.defaultOrganizationID = StringPtr("") }, - errStr: "scaleway-sdk-go: default organization id cannot be empty", + errStr: "scaleway-sdk-go: default organization ID cannot be empty", + }, + { + name: "Should throw a bad organization ID error", + clientOption: func(s *settings) { + s.token = auth.NewToken(v2ValidAccessKey, v2ValidSecretKey) + s.defaultOrganizationID = StringPtr(v2InvalidDefaultOrganizationID) + }, + errStr: "scaleway-sdk-go: default organization ID must be a valid UUID", }, { name: "Should throw a region error", @@ -78,6 +97,15 @@ func TestClientOptions(t *testing.T) { }, errStr: "scaleway-sdk-go: default region cannot be empty", }, + { + name: "Should throw a bad region error", + clientOption: func(s *settings) { + v := Region(v2InvalidDefaultRegion) + s.token = auth.NewToken(testAccessKey, testSecretKey) + s.defaultRegion = &v + }, + errStr: "scaleway-sdk-go: bad default region format, available regions are: fr-par, nl-ams", + }, { name: "Should throw a zone error", clientOption: func(s *settings) { @@ -87,6 +115,15 @@ func TestClientOptions(t *testing.T) { }, errStr: "scaleway-sdk-go: default zone cannot be empty", }, + { + name: "Should throw a bad zone error", + clientOption: func(s *settings) { + v := Zone(v2InvalidDefaultZone) + s.token = auth.NewToken(testAccessKey, testSecretKey) + s.defaultZone = &v + }, + errStr: "scaleway-sdk-go: bad default zone format, available zones are: fr-par-1, fr-par-2, nl-ams-1", + }, } for _, c := range testCases { diff --git a/scw/client_test.go b/scw/client_test.go index f4e747f6..4b5001b7 100644 --- a/scw/client_test.go +++ b/scw/client_test.go @@ -15,7 +15,7 @@ import ( const ( testAPIURL = "https://api.example.com/" defaultAPIURL = "https://api.scaleway.com" - testAccessKey = "ACCESS_KEY" + testAccessKey = "SCW1234567890ABCDEFG" testSecretKey = "7363616c-6577-6573-6862-6f7579616161" // hint: | xxd -ps -r testDefaultOrganizationID = "6170692e-7363-616c-6577-61792e636f6d" // hint: | xxd -ps -r testDefaultRegion = RegionFrPar diff --git a/scw/config_test.go b/scw/config_test.go index 5a3fe844..463b461c 100644 --- a/scw/config_test.go +++ b/scw/config_test.go @@ -404,7 +404,7 @@ const emptyFile = "" // v2 config var ( - v2ValidAccessKey2 = "ACCESS_KEY2" + v2ValidAccessKey2 = "SCW234567890ABCDEFGH" v2ValidSecretKey2 = "6f6e6574-6f72-756c-6c74-68656d616c6c" // hint: | xxd -ps -r v2ValidAPIURL2 = "api-fr-par.scaleway.com" v2ValidInsecure2 = "true" @@ -412,7 +412,7 @@ var ( v2ValidDefaultRegion2 = string(RegionFrPar) v2ValidDefaultZone2 = string(ZoneFrPar2) - v2ValidAccessKey = "ACCESS_KEY" + v2ValidAccessKey = "SCW1234567890ABCDEFG" v2ValidSecretKey = "7363616c-6577-6573-6862-6f7579616161" // hint: | xxd -ps -r v2ValidAPIURL = "api.scaleway.com" v2ValidInsecure = "false" @@ -421,6 +421,12 @@ var ( v2ValidDefaultZone = string(ZoneNlAms1) v2ValidProfile = "flantier" + v2InvalidAccessKey = "invalid" + v2InvalidSecretKey = "invalid" + v2InvalidDefaultOrganizationID = "invalid" + v2InvalidDefaultRegion = "invalid" + v2InvalidDefaultZone = "invalid" + v2SimpleValidConfig = &Config{ Profile: Profile{ AccessKey: &v2ValidAccessKey, @@ -500,19 +506,19 @@ func TestConfigString(t *testing.T) { }, } - testhelpers.Equals(t, `access_key: ACCESS_KEY + testhelpers.Equals(t, `access_key: SCW1234567890ABCDEFG secret_key: 7363616c-xxxx-xxxx-xxxx-xxxxxxxxxxxx active_profile: flantier profiles: flantier: - access_key: ACCESS_KEY2 + access_key: SCW234567890ABCDEFGH secret_key: 6f6e6574-xxxx-xxxx-xxxx-xxxxxxxxxxxx `, c.String()) testhelpers.Equals(t, v2ValidSecretKey, *c.SecretKey) p, err := c.GetActiveProfile() testhelpers.AssertNoError(t, err) - testhelpers.Equals(t, `access_key: ACCESS_KEY2 + testhelpers.Equals(t, `access_key: SCW234567890ABCDEFGH secret_key: 6f6e6574-xxxx-xxxx-xxxx-xxxxxxxxxxxx `, p.String()) testhelpers.Equals(t, v2ValidSecretKey2, *p.SecretKey) diff --git a/scw/errors.go b/scw/errors.go index cd1e201e..e97688e1 100644 --- a/scw/errors.go +++ b/scw/errors.go @@ -256,20 +256,17 @@ func (e *OutOfStockError) GetRawBody() json.RawMessage { return e.RawBody } -type clientCredentialErrorType string - -const ( - clientCredentialError_EmptyAccessKey = clientCredentialErrorType("access key cannot be empty") - clientCredentialError_EmptySecreyKey = clientCredentialErrorType("secret key cannot be empty") -) +// ClientValidationError indicates that at least one of client data have been badly provided for the client creation. +type ClientValidationError struct { + errorType string +} -// clientCredentialError indicates that credentials have been badly provided for the client creation. -type ClientCredentialError struct { - errorType clientCredentialErrorType +func NewClientValidationError(format string, a ...interface{}) *ClientValidationError { + return &ClientValidationError{errorType: fmt.Sprintf(format, a...)} } // IsScwSdkError implements the SdkError interface -func (e ClientCredentialError) IsScwSdkError() {} -func (e ClientCredentialError) Error() string { +func (e ClientValidationError) IsScwSdkError() {} +func (e ClientValidationError) Error() string { return fmt.Sprintf("scaleway-sdk-go: %s", e.errorType) } diff --git a/scw/locality.go b/scw/locality.go index 1dc7b9e4..8f60375d 100644 --- a/scw/locality.go +++ b/scw/locality.go @@ -2,18 +2,13 @@ package scw import ( "encoding/json" - "regexp" "strings" "github.com/scaleway/scaleway-sdk-go/internal/errors" + "github.com/scaleway/scaleway-sdk-go/internal/validation" "github.com/scaleway/scaleway-sdk-go/logger" ) -var ( - regionRegex = regexp.MustCompile("^[a-z]{2}-[a-z]{3}$") - zoneRegex = regexp.MustCompile("^[a-z]{2}-[a-z]{3}-[1-9]$") -) - // Zone is an availability zone type Zone string @@ -97,12 +92,12 @@ func ParseZone(zone string) (Zone, error) { // logger.Warningf("ams1 is a deprecated name for zone, use nl-ams-1 instead") return ZoneNlAms1, nil default: - if !zoneRegex.Match([]byte(zone)) { + if !validation.IsZone(zone) { zones := []string(nil) for _, z := range AllZones { zones = append(zones, string(z)) } - return "", errors.New("wrong zone format, available zones are: %s", strings.Join(zones, ", ")) + return "", errors.New("bad zone format, available zones are: %s", strings.Join(zones, ", ")) } newZone := Zone(zone) @@ -144,12 +139,12 @@ func ParseRegion(region string) (Region, error) { // logger.Warningf("ams1 is a deprecated name for region, use nl-ams instead") return RegionNlAms, nil default: - if !regionRegex.Match([]byte(region)) { + if !validation.IsRegion(region) { regions := []string(nil) for _, r := range AllRegions { regions = append(regions, string(r)) } - return "", errors.New("wrong region format, available regions are: %s", strings.Join(regions, ", ")) + return "", errors.New("bad region format, available regions are: %s", strings.Join(regions, ", ")) } newRegion := Region(region) diff --git a/scw/locality_test.go b/scw/locality_test.go index 9784b559..85a338ec 100644 --- a/scw/locality_test.go +++ b/scw/locality_test.go @@ -34,17 +34,17 @@ func TestParseZone(t *testing.T) { { input: "fr-par", expected: "", - err: errors.New("wrong zone format, available zones are: fr-par-1, fr-par-2, nl-ams-1"), + err: errors.New("bad zone format, available zones are: fr-par-1, fr-par-2, nl-ams-1"), }, { input: "fr-par-n", expected: "", - err: errors.New("wrong zone format, available zones are: fr-par-1, fr-par-2, nl-ams-1"), + err: errors.New("bad zone format, available zones are: fr-par-1, fr-par-2, nl-ams-1"), }, { input: "fr-par-0", expected: "", - err: errors.New("wrong zone format, available zones are: fr-par-1, fr-par-2, nl-ams-1"), + err: errors.New("bad zone format, available zones are: fr-par-1, fr-par-2, nl-ams-1"), }, } @@ -112,12 +112,12 @@ func TestParseRegion(t *testing.T) { { input: "fr-par-1", expected: "", - err: errors.New("wrong region format, available regions are: fr-par, nl-ams"), + err: errors.New("bad region format, available regions are: fr-par, nl-ams"), }, { input: "fr-pa1", expected: "", - err: errors.New("wrong region format, available regions are: fr-par, nl-ams"), + err: errors.New("bad region format, available regions are: fr-par, nl-ams"), }, } From 80b82e08fab51ab04a5031e9e32d93b686e53247 Mon Sep 17 00:00:00 2001 From: Quentin Brosse Date: Thu, 14 Nov 2019 15:50:54 +0100 Subject: [PATCH 2/4] rework error messages --- scw/client_option.go | 10 +++++----- scw/client_option_test.go | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/scw/client_option.go b/scw/client_option.go index 73b27a2e..741cfb57 100644 --- a/scw/client_option.go +++ b/scw/client_option.go @@ -181,13 +181,13 @@ func (s *settings) validate() error { return NewClientValidationError("access key cannot be empty") } if !validation.IsAccessKey(token.AccessKey) { - return NewClientValidationError("bad access key format") + return NewClientValidationError("invalid access key format '%s', must be: SCWXXXXXXXXXXXXXXXXX", token.AccessKey) } if token.SecretKey == "" { return NewClientValidationError("secret key cannot be empty") } if !validation.IsSecretKey(token.SecretKey) { - return NewClientValidationError("bad secret key format") + return NewClientValidationError("invalid access key format '%s', must be: SCWXXXXXXXXXXXXXXXXX", token.AccessKey) } } @@ -197,7 +197,7 @@ func (s *settings) validate() error { return NewClientValidationError("default organization ID cannot be empty") } if !validation.IsOrganizationID(*s.defaultOrganizationID) { - return NewClientValidationError("default organization ID must be a valid UUID") + return NewClientValidationError("invalid organization ID format '%s', must be an UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", *s.defaultOrganizationID) } } @@ -211,7 +211,7 @@ func (s *settings) validate() error { for _, r := range AllRegions { regions = append(regions, string(r)) } - return NewClientValidationError("bad default region format, available regions are: %s", strings.Join(regions, ", ")) + return NewClientValidationError("invalid default region format '%s', available regions are: %s", *s.defaultRegion, strings.Join(regions, ", ")) } } @@ -225,7 +225,7 @@ func (s *settings) validate() error { for _, z := range AllZones { zones = append(zones, string(z)) } - return NewClientValidationError("bad default zone format, available zones are: %s", strings.Join(zones, ", ")) + return NewClientValidationError("invalid default zone format '%s', available zones are: %s", *s.defaultZone, strings.Join(zones, ", ")) } } diff --git a/scw/client_option_test.go b/scw/client_option_test.go index 24d4f451..4a2ca1de 100644 --- a/scw/client_option_test.go +++ b/scw/client_option_test.go @@ -48,7 +48,7 @@ func TestClientOptions(t *testing.T) { clientOption: func(s *settings) { s.token = auth.NewToken(v2InvalidAccessKey, v2ValidSecretKey) }, - errStr: "scaleway-sdk-go: bad access key format", + errStr: "scaleway-sdk-go: invalid access key format 'invalid', must be: SCWXXXXXXXXXXXXXXXXX", }, { name: "Should throw an empty secret key error", @@ -62,7 +62,7 @@ func TestClientOptions(t *testing.T) { clientOption: func(s *settings) { s.token = auth.NewToken(v2ValidAccessKey, v2InvalidSecretKey) }, - errStr: "scaleway-sdk-go: bad secret key format", + errStr: "scaleway-sdk-go: invalid access key format 'SCW1234567890ABCDEFG', must be: SCWXXXXXXXXXXXXXXXXX", }, { name: "Should throw an url error", @@ -86,7 +86,7 @@ func TestClientOptions(t *testing.T) { s.token = auth.NewToken(v2ValidAccessKey, v2ValidSecretKey) s.defaultOrganizationID = StringPtr(v2InvalidDefaultOrganizationID) }, - errStr: "scaleway-sdk-go: default organization ID must be a valid UUID", + errStr: "scaleway-sdk-go: invalid organization ID format 'invalid', must be an UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", }, { name: "Should throw a region error", @@ -104,7 +104,7 @@ func TestClientOptions(t *testing.T) { s.token = auth.NewToken(testAccessKey, testSecretKey) s.defaultRegion = &v }, - errStr: "scaleway-sdk-go: bad default region format, available regions are: fr-par, nl-ams", + errStr: "scaleway-sdk-go: invalid default region format 'invalid', available regions are: fr-par, nl-ams", }, { name: "Should throw a zone error", @@ -122,7 +122,7 @@ func TestClientOptions(t *testing.T) { s.token = auth.NewToken(testAccessKey, testSecretKey) s.defaultZone = &v }, - errStr: "scaleway-sdk-go: bad default zone format, available zones are: fr-par-1, fr-par-2, nl-ams-1", + errStr: "scaleway-sdk-go: invalid default zone format 'invalid', available zones are: fr-par-1, fr-par-2, nl-ams-1", }, } From 230fc2242551e81f46a76b77e550ecf90e085c9d Mon Sep 17 00:00:00 2001 From: Quentin Brosse Date: Thu, 14 Nov 2019 16:00:44 +0100 Subject: [PATCH 3/4] address comments --- scw/client_option.go | 6 +++--- scw/client_option_test.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scw/client_option.go b/scw/client_option.go index 741cfb57..e39a72d5 100644 --- a/scw/client_option.go +++ b/scw/client_option.go @@ -181,13 +181,13 @@ func (s *settings) validate() error { return NewClientValidationError("access key cannot be empty") } if !validation.IsAccessKey(token.AccessKey) { - return NewClientValidationError("invalid access key format '%s', must be: SCWXXXXXXXXXXXXXXXXX", token.AccessKey) + return NewClientValidationError("invalid access key format '%s', expected SCWXXXXXXXXXXXXXXXXX format", token.AccessKey) } if token.SecretKey == "" { return NewClientValidationError("secret key cannot be empty") } if !validation.IsSecretKey(token.SecretKey) { - return NewClientValidationError("invalid access key format '%s', must be: SCWXXXXXXXXXXXXXXXXX", token.AccessKey) + return NewClientValidationError("invalid secret key format '%s', expected a UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", token.SecretKey) } } @@ -197,7 +197,7 @@ func (s *settings) validate() error { return NewClientValidationError("default organization ID cannot be empty") } if !validation.IsOrganizationID(*s.defaultOrganizationID) { - return NewClientValidationError("invalid organization ID format '%s', must be an UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", *s.defaultOrganizationID) + return NewClientValidationError("invalid organization ID format '%s', expected a UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", *s.defaultOrganizationID) } } diff --git a/scw/client_option_test.go b/scw/client_option_test.go index 4a2ca1de..d523c31d 100644 --- a/scw/client_option_test.go +++ b/scw/client_option_test.go @@ -48,7 +48,7 @@ func TestClientOptions(t *testing.T) { clientOption: func(s *settings) { s.token = auth.NewToken(v2InvalidAccessKey, v2ValidSecretKey) }, - errStr: "scaleway-sdk-go: invalid access key format 'invalid', must be: SCWXXXXXXXXXXXXXXXXX", + errStr: "scaleway-sdk-go: invalid access key format 'invalid', expected SCWXXXXXXXXXXXXXXXXX format", }, { name: "Should throw an empty secret key error", @@ -62,7 +62,7 @@ func TestClientOptions(t *testing.T) { clientOption: func(s *settings) { s.token = auth.NewToken(v2ValidAccessKey, v2InvalidSecretKey) }, - errStr: "scaleway-sdk-go: invalid access key format 'SCW1234567890ABCDEFG', must be: SCWXXXXXXXXXXXXXXXXX", + errStr: "scaleway-sdk-go: invalid secret key format 'invalid', expected a UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", }, { name: "Should throw an url error", @@ -86,7 +86,7 @@ func TestClientOptions(t *testing.T) { s.token = auth.NewToken(v2ValidAccessKey, v2ValidSecretKey) s.defaultOrganizationID = StringPtr(v2InvalidDefaultOrganizationID) }, - errStr: "scaleway-sdk-go: invalid organization ID format 'invalid', must be an UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + errStr: "scaleway-sdk-go: invalid organization ID format 'invalid', expected a UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", }, { name: "Should throw a region error", From de43f7ccceb4baa657d72c2db8e109f779260ed6 Mon Sep 17 00:00:00 2001 From: Quentin Brosse Date: Thu, 14 Nov 2019 16:41:07 +0100 Subject: [PATCH 4/4] rename error struct --- scw/client_option.go | 22 +++++++++++----------- scw/errors.go | 12 ++++++------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/scw/client_option.go b/scw/client_option.go index e39a72d5..7c5e36fd 100644 --- a/scw/client_option.go +++ b/scw/client_option.go @@ -178,60 +178,60 @@ func (s *settings) validate() error { } if token, isToken := s.token.(*auth.Token); isToken { if token.AccessKey == "" { - return NewClientValidationError("access key cannot be empty") + return NewInvalidClientOptionError("access key cannot be empty") } if !validation.IsAccessKey(token.AccessKey) { - return NewClientValidationError("invalid access key format '%s', expected SCWXXXXXXXXXXXXXXXXX format", token.AccessKey) + return NewInvalidClientOptionError("invalid access key format '%s', expected SCWXXXXXXXXXXXXXXXXX format", token.AccessKey) } if token.SecretKey == "" { - return NewClientValidationError("secret key cannot be empty") + return NewInvalidClientOptionError("secret key cannot be empty") } if !validation.IsSecretKey(token.SecretKey) { - return NewClientValidationError("invalid secret key format '%s', expected a UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", token.SecretKey) + return NewInvalidClientOptionError("invalid secret key format '%s', expected a UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", token.SecretKey) } } // Default Organization ID. if s.defaultOrganizationID != nil { if *s.defaultOrganizationID == "" { - return NewClientValidationError("default organization ID cannot be empty") + return NewInvalidClientOptionError("default organization ID cannot be empty") } if !validation.IsOrganizationID(*s.defaultOrganizationID) { - return NewClientValidationError("invalid organization ID format '%s', expected a UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", *s.defaultOrganizationID) + return NewInvalidClientOptionError("invalid organization ID format '%s', expected a UUID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", *s.defaultOrganizationID) } } // Default Region. if s.defaultRegion != nil { if *s.defaultRegion == "" { - return NewClientValidationError("default region cannot be empty") + return NewInvalidClientOptionError("default region cannot be empty") } if !validation.IsRegion(string(*s.defaultRegion)) { regions := []string(nil) for _, r := range AllRegions { regions = append(regions, string(r)) } - return NewClientValidationError("invalid default region format '%s', available regions are: %s", *s.defaultRegion, strings.Join(regions, ", ")) + return NewInvalidClientOptionError("invalid default region format '%s', available regions are: %s", *s.defaultRegion, strings.Join(regions, ", ")) } } // Default Zone. if s.defaultZone != nil { if *s.defaultZone == "" { - return NewClientValidationError("default zone cannot be empty") + return NewInvalidClientOptionError("default zone cannot be empty") } if !validation.IsZone(string(*s.defaultZone)) { zones := []string(nil) for _, z := range AllZones { zones = append(zones, string(z)) } - return NewClientValidationError("invalid default zone format '%s', available zones are: %s", *s.defaultZone, strings.Join(zones, ", ")) + return NewInvalidClientOptionError("invalid default zone format '%s', available zones are: %s", *s.defaultZone, strings.Join(zones, ", ")) } } // API URL. if !validation.IsURL(s.apiURL) { - return NewClientValidationError("invalid url %s", s.apiURL) + return NewInvalidClientOptionError("invalid url %s", s.apiURL) } // TODO: check for max s.defaultPageSize diff --git a/scw/errors.go b/scw/errors.go index e97688e1..0473008d 100644 --- a/scw/errors.go +++ b/scw/errors.go @@ -256,17 +256,17 @@ func (e *OutOfStockError) GetRawBody() json.RawMessage { return e.RawBody } -// ClientValidationError indicates that at least one of client data have been badly provided for the client creation. -type ClientValidationError struct { +// InvalidClientOptionError indicates that at least one of client data has been badly provided for the client creation. +type InvalidClientOptionError struct { errorType string } -func NewClientValidationError(format string, a ...interface{}) *ClientValidationError { - return &ClientValidationError{errorType: fmt.Sprintf(format, a...)} +func NewInvalidClientOptionError(format string, a ...interface{}) *InvalidClientOptionError { + return &InvalidClientOptionError{errorType: fmt.Sprintf(format, a...)} } // IsScwSdkError implements the SdkError interface -func (e ClientValidationError) IsScwSdkError() {} -func (e ClientValidationError) Error() string { +func (e InvalidClientOptionError) IsScwSdkError() {} +func (e InvalidClientOptionError) Error() string { return fmt.Sprintf("scaleway-sdk-go: %s", e.errorType) }