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  }