Skip to content

Commit a169c4b

Browse files
add test for internal/colonyapi (#9)
* add test * fix: add code review * refactor httptest server * add test for server error * refactor: use const --------- Co-authored-by: Patrick D'appollonio <[email protected]>
1 parent 34b3565 commit a169c4b

File tree

4 files changed

+90
-73
lines changed

4 files changed

+90
-73
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ require (
99
k8s.io/api v0.31.0
1010
k8s.io/apimachinery v0.31.0
1111
k8s.io/client-go v0.31.0
12-
sigs.k8s.io/yaml v1.4.0
1312
)
1413

1514
require (
@@ -52,4 +51,5 @@ require (
5251
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect
5352
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
5453
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
54+
sigs.k8s.io/yaml v1.4.0 // indirect
5555
)

internal/colony/api.go

+7-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"crypto/tls"
66
"encoding/json"
7+
"errors"
78
"fmt"
89
"net/http"
910
"time"
@@ -15,8 +16,11 @@ type API struct {
1516
token string
1617
}
1718

19+
var errInvalidKey = errors.New("invalid Colony API key")
20+
1821
const (
19-
validateAPIKeyURL = "/api/v1/token/validate"
22+
templateEndpoint = "/api/v1/templates/all/system"
23+
validateEndpoint = "/api/v1/token/validate"
2024
)
2125

2226
// New creates a new colony API client
@@ -37,7 +41,7 @@ func New(baseURL, token string) *API {
3741
}
3842

3943
func (a *API) ValidateAPIKey(ctx context.Context) error {
40-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, a.baseURL+validateAPIKeyURL, nil)
44+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, a.baseURL+validateEndpoint, nil)
4145
if err != nil {
4246
return fmt.Errorf("error creating request: %w", err)
4347
}
@@ -64,7 +68,7 @@ func (a *API) ValidateAPIKey(ctx context.Context) error {
6468
}
6569

6670
if !r.IsValid {
67-
return fmt.Errorf("invalid api key")
71+
return errInvalidKey
6872
}
6973

7074
return nil

internal/colony/api_test.go

+80-65
Original file line numberDiff line numberDiff line change
@@ -2,103 +2,118 @@ package colony
22

33
import (
44
"context"
5+
"encoding/json"
6+
"errors"
7+
"fmt"
8+
"net"
59
"net/http"
610
"net/http/httptest"
11+
"reflect"
712
"testing"
813
)
914

10-
func createServer(t *testing.T, path string, fn http.HandlerFunc) *httptest.Server {
11-
t.Helper()
12-
mux := http.NewServeMux()
13-
mux.HandleFunc(path, fn)
14-
return httptest.NewServer(mux)
15-
}
15+
const (
16+
testValidToken = "super-duper-valid-token"
17+
)
1618

17-
func Test_ValidateAPIKey(t *testing.T) {
18-
t.Run("full request flow", func(t *testing.T) {
19-
fakeToken := "my-super-secret"
19+
func TestAPI_ValidateApiKey(t *testing.T) {
20+
t.Run("valid API key", func(t *testing.T) {
21+
response := map[string]interface{}{
22+
"isValid": true,
23+
}
2024

21-
srv := createServer(t, validateAPIKeyURL, func(w http.ResponseWriter, r *http.Request) {
22-
if r.Header.Get("Authorization") != "Bearer "+fakeToken {
23-
t.Fatalf("unexpected Authorization header: %s", r.Header.Get("Authorization"))
24-
}
25+
mockServer := createServer(t, response, validateEndpoint)
2526

26-
w.WriteHeader(http.StatusOK)
27-
w.Write([]byte(`{"isValid": true}`))
28-
})
29-
defer srv.Close()
27+
defer mockServer.Close()
3028

31-
ctx := context.Background()
32-
api := New(srv.URL, fakeToken)
29+
api := New(mockServer.URL, testValidToken)
3330

34-
if err := api.ValidateAPIKey(ctx); err != nil {
35-
t.Fatalf("unexpected error: %v", err)
31+
err := api.ValidateAPIKey(context.TODO())
32+
if err != nil {
33+
t.Fatalf("expected nil but got: %s", err)
3634
}
3735
})
3836

39-
t.Run("malformed URL", func(t *testing.T) {
40-
baseURL := ":"
41-
api := New(baseURL, "token")
37+
t.Run("invalid API key", func(t *testing.T) {
38+
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
39+
fmt.Fprintln(w, `{"isValid": false}`)
40+
}))
4241

43-
err := api.ValidateAPIKey(context.Background())
44-
if err == nil {
45-
t.Fatal("expected error, got nil")
42+
defer mockServer.Close()
43+
44+
api := New(mockServer.URL, testValidToken)
45+
46+
err := api.ValidateAPIKey(context.TODO())
47+
if !errors.Is(err, errInvalidKey) {
48+
t.Fatalf("expected %s, but got: %s", errInvalidKey, err)
4649
}
4750
})
51+
}
4852

49-
t.Run("unable to connect", func(t *testing.T) {
50-
srv := httptest.NewServer(nil)
51-
srv.Close()
53+
func TestAPI_GetSystemTemplates(t *testing.T) {
54+
t.Run("valid response", func(t *testing.T) {
55+
response := []Template{{
56+
ID: "k1",
57+
Name: "name",
58+
Label: "label",
59+
IsTinkTemplate: true,
60+
IsSystem: true,
61+
Template: "template_data",
62+
}}
5263

53-
api := New(srv.URL, "token")
64+
mockServer := createServer(t, response, templateEndpoint)
5465

55-
err := api.ValidateAPIKey(context.Background())
56-
if err == nil {
57-
t.Fatal("expected error, got nil")
58-
}
59-
})
66+
defer mockServer.Close()
6067

61-
t.Run("invalid status code", func(t *testing.T) {
62-
srv := createServer(t, validateAPIKeyURL, func(w http.ResponseWriter, r *http.Request) {
63-
w.WriteHeader(http.StatusNotFound)
64-
})
65-
defer srv.Close()
68+
api := New(mockServer.URL, testValidToken)
6669

67-
api := New(srv.URL, "token")
70+
templates, err := api.GetSystemTemplates(context.TODO())
71+
if err != nil {
72+
t.Fatalf("expected nil but got: %s", err)
73+
}
6874

69-
err := api.ValidateAPIKey(context.Background())
70-
if err == nil {
71-
t.Fatal("expected error, got nil")
75+
if !reflect.DeepEqual(response, templates) {
76+
t.Fatalf("expected %#v got %#v", response, templates)
7277
}
7378
})
7479

75-
t.Run("invalid response body", func(t *testing.T) {
76-
srv := createServer(t, validateAPIKeyURL, func(w http.ResponseWriter, r *http.Request) {
77-
w.WriteHeader(http.StatusOK)
78-
w.Write([]byte(`not JSON`))
79-
})
80-
defer srv.Close()
80+
t.Run("connection reset by peer", func(t *testing.T) {
81+
myListener, err := net.Listen("tcp", "localhost:0")
82+
if err != nil {
83+
t.Fatalf("error creating listener %s", err)
84+
}
85+
address := myListener.Addr().String()
86+
87+
go func() {
88+
for {
89+
con, err := myListener.Accept()
90+
if err != nil {
91+
t.Log(err)
92+
}
93+
con.Close()
94+
}
95+
}()
8196

82-
api := New(srv.URL, "token")
97+
api := New(address, testValidToken)
8398

84-
err := api.ValidateAPIKey(context.Background())
99+
_, err = api.GetSystemTemplates(context.TODO())
85100
if err == nil {
86-
t.Fatal("expected error, got nil")
101+
t.Fatal("was expecting error but got none")
87102
}
88103
})
104+
}
89105

90-
t.Run("invalid API key", func(t *testing.T) {
91-
srv := createServer(t, validateAPIKeyURL, func(w http.ResponseWriter, r *http.Request) {
92-
w.WriteHeader(http.StatusOK)
93-
w.Write([]byte(`{"isValid": false}`))
94-
})
95-
defer srv.Close()
96-
97-
api := New(srv.URL, "token")
106+
func createServer(t *testing.T, response interface{}, apiEndpoint string) *httptest.Server {
107+
t.Helper()
98108

99-
err := api.ValidateAPIKey(context.Background())
100-
if err == nil {
101-
t.Fatal("expected error, got nil")
109+
mux := http.NewServeMux()
110+
mux.HandleFunc("GET "+apiEndpoint, func(w http.ResponseWriter, r *http.Request) {
111+
if r.Header.Get("Authorization") != fmt.Sprintf("Bearer %s", testValidToken) {
112+
t.Fatalf("expected to get a bearer token %s but got: %s", fmt.Sprintf("Bearer %s", testValidToken), r.Header.Get("Authorization"))
102113
}
114+
115+
json.NewEncoder(w).Encode(response)
103116
})
117+
118+
return httptest.NewServer(mux)
104119
}

internal/k8s/k8s_test.go

+2-4
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ import (
44
"context"
55
"testing"
66

7+
"github.com/konstructio/colony/internal/logger"
78
"k8s.io/apimachinery/pkg/api/errors"
89
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
910
fakeServer "k8s.io/client-go/kubernetes/fake"
1011
)
1112

1213
func TestClient_CreateAPIKeySecret(t *testing.T) {
13-
1414
t.Run("successful creation", func(tt *testing.T) {
15-
1615
var (
1716
secretNamespace = "tink-system"
1817
secretName = "colony-api"
@@ -24,6 +23,7 @@ func TestClient_CreateAPIKeySecret(t *testing.T) {
2423

2524
client := &Client{
2625
clientSet: mockServer,
26+
logger: logger.NOOPLogger,
2727
}
2828

2929
ctx := context.TODO()
@@ -35,7 +35,6 @@ func TestClient_CreateAPIKeySecret(t *testing.T) {
3535

3636
// check secret exists
3737
secret, err := client.clientSet.CoreV1().Secrets(secretNamespace).Get(ctx, secretName, v1.GetOptions{})
38-
3938
if err != nil {
4039
if errors.IsNotFound(err) {
4140
tt.Fatalf("can't find the secret %q", secretName)
@@ -52,5 +51,4 @@ func TestClient_CreateAPIKeySecret(t *testing.T) {
5251
tt.Fatalf("expected key value %q but got %q", secretValue, string(data))
5352
}
5453
})
55-
5654
}

0 commit comments

Comments
 (0)