Skip to content

Commit

Permalink
feat(rpaas/api): receive flavors, IP and plan template as plan parame…
Browse files Browse the repository at this point in the history
…ter (#67)
  • Loading branch information
nettoclaudio authored Apr 17, 2020
1 parent 8f5eece commit 78d7c06
Show file tree
Hide file tree
Showing 11 changed files with 853 additions and 205 deletions.
31 changes: 30 additions & 1 deletion api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ package api
import (
"context"
"fmt"
"io"
"net/http"
"os"
"os/signal"
"strings"
"sync"
"syscall"
"time"

"github.com/ajg/form"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/tsuru/rpaas-operator/config"
Expand Down Expand Up @@ -158,7 +161,7 @@ func errorMiddleware(next echo.HandlerFunc) echo.HandlerFunc {

func newEcho() *echo.Echo {
e := echo.New()

e.Binder = new(requestBinder)
e.HideBanner = true

e.Use(middleware.Recover())
Expand Down Expand Up @@ -221,3 +224,29 @@ func newEcho() *echo.Echo {

return e
}

type requestBinder struct{}

func (b *requestBinder) Bind(i interface{}, c echo.Context) error {
req := c.Request()

ctype := req.Header.Get(echo.HeaderContentType)
if !strings.HasPrefix(ctype, echo.MIMEApplicationForm) {
c.Response().Header().Set("Accept", echo.MIMEApplicationForm)
return echo.ErrUnsupportedMediaType
}

if err := newDecoder(req.Body).Decode(i); err != nil {
return fmt.Errorf("cannot decode the parameters: %w", err)
}
defer req.Body.Close()

return nil
}

func newDecoder(r io.Reader) *form.Decoder {
decoder := form.NewDecoder(r)
decoder.IgnoreCase(true)
decoder.IgnoreUnknownKeys(true)
return decoder
}
96 changes: 96 additions & 0 deletions api/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2020 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api

import (
"net/http"
"net/http/httptest"
"strings"
"testing"

"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestRequestBinder_Bind(t *testing.T) {
type t1 struct {
Name string `form:"name"`
Tags []string `form:"tags"`
Complex map[string]interface{} `form:"complex"`
Ignored bool `form:"-"`
}

tests := []struct {
name string
c echo.Context
data interface{}
assert func(*testing.T, error, interface{}, echo.Context)
}{
{
name: "when content-type is not application/x-www-form-urleconded",
c: func() echo.Context {
body := `{"name": "my-instance"}`
e := newEcho()
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
return e.NewContext(req, httptest.NewRecorder())
}(),
assert: func(t *testing.T, err error, d interface{}, c echo.Context) {
require.Error(t, err)
assert.EqualError(t, err, "code=415, message=Unsupported Media Type, internal=<nil>")
assert.Equal(t, "application/x-www-form-urlencoded", c.Response().Header().Get("Accept"))
},
},
{
name: "submitting a complex object",
c: func() echo.Context {
body := `name=my-instance&tags.0=tag1&tags.1=tag2&tags.2=tag3&ignored=true&complex.key1=1&complex.other.key=value`
e := newEcho()
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationForm)
return e.NewContext(req, httptest.NewRecorder())
}(),
data: &t1{},
assert: func(t *testing.T, err error, d interface{}, c echo.Context) {
require.NoError(t, err)
assert.Equal(t, &t1{
Name: "my-instance",
Tags: []string{"tag1", "tag2", "tag3"},
Complex: map[string]interface{}{
"key1": "1",
"other": map[string]interface{}{
"key": "value",
},
},
}, d)
},
},
{
name: "when some error occurs on decode method",
c: func() echo.Context {
body := `name=my-instance&tags.0=tag1&tags.1=tag2&tags.2=tag3&ignored=true&complex.key1=1&complex.other.key=value`
e := newEcho()
req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body))
req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationForm)
return e.NewContext(req, httptest.NewRecorder())
}(),
data: func() string { return "cannot decode a function" },
assert: func(t *testing.T, err error, d interface{}, c echo.Context) {
require.Error(t, err)
assert.EqualError(t, err, "cannot decode the parameters: func() string has unsupported kind func")
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
require.NotNil(t, tt.assert)
b := &requestBinder{}
err := b.Bind(tt.data, tt.c)
tt.assert(t, err, tt.data, tt.c)
})
}
}
39 changes: 9 additions & 30 deletions api/service_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,20 @@ import (
)

func serviceCreate(c echo.Context) error {
if c.Request().ContentLength == 0 {
return echo.NewHTTPError(http.StatusBadRequest, "Request body can't be empty")
}

var args rpaas.CreateArgs
err := c.Bind(&args)
if err != nil {
if err := c.Bind(&args); err != nil {
return err
}

manager, err := getManager(c)
if err != nil {
return err
}
err = manager.CreateInstance(c.Request().Context(), args)
if err != nil {

if err = manager.CreateInstance(c.Request().Context(), args); err != nil {
return err
}

return c.NoContent(http.StatusCreated)
}

Expand All @@ -39,6 +36,7 @@ func serviceDelete(c echo.Context) error {
if len(name) == 0 {
return c.String(http.StatusBadRequest, "name is required")
}

manager, err := getManager(c)
if err != nil {
return err
Expand All @@ -51,10 +49,6 @@ func serviceDelete(c echo.Context) error {
}

func serviceUpdate(c echo.Context) error {
if c.Request().ContentLength == 0 {
return echo.NewHTTPError(http.StatusBadRequest, "Request body can't be empty")
}

var args rpaas.UpdateInstanceArgs
if err := c.Bind(&args); err != nil {
return err
Expand All @@ -72,12 +66,6 @@ func serviceUpdate(c echo.Context) error {
return c.NoContent(http.StatusOK)
}

type plan struct {
Name string `json:"name"`
Description string `json:"description"`
Default bool `json:"default"`
}

func servicePlans(c echo.Context) error {
manager, err := getManager(c)
if err != nil {
Expand All @@ -89,20 +77,11 @@ func servicePlans(c echo.Context) error {
return err
}

var result []plan
for _, p := range plans {
result = append(result, plan{
Name: p.Name,
Description: p.Spec.Description,
Default: p.Spec.Default,
})
}

if result == nil {
result = []plan{}
if plans == nil {
plans = make([]rpaas.Plan, 0)
}

return c.JSON(http.StatusOK, result)
return c.JSON(http.StatusOK, plans)
}

func serviceInfo(c echo.Context) error {
Expand Down
Loading

0 comments on commit 78d7c06

Please sign in to comment.