Skip to content

Commit 66c5367

Browse files
Remove usage of log.Fatal from httpclient.go; return an error object instead (FF-1934) (#36)
* Remove usage of log.Fatal from httpclient.go; return an error object instead (FF-1934) * add comment
1 parent bf8c56b commit 66c5367

File tree

3 files changed

+115
-9
lines changed

3 files changed

+115
-9
lines changed

eppoclient/configurationrequestor.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,15 @@ func (ecr *experimentConfigurationRequestor) GetConfiguration(experimentKey stri
4040
}
4141

4242
func (ecr *experimentConfigurationRequestor) FetchAndStoreConfigurations() {
43-
result := ecr.httpClient.get(RAC_ENDPOINT)
43+
result, err := ecr.httpClient.get(RAC_ENDPOINT)
44+
if err != nil {
45+
fmt.Println("Failed to fetch RAC response", err)
46+
return
47+
}
4448
var wrapper racResponse
4549

4650
// Unmarshal JSON data directly into the wrapper struct
47-
err := json.Unmarshal([]byte(result), &wrapper)
51+
err = json.Unmarshal([]byte(result), &wrapper)
4852
if err != nil {
4953
fmt.Println("Failed to unmarshal RAC response JSON", result)
5054
fmt.Println(err)

eppoclient/httpclient.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package eppoclient
22

33
import (
4+
"fmt"
45
"io"
5-
"log"
66
"time"
77

88
"net/http"
@@ -33,10 +33,13 @@ func newHttpClient(baseUrl string, client *http.Client, sdkParams SDKParams) *ht
3333
return hc
3434
}
3535

36-
func (hc *httpClient) get(resource string) string {
36+
func (hc *httpClient) get(resource string) (string, error) {
3737
url := hc.baseUrl + resource
3838

39-
req, _ := http.NewRequest(http.MethodGet, url, nil)
39+
req, err := http.NewRequest(http.MethodGet, url, nil)
40+
if err != nil {
41+
return "", err // Return an empty string and the error
42+
}
4043
req.Header.Set("Content-Type", "application/json; charset=UTF-8")
4144

4245
q := req.URL.Query()
@@ -46,18 +49,31 @@ func (hc *httpClient) get(resource string) string {
4649
req.URL.RawQuery = q.Encode()
4750

4851
resp, err := hc.client.Do(req)
49-
5052
if err != nil {
51-
log.Fatal(err)
53+
// from https://golang.org/pkg/net/http/#Client.Do
54+
//
55+
// An error is returned if caused by client policy (such as
56+
// CheckRedirect), or failure to speak HTTP (such as a network
57+
// connectivity problem). A non-2xx status code doesn't cause an
58+
// error.
59+
//
60+
// We should almost never expect to see this condition be executed.
61+
return "", err // Return an empty string and the error
5262
}
63+
defer resp.Body.Close() // Ensure the response body is closed
5364

5465
if resp.StatusCode == 401 {
5566
hc.isUnauthorized = true
67+
return "", fmt.Errorf("unauthorized access") // Return an error indicating unauthorized access
68+
}
69+
70+
if resp.StatusCode >= 500 {
71+
return "", fmt.Errorf("server error: %d", resp.StatusCode) // Handle server errors (status code > 500)
5672
}
5773

5874
b, err := io.ReadAll(resp.Body)
5975
if err != nil {
60-
log.Fatalln(err)
76+
return "", fmt.Errorf("server error: unreadable body") // Return an empty string and the error
6177
}
62-
return string(b)
78+
return string(b), nil // Return the response body as a string and nil for the error
6379
}

eppoclient/httpclient_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package eppoclient
2+
3+
import (
4+
"net/http"
5+
"net/http/httptest"
6+
"testing"
7+
)
8+
9+
func TestHttpClientGet(t *testing.T) {
10+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
11+
switch r.URL.Path {
12+
case "/test":
13+
w.WriteHeader(http.StatusOK)
14+
_, _ = w.Write([]byte(`OK`))
15+
case "/unauthorized":
16+
w.WriteHeader(http.StatusUnauthorized)
17+
_, _ = w.Write([]byte(`Unauthorized`))
18+
case "/internal-error":
19+
w.WriteHeader(http.StatusInternalServerError)
20+
_, _ = w.Write([]byte(`Internal Server Error`))
21+
case "/bad-response":
22+
w.WriteHeader(http.StatusOK)
23+
if hijacker, ok := w.(http.Hijacker); ok {
24+
conn, _, _ := hijacker.Hijack()
25+
conn.Close() // Close the connection to simulate an unreadable body
26+
}
27+
}
28+
}))
29+
defer server.Close()
30+
31+
client := &http.Client{}
32+
hc := newHttpClient(server.URL, client, SDKParams{
33+
apiKey: "testApiKey",
34+
sdkName: "testSdkName",
35+
sdkVersion: "testSdkVersion",
36+
})
37+
38+
tests := []struct {
39+
name string
40+
resource string
41+
expectedError string
42+
expectedResult string
43+
}{
44+
{
45+
name: "api returns http 200",
46+
resource: "/test",
47+
expectedResult: "OK",
48+
},
49+
{
50+
name: "api returns 401 unauthorized error",
51+
resource: "/unauthorized",
52+
expectedError: "unauthorized access",
53+
},
54+
{
55+
name: "api returns an 500 error",
56+
resource: "/internal-error",
57+
expectedError: "server error: 500",
58+
},
59+
{
60+
name: "api returns unreadable body",
61+
resource: "/bad-response",
62+
expectedError: "server error: unreadable body",
63+
},
64+
}
65+
66+
for _, tc := range tests {
67+
t.Run(tc.name, func(t *testing.T) {
68+
result, err := hc.get(tc.resource)
69+
if err != nil {
70+
if err.Error() != tc.expectedError {
71+
t.Errorf("Expected error %v, got %v", tc.expectedError, err)
72+
}
73+
if result != "" { // Check if result is not an empty string when an error is expected
74+
t.Errorf("Expected result to be an empty string when there is an error, got %v", result)
75+
}
76+
} else {
77+
if tc.expectedError != "" {
78+
t.Errorf("Expected error %v, got nil", tc.expectedError)
79+
}
80+
if result != tc.expectedResult {
81+
t.Errorf("Expected result %v, got %v", tc.expectedResult, result)
82+
}
83+
}
84+
})
85+
}
86+
}

0 commit comments

Comments
 (0)