-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add concrete errors to public API (#36)
* feat: add concrete errors to public API This commit adds four concrete errors to the public API and ensures that all returned errors are either instances of those concrete types OR are wrapped by more descriptive errors. The four error types are: 1. ClientError: for all errors that are the result of the client making semantic error in their request 2. ServerError: for all the (uncommon) cases where the server returns data that is somehow and unexpectedly invalid. 3. APIError: for any errors that occurs when interacting with the SQL Admin API. These errors wrap the underlying google.golang.org/api/googleapi.Error types. 4. DialError: for any error that occurs when attempting to connect to a particular SQL instance. By providing concrete errors or wrapping concrete errors, we allow our clients to uses the errors.As API to possibly react differently to errors coming out of the dialer. Co-authored-by: Kurtis Van Gent <31518063+kurtisvg@users.noreply.github.com>
- Loading branch information
Showing
9 changed files
with
293 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Copyright 2021 Google LLC | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
|
||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
// Package errtypes provides a number of concrete types which are used by the | ||
// cloudsqlconn package. | ||
package errtypes // import "cloud.google.com/go/cloudsqlconn/errtypes" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// Copyright 2021 Google LLC | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
|
||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package errtypes | ||
|
||
import "fmt" | ||
|
||
type genericError struct { | ||
Message string | ||
ConnName string | ||
} | ||
|
||
func (e *genericError) Error() string { | ||
return fmt.Sprintf("%v (connection name = %q)", e.Message, e.ConnName) | ||
} | ||
|
||
// NewConfigError initializes a ConfigError. | ||
func NewConfigError(msg, cn string) *ConfigError { | ||
return &ConfigError{ | ||
genericError: &genericError{Message: "Client error: " + msg, ConnName: cn}, | ||
} | ||
} | ||
|
||
// ConfigError represents an incorrect request by the user. Config errors | ||
// usually indicate a semantic error (e.g., the instance connection name is | ||
// malformated, the SQL instance does not support the requested IP type, etc.) | ||
type ConfigError struct{ *genericError } | ||
|
||
// NewRefreshError initializes a RefreshError. | ||
func NewRefreshError(msg, cn string, err error) *RefreshError { | ||
return &RefreshError{ | ||
genericError: &genericError{Message: msg, ConnName: cn}, | ||
Err: err, | ||
} | ||
} | ||
|
||
// RefreshError means that an error occurred during the background | ||
// refresh operation. In general, this is an unexpected error caused by | ||
// an interaction with the API itself (e.g., missing certificates, | ||
// invalid certificate encoding, region mismatch with the requested | ||
// instance connection name, etc.). | ||
type RefreshError struct { | ||
*genericError | ||
// Err is the underlying error and may be nil. | ||
Err error | ||
} | ||
|
||
func (e *RefreshError) Error() string { | ||
if e.Err == nil { | ||
return fmt.Sprintf("Server error: %v", e.genericError) | ||
} | ||
return fmt.Sprintf("Server error: %v: %v", e.genericError, e.Err) | ||
} | ||
|
||
func (e *RefreshError) Unwrap() error { return e.Err } | ||
|
||
// NewDialError initializes a DialError. | ||
func NewDialError(msg, cn string, err error) *DialError { | ||
return &DialError{ | ||
genericError: &genericError{Message: msg, ConnName: cn}, | ||
Err: err, | ||
} | ||
} | ||
|
||
// DialError represents a problem that occurred when trying to dial a SQL | ||
// instance (e.g., a failure to set the keep-alive property, a TLS handshake | ||
// failure, a missing certificate, etc.) | ||
type DialError struct { | ||
*genericError | ||
// Err is the underlying error and may be nil. | ||
Err error | ||
} | ||
|
||
func (e *DialError) Error() string { | ||
if e.Err == nil { | ||
return fmt.Sprintf("Dial error: %v", e.genericError) | ||
} | ||
return fmt.Sprintf("Dial error: %v: %v", e.genericError, e.Err) | ||
} | ||
|
||
func (e *DialError) Unwrap() error { return e.Err } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Copyright 2021 Google LLC | ||
|
||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
|
||
// https://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package errtypes_test | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
|
||
"cloud.google.com/go/cloudsqlconn/errtypes" | ||
) | ||
|
||
func TestErrorFormatting(t *testing.T) { | ||
tc := []struct { | ||
desc string | ||
err error | ||
want string | ||
}{ | ||
{ | ||
desc: "client error message", | ||
err: errtypes.NewConfigError("error message", "proj:reg:inst"), | ||
want: "Client error: error message (connection name = \"proj:reg:inst\")", | ||
}, | ||
{ | ||
desc: "server error message without internal error", | ||
err: errtypes.NewRefreshError("error message", "proj:reg:inst", nil), | ||
want: "Server error: error message (connection name = \"proj:reg:inst\")", | ||
}, | ||
{ | ||
desc: "server error message with internal error", | ||
err: errtypes.NewRefreshError("error message", "proj:reg:inst", errors.New("inner-error")), | ||
want: "Server error: error message (connection name = \"proj:reg:inst\"): inner-error", | ||
}, | ||
{ | ||
desc: "Dial error without inner error", | ||
err: errtypes.NewDialError( | ||
"message", | ||
"proj:reg:inst", | ||
nil, // no error here | ||
), | ||
want: "Dial error: message (connection name = \"proj:reg:inst\")", | ||
}, | ||
{ | ||
desc: "Dial error with inner error", | ||
err: errtypes.NewDialError( | ||
"message", | ||
"proj:reg:inst", | ||
errors.New("inner-error"), | ||
), | ||
want: "Dial error: message (connection name = \"proj:reg:inst\"): inner-error", | ||
}, | ||
} | ||
|
||
for _, c := range tc { | ||
if got := c.err.Error(); got != c.want { | ||
t.Errorf("%v, got = %q, want = %q", c.desc, got, c.want) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.