github.com/kyma-project/kyma-environment-broker@v0.0.1/internal/avs/mock_server.go (about) 1 package avs 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "math/rand" 7 "net/http" 8 "net/http/httptest" 9 "strconv" 10 "testing" 11 "time" 12 13 "github.com/gorilla/mux" 14 "github.com/stretchr/testify/assert" 15 "golang.org/x/oauth2" 16 ) 17 18 const ( 19 accessToken = "1234abcd" 20 tokenType = "test" 21 ) 22 23 // MockAvsEvaluationRepository represents BasicEvaluations in AVS 24 // where BasicEvals is mapping BasicEvaluation ID to BasicEvaluation (Subevaluation) definition 25 // and ParentIDrefs is mapping CompoundEvaluation ID (parentID) to BasicEvaluations (Subevaluations) IDs 26 type MockAvsEvaluationRepository struct { 27 BasicEvals map[int64]*BasicEvaluationCreateResponse 28 EvalSet map[int64]bool 29 ParentIDrefs map[int64][]int64 30 } 31 32 type MockAvsServer struct { 33 T *testing.T 34 Evaluations *MockAvsEvaluationRepository 35 TokenExpired int 36 } 37 38 func NewMockAvsServer(t *testing.T) *MockAvsServer { 39 return &MockAvsServer{ 40 T: t, 41 Evaluations: &MockAvsEvaluationRepository{ 42 BasicEvals: make(map[int64]*BasicEvaluationCreateResponse, 0), 43 EvalSet: make(map[int64]bool, 0), 44 ParentIDrefs: make(map[int64][]int64, 0), 45 }, 46 } 47 } 48 49 func FixMockAvsServer(srv *MockAvsServer) *httptest.Server { 50 r := mux.NewRouter() 51 52 r.HandleFunc("/oauth/token", srv.token).Methods(http.MethodPost) 53 r.HandleFunc("/api/v2/evaluationmetadata", srv.createEvaluation).Methods(http.MethodPost) 54 r.HandleFunc("/api/v2/evaluationmetadata/{evalId}", srv.deleteEvaluation).Methods(http.MethodDelete) 55 r.HandleFunc("/api/v2/evaluationmetadata/{evalId}", srv.getEvaluation).Methods(http.MethodGet) 56 r.HandleFunc("/api/v2/evaluationmetadata/{evalId}/tag", srv.addTagToEvaluation).Methods(http.MethodPost) 57 r.HandleFunc("/api/v2/evaluationmetadata/{evalId}/lifecycle", srv.setStatus).Methods(http.MethodPut) 58 r.HandleFunc("/api/v2/evaluationmetadata/{parentId}/child/{evalId}", srv.removeReferenceFromParentEval).Methods(http.MethodDelete) 59 60 return httptest.NewServer(r) 61 } 62 63 func (s *MockAvsServer) token(w http.ResponseWriter, _ *http.Request) { 64 token := oauth2.Token{ 65 AccessToken: accessToken, 66 TokenType: tokenType, 67 RefreshToken: "", 68 Expiry: time.Time{}, 69 } 70 71 response, err := json.Marshal(token) 72 assert.NoError(s.T, err) 73 w.Header().Set("Content-Type", "application/json") 74 _, err = w.Write(response) 75 assert.NoError(s.T, err) 76 } 77 78 func (s *MockAvsServer) hasAccess(token string) bool { 79 if s.TokenExpired > 0 { 80 s.TokenExpired-- 81 return false 82 } 83 if token == fmt.Sprintf("%s %s", tokenType, accessToken) { 84 return true 85 } 86 87 return false 88 } 89 90 func (er *MockAvsEvaluationRepository) addEvaluation(parentID int64, eval *BasicEvaluationCreateResponse) { 91 er.BasicEvals[eval.Id] = eval 92 er.EvalSet[eval.Id] = true 93 er.ParentIDrefs[parentID] = append(er.ParentIDrefs[parentID], eval.Id) 94 } 95 96 func (er *MockAvsEvaluationRepository) removeParentRef(parentID, evalID int64) { 97 refs := er.ParentIDrefs[parentID] 98 99 for i, evalWithRef := range refs { 100 if evalID == evalWithRef { 101 refs[i] = refs[len(refs)-1] 102 er.ParentIDrefs[parentID] = refs[:len(refs)-1] 103 } 104 } 105 } 106 107 func (s *MockAvsServer) createEvaluation(w http.ResponseWriter, r *http.Request) { 108 assert.Equal(s.T, r.Header.Get("Content-Type"), "application/json") 109 if !s.hasAccess(r.Header.Get("Authorization")) { 110 w.WriteHeader(http.StatusUnauthorized) 111 return 112 } 113 114 var requestObj BasicEvaluationCreateRequest 115 err := json.NewDecoder(r.Body).Decode(&requestObj) 116 assert.NoError(s.T, err) 117 118 evalCreateResponse := s.createResponseObj(requestObj) 119 s.Evaluations.addEvaluation(requestObj.ParentId, evalCreateResponse) 120 121 createdEval := s.Evaluations.BasicEvals[evalCreateResponse.Id] 122 responseObjAsBytes, _ := json.Marshal(createdEval) 123 _, err = w.Write(responseObjAsBytes) 124 assert.NoError(s.T, err) 125 126 w.WriteHeader(http.StatusOK) 127 } 128 129 func (s *MockAvsServer) getEvaluation(w http.ResponseWriter, r *http.Request) { 130 assert.Equal(s.T, r.Header.Get("Content-Type"), "application/json") 131 if !s.hasAccess(r.Header.Get("Authorization")) { 132 w.WriteHeader(http.StatusUnauthorized) 133 return 134 } 135 136 vars := mux.Vars(r) 137 evalId, err := strconv.ParseInt(vars["evalId"], 10, 64) 138 if err != nil { 139 w.WriteHeader(http.StatusInternalServerError) 140 } 141 response, exists := s.Evaluations.BasicEvals[evalId] 142 if !exists { 143 w.WriteHeader(http.StatusNotFound) 144 } 145 146 responseObjAsBytes, _ := json.Marshal(response) 147 _, err = w.Write(responseObjAsBytes) 148 assert.NoError(s.T, err) 149 } 150 151 func (s *MockAvsServer) addTagToEvaluation(w http.ResponseWriter, r *http.Request) { 152 assert.Equal(s.T, r.Header.Get("Content-Type"), "application/json") 153 if !s.hasAccess(r.Header.Get("Authorization")) { 154 w.WriteHeader(http.StatusUnauthorized) 155 return 156 } 157 158 var requestObj *Tag 159 err := json.NewDecoder(r.Body).Decode(&requestObj) 160 assert.NoError(s.T, err) 161 162 vars := mux.Vars(r) 163 evalId, err := strconv.ParseInt(vars["evalId"], 10, 64) 164 if err != nil { 165 w.WriteHeader(http.StatusInternalServerError) 166 } 167 evaluation, exists := s.Evaluations.BasicEvals[evalId] 168 if !exists { 169 w.WriteHeader(http.StatusNotFound) 170 } 171 172 evaluation.Tags = append(evaluation.Tags, requestObj) 173 174 responseObjAsBytes, _ := json.Marshal(evaluation) 175 _, err = w.Write(responseObjAsBytes) 176 assert.NoError(s.T, err) 177 } 178 179 func (s *MockAvsServer) setStatus(w http.ResponseWriter, r *http.Request) { 180 assert.Equal(s.T, r.Header.Get("Content-Type"), "application/json") 181 if !s.hasAccess(r.Header.Get("Authorization")) { 182 w.WriteHeader(http.StatusUnauthorized) 183 return 184 } 185 186 var requestObj string 187 err := json.NewDecoder(r.Body).Decode(&requestObj) 188 assert.NoError(s.T, err) 189 190 if !ValidStatus(requestObj) { 191 w.WriteHeader(http.StatusInternalServerError) 192 } 193 194 vars := mux.Vars(r) 195 evalId, err := strconv.ParseInt(vars["evalId"], 10, 64) 196 if err != nil { 197 w.WriteHeader(http.StatusInternalServerError) 198 } 199 evaluation, exists := s.Evaluations.BasicEvals[evalId] 200 if !exists { 201 w.WriteHeader(http.StatusNotFound) 202 } 203 204 evaluation.Status = requestObj 205 206 responseObjAsBytes, _ := json.Marshal(evaluation) 207 _, err = w.Write(responseObjAsBytes) 208 assert.NoError(s.T, err) 209 } 210 211 func (s *MockAvsServer) deleteEvaluation(w http.ResponseWriter, r *http.Request) { 212 if !s.hasAccess(r.Header.Get("Authorization")) { 213 w.WriteHeader(http.StatusUnauthorized) 214 return 215 } 216 217 vars := mux.Vars(r) 218 id, err := strconv.ParseInt(vars["evalId"], 10, 64) 219 assert.NoError(s.T, err) 220 221 if _, exists := s.Evaluations.BasicEvals[id]; exists { 222 delete(s.Evaluations.BasicEvals, id) 223 delete(s.Evaluations.EvalSet, id) 224 w.WriteHeader(http.StatusOK) 225 return 226 } 227 228 w.WriteHeader(http.StatusNotFound) 229 } 230 231 func (s *MockAvsServer) removeReferenceFromParentEval(w http.ResponseWriter, r *http.Request) { 232 if !s.hasAccess(r.Header.Get("Authorization")) { 233 w.WriteHeader(http.StatusUnauthorized) 234 return 235 } 236 237 vars := mux.Vars(r) 238 parentID, err := strconv.ParseInt(vars["parentId"], 10, 64) 239 assert.NoError(s.T, err) 240 241 evalID, err := strconv.ParseInt(vars["evalId"], 10, 64) 242 assert.NoError(s.T, err) 243 244 _, exists := s.Evaluations.ParentIDrefs[parentID] 245 if !exists { 246 resp := avsApiErrorResp{ 247 StatusCode: http.StatusBadRequest, 248 Status: "BAD_REQUEST", 249 Message: fmt.Sprintf("Evaluation %d does not contain subevaluation %d", parentID, evalID), 250 } 251 w.WriteHeader(http.StatusBadRequest) 252 bytes, _ := json.Marshal(resp) 253 _, err := w.Write(bytes) 254 assert.NoError(s.T, err) 255 } 256 257 s.Evaluations.removeParentRef(parentID, evalID) 258 } 259 260 func FixTag() *Tag { 261 return &Tag{ 262 Content: "test-tag", 263 TagClassId: 111111, 264 } 265 } 266 267 func (s *MockAvsServer) createResponseObj(requestObj BasicEvaluationCreateRequest) *BasicEvaluationCreateResponse { 268 parsedThreshold, err := strconv.ParseInt(requestObj.Threshold, 10, 64) 269 if err != nil { 270 parsedThreshold = int64(1234) 271 } 272 273 timeUnixEpoch, id := s.generateId() 274 275 evalCreateResponse := &BasicEvaluationCreateResponse{ 276 DefinitionType: requestObj.DefinitionType, 277 Name: requestObj.Name, 278 Description: requestObj.Description, 279 Service: requestObj.Service, 280 URL: requestObj.URL, 281 CheckType: requestObj.CheckType, 282 Interval: requestObj.Interval, 283 TesterAccessId: requestObj.TesterAccessId, 284 Timeout: requestObj.Timeout, 285 ReadOnly: requestObj.ReadOnly, 286 ContentCheck: requestObj.ContentCheck, 287 ContentCheckType: requestObj.ContentCheck, 288 Threshold: parsedThreshold, 289 GroupId: requestObj.GroupId, 290 Visibility: requestObj.Visibility, 291 DateCreated: timeUnixEpoch, 292 DateChanged: timeUnixEpoch, 293 Owner: "abc@xyz.corp", 294 Status: "ACTIVE", 295 Alerts: nil, 296 Tags: requestObj.Tags, 297 Id: id, 298 LegacyCheckId: id, 299 InternalInterval: 60, 300 AuthType: "AUTH_NONE", 301 IndividualOutageEventsOnly: false, 302 IdOnTester: "", 303 } 304 return evalCreateResponse 305 } 306 307 func (s *MockAvsServer) generateId() (int64, int64) { 308 for { 309 timeUnixEpoch := time.Now().Unix() 310 id := rand.Int63() + time.Now().Unix() 311 if _, exists := s.Evaluations.EvalSet[id]; !exists { 312 return timeUnixEpoch, id 313 } 314 } 315 }