Skip to content

Commit

Permalink
Feat/searchbar (#67)
Browse files Browse the repository at this point in the history
Implement global search over instances, nodes and cluster names

Co-authored-by: Julian Geywitz <[email protected]>
Co-authored-by: Rudolph Bott <[email protected]>
Co-authored-by: Paul Schwoerer <[email protected]>
  • Loading branch information
3 people authored May 13, 2022
1 parent 4df5a06 commit 5ac17af
Show file tree
Hide file tree
Showing 30 changed files with 1,119 additions and 7 deletions.
35 changes: 35 additions & 0 deletions api/controllers/search.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package controllers

import (
"github.com/gin-gonic/gin"
)

type SearchController struct {
SearchService searchService
}

// Search godoc
// @Summary Search in all known resources
// @Description ...
// @Produce json
// @Success 200 {object} model.SearchResultsResponse
// @Failure 400 {object} model.ErrorResponse
// @Failure 500 {object} model.ErrorResponse
// @Router /search [get]
//TODO: Add Tests
func (controller *SearchController) Search(c *gin.Context) {
query, exists := c.GetQuery("query")
if !exists {
c.AbortWithStatusJSON(400, createErrorBody("query parameter is required"))
return
}

if len(query) == 0 {
c.AbortWithStatusJSON(400, createErrorBody("query parameter must not be empty"))
return
}

results := controller.SearchService.Search(query)

c.JSON(200, results)
}
4 changes: 4 additions & 0 deletions api/controllers/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,8 @@ type (
instanceActions interface {
PerformSimpleInstanceAction(clusterName string, instanceName string, rapiAction string) (int, error)
}

searchService interface {
Search(query string) model.SearchResults
}
)
19 changes: 19 additions & 0 deletions api/mocking/cluster_repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package mocking

import (
"github.com/stretchr/testify/mock"
)

type clusterRepository struct {
mock.Mock
}

func NewClusterRepository() *clusterRepository {
return &clusterRepository{}
}

func (mock *clusterRepository) GetAllNames() []string {
args := mock.Called()

return args.Get(0).([]string)
}
5 changes: 5 additions & 0 deletions api/mocking/instance_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ func (mock *instanceRepository) GetAll(clusterName string) ([]model.GntInstance,

return args.Get(0).([]model.GntInstance), args.Error(1)
}

func (mock *instanceRepository) GetAllNames(clusterName string) ([]string, error) {
args := mock.Called(clusterName)
return args.Get(0).([]string), args.Error(1)
}
6 changes: 6 additions & 0 deletions api/mocking/node_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,9 @@ func (mock *nodeRepository) GetAll(clusterName string) ([]model.GntNode, error)

return args.Get(0).([]model.GntNode), args.Error(1)
}

func (mock *nodeRepository) GetAllNames(clusterName string) ([]string, error) {
args := mock.Called(clusterName)

return args.Get(0).([]string), args.Error(1)
}
15 changes: 15 additions & 0 deletions api/model/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,18 @@ type GntJob struct {
Status string `json:"status"`
Log *[]GntJobLogEntry `json:"log"`
}

type ClusterResource struct {
ClusterName string `json:"clusterName"`
Name string `json:"name"`
}

type Resource struct {
Name string `json:"name"`
}

type SearchResults struct {
Nodes []ClusterResource `json:"nodes"`
Instances []ClusterResource `json:"instances"`
Clusters []Resource `json:"clusters"`
}
2 changes: 2 additions & 0 deletions api/model/response.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@ type StatisticsResponse struct {
Nodes StatisticsElement `json:"nodes"`
Master string `json:"master"`
}

type SearchResultsResponse SearchResults
15 changes: 15 additions & 0 deletions api/repository/cluster.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package repository

import "gnt-cc/config"

type ClusterRepository struct {
}

func (*ClusterRepository) GetAllNames() []string {
c := config.Get()
clusters := make([]string, len(c.Clusters))
for i, cluster := range c.Clusters {
clusters[i] = cluster.Name
}
return clusters
}
22 changes: 22 additions & 0 deletions api/repository/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,28 @@ func (repo *InstanceRepository) GetAll(clusterName string) ([]model.GntInstance,
return parseInstanceResourceArray(resources)
}

