From fe33edf919cb7e0b27ca8d6529fd009aa5a79681 Mon Sep 17 00:00:00 2001
From: Jules Casteran <jcasteran@scaleway.com>
Date: Tue, 16 May 2023 15:04:38 +0200
Subject: [PATCH] feat: add UnknownServiceError

---
 scw/errors.go      | 28 ++++++++++++++++++++++++++++
 scw/errors_test.go | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+)

diff --git a/scw/errors.go b/scw/errors.go
index 3563b0de9..26361bcec 100644
--- a/scw/errors.go
+++ b/scw/errors.go
@@ -123,6 +123,13 @@ func hasResponseError(res *http.Response) error {
 		return err
 	}
 
+	if newErr.Type == "" {
+		err = convertNonTypedError(newErr)
+		if err != nil {
+			return err
+		}
+	}
+
 	return newErr
 }
 
@@ -200,6 +207,14 @@ func unmarshalNonStandardError(errorType string, body []byte) error {
 	}
 }
 
+func convertNonTypedError(err *ResponseError) error {
+	if err.StatusCode == http.StatusNotImplemented && err.Message == "unknown service" {
+		return &UnknownServiceError{RawBody: err.RawBody}
+	}
+
+	return nil
+}
+
 type InvalidArgumentsErrorDetail struct {
 	ArgumentName string `json:"argument_name"`
 	Reason       string `json:"reason"`
@@ -550,3 +565,16 @@ func (r PreconditionFailedError) Error() string {
 }
 
 func (r PreconditionFailedError) IsScwSdkError() {}
+
+// UnknownServiceError implements the SdkError interface
+type UnknownServiceError struct {
+	RawBody json.RawMessage `json:"-"`
+}
+
+func (e *UnknownServiceError) IsScwSdkError() {}
+func (e *UnknownServiceError) Error() string {
+	return "scaleway-sdk-go: service is unknown in used locality"
+}
+func (e *UnknownServiceError) GetRawBody() json.RawMessage {
+	return e.RawBody
+}
diff --git a/scw/errors_test.go b/scw/errors_test.go
index 6e218f039..4ffc2b112 100644
--- a/scw/errors_test.go
+++ b/scw/errors_test.go
@@ -204,3 +204,41 @@ func TestHasResponseErrorWithValidError(t *testing.T) {
 	testhelpers.Assert(t, newErr != nil, "Should have error")
 	testhelpers.Equals(t, testErrorReponse, newErr)
 }
+
+func TestNonTypedError(t *testing.T) {
+	type testCase struct {
+		resStatus     string
+		resStatusCode int
+		resBody       string
+		contentType   string
+		expectedError SdkError
+	}
+
+	run := func(c *testCase) func(t *testing.T) {
+		return func(t *testing.T) {
+			res := &http.Response{
+				Status:     c.resStatus,
+				StatusCode: c.resStatusCode,
+				Body:       ioutil.NopCloser(strings.NewReader(c.resBody)),
+				Header: http.Header{
+					"Content-Type": []string{c.contentType},
+				},
+			}
+
+			// Test that hasResponseError converts the response to the expected SdkError.
+			newErr := hasResponseError(res)
+			testhelpers.Assert(t, newErr != nil, "Should have error")
+			testhelpers.Equals(t, c.expectedError, newErr)
+		}
+	}
+
+	t.Run("unknown service", run(&testCase{
+		resStatus:     "501 Not Implemented",
+		resStatusCode: http.StatusNotImplemented,
+		contentType:   "application/json",
+		resBody:       `{"message": "unknown service"}`,
+		expectedError: &UnknownServiceError{
+			RawBody: []byte(`{"message": "unknown service"}`),
+		},
+	}))
+}