func (server *Server) serveGroup(writer http.ResponseWriter, request *http.Request) { var ( groupID string groupType int ) if strings.HasPrefix(request.URL.Path, urlLibraryPath+"sourcegroups") { groupID = strings.TrimPrefix(request.URL.Path, urlLibraryPath+"sourcegroups/") groupType = library.LibraryItemSourceGroup } else if strings.HasPrefix(request.URL.Path, urlLibraryPath+"metricgroups") { groupID = strings.TrimPrefix(request.URL.Path, urlLibraryPath+"metricgroups/") groupType = library.LibraryItemMetricGroup } switch request.Method { case "DELETE": if groupID == "" { server.serveResponse(writer, serverResponse{mesgMethodNotAllowed}, http.StatusMethodNotAllowed) return } err := server.Library.DeleteItem(groupID, groupType) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } server.serveResponse(writer, nil, http.StatusOK) case "GET", "HEAD": if groupID == "" { server.serveGroupList(writer, request) return } item, err := server.Library.GetItem(groupID, groupType) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } server.serveResponse(writer, item, http.StatusOK) case "POST", "PUT": var group *library.Group if response, status := server.parseStoreRequest(writer, request, groupID); status != http.StatusOK { server.serveResponse(writer, response, status) return } if request.Method == "POST" && request.FormValue("inherit") != "" { // Get group from library item, err := server.Library.GetItem(request.FormValue("inherit"), groupType) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } group = &library.Group{} utils.Clone(item.(*library.Group), group) group.ID = "" } else { // Create a new group instance group = &library.Group{Item: library.Item{ID: groupID}, Type: groupType} } group.Modified = time.Now() // Parse input JSON for group data body, _ := ioutil.ReadAll(request.Body) if err := json.Unmarshal(body, group); err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgResourceInvalid}, http.StatusBadRequest) return } // Store group data err := server.Library.StoreItem(group, groupType) if response, status := server.parseError(writer, request, err); status != http.StatusOK { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, response, status) return } if request.Method == "POST" { writer.Header().Add("Location", strings.TrimRight(request.URL.Path, "/")+"/"+group.ID) server.serveResponse(writer, nil, http.StatusCreated) } else { server.serveResponse(writer, nil, http.StatusOK) } default: server.serveResponse(writer, serverResponse{mesgMethodNotAllowed}, http.StatusMethodNotAllowed) } }
func (server *Server) servePlots(writer http.ResponseWriter, request *http.Request) { var ( err error graph *library.Graph item interface{} ) if request.Method != "POST" && request.Method != "HEAD" { server.serveResponse(writer, serverResponse{mesgMethodNotAllowed}, http.StatusMethodNotAllowed) return } else if utils.HTTPGetContentType(request) != "application/json" { server.serveResponse(writer, serverResponse{mesgUnsupportedMediaType}, http.StatusUnsupportedMediaType) return } // Check for requests loop if request.Header.Get("X-Facette-Requestor") == server.ID { logger.Log(logger.LevelWarning, "server", "request loop detected, cancelled") server.serveResponse(writer, serverResponse{mesgEmptyData}, http.StatusBadRequest) return } // Parse plots request plotReq, err := parsePlotRequest(request) if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgResourceInvalid}, http.StatusBadRequest) return } // Get graph definition from the plot request graph = plotReq.Graph // If a Graph ID has been provided in the plot request, fetch the graph definition from the library instead if plotReq.ID != "" { graph = &library.Graph{} if item, err = server.Library.GetItem(plotReq.ID, library.LibraryItemGraph); err == nil { utils.Clone(item.(*library.Graph), graph) } } if graph == nil { err = os.ErrNotExist } // Stop if an error was encountered if err != nil { if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) } else { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) } return } // If linked graph, expand its template if graph.Link != "" || graph.ID == "" && len(graph.Attributes) > 0 { if graph.Link != "" { // Get graph template from library item, err := server.Library.GetItem(graph.Link, library.LibraryItemGraph) if err != nil { logger.Log(logger.LevelError, "server", "graph template not found: %s", graph.Link) return } utils.Clone(item.(*library.Graph), graph) } if err = server.expandGraphTemplate(graph); err != nil { logger.Log(logger.LevelError, "server", "unable to apply graph template: %s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) } } // Prepare queries to be executed by the providers providerQueries, err := server.prepareProviderQueries(plotReq, graph) if err != nil { if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) } else { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) } return } plotSeries, err := executeQueries(providerQueries) if err != nil { logger.Log(logger.LevelError, "server", "unable to execute provider queries: %s", err) server.serveResponse(writer, serverResponse{mesgProviderQueryError}, http.StatusInternalServerError) return } if len(plotSeries) == 0 { server.serveResponse(writer, serverResponse{mesgEmptyData}, http.StatusOK) return } response, err := makePlotsResponse(plotSeries, plotReq, graph) if err != nil { logger.Log(logger.LevelError, "server", "unable to make plots response: %s", err) server.serveResponse(writer, serverResponse{mesgPlotOperationError}, http.StatusInternalServerError) return } server.serveResponse(writer, response, http.StatusOK) }
func (server *Server) serveCollection(writer http.ResponseWriter, request *http.Request) { type tmpCollection struct { *library.Collection Parent string `json:"parent"` } if request.Method != "GET" && request.Method != "HEAD" && server.Config.ReadOnly { server.serveResponse(writer, serverResponse{mesgReadOnlyMode}, http.StatusForbidden) return } collectionID := routeTrimPrefix(request.URL.Path, urlLibraryPath+"collections") switch request.Method { case "DELETE": if collectionID == "" { server.serveResponse(writer, serverResponse{mesgMethodNotAllowed}, http.StatusMethodNotAllowed) return } err := server.Library.DeleteItem(collectionID, library.LibraryItemCollection) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } server.serveResponse(writer, nil, http.StatusOK) case "GET", "HEAD": if collectionID == "" { server.serveCollectionList(writer, request) return } item, err := server.Library.GetItem(collectionID, library.LibraryItemCollection) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } server.serveResponse(writer, item, http.StatusOK) case "POST", "PUT": if response, status := server.parseStoreRequest(writer, request, collectionID); status != http.StatusOK { server.serveResponse(writer, response, status) return } collectionTemp := &tmpCollection{ Collection: &library.Collection{ Item: library.Item{ID: collectionID}, }, } if request.Method == "POST" && request.FormValue("inherit") != "" { // Get collection from library item, err := server.Library.GetItem(request.FormValue("inherit"), library.LibraryItemCollection) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } // Temporarily remove children information then clone item children := item.(*library.Collection).Children item.(*library.Collection).Children = nil utils.Clone(item.(*library.Collection), collectionTemp.Collection) item.(*library.Collection).Children = children // Reset item identifier collectionTemp.Collection.ID = "" } collectionTemp.Collection.Modified = time.Now() // Parse input JSON for collection data body, _ := ioutil.ReadAll(request.Body) if err := json.Unmarshal(body, &collectionTemp); err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgResourceInvalid}, http.StatusBadRequest) return } // Update parent relation if item, _ := server.Library.GetItem(collectionTemp.Parent, library.LibraryItemCollection); item != nil { parent := item.(*library.Collection) // Register parent relation collectionTemp.Collection.Parent = parent collectionTemp.Collection.ParentID = parent.ID if collectionTemp.Collection.ID == "" || parent.IndexOfChild(collectionTemp.Collection.ID) == -1 { parent.Children = append(parent.Children, collectionTemp.Collection) } } else { // Remove existing parent relation if item, _ := server.Library.GetItem(collectionTemp.Collection.ID, library.LibraryItemCollection); item != nil { collection := item.(*library.Collection) if collection.Parent != nil { if index := collection.Parent.IndexOfChild(collectionTemp.Collection.ID); index != -1 { collection.Parent.Children = append(collection.Parent.Children[:index], collection.Parent.Children[index+1:]...) } } } } // Keep current children list if item, _ := server.Library.GetItem(collectionTemp.Collection.ID, library.LibraryItemCollection); item != nil { collectionTemp.Collection.Children = item.(*library.Collection).Children } // Store collection data err := server.Library.StoreItem(collectionTemp.Collection, library.LibraryItemCollection) if response, status := server.parseError(writer, request, err); status != http.StatusOK { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, response, status) return } if request.Method == "POST" { writer.Header().Add("Location", strings.TrimRight(request.URL.Path, "/")+"/"+collectionTemp.Collection.ID) server.serveResponse(writer, nil, http.StatusCreated) } else { server.serveResponse(writer, nil, http.StatusOK) } default: server.serveResponse(writer, serverResponse{mesgMethodNotAllowed}, http.StatusMethodNotAllowed) } }
func (server *Server) serveUnit(writer http.ResponseWriter, request *http.Request) { if request.Method != "GET" && request.Method != "HEAD" && server.Config.ReadOnly { server.serveResponse(writer, serverResponse{mesgReadOnlyMode}, http.StatusForbidden) return } unitID := routeTrimPrefix(request.URL.Path, urlLibraryPath+"units") switch request.Method { case "DELETE": if unitID == "" { server.serveResponse(writer, serverResponse{mesgMethodNotAllowed}, http.StatusMethodNotAllowed) return } err := server.Library.DeleteItem(unitID, library.LibraryItemUnit) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } server.serveResponse(writer, nil, http.StatusOK) case "GET", "HEAD": if unitID == "" { server.serveUnitList(writer, request) return } item, err := server.Library.GetItem(unitID, library.LibraryItemUnit) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } server.serveResponse(writer, item, http.StatusOK) case "POST", "PUT": var unit *library.Unit if response, status := server.parseStoreRequest(writer, request, unitID); status != http.StatusOK { server.serveResponse(writer, response, status) return } if request.Method == "POST" && request.FormValue("inherit") != "" { // Get unit from library item, err := server.Library.GetItem(request.FormValue("inherit"), library.LibraryItemUnit) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } // Clone item unit = &library.Unit{} utils.Clone(item.(*library.Unit), unit) // Reset item identifier unit.ID = "" } else { // Create a new unit instance unit = &library.Unit{Item: library.Item{ID: unitID}} } unit.Modified = time.Now() // Parse input JSON for unit data body, _ := ioutil.ReadAll(request.Body) if err := json.Unmarshal(body, unit); err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgResourceInvalid}, http.StatusBadRequest) return } // Store unit data err := server.Library.StoreItem(unit, library.LibraryItemUnit) if response, status := server.parseError(writer, request, err); status != http.StatusOK { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, response, status) return } if request.Method == "POST" { writer.Header().Add("Location", strings.TrimRight(request.URL.Path, "/")+"/"+unit.ID) server.serveResponse(writer, nil, http.StatusCreated) } else { server.serveResponse(writer, nil, http.StatusOK) } default: server.serveResponse(writer, serverResponse{mesgMethodNotAllowed}, http.StatusMethodNotAllowed) } }
func (server *Server) serveGraph(writer http.ResponseWriter, request *http.Request) { var graph *library.Graph if request.Method != "GET" && request.Method != "HEAD" && server.Config.ReadOnly { server.serveResponse(writer, serverResponse{mesgReadOnlyMode}, http.StatusForbidden) return } graphID := routeTrimPrefix(request.URL.Path, urlLibraryPath+"graphs") switch request.Method { case "DELETE": if graphID == "" { server.serveResponse(writer, serverResponse{mesgMethodNotAllowed}, http.StatusMethodNotAllowed) return } err := server.Library.DeleteItem(graphID, library.LibraryItemGraph) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } server.serveResponse(writer, nil, http.StatusOK) case "GET", "HEAD": if graphID == "" { server.serveGraphList(writer, request) return } item, err := server.Library.GetItem(graphID, library.LibraryItemGraph) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } server.serveResponse(writer, item, http.StatusOK) case "POST", "PUT": if response, status := server.parseStoreRequest(writer, request, graphID); status != http.StatusOK { server.serveResponse(writer, response, status) return } // Inheritance requested: clone an existing graph if request.Method == "POST" && request.FormValue("inherit") != "" { item, err := server.Library.GetItem(request.FormValue("inherit"), library.LibraryItemGraph) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } // Clone item graph = &library.Graph{} utils.Clone(item.(*library.Graph), graph) // Reset item identifier graph.ID = "" } else { // Create a new graph instance graph = &library.Graph{Item: library.Item{ID: graphID}} } // Parse input JSON for graph data body, _ := ioutil.ReadAll(request.Body) if err := json.Unmarshal(body, graph); err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgResourceInvalid}, http.StatusBadRequest) return } // Check for graph type consistency (either a graph or an instance but not both) if !graph.Template && (graph.Link != "" || len(graph.Attributes) > 0) && (graph.Description != "" || graph.Title != "" || graph.Type != 0 || graph.StackMode != 0 || graph.UnitType != 0 || graph.UnitLegend != "" || graph.Groups != nil) || graph.Template && (graph.Link != "" || len(graph.Attributes) > 0) { server.serveResponse(writer, serverResponse{mesgResourceInvalid}, http.StatusBadRequest) return } // Store graph item err := server.Library.StoreItem(graph, library.LibraryItemGraph) if response, status := server.parseError(writer, request, err); status != http.StatusOK { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, response, status) return } if request.Method == "POST" { writer.Header().Add("Location", strings.TrimRight(request.URL.Path, "/")+"/"+graph.ID) server.serveResponse(writer, nil, http.StatusCreated) } else { server.serveResponse(writer, nil, http.StatusOK) } default: server.serveResponse(writer, serverResponse{mesgMethodNotAllowed}, http.StatusMethodNotAllowed) } }
func Test_LibraryCollectionHandle(test *testing.T) { var collectionBase struct { *library.Collection Parent string `json:"parent"` } baseURL := fmt.Sprintf("http://%s/api/v1/library/collections/", serverConfig.BindAddr) // Define a sample collection collectionBase.Collection = &library.Collection{Item: library.Item{Name: "collection0", Description: "A great collection description."}} collectionBase.Entries = append(collectionBase.Entries, &library.CollectionEntry{ID: "00000000-0000-0000-0000-000000000000", Options: map[string]interface{}{"range": "-1h"}}) collectionBase.Entries = append(collectionBase.Entries, &library.CollectionEntry{ID: "00000000-0000-0000-0000-000000000000", Options: map[string]interface{}{"range": "-1d"}}) collectionBase.Entries = append(collectionBase.Entries, &library.CollectionEntry{ID: "00000000-0000-0000-0000-000000000000", Options: map[string]interface{}{"range": "-1w"}}) // Test GET on collections list listBase := server.ItemListResponse{} listResult := server.ItemListResponse{} response := execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } // Test GET on a unknown collection item response = execTestRequest(test, "GET", baseURL+"/00000000-0000-0000-0000-000000000000", nil, nil) if response.StatusCode != http.StatusNotFound { test.Logf("\nExpected %d\nbut got %d", http.StatusNotFound, response.StatusCode) test.Fail() } // Test POST into collection data, _ := json.Marshal(collectionBase) response = execTestRequest(test, "POST", baseURL, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusCreated { test.Logf("\nExpected %d\nbut got %d", http.StatusCreated, response.StatusCode) test.Fail() } if response.Header.Get("Location") == "" { test.Logf("\nExpected `Location' header") test.Fail() } collectionBase.ID = response.Header.Get("Location")[strings.LastIndex(response.Header.Get("Location"), "/")+1:] // Test GET on collection item collectionResult := &library.Collection{} response = execTestRequest(test, "GET", baseURL+collectionBase.ID, nil, &collectionResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(collectionBase.Collection, collectionResult) { test.Logf("\nExpected %#v\nbut got %#v", collectionBase.Collection, collectionResult) test.Fail() } // Test GET on collections list listBase = server.ItemListResponse{&server.ItemResponse{ ID: collectionBase.ID, Name: collectionBase.Name, Description: collectionBase.Description, }} listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } // Test PUT on collection item collectionBase.Name = "collection0-updated" data, _ = json.Marshal(collectionBase.Collection) response = execTestRequest(test, "PUT", baseURL+collectionBase.ID, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } // Test GET on collection item collectionResult = &library.Collection{} response = execTestRequest(test, "GET", baseURL+collectionBase.ID, nil, &collectionResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(collectionBase.Collection, collectionResult) { test.Logf("\nExpected %#v\nbut got %#v", collectionBase, collectionResult) test.Fail() } // Test DELETE on collection item response = execTestRequest(test, "DELETE", baseURL+collectionBase.ID, nil, nil) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } response = execTestRequest(test, "DELETE", baseURL+collectionBase.ID, nil, nil) if response.StatusCode != http.StatusNotFound { test.Logf("\nExpected %d\nbut got %d", http.StatusNotFound, response.StatusCode) test.Fail() } // Test GET on collections list (offset and limit) listBase = server.ItemListResponse{} for i := 0; i < 3; i += 1 { collectionTemp := &library.Collection{} utils.Clone(collectionBase, collectionTemp) collectionTemp.ID = "" collectionTemp.Name = fmt.Sprintf("collection0-%d", i) data, _ = json.Marshal(collectionTemp) response = execTestRequest(test, "POST", baseURL, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusCreated { test.Logf("\nExpected %d\nbut got %d", http.StatusCreated, response.StatusCode) test.Fail() } location := response.Header.Get("Location") if location == "" { test.Logf("\nExpected `Location' header") test.Fail() } collectionTemp.ID = location[strings.LastIndex(location, "/")+1:] listBase = append(listBase, &server.ItemResponse{ ID: collectionTemp.ID, Name: collectionTemp.Name, Description: collectionTemp.Description, }) } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL+"?limit=1", nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase[:1], listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase[:1], listResult) test.Fail() } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL+"?offset=1&limit=2", nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase[1:3], listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase[1:3], listResult) test.Fail() } }
func Test_LibraryGraphHandle(test *testing.T) { baseURL := fmt.Sprintf("http://%s/api/v1/library/graphs/", serverConfig.BindAddr) // Define a sample graph graphBase := &library.Graph{Item: library.Item{Name: "graph0", Description: "A great graph description."}, StackMode: library.StackModeNormal} group := &library.OperGroup{Name: "group0", Type: connector.OperGroupTypeAvg} group.Series = append(group.Series, &library.Serie{Name: "serie0", Origin: "test", Source: "source1", Metric: "database1/test"}) group.Series = append(group.Series, &library.Serie{Name: "serie1", Origin: "test", Source: "source2", Metric: "group:group0"}) graphBase.Groups = append(graphBase.Groups, group) group = &library.OperGroup{Name: "serie2", Type: connector.OperGroupTypeNone} group.Series = append(group.Series, &library.Serie{Name: "serie2", Origin: "test", Source: "group:group0", Metric: "database2/test"}) graphBase.Groups = append(graphBase.Groups, group) // Test GET on graphs list listBase := server.ItemListResponse{} listResult := server.ItemListResponse{} response := execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } // Test GET on a unknown graph item response = execTestRequest(test, "GET", baseURL+"/00000000-0000-0000-0000-000000000000", nil, nil) if response.StatusCode != http.StatusNotFound { test.Logf("\nExpected %d\nbut got %d", http.StatusNotFound, response.StatusCode) test.Fail() } // Test POST into graph data, _ := json.Marshal(graphBase) response = execTestRequest(test, "POST", baseURL, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusCreated { test.Logf("\nExpected %d\nbut got %d", http.StatusCreated, response.StatusCode) test.Fail() } if response.Header.Get("Location") == "" { test.Logf("\nExpected `Location' header") test.Fail() } graphBase.ID = response.Header.Get("Location")[strings.LastIndex(response.Header.Get("Location"), "/")+1:] // Test GET on graph item graphResult := &library.Graph{} response = execTestRequest(test, "GET", baseURL+graphBase.ID, nil, &graphResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(graphBase, graphResult) { test.Logf("\nExpected %#v\nbut got %#v", graphBase, graphResult) test.Fail() } // Test GET on graphs list listBase = server.ItemListResponse{&server.ItemResponse{ ID: graphBase.ID, Name: graphBase.Name, Description: graphBase.Description, }} listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } // Test PUT on graph item graphBase.Name = "graph0-updated" data, _ = json.Marshal(graphBase) response = execTestRequest(test, "PUT", baseURL+graphBase.ID, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } // Test GET on graph item graphResult = &library.Graph{} response = execTestRequest(test, "GET", baseURL+graphBase.ID, nil, &graphResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(graphBase, graphResult) { test.Logf("\nExpected %#v\nbut got %#v", graphBase, graphResult) test.Fail() } // Test DELETE on graph item response = execTestRequest(test, "DELETE", baseURL+graphBase.ID, nil, nil) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } response = execTestRequest(test, "DELETE", baseURL+graphBase.ID, nil, nil) if response.StatusCode != http.StatusNotFound { test.Logf("\nExpected %d\nbut got %d", http.StatusNotFound, response.StatusCode) test.Fail() } // Test GET on graphs list (offset and limit) listBase = server.ItemListResponse{} for i := 0; i < 3; i += 1 { graphTemp := &library.Graph{} utils.Clone(graphBase, graphTemp) graphTemp.ID = "" graphTemp.Name = fmt.Sprintf("graph0-%d", i) data, _ = json.Marshal(graphTemp) response = execTestRequest(test, "POST", baseURL, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusCreated { test.Logf("\nExpected %d\nbut got %d", http.StatusCreated, response.StatusCode) test.Fail() } location := response.Header.Get("Location") if location == "" { test.Logf("\nExpected `Location' header") test.Fail() } graphTemp.ID = location[strings.LastIndex(location, "/")+1:] listBase = append(listBase, &server.ItemResponse{ ID: graphTemp.ID, Name: graphTemp.Name, Description: graphTemp.Description, }) } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL+"?limit=1", nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase[:1], listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase[:1], listResult) test.Fail() } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL+"?offset=1&limit=2", nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase[1:3], listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase[1:3], listResult) test.Fail() } }
func Test_LibraryScaleHandle(test *testing.T) { baseURL := fmt.Sprintf("http://%s/api/v1/library/scales/", serverConfig.BindAddr) // Define a sample scale scaleBase := &library.Scale{Item: library.Item{Name: "scale0", Description: "A great scale description."}, Value: 0.125} // Test GET on scales list listBase := server.ItemListResponse{} listResult := server.ItemListResponse{} response := execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } // Test GET on a unknown scale item response = execTestRequest(test, "GET", baseURL+"/00000000-0000-0000-0000-000000000000", nil, nil) if response.StatusCode != http.StatusNotFound { test.Logf("\nExpected %d\nbut got %d", http.StatusNotFound, response.StatusCode) test.Fail() } // Test POST into scale data, _ := json.Marshal(scaleBase) response = execTestRequest(test, "POST", baseURL, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusCreated { test.Logf("\nExpected %d\nbut got %d", http.StatusCreated, response.StatusCode) test.Fail() } if response.Header.Get("Location") == "" { test.Logf("\nExpected `Location' header") test.Fail() } scaleBase.ID = response.Header.Get("Location")[strings.LastIndex(response.Header.Get("Location"), "/")+1:] // Test GET on scale item scaleResult := &library.Scale{} response = execTestRequest(test, "GET", baseURL+scaleBase.ID, nil, &scaleResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(scaleBase, scaleResult) { test.Logf("\nExpected %#v\nbut got %#v", scaleBase, scaleResult) test.Fail() } // Test GET on scales list listBase = server.ItemListResponse{&server.ItemResponse{ ID: scaleBase.ID, Name: scaleBase.Name, Description: scaleBase.Description, }} listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } // Test PUT on scale item scaleBase.Name = "scale0-updated" data, _ = json.Marshal(scaleBase) response = execTestRequest(test, "PUT", baseURL+scaleBase.ID, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } // Test GET on scale item scaleResult = &library.Scale{} response = execTestRequest(test, "GET", baseURL+scaleBase.ID, nil, &scaleResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(scaleBase, scaleResult) { test.Logf("\nExpected %#v\nbut got %#v", scaleBase, scaleResult) test.Fail() } // Test DELETE on scale item response = execTestRequest(test, "DELETE", baseURL+scaleBase.ID, nil, nil) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } response = execTestRequest(test, "DELETE", baseURL+scaleBase.ID, nil, nil) if response.StatusCode != http.StatusNotFound { test.Logf("\nExpected %d\nbut got %d", http.StatusNotFound, response.StatusCode) test.Fail() } // Test GET on scales list (offset and limit) listBase = server.ItemListResponse{} for i := 0; i < 3; i += 1 { scaleTemp := &library.Scale{} utils.Clone(scaleBase, scaleTemp) scaleTemp.ID = "" scaleTemp.Name = fmt.Sprintf("scale0-%d", i) data, _ = json.Marshal(scaleTemp) response = execTestRequest(test, "POST", baseURL, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusCreated { test.Logf("\nExpected %d\nbut got %d", http.StatusCreated, response.StatusCode) test.Fail() } location := response.Header.Get("Location") if location == "" { test.Logf("\nExpected `Location' header") test.Fail() } scaleTemp.ID = location[strings.LastIndex(location, "/")+1:] listBase = append(listBase, &server.ItemResponse{ ID: scaleTemp.ID, Name: scaleTemp.Name, Description: scaleTemp.Description, }) } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL+"?limit=1", nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase[:1], listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase[:1], listResult) test.Fail() } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL+"?offset=1&limit=2", nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase[1:3], listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase[1:3], listResult) test.Fail() } }
func execGroupHandle(test *testing.T, urlPrefix string, groupBase *library.Group, expandData, expandBase server.ExpandRequest) { baseURL := fmt.Sprintf("http://%s/api/v1/library/%s/", serverConfig.BindAddr, urlPrefix) // Test GET on groups list listBase := server.ItemListResponse{} listResult := server.ItemListResponse{} response := execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } // Test GET on a unknown group item response = execTestRequest(test, "GET", baseURL+"/00000000-0000-0000-0000-000000000000", nil, nil) if response.StatusCode != http.StatusNotFound { test.Logf("\nExpected %d\nbut got %d", http.StatusNotFound, response.StatusCode) test.Fail() } // Test POST into group data, _ := json.Marshal(groupBase) response = execTestRequest(test, "POST", baseURL, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusCreated { test.Logf("\nExpected %d\nbut got %d", http.StatusCreated, response.StatusCode) test.Fail() } if response.Header.Get("Location") == "" { test.Logf("\nExpected `Location' header") test.Fail() } groupBase.ID = response.Header.Get("Location")[strings.LastIndex(response.Header.Get("Location"), "/")+1:] // Test GET on group item groupResult := &library.Group{} response = execTestRequest(test, "GET", baseURL+groupBase.ID, nil, &groupResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(groupBase, groupResult) { test.Logf("\nExpected %#v\nbut got %#v", groupBase, groupResult) test.Fail() } // Test GET on groups list listBase = server.ItemListResponse{&server.ItemResponse{ ID: groupBase.ID, Name: groupBase.Name, Description: groupBase.Description, }} listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } // Test PUT on group item groupBase.Name = "group0-updated" data, _ = json.Marshal(groupBase) response = execTestRequest(test, "PUT", baseURL+groupBase.ID, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } // Test GET on group item groupResult = &library.Group{} response = execTestRequest(test, "GET", baseURL+groupBase.ID, nil, &groupResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if !reflect.DeepEqual(groupBase, groupResult) { test.Logf("\nExpected %#v\nbut got %#v", groupBase, groupResult) test.Fail() } // Test group expansion data, _ = json.Marshal(expandData) expandResult := make([]server.ExpandRequest, 0) response = execTestRequest(test, "POST", fmt.Sprintf("http://%s/api/v1/library/expand", serverConfig.BindAddr), strings.NewReader(string(data)), &expandResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } if len(expandResult) == 0 { test.Logf("\nExpected %#v\nbut got %#v", expandBase, expandResult) test.Fail() } else if !reflect.DeepEqual(expandBase, expandResult[0]) { test.Logf("\nExpected %#v\nbut got %#v", expandBase, expandResult[0]) test.Fail() } // Test DELETE on group item response = execTestRequest(test, "DELETE", baseURL+groupBase.ID, nil, nil) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } response = execTestRequest(test, "DELETE", baseURL+groupBase.ID, nil, nil) if response.StatusCode != http.StatusNotFound { test.Logf("\nExpected %d\nbut got %d", http.StatusNotFound, response.StatusCode) test.Fail() } // Test GET on groups list (offset and limit) listBase = server.ItemListResponse{} for i := 0; i < 3; i += 1 { groupTemp := &library.Group{} utils.Clone(groupBase, groupTemp) groupTemp.ID = "" groupTemp.Name = fmt.Sprintf("group0-%d", i) data, _ = json.Marshal(groupTemp) response = execTestRequest(test, "POST", baseURL, strings.NewReader(string(data)), nil) if response.StatusCode != http.StatusCreated { test.Logf("\nExpected %d\nbut got %d", http.StatusCreated, response.StatusCode) test.Fail() } location := response.Header.Get("Location") if location == "" { test.Logf("\nExpected `Location' header") test.Fail() } groupTemp.ID = location[strings.LastIndex(location, "/")+1:] listBase = append(listBase, &server.ItemResponse{ ID: groupTemp.ID, Name: groupTemp.Name, Description: groupTemp.Description, }) } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL, nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase, listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase, listResult) test.Fail() } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL+"?limit=1", nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase[:1], listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase[:1], listResult) test.Fail() } listResult = server.ItemListResponse{} response = execTestRequest(test, "GET", baseURL+"?offset=1&limit=2", nil, &listResult) if response.StatusCode != http.StatusOK { test.Logf("\nExpected %d\nbut got %d", http.StatusOK, response.StatusCode) test.Fail() } for _, listItem := range listResult { listItem.Modified = "" } if !reflect.DeepEqual(listBase[1:3], listResult) { test.Logf("\nExpected %#v\nbut got %#v", listBase[1:3], listResult) test.Fail() } }
func (server *Server) serveScale(writer http.ResponseWriter, request *http.Request) { scaleID := strings.TrimPrefix(request.URL.Path, urlLibraryPath+"scales/") switch request.Method { case "DELETE": if scaleID == "" { server.serveResponse(writer, serverResponse{mesgMethodNotAllowed}, http.StatusMethodNotAllowed) return } err := server.Library.DeleteItem(scaleID, library.LibraryItemScale) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } server.serveResponse(writer, nil, http.StatusOK) case "GET", "HEAD": if scaleID == "" { server.serveScaleList(writer, request) return } item, err := server.Library.GetItem(scaleID, library.LibraryItemScale) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } server.serveResponse(writer, item, http.StatusOK) case "POST", "PUT": var scale *library.Scale if response, status := server.parseStoreRequest(writer, request, scaleID); status != http.StatusOK { server.serveResponse(writer, response, status) return } if request.Method == "POST" && request.FormValue("inherit") != "" { // Get scale from library item, err := server.Library.GetItem(request.FormValue("inherit"), library.LibraryItemScale) if os.IsNotExist(err) { server.serveResponse(writer, serverResponse{mesgResourceNotFound}, http.StatusNotFound) return } else if err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgUnhandledError}, http.StatusInternalServerError) return } scale = &library.Scale{} utils.Clone(item.(*library.Scale), scale) scale.ID = "" } else { // Create a new scale instance scale = &library.Scale{Item: library.Item{ID: scaleID}} } scale.Modified = time.Now() // Parse input JSON for scale data body, _ := ioutil.ReadAll(request.Body) if err := json.Unmarshal(body, scale); err != nil { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, serverResponse{mesgResourceInvalid}, http.StatusBadRequest) return } // Store scale data err := server.Library.StoreItem(scale, library.LibraryItemScale) if response, status := server.parseError(writer, request, err); status != http.StatusOK { logger.Log(logger.LevelError, "server", "%s", err) server.serveResponse(writer, response, status) return } if request.Method == "POST" { writer.Header().Add("Location", strings.TrimRight(request.URL.Path, "/")+"/"+scale.ID) server.serveResponse(writer, nil, http.StatusCreated) } else { server.serveResponse(writer, nil, http.StatusOK) } default: server.serveResponse(writer, serverResponse{mesgMethodNotAllowed}, http.StatusMethodNotAllowed) } }