func (repo *InstanceRepository) GetAllNames(clusterName string) ([]string, error) {
response, err := repo.RAPIClient.Get(clusterName, "/2/instances")

if err != nil {
return nil, err
}

var instanceList rapiInstanceNamesResponse
err = json.Unmarshal([]byte(response.Body), &instanceList)

if err != nil {
return nil, err
}

instanceNames := make([]string, len(instanceList))
for i, instance := range instanceList {
instanceNames[i] = instance.ID
}

return instanceNames, nil
}

func parseInstanceResourceArray(resources []query.Resource) ([]model.GntInstance, error) {
instances := make([]model.GntInstance, len(resources))

Expand Down
41 changes: 39 additions & 2 deletions api/repository/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ package repository_test

import (
"errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"gnt-cc/mocking"
"gnt-cc/model"
"gnt-cc/query"
"gnt-cc/rapi_client"
"gnt-cc/repository"
"io/ioutil"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)

func TestInstanceRepoGetAllFuncReturnsError_WhenRAPIClientReturnsError(t *testing.T) {
Expand All @@ -23,6 +24,16 @@ func TestInstanceRepoGetAllFuncReturnsError_WhenRAPIClientReturnsError(t *testin
assert.EqualError(t, err, "expected error")
}

func TestInstanceRepoGetAllNamesFuncReturnsError_WhenRAPIClientReturnsError(t *testing.T) {
client := mocking.NewRAPIClient()
client.On("Get", mock.Anything, mock.Anything).
Once().Return(rapi_client.Response{}, errors.New("expected error"))
repo := repository.InstanceRepository{RAPIClient: client}
_, err := repo.GetAllNames("test")

assert.EqualError(t, err, "expected error")
}

func TestInstanceRepoGetFuncReturnsError_WhenRAPIClientReturnsError(t *testing.T) {
client := mocking.NewRAPIClient()
client.On("Get", mock.Anything, mock.Anything).
Expand Down Expand Up @@ -54,6 +65,16 @@ func TestInstanceRepoGetAllFuncReturnsError_OnInvalidResourceReturned(t *testing
assert.Error(t, err)
}

func TestInstanceRepoGetAllNamesFuncReturnsError_OnInvalidResourceReturned(t *testing.T) {
client := mocking.NewRAPIClient()
client.On("Get", mock.Anything, mock.Anything).
Once().Return(rapi_client.Response{Status: 200, Body: "{"}, nil)
repo := repository.InstanceRepository{RAPIClient: client}
_, err := repo.GetAllNames("test")

assert.Error(t, err)
}

func TestInstanceRepoGetFuncReturnsError_WhenJSONResponseIsInvalid(t *testing.T) {
client := mocking.NewRAPIClient()
client.On("Get", mock.Anything, mock.Anything).
Expand Down Expand Up @@ -148,3 +169,19 @@ func TestInstanceRepoGetAllFuncCorrectlyReturnsInstances_WhenAValidRAPIResponseW
},
}, allInstances)
}

func TestInstanceRepoGetAllNamesFuncReturnsInstances(t *testing.T) {
validNodeNamesResponse, _ := ioutil.ReadFile("../testfiles/rapi_responses/valid_names_response.json")
client := mocking.NewRAPIClient()
client.On("Get", mock.Anything, "/2/instances").
Once().Return(rapi_client.Response{Status: 200, Body: string(validNodeNamesResponse)}, nil)
repo := repository.InstanceRepository{RAPIClient: client}
instances, err := repo.GetAllNames("test")

assert.NoError(t, err)
assert.EqualValues(t, []string{
"homer",
"marge",
"bart",
}, instances)
}
4 changes: 4 additions & 0 deletions api/repository/instance_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,7 @@ type rapiInstanceResponse struct {
HvParams hvParams `json:"hvparams"`
CustomHvParams hvParams `json:"custom_hvparams"`
}

type rapiInstanceNamesResponse []struct {
ID string `json:"id"`
}
25 changes: 24 additions & 1 deletion api/repository/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package repository
import (
"encoding/json"
"fmt"
log "github.com/sirupsen/logrus"
"gnt-cc/model"
"gnt-cc/rapi_client"
"strings"

log "github.com/sirupsen/logrus"
)

type NodeRepository struct {
Expand Down Expand Up @@ -115,3 +116,25 @@ func (repo *NodeRepository) GetAll(clusterName string) ([]model.GntNode, error)

return nodes, nil
}

