1 package cluster_test
2
3 import (
4 "bytes"
5 "context"
6 "encoding/json"
7 "net/http"
8 "net/http/httptest"
9 "os"
10 "testing"
11
12 "github.com/gin-gonic/gin"
13 "github.com/go-logr/logr/testr"
14 "github.com/spf13/afero"
15 "github.com/stretchr/testify/assert"
16 "github.com/stretchr/testify/require"
17 kruntime "k8s.io/apimachinery/pkg/runtime"
18 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
19 clientgoscheme "k8s.io/client-go/kubernetes/scheme"
20 ctrl "sigs.k8s.io/controller-runtime"
21 "sigs.k8s.io/controller-runtime/pkg/cache/informertest"
22 "sigs.k8s.io/controller-runtime/pkg/client"
23 "sigs.k8s.io/controller-runtime/pkg/client/fake"
24
25 "edge-infra.dev/pkg/edge/info"
26 "edge-infra.dev/pkg/sds/interlock/internal/config"
27 "edge-infra.dev/pkg/sds/interlock/internal/errors"
28 "edge-infra.dev/pkg/sds/interlock/topic/cluster"
29 "edge-infra.dev/pkg/sds/interlock/websocket"
30 "edge-infra.dev/pkg/sds/lib/k8s/retryclient"
31 )
32
33 var testClusterName = "test-cluster"
34
35 func init() {
36 gin.SetMode(gin.TestMode)
37
38
39 os.Setenv("KUBERNETES_SERVICE_HOST", "1")
40 os.Setenv("KUBERNETES_SERVICE_PORT", "1")
41
42
43 os.Setenv("NODE_NAME", "test-node")
44 }
45
46 func SetupTestCtx(t *testing.T) context.Context {
47 logOptions := testr.Options{
48 LogTimestamp: true,
49 Verbosity: -1,
50 }
51
52 ctx := ctrl.LoggerInto(context.Background(), testr.NewWithOptions(t, logOptions))
53 return ctx
54 }
55
56 func TestGetState(t *testing.T) {
57 r, err := initializeClusterRouter(SetupTestCtx(t))
58 require.NoError(t, err)
59
60 w := httptest.NewRecorder()
61 req, _ := http.NewRequest("GET", cluster.Path, nil)
62 r.ServeHTTP(w, req)
63
64 assert.Equal(t, http.StatusOK, w.Code)
65
66 actual := &cluster.State{}
67 require.NoError(t, json.Unmarshal(w.Body.Bytes(), actual))
68
69 expected := &cluster.State{
70 Name: testClusterName,
71 }
72 assert.Equal(t, expected, actual)
73 }
74
75 type NameEditor struct {
76 Name string `json:"name"`
77 }
78
79 type Errors struct {
80 Errors []*errors.Error `json:"errors"`
81 }
82
83 func TestPatchState(t *testing.T) {
84 r, err := initializeClusterRouter(SetupTestCtx(t))
85 require.NoError(t, err)
86
87 testCases := map[string]struct {
88 input interface{}
89 expectedStatus int
90 response interface{}
91 expectedResponse interface{}
92 }{
93 "Success": {
94 input: struct{}{},
95 expectedStatus: http.StatusAccepted,
96 response: &cluster.State{},
97 expectedResponse: &cluster.State{
98 Name: testClusterName,
99 },
100 },
101 "Faillure_ReadOnlyName": {
102 input: NameEditor{
103 Name: "any-name",
104 },
105 expectedStatus: http.StatusBadRequest,
106 response: &Errors{},
107 expectedResponse: &Errors{
108 Errors: []*errors.Error{
109 {
110 Detail: errors.NewReadOnlyFieldMessage("Name"),
111 },
112 },
113 },
114 },
115 }
116
117 for name, tc := range testCases {
118 t.Run(name, func(t *testing.T) {
119 out, err := json.Marshal(tc.input)
120 require.NoError(t, err)
121
122 w := httptest.NewRecorder()
123 req, _ := http.NewRequest("PATCH", cluster.Path, bytes.NewBuffer(out))
124 r.ServeHTTP(w, req)
125
126 assert.Equal(t, tc.expectedStatus, w.Code)
127
128 require.NoError(t, json.Unmarshal(w.Body.Bytes(), tc.response))
129 assert.Equal(t, tc.expectedResponse, tc.response)
130 })
131 }
132 }
133
134 func initializeClusterRouter(ctx context.Context) (*gin.Engine, error) {
135 ei := &info.EdgeInfo{
136 BannerName: "example",
137 ProjectID: "example",
138 Store: testClusterName,
139 Fleet: "example",
140 ClusterType: "example",
141 Location: "example",
142 ForemanProjectID: "example",
143 BannerEdgeID: "example",
144 ClusterEdgeID: "example",
145 EdgeAPIEndpoint: "example",
146 }
147 cm := ei.ToConfigMap()
148
149 cli := getFakeKubeClient(cm)
150
151 cfg := &config.Config{
152 Fs: afero.NewMemMapFs(),
153 KubeRetryClient: retryclient.New(cli, cli, retryclient.Config{}),
154 Cache: &informertest.FakeInformers{},
155 }
156
157 wm := websocket.NewManager()
158
159 c, err := cluster.New(ctx, cfg, wm)
160 if err != nil {
161 return nil, err
162 }
163
164 r := gin.Default()
165 c.RegisterEndpoints(r)
166
167 return r, nil
168 }
169
170 func getFakeKubeClient(initObjs ...client.Object) client.Client {
171 return fake.NewClientBuilder().WithScheme(createScheme()).WithObjects(initObjs...).Build()
172 }
173
174 func createScheme() *kruntime.Scheme {
175 scheme := kruntime.NewScheme()
176 utilruntime.Must(clientgoscheme.AddToScheme(scheme))
177 return scheme
178 }
179
View as plain text