Skip to content

Commit

Permalink
update e2e test
Browse files Browse the repository at this point in the history
  • Loading branch information
redradrat committed Oct 24, 2020
1 parent b22fe75 commit f9a6826
Show file tree
Hide file tree
Showing 28 changed files with 215 additions and 1,900 deletions.
4 changes: 2 additions & 2 deletions e2e-test/testconcept1/concept.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"metadata": {
"name": "testconcept1",
"maintainer": {
"name": "",
"email": ""
"name": "Demo Maintainer",
"email": "[email protected]"
}
},
"inputs": {
Expand Down
4 changes: 2 additions & 2 deletions e2e-test/testconcept2/concept.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"metadata": {
"name": "testconcept2",
"maintainer": {
"name": "",
"email": ""
"name": "Demo Maintainer",
"email": "[email protected]"
}
},
"inputs": {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f
github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect
github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434
github.com/facebookgo/grace v0.0.0-20180706040059-75cf19382434 // indirect
github.com/facebookgo/httpdown v0.0.0-20180706035922-5979d39b15c2 // indirect
github.com/facebookgo/stats v0.0.0-20151006221625-1b76add642e4 // indirect
github.com/fatih/color v1.9.0
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,12 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k=
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
Expand Down
33 changes: 25 additions & 8 deletions pkg/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@ import (
"github.com/labstack/echo/v4"
)

const (
ConceptsApiPath = "/concepts"
RepositoriesApiPath = "/repositories"
)

func RegisterHandlersV1(e *echo.Group, serv *Serv) {
e.GET("/concepts", serv.GetConcepts)
e.GET("/concepts/:id", serv.GetConcept)
e.GET("/repositories", serv.GetRepositories)
e.GET("/repositories/:id", serv.GetRepository)
e.PUT("/repositories/:id", serv.PutRepository)
e.GET("/repositories/:id/concepts", serv.GetRepositoryConcepts)
e.GET("/repositories/:id/concepts/:path", serv.GetRepositoryConcept)
e.GET(ConceptsApiPath, serv.GetConcepts)
e.GET(ConceptsApiPath+"/:id", serv.GetConcept)
e.GET(RepositoriesApiPath, serv.GetRepositories)
e.GET(RepositoriesApiPath+"/:id", serv.GetRepository)
e.PUT(RepositoriesApiPath+"/:id", serv.PutRepository)
e.GET(RepositoriesApiPath+"/:id"+ConceptsApiPath, serv.GetRepositoryConcepts)
e.GET(RepositoriesApiPath+"/:id"+ConceptsApiPath+"/:path", serv.GetRepositoryConcept)
}

type MessagePayload struct {
Expand Down Expand Up @@ -57,9 +62,15 @@ type ConceptPayload struct {
Inputs []ConceptInputsPayload `json:"inputs,omitempty"`
}

func NewConceptPayload() ConceptPayload {
return ConceptPayload{
Inputs: []ConceptInputsPayload{},
}
}

type ConceptMetadataPayload struct {
Maintainer ConceptMaintainerPayload `json:"maintainer,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
Tags []string `json:"tags,omitempty"`
}

type ConceptMaintainerPayload struct {
Expand All @@ -72,3 +83,9 @@ type ConceptInputsPayload struct {
Type string `json:"type"`
Mandatory bool `json:"mandatory"`
}

type ByID []ConceptInputsPayload

func (a ByID) Len() int { return len(a) }
func (a ByID) Less(i, j int) bool { return a[i].ID < a[j].ID }
func (a ByID) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
97 changes: 81 additions & 16 deletions pkg/api/client/v1/concepts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package v1

import (
"context"
"fmt"
"net/http"
"net/url"

Expand All @@ -10,13 +11,17 @@ import (
"github.com/redradrat/kable/pkg/concepts"
)

const conceptsBasePath = "v1/concepts"
const (
conceptsBasePath = "v1" + api.ConceptsApiPath
conceptsFromFormatPath = repositoriessBasePath + "/%s" + api.ConceptsApiPath
)

type ConceptsService interface {
Get(context.Context, concepts.ConceptIdentifier) (*api.ConceptPayload, *Response, error)
GetFromRepository(context.Context, string, concepts.ConceptIdentifier) (*api.ConceptPayload, *Response, error)
List(context.Context, *ListOptions) (*api.ConceptsPayload, *Response, error)
ListFromRepository(context.Context, string, *ListOptions) (*api.ConceptsPayload, *Response, error)
ListByTag(context.Context, string, *ListOptions) (*api.ConceptsPayload, *Response, error)
Get(context.Context, concepts.ConceptIdentifier) (*api.ConceptPayload, *Response, error)
GetFromRepository(context.Context, string, string) (*api.ConceptPayload, *Response, error)
}

var _ ConceptsService = &ConceptsClient{}
Expand All @@ -25,8 +30,80 @@ type ConceptsClient struct {
client *Client
}

func (c ConceptsClient) Get(ctx context.Context, identifier concepts.ConceptIdentifier) (*api.ConceptPayload, *Response, error) {
basePath := conceptsBasePath
return c.getWithBasepath(basePath, ctx, identifier)
}

func (c ConceptsClient) GetFromRepository(ctx context.Context, repo string, identifier concepts.ConceptIdentifier) (*api.ConceptPayload, *Response, error) {
basePath := fmt.Sprintf(conceptsFromFormatPath, repo)
return c.getWithBasepath(basePath, ctx, identifier)
}

func (c ConceptsClient) List(ctx context.Context, options *ListOptions) (*api.ConceptsPayload, *Response, error) {
uri, err := url.Parse(conceptsBasePath)
basePath := conceptsBasePath
return c.listWithBasepath(basePath, ctx, options)
}

func (c ConceptsClient) ListByTag(ctx context.Context, s string, options *ListOptions) (*api.ConceptsPayload, *Response, error) {
payload, resp, err := c.List(ctx, options)
if err != nil {
return nil, resp, err
}

filteredPayload := *payload

for path, concept := range filteredPayload.Concepts {
if !hasEntry(concept.Metadata.Tags, s) {
delete(filteredPayload.Concepts, path)
}
}

return &filteredPayload, resp, err
}

func hasEntry(l []string, s string) bool {
hasEntry := false
for _, tag := range l {
if tag == s {
hasEntry = true
}
}
return hasEntry
}

func (c ConceptsClient) ListFromRepository(ctx context.Context, repo string, options *ListOptions) (*api.ConceptsPayload, *Response, error) {
basePath := fmt.Sprintf(conceptsFromFormatPath, repo)
return c.listWithBasepath(basePath, ctx, options)
}

func (c ConceptsClient) getWithBasepath(basePath string, ctx context.Context, identifier concepts.ConceptIdentifier) (*api.ConceptPayload, *Response, error) {
uri, err := url.Parse(basePath + "/")
if err != nil {
return nil, nil, err
}

getUri, err := uri.Parse(api.MarshalId(identifier.String()))
if err != nil {
return nil, nil, err
}

req, err := c.client.NewRequest(http.MethodGet, getUri.String(), nil)
if err != nil {
return nil, nil, err
}

payload := api.NewConceptPayload()
resp, err := c.client.Do(ctx, req, &payload)
if err != nil {
return nil, resp, err
}

return &payload, resp, err
}

func (c ConceptsClient) listWithBasepath(basePath string, ctx context.Context, options *ListOptions) (*api.ConceptsPayload, *Response, error) {
uri, err := url.Parse(basePath)
if err != nil {
return nil, nil, err
}
Expand All @@ -51,15 +128,3 @@ func (c ConceptsClient) List(ctx context.Context, options *ListOptions) (*api.Co

return &payload, resp, err
}

func (c ConceptsClient) ListByTag(ctx context.Context, s string, options *ListOptions) (*api.ConceptsPayload, *Response, error) {
panic("implement me")
}

func (c ConceptsClient) Get(ctx context.Context, identifier concepts.ConceptIdentifier) (*api.ConceptPayload, *Response, error) {
panic("implement me")
}

func (c ConceptsClient) GetFromRepository(ctx context.Context, s string, s2 string) (*api.ConceptPayload, *Response, error) {
panic("implement me")
}
44 changes: 38 additions & 6 deletions pkg/api/client/v1/concepts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,49 @@ func TestConceptsClient_List_None(t *testing.T) {
}

func TestConceptsClient_List_Some(t *testing.T) {
client, err := addDemoHttps(t)
assert.NoError(t, err)

concepts, response, err := client.Concepts.List(context.Background(), nil)
assert.NoError(t, err)
assert.Equal(t, 200, response.StatusCode)
act := api.ConceptsPayload{Concepts: api.ConceptsMapPayload{"apps/grafana@demo-https": api.ConceptPayload{Type: "jsonnet", Metadata: api.ConceptMetadataPayload{Maintainer: api.ConceptMaintainerPayload{MaintainerName: "Ralph Kühnert", MaintainerEmail: "[email protected]"}, Tags: []string(nil)}, Inputs: []api.ConceptInputsPayload{api.ConceptInputsPayload{ID: "instanceName", Type: "string", Mandatory: true}, api.ConceptInputsPayload{ID: "nameSelection", Type: "select", Mandatory: true}}}, "apps/sentry@demo-https": api.ConceptPayload{Type: "jsonnet", Metadata: api.ConceptMetadataPayload{Maintainer: api.ConceptMaintainerPayload{MaintainerName: "Ralph Kühnert", MaintainerEmail: "[email protected]"}, Tags: []string(nil)}, Inputs: []api.ConceptInputsPayload{api.ConceptInputsPayload{ID: "instanceName", Type: "string", Mandatory: true}, api.ConceptInputsPayload{ID: "nameSelection", Type: "select", Mandatory: true}}}}}
assert.Equal(t, act, *concepts)
}

func TestConceptsClient_ListFromRepository_Some(t *testing.T) {
client, err := addDemoHttps(t)
assert.NoError(t, err)

concepts, response, err := client.Concepts.ListFromRepository(context.Background(), repositories.DemoHttpsRepository.Name, nil)
assert.NoError(t, err)
assert.Equal(t, 200, response.StatusCode)
act := api.ConceptsPayload{Concepts: api.ConceptsMapPayload{"apps/grafana@demo-https": api.ConceptPayload{Type: "jsonnet", Metadata: api.ConceptMetadataPayload{Maintainer: api.ConceptMaintainerPayload{MaintainerName: "Ralph Kühnert", MaintainerEmail: "[email protected]"}, Tags: []string(nil)}, Inputs: []api.ConceptInputsPayload{api.ConceptInputsPayload{ID: "instanceName", Type: "string", Mandatory: true}, api.ConceptInputsPayload{ID: "nameSelection", Type: "select", Mandatory: true}}}, "apps/sentry@demo-https": api.ConceptPayload{Type: "jsonnet", Metadata: api.ConceptMetadataPayload{Maintainer: api.ConceptMaintainerPayload{MaintainerName: "Ralph Kühnert", MaintainerEmail: "[email protected]"}, Tags: []string(nil)}, Inputs: []api.ConceptInputsPayload{api.ConceptInputsPayload{ID: "instanceName", Type: "string", Mandatory: true}, api.ConceptInputsPayload{ID: "nameSelection", Type: "select", Mandatory: true}}}}}
assert.Equal(t, act, *concepts)
}

func TestConceptsClient_GetFromRepository_Some(t *testing.T) {
client, err := addDemoHttps(t)
assert.NoError(t, err)

concepts, response, err := client.Concepts.GetFromRepository(context.Background(), repositories.DemoHttpsRepository.Name, "apps/sentry")
assert.NoError(t, err)
assert.Equal(t, 200, response.StatusCode)
act := api.ConceptPayload(api.ConceptPayload{Type: "jsonnet", Metadata: api.ConceptMetadataPayload{Maintainer: api.ConceptMaintainerPayload{MaintainerName: "Ralph Kühnert", MaintainerEmail: "[email protected]"}, Tags: []string(nil)}, Inputs: []api.ConceptInputsPayload{api.ConceptInputsPayload{ID: "instanceName", Type: "string", Mandatory: true}, api.ConceptInputsPayload{ID: "nameSelection", Type: "select", Mandatory: true}}})
assert.Equal(t, act, *concepts)
}

/////////////
// HELPERS //
/////////////

func addDemoHttps(t *testing.T) (*Client, error) {
viper.Set(repositories.StoreKey, repositories.MockStoreConfigMap().Map())
client := NewClient(nil, &uri)

// Add repo to mock store
addMod, err := repositories.AddRepository(repositories.DemoHttpsRepository)
assert.NoError(t, err)
assert.NoError(t, repositories.UpdateRegistry(addMod))

concepts, response, err := client.Concepts.List(context.Background(), nil)
assert.NoError(t, err)
assert.Equal(t, 200, response.StatusCode)
act := api.ConceptsPayload{Concepts: api.ConceptsMapPayload{"apps/sentry@demo-https": api.ConceptPayload{Type: "jsonnet", Metadata: api.ConceptMetadataPayload{Maintainer: api.ConceptMaintainerPayload{MaintainerName: "Ralph Kühnert", MaintainerEmail: "[email protected]"}, Tags: map[string]string(nil)}, Inputs: []api.ConceptInputsPayload{api.ConceptInputsPayload{ID: "instanceName", Type: "string", Mandatory: true}, api.ConceptInputsPayload{ID: "nameSelection", Type: "select", Mandatory: true}}}}}
assert.Equal(t, act, *concepts)
return client, err
}
45 changes: 26 additions & 19 deletions pkg/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package api
import (
"fmt"
"net/http"
"sort"
"strings"

"github.com/labstack/gommon/log"
Expand Down Expand Up @@ -111,22 +112,22 @@ func (serv Serv) GetConcepts(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("unable to get concept '%s': %v", cpt.String(), err))
}

payload.Concepts = constructPayloadFrom(cpt.String(), concept)
payload.Concepts[cpt.String()] = constructConceptPayloadFrom(concept)
}
return ctx.JSON(http.StatusOK, payload)
}

func (serv Serv) GetConcept(ctx echo.Context) error {
ctx.Logger().Infof("'%s' hit by user-agent => %s [%s]", ctx.Path(), ctx.Request().UserAgent(), ctx.RealIP())
id := strings.ReplaceAll(ctx.Param("id"), "_", "/")
id := UnmarshalId(getRepoIdFromContext(ctx))
if !concepts.IsValidConceptIdentifier(id) {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("given id '%s' is not a valid concept identifier ", id))
}
cpt, err := concepts.GetRepoConcept(concepts.ConceptIdentifier(id))
if err != nil {
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("concept with identifier '%s' does not exist", id))
}
payload := constructPayloadFrom(id, cpt)
payload := constructConceptPayloadFrom(cpt)
return ctx.JSON(http.StatusOK, payload)
}

Expand All @@ -149,6 +150,7 @@ func ConceptInputsPayloadFrom(c concepts.Concept) []ConceptInputsPayload {
Mandatory: false,
})
}
sort.Sort(ByID(inputs))
return inputs
}

Expand Down Expand Up @@ -176,14 +178,14 @@ func (serv Serv) GetRepositoryConcepts(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("unable to get concept '%s': %v", cpt.Concept(), err))
}

payload.Concepts = constructPayloadFrom(cpt.Concept(), concept)
payload.Concepts[cpt.String()] = constructConceptPayloadFrom(concept)
}
return ctx.JSON(http.StatusOK, payload)
}

func (serv Serv) GetRepositoryConcept(ctx echo.Context) error {
ctx.Logger().Infof("'%s' hit by user-agent => %s [%s]", ctx.Path(), ctx.Request().UserAgent(), ctx.RealIP())
id := getRepoIdFromContext(ctx)
id := UnmarshalId(getRepoIdFromContext(ctx))
_, err := getRepo(id)
if err != nil {
ctx.Logger().Errorf("could not get repo: %v", err)
Expand All @@ -195,23 +197,28 @@ func (serv Serv) GetRepositoryConcept(ctx echo.Context) error {
if err != nil {
return echo.NewHTTPError(http.StatusNotFound, fmt.Sprintf("concept with identifier '%s' does not exist", ci))
}
payload := constructPayloadFrom(ci.Concept(), cpt)
payload := constructConceptPayloadFrom(cpt)
return ctx.JSON(http.StatusOK, payload)

}

func constructPayloadFrom(s string, cpt *concepts.Concept) ConceptsMapPayload {
payload := ConceptsMapPayload{
s: {
Type: cpt.Type.String(),
Metadata: ConceptMetadataPayload{
Tags: cpt.Meta.Tags,
Maintainer: ConceptMaintainerPayload{
MaintainerName: cpt.Meta.Maintainer.Name,
MaintainerEmail: cpt.Meta.Maintainer.Email,
}},
Inputs: ConceptInputsPayloadFrom(*cpt),
},
func constructConceptPayloadFrom(cpt *concepts.Concept) ConceptPayload {
return ConceptPayload{
Type: cpt.Type.String(),
Metadata: ConceptMetadataPayload{
Tags: cpt.Meta.Tags,
Maintainer: ConceptMaintainerPayload{
MaintainerName: cpt.Meta.Maintainer.Name,
MaintainerEmail: cpt.Meta.Maintainer.Email,
}},
Inputs: ConceptInputsPayloadFrom(*cpt),
}
return payload
}

func UnmarshalId(id string) string {
return strings.ReplaceAll(id, "_", "/")
}

func MarshalId(id string) string {
return strings.ReplaceAll(id, "/", "_")
}
Loading

0 comments on commit f9a6826

Please sign in to comment.