func (repo *NodeRepository) GetAllNames(clusterName string) ([]string, error) {
response, err := repo.RAPIClient.Get(clusterName, "/2/nodes")

if err != nil {
return nil, err
}

var nodeList rapiNodeNamesResponse
err = json.Unmarshal([]byte(response.Body), &nodeList)

if err != nil {
return nil, err
}

instanceNames := make([]string, len(nodeList))
for i, instance := range nodeList {
instanceNames[i] = instance.ID
}

return instanceNames, nil
}
42 changes: 40 additions & 2 deletions api/repository/node_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ package repository_test

import (
"errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"gnt-cc/mocking"
"gnt-cc/model"
"gnt-cc/rapi_client"
"gnt-cc/repository"
"io/ioutil"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)

func TestNodeRepoGetAllFuncReturnsError_WhenRAPIClientReturnsError(t *testing.T) {
Expand All @@ -22,6 +23,16 @@ func TestNodeRepoGetAllFuncReturnsError_WhenRAPIClientReturnsError(t *testing.T)
assert.EqualError(t, err, "expected error")
}

func TestNodeRepoGetAllNamesFuncReturnsError_WhenRAPIClientReturnsError(t *testing.T) {
client := mocking.NewRAPIClient()
client.On("Get", mock.Anything, mock.Anything).
Once().Return(rapi_client.Response{}, errors.New("expected error"))
repo := repository.NodeRepository{RAPIClient: client}
_, err := repo.GetAllNames("test")

assert.EqualError(t, err, "expected error")
}

func TestNodeRepoGetFuncReturnsError_WhenRAPIClientReturnsError(t *testing.T) {
client := mocking.NewRAPIClient()
client.On("Get", mock.Anything, mock.Anything).
Expand Down Expand Up @@ -63,6 +74,16 @@ func TestNodeRepoGetAllFuncReturnsError_WhenJSONResponseIsInvalid(t *testing.T)
assert.NotNil(t, err)
}

func TestNodeRepoGetAllNamesFuncReturnsError_WhenJSONResponseIsInvalid(t *testing.T) {
client := mocking.NewRAPIClient()
client.On("Get", mock.Anything, mock.Anything).
Once().Return(rapi_client.Response{Status: 200, Body: "{"}, nil)
repo := repository.NodeRepository{RAPIClient: client}
_, err := repo.GetAllNames("test")

assert.NotNil(t, err)
}

func TestNodeRepoGetAllFuncReturnsNodes(t *testing.T) {
validNodesResponse, _ := ioutil.ReadFile("../testfiles/rapi_responses/valid_nodes_response.json")
validGroupsResponse, _ := ioutil.ReadFile("../testfiles/rapi_responses/valid_groups_response.json")
Expand Down Expand Up @@ -106,6 +127,23 @@ func TestNodeRepoGetAllFuncReturnsNodes(t *testing.T) {
}}, nodes)
}

func TestNodeRepoGetAllNamesFuncReturnsNodes(t *testing.T) {
validNodeNamesResponse, _ := ioutil.ReadFile("../testfiles/rapi_responses/valid_names_response.json")
client := mocking.NewRAPIClient()
client.On("Get", mock.Anything, "/2/nodes").
Once().Return(rapi_client.Response{Status: 200, Body: string(validNodeNamesResponse)}, nil)
groupRepo := repository.GroupRepository{RAPIClient: client}
repo := repository.NodeRepository{RAPIClient: client, GroupRepository: groupRepo}
nodes, err := repo.GetAllNames("test")

assert.NoError(t, err)
assert.EqualValues(t, []string{
"homer",
"marge",
"bart",
}, nodes)
}

func TestNodeRepoGetFuncReturnsNode(t *testing.T) {
validResponse, _ := ioutil.ReadFile("../testfiles/rapi_responses/valid_node_response.json")
client := mocking.NewRAPIClient()
Expand Down
4 changes: 4 additions & 0 deletions api/repository/node_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ type rapiNodeResponse struct {
OobProgram string `json:"oob_program"`
} `json:"ndparams"`
}

type rapiNodeNamesResponse []struct {
ID string `json:"id"`
}
Loading

0 comments on commit 5ac17af

Please sign in to comment.