/* ================================================================================== Copyright (c) 2019 AT&T Intellectual Property. Copyright (c) 2019 Nokia Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================================================== */ package main import ( "bytes" "encoding/json" "errors" "github.com/gorilla/mux" "net/http" "net/http/httptest" "os" "reflect" "strconv" "testing" "time" ) var x XappManager var xapp Xapp var xapps []Xapp var helmError error type MockedHelmer struct { } func (sd *MockedHelmer) Initialize() { } func (h *MockedHelmer) Status(name string) (Xapp, error) { return xapp, helmError } func (h *MockedHelmer) StatusAll() ([]Xapp, error) { return xapps, helmError } func (h *MockedHelmer) List() (names []string, err error) { return names, helmError } func (h *MockedHelmer) Install(m ConfigMetadata) (Xapp, error) { return xapp, helmError } func (h *MockedHelmer) Delete(name string) (Xapp, error) { return xapp, helmError } // Test cases func TestMain(m *testing.M) { loadConfig() xapp = Xapp{} xapps = []Xapp{} h := MockedHelmer{} x = XappManager{} x.Initialize(&h) // Just run on the background (for coverage) go x.Run() x.ready = true time.Sleep(time.Duration(2 * time.Second)) code := m.Run() os.Exit(code) } func TestGetHealthCheck(t *testing.T) { req, _ := http.NewRequest("GET", "/ric/v1/health/ready", nil) response := executeRequest(req) checkResponseCode(t, http.StatusOK, response.Code) } func TestGetAppsReturnsEmpty(t *testing.T) { req, _ := http.NewRequest("GET", "/ric/v1/xapps", nil) response := executeRequest(req) checkResponseCode(t, http.StatusOK, response.Code) if body := response.Body.String(); body != "[]" { t.Errorf("handler returned unexpected body: got %v want []", body) } } func TestCreateXApp(t *testing.T) { xapp = generateXapp("dummy-xapp", "started", "1.0", "dummy-xapp-1234-5678", "running", "127.0.0.1", "9999") payload := []byte(`{"name":"dummy-xapp"}`) req, _ := http.NewRequest("POST", "/ric/v1/xapps", bytes.NewBuffer(payload)) response := executeRequest(req) checkResponseData(t, response, http.StatusCreated, false) } func TestGetAppsReturnsListOfXapps(t *testing.T) { xapps = append(xapps, xapp) req, _ := http.NewRequest("GET", "/ric/v1/xapps", nil) response := executeRequest(req) checkResponseData(t, response, http.StatusOK, true) } func TestGetAppByIdReturnsGivenXapp(t *testing.T) { req, _ := http.NewRequest("GET", "/ric/v1/xapps/"+xapp.Name, nil) response := executeRequest(req) checkResponseData(t, response, http.StatusOK, false) } func TestGetAppInstanceByIdReturnsGivenXapp(t *testing.T) { req, _ := http.NewRequest("GET", "/ric/v1/xapps/"+xapp.Name+"/instances/dummy-xapp-1234-5678", nil) response := executeRequest(req) var ins XappInstance checkResponseCode(t, http.StatusOK, response.Code) json.NewDecoder(response.Body).Decode(&ins) if !reflect.DeepEqual(ins, xapp.Instances[0]) { t.Errorf("handler returned unexpected body: got: %v, expected: %v", ins, xapp.Instances[0]) } } func TestDeleteAppRemovesGivenXapp(t *testing.T) { req, _ := http.NewRequest("DELETE", "/ric/v1/xapps/"+xapp.Name, nil) response := executeRequest(req) checkResponseData(t, response, http.StatusNoContent, false) // Xapp not found from the Redis DB helmError = errors.New("Not found") req, _ = http.NewRequest("GET", "/ric/v1/xapps/"+xapp.Name, nil) response = executeRequest(req) checkResponseCode(t, http.StatusNotFound, response.Code) } // Error handling func TestGetXappReturnsError(t *testing.T) { helmError = errors.New("Not found") req, _ := http.NewRequest("GET", "/ric/v1/xapps/invalidXappName", nil) response := executeRequest(req) checkResponseCode(t, http.StatusNotFound, response.Code) } func TestGetXappInstanceReturnsError(t *testing.T) { helmError = errors.New("Some error") req, _ := http.NewRequest("GET", "/ric/v1/xapps/"+xapp.Name+"/instances/invalidXappName", nil) response := executeRequest(req) checkResponseCode(t, http.StatusNotFound, response.Code) } func TestGetXappListReturnsError(t *testing.T) { helmError = errors.New("Internal error") req, _ := http.NewRequest("GET", "/ric/v1/xapps", nil) response := executeRequest(req) checkResponseCode(t, http.StatusInternalServerError, response.Code) } func TestCreateXAppWithoutXappData(t *testing.T) { req, _ := http.NewRequest("POST", "/ric/v1/xapps", nil) response := executeRequest(req) checkResponseData(t, response, http.StatusMethodNotAllowed, false) } func TestCreateXAppWithInvalidXappData(t *testing.T) { body := []byte("Invalid JSON data ...") req, _ := http.NewRequest("POST", "/ric/v1/xapps", bytes.NewBuffer(body)) response := executeRequest(req) checkResponseData(t, response, http.StatusMethodNotAllowed, false) } func TestCreateXAppReturnsError(t *testing.T) { helmError = errors.New("Not found") payload := []byte(`{"name":"dummy-xapp"}`) req, _ := http.NewRequest("POST", "/ric/v1/xapps", bytes.NewBuffer(payload)) response := executeRequest(req) checkResponseData(t, response, http.StatusInternalServerError, false) } func TestDeleteXappListReturnsError(t *testing.T) { helmError = errors.New("Internal error") req, _ := http.NewRequest("DELETE", "/ric/v1/xapps/invalidXappName", nil) response := executeRequest(req) checkResponseCode(t, http.StatusInternalServerError, response.Code) } // Helper functions type fn func(w http.ResponseWriter, r *http.Request) func executeRequest(req *http.Request) *httptest.ResponseRecorder { rr := httptest.NewRecorder() vars := map[string]string{ "id": "1", } req = mux.SetURLVars(req, vars) x.router.ServeHTTP(rr, req) return rr } func checkResponseCode(t *testing.T, expected, actual int) { if expected != actual { t.Errorf("Expected response code %d. Got %d\n", expected, actual) } } func checkResponseData(t *testing.T, response *httptest.ResponseRecorder, expectedHttpStatus int, isList bool) { expectedData := xapp checkResponseCode(t, expectedHttpStatus, response.Code) if isList == true { jsonResp := []Xapp{} json.NewDecoder(response.Body).Decode(&jsonResp) if !reflect.DeepEqual(jsonResp[0], expectedData) { t.Errorf("handler returned unexpected body: %v", jsonResp) } } else { json.NewDecoder(response.Body).Decode(&xapp) if !reflect.DeepEqual(xapp, expectedData) { t.Errorf("handler returned unexpected body: got: %v, expected: %v", xapp, expectedData) } } } func generateXapp(name, status, ver, iname, istatus, ip, port string) (x Xapp) { x.Name = name x.Status = status x.Version = ver p, _ := strconv.Atoi(port) instance := XappInstance{ Name: iname, Status: istatus, Ip: ip, Port: p, TxMessages: []string{"RIC_E2_TERMINATION_HC_REQUEST", "RIC_E2_MANAGER_HC_REQUEST"}, RxMessages: []string{"RIC_E2_TERMINATION_HC_RESPONSE", "RIC_E2_MANAGER_HC_RESPONSE"}, } x.Instances = append(x.Instances, instance) return }