mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Datastore refactor and added postgres tests (#259)
* fix apps & routes creation/update * refactor datastore and added postgres tests * added test-datastore and fixed circleci test
This commit is contained in:
@@ -72,18 +72,31 @@ func New(url *url.URL) (models.Datastore, error) {
|
||||
return ds, nil
|
||||
}
|
||||
|
||||
func (ds *BoltDatastore) StoreApp(app *models.App) (*models.App, error) {
|
||||
func (ds *BoltDatastore) InsertApp(app *models.App) (*models.App, error) {
|
||||
if app == nil {
|
||||
return nil, models.ErrDatastoreEmptyApp
|
||||
}
|
||||
|
||||
if app.Name == "" {
|
||||
return nil, models.ErrDatastoreEmptyAppName
|
||||
}
|
||||
|
||||
appname := []byte(app.Name)
|
||||
|
||||
err := ds.db.Update(func(tx *bolt.Tx) error {
|
||||
bIm := tx.Bucket(ds.appsBucket)
|
||||
|
||||
v := bIm.Get(appname)
|
||||
if v != nil {
|
||||
return models.ErrAppsAlreadyExists
|
||||
}
|
||||
|
||||
buf, err := json.Marshal(app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = bIm.Put([]byte(app.Name), buf)
|
||||
|
||||
err = bIm.Put(appname, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -94,6 +107,62 @@ func (ds *BoltDatastore) StoreApp(app *models.App) (*models.App, error) {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return app, err
|
||||
}
|
||||
|
||||
func (ds *BoltDatastore) UpdateApp(newapp *models.App) (*models.App, error) {
|
||||
if newapp == nil {
|
||||
return nil, models.ErrDatastoreEmptyApp
|
||||
}
|
||||
|
||||
if newapp.Name == "" {
|
||||
return nil, models.ErrDatastoreEmptyAppName
|
||||
}
|
||||
|
||||
var app *models.App
|
||||
appname := []byte(newapp.Name)
|
||||
|
||||
err := ds.db.Update(func(tx *bolt.Tx) error {
|
||||
bIm := tx.Bucket(ds.appsBucket)
|
||||
|
||||
v := bIm.Get(appname)
|
||||
if v == nil {
|
||||
return models.ErrAppsNotFound
|
||||
}
|
||||
|
||||
err := json.Unmarshal(v, &app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update app fields
|
||||
if newapp.Config != nil {
|
||||
if app.Config == nil {
|
||||
app.Config = map[string]string{}
|
||||
}
|
||||
for k, v := range newapp.Config {
|
||||
app.Config[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
buf, err := json.Marshal(app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = bIm.Put(appname, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bjParent := tx.Bucket(ds.routesBucket)
|
||||
_, err = bjParent.CreateBucketIfNotExists([]byte(app.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return app, err
|
||||
}
|
||||
|
||||
@@ -181,23 +250,114 @@ func (ds *BoltDatastore) getRouteBucketForApp(tx *bolt.Tx, appName string) (*bol
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (ds *BoltDatastore) StoreRoute(route *models.Route) (*models.Route, error) {
|
||||
func (ds *BoltDatastore) InsertRoute(route *models.Route) (*models.Route, error) {
|
||||
if route == nil {
|
||||
return nil, models.ErrDatastoreEmptyApp
|
||||
}
|
||||
|
||||
if route.AppName == "" {
|
||||
return nil, models.ErrDatastoreEmptyAppName
|
||||
}
|
||||
|
||||
if route.Path == "" {
|
||||
return nil, models.ErrDatastoreEmptyRoutePath
|
||||
}
|
||||
|
||||
routePath := []byte(route.Path)
|
||||
|
||||
err := ds.db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := ds.getRouteBucketForApp(tx, route.AppName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v := b.Get(routePath)
|
||||
if v != nil {
|
||||
return models.ErrRoutesAlreadyExists
|
||||
}
|
||||
|
||||
buf, err := json.Marshal(route)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = b.Put([]byte(route.Path), buf)
|
||||
err = b.Put(routePath, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return route, nil
|
||||
}
|
||||
|
||||
func (ds *BoltDatastore) UpdateRoute(newroute *models.Route) (*models.Route, error) {
|
||||
if newroute == nil {
|
||||
return nil, models.ErrDatastoreEmptyRoute
|
||||
}
|
||||
|
||||
if newroute.AppName == "" {
|
||||
return nil, models.ErrDatastoreEmptyAppName
|
||||
}
|
||||
|
||||
if newroute.Path == "" {
|
||||
return nil, models.ErrDatastoreEmptyRoutePath
|
||||
}
|
||||
|
||||
routePath := []byte(newroute.Path)
|
||||
|
||||
var route *models.Route
|
||||
|
||||
err := ds.db.Update(func(tx *bolt.Tx) error {
|
||||
b, err := ds.getRouteBucketForApp(tx, newroute.AppName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v := b.Get(routePath)
|
||||
if v == nil {
|
||||
return models.ErrRoutesNotFound
|
||||
}
|
||||
|
||||
err = json.Unmarshal(v, &route)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Update route fields
|
||||
if newroute.Image != "" {
|
||||
route.Image = newroute.Image
|
||||
}
|
||||
if route.Memory != 0 {
|
||||
route.Memory = newroute.Memory
|
||||
}
|
||||
if route.Type != "" {
|
||||
route.Type = newroute.Type
|
||||
}
|
||||
if newroute.Headers != nil {
|
||||
if route.Config == nil {
|
||||
route.Config = map[string]string{}
|
||||
}
|
||||
for k, v := range newroute.Headers {
|
||||
route.Headers[k] = v
|
||||
}
|
||||
}
|
||||
if newroute.Config != nil {
|
||||
if route.Config == nil {
|
||||
route.Config = map[string]string{}
|
||||
}
|
||||
for k, v := range newroute.Config {
|
||||
route.Config[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
buf, err := json.Marshal(route)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = b.Put(routePath, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -21,15 +21,16 @@ func setLogBuffer() *bytes.Buffer {
|
||||
return &buf
|
||||
}
|
||||
|
||||
const tmpBolt = "/tmp/func_test_bolt.db"
|
||||
|
||||
func TestBolt(t *testing.T) {
|
||||
buf := setLogBuffer()
|
||||
|
||||
const tmpBolt = "/tmp/func_test_bolt.db"
|
||||
os.Remove(tmpBolt)
|
||||
ds, err := New("bolt://" + tmpBolt)
|
||||
if err != nil {
|
||||
t.Fatal("Error when creating datastore: %s", err)
|
||||
t.Fatalf("Error when creating datastore: %v", err)
|
||||
}
|
||||
defer os.Remove(tmpBolt)
|
||||
|
||||
testApp := &models.App{
|
||||
Name: "Test",
|
||||
@@ -41,24 +42,47 @@ func TestBolt(t *testing.T) {
|
||||
Image: "iron/hello",
|
||||
}
|
||||
|
||||
// Testing store app
|
||||
_, err = ds.StoreApp(nil)
|
||||
if err == nil {
|
||||
// Testing insert app
|
||||
_, err = ds.InsertApp(nil)
|
||||
if err != models.ErrDatastoreEmptyApp {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test StoreApp: expected error when using nil app", err)
|
||||
t.Fatalf("Test InsertApp(nil): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyApp, err)
|
||||
}
|
||||
|
||||
_, err = ds.StoreApp(testApp)
|
||||
_, err = ds.InsertApp(&models.App{})
|
||||
if err != models.ErrDatastoreEmptyAppName {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test InsertApp(nil): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyAppName, err)
|
||||
}
|
||||
|
||||
_, err = ds.InsertApp(testApp)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test StoreApp: error when Bolt was storing new app: %s", err)
|
||||
t.Fatalf("Test InsertApp: error when Bolt was storing new app: %s", err)
|
||||
}
|
||||
|
||||
_, err = ds.InsertApp(testApp)
|
||||
if err != models.ErrAppsAlreadyExists {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test InsertApp duplicated: expected error `%v`, but it was `%v`", models.ErrAppsAlreadyExists, err)
|
||||
}
|
||||
|
||||
_, err = ds.UpdateApp(&models.App{
|
||||
Name: testApp.Name,
|
||||
Config: map[string]string{
|
||||
"TEST": "1",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test UpdateApp: error when Bolt was updating app: %v", err)
|
||||
}
|
||||
|
||||
// Testing get app
|
||||
_, err = ds.GetApp("")
|
||||
if err == nil {
|
||||
if err != models.ErrDatastoreEmptyAppName {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetApp: expected error when using empty app name", err)
|
||||
t.Fatalf("Test GetApp: expected error to be %v, but it was %s", models.ErrDatastoreEmptyAppName, err)
|
||||
}
|
||||
|
||||
app, err := ds.GetApp(testApp.Name)
|
||||
@@ -75,7 +99,7 @@ func TestBolt(t *testing.T) {
|
||||
apps, err := ds.GetApps(&models.AppFilter{})
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetApps: error: %s", err)
|
||||
t.Fatalf("Test GetApps: unexpected error %v", err)
|
||||
}
|
||||
if len(apps) == 0 {
|
||||
t.Fatal("Test GetApps: expected result count to be greater than 0")
|
||||
@@ -87,9 +111,9 @@ func TestBolt(t *testing.T) {
|
||||
|
||||
// Testing app delete
|
||||
err = ds.RemoveApp("")
|
||||
if err == nil {
|
||||
if err != models.ErrDatastoreEmptyAppName {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test RemoveApp: expected error when using empty app name", err)
|
||||
t.Fatalf("Test RemoveApp: expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyAppName, err)
|
||||
}
|
||||
|
||||
err = ds.RemoveApp(testApp.Name)
|
||||
@@ -107,39 +131,63 @@ func TestBolt(t *testing.T) {
|
||||
t.Fatalf("Test RemoveApp: failed to remove the app")
|
||||
}
|
||||
|
||||
// Store app again to test routes
|
||||
ds.StoreApp(testApp)
|
||||
|
||||
// Testing store route
|
||||
_, err = ds.StoreRoute(nil)
|
||||
if err == nil {
|
||||
// Test update inexistent app
|
||||
_, err = ds.UpdateApp(&models.App{
|
||||
Name: testApp.Name,
|
||||
Config: map[string]string{
|
||||
"TEST": "1",
|
||||
},
|
||||
})
|
||||
if err != models.ErrAppsNotFound {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test StoreRoute: expected error when using nil route", err)
|
||||
t.Fatalf("Test UpdateApp inexistent: expected error to be %v, but it was %v", models.ErrAppsNotFound, err)
|
||||
}
|
||||
|
||||
_, err = ds.StoreRoute(testRoute)
|
||||
// Insert app again to test routes
|
||||
ds.InsertApp(testApp)
|
||||
|
||||
// Testing insert route
|
||||
_, err = ds.InsertRoute(nil)
|
||||
if err == models.ErrDatastoreEmptyRoute {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test InsertRoute(nil): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyRoute, err)
|
||||
}
|
||||
|
||||
_, err = ds.InsertRoute(testRoute)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test StoreReoute: error when Bolt was storing new route: %s", err)
|
||||
t.Fatalf("Test InsertRoute: error when Bolt was storing new route: %s", err)
|
||||
}
|
||||
|
||||
_, err = ds.InsertRoute(testRoute)
|
||||
if err != models.ErrRoutesAlreadyExists {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test InsertRoute duplicated: expected error to be `%v`, but it was `%v`", models.ErrRoutesAlreadyExists, err)
|
||||
}
|
||||
|
||||
_, err = ds.UpdateRoute(testRoute)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test UpdateRoute: unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Testing get
|
||||
_, err = ds.GetRoute("a", "")
|
||||
if err == nil {
|
||||
if err != models.ErrDatastoreEmptyRoutePath {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoute: expected error when using empty route name", err)
|
||||
t.Fatalf("Test GetRoute(empty route path): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyRoutePath, err)
|
||||
}
|
||||
|
||||
_, err = ds.GetRoute("", "a")
|
||||
if err == nil {
|
||||
if err != models.ErrDatastoreEmptyAppName {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoute: expected error when using empty app name", err)
|
||||
t.Fatalf("Test GetRoute(empty app name): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyAppName, err)
|
||||
}
|
||||
|
||||
route, err := ds.GetRoute(testApp.Name, testRoute.Path)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoute: error: %s", err)
|
||||
t.Fatalf("Test GetRoute: unexpected error %v", err)
|
||||
}
|
||||
if route.Path != testRoute.Path {
|
||||
t.Log(buf.String())
|
||||
@@ -150,7 +198,7 @@ func TestBolt(t *testing.T) {
|
||||
routes, err := ds.GetRoutesByApp(testApp.Name, &models.RouteFilter{})
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoutes: error: %s", err)
|
||||
t.Fatalf("Test GetRoutes: unexpected error %v", err)
|
||||
}
|
||||
if len(routes) == 0 {
|
||||
t.Fatal("Test GetRoutes: expected result count to be greater than 0")
|
||||
@@ -176,21 +224,31 @@ func TestBolt(t *testing.T) {
|
||||
|
||||
// Testing app delete
|
||||
err = ds.RemoveRoute("", "")
|
||||
if err == nil {
|
||||
if err != models.ErrDatastoreEmptyAppName {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test RemoveRoute: expected error when using empty app name", err)
|
||||
t.Fatalf("Test RemoveRoute(empty app name): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyAppName, err)
|
||||
}
|
||||
|
||||
err = ds.RemoveRoute("a", "")
|
||||
if err == nil {
|
||||
if err != models.ErrDatastoreEmptyRoutePath {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test RemoveRoute: expected error when using empty route name", err)
|
||||
t.Fatalf("Test RemoveRoute(empty route path): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyRoutePath, err)
|
||||
}
|
||||
|
||||
err = ds.RemoveRoute(testRoute.AppName, testRoute.Path)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test RemoveApp: error: %s", err)
|
||||
t.Fatalf("Test RemoveApp: unexpected error: %v", err)
|
||||
}
|
||||
|
||||
_, err = ds.UpdateRoute(&models.Route{
|
||||
AppName: testRoute.AppName,
|
||||
Path: testRoute.Path,
|
||||
Image: "test",
|
||||
})
|
||||
if err != models.ErrRoutesNotFound {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test UpdateRoute inexistent: expected error to be `%v`, but it was `%v`", models.ErrRoutesNotFound, err)
|
||||
}
|
||||
|
||||
route, err = ds.GetRoute(testRoute.AppName, testRoute.Path)
|
||||
|
||||
@@ -27,7 +27,12 @@ func (m *Mock) GetApps(appFilter *models.AppFilter) ([]*models.App, error) {
|
||||
return m.FakeApps, nil
|
||||
}
|
||||
|
||||
func (m *Mock) StoreApp(app *models.App) (*models.App, error) {
|
||||
func (m *Mock) InsertApp(app *models.App) (*models.App, error) {
|
||||
// TODO: improve this mock method
|
||||
return m.FakeApp, nil
|
||||
}
|
||||
|
||||
func (m *Mock) UpdateApp(app *models.App) (*models.App, error) {
|
||||
// TODO: improve this mock method
|
||||
return m.FakeApp, nil
|
||||
}
|
||||
@@ -69,7 +74,12 @@ func (m *Mock) GetRoutesByApp(appName string, routeFilter *models.RouteFilter) (
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
func (m *Mock) StoreRoute(route *models.Route) (*models.Route, error) {
|
||||
func (m *Mock) InsertRoute(route *models.Route) (*models.Route, error) {
|
||||
// TODO: improve this mock method
|
||||
return m.FakeRoute, nil
|
||||
}
|
||||
|
||||
func (m *Mock) UpdateRoute(route *models.Route) (*models.Route, error) {
|
||||
// TODO: improve this mock method
|
||||
return m.FakeRoute, nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
"github.com/lib/pq"
|
||||
_ "github.com/lib/pq"
|
||||
)
|
||||
|
||||
@@ -75,17 +76,56 @@ func New(url *url.URL) (models.Datastore, error) {
|
||||
return pg, nil
|
||||
}
|
||||
|
||||
func (ds *PostgresDatastore) StoreApp(app *models.App) (*models.App, error) {
|
||||
func (ds *PostgresDatastore) InsertApp(app *models.App) (*models.App, error) {
|
||||
var cbyte []byte
|
||||
var err error
|
||||
|
||||
if app == nil {
|
||||
return nil, models.ErrDatastoreEmptyApp
|
||||
}
|
||||
|
||||
if app.Name == "" {
|
||||
return nil, models.ErrDatastoreEmptyAppName
|
||||
}
|
||||
|
||||
if app.Config != nil {
|
||||
cbyte, err = json.Marshal(app.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = ds.db.Exec(`INSERT INTO apps (name, config) VALUES ($1, $2);`,
|
||||
app.Name,
|
||||
string(cbyte),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
pqErr := err.(*pq.Error)
|
||||
if pqErr.Code == "23505" {
|
||||
return nil, models.ErrAppsAlreadyExists
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func (ds *PostgresDatastore) UpdateApp(app *models.App) (*models.App, error) {
|
||||
if app == nil {
|
||||
return nil, models.ErrAppsNotFound
|
||||
}
|
||||
|
||||
cbyte, err := json.Marshal(app.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = ds.db.Exec(`
|
||||
INSERT INTO apps (name, config)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT (name) DO UPDATE SET
|
||||
config = $2;
|
||||
res, err := ds.db.Exec(`
|
||||
UPDATE apps SET
|
||||
config = $2
|
||||
WHERE name = $1
|
||||
RETURNING *;
|
||||
`,
|
||||
app.Name,
|
||||
string(cbyte),
|
||||
@@ -95,10 +135,23 @@ func (ds *PostgresDatastore) StoreApp(app *models.App) (*models.App, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
return nil, models.ErrAppsNotFound
|
||||
}
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
func (ds *PostgresDatastore) RemoveApp(appName string) error {
|
||||
if appName == "" {
|
||||
return models.ErrDatastoreEmptyAppName
|
||||
}
|
||||
|
||||
_, err := ds.db.Exec(`
|
||||
DELETE FROM apps
|
||||
WHERE name = $1
|
||||
@@ -112,6 +165,10 @@ func (ds *PostgresDatastore) RemoveApp(appName string) error {
|
||||
}
|
||||
|
||||
func (ds *PostgresDatastore) GetApp(name string) (*models.App, error) {
|
||||
if name == "" {
|
||||
return nil, models.ErrDatastoreEmptyAppName
|
||||
}
|
||||
|
||||
row := ds.db.QueryRow("SELECT name, config FROM apps WHERE name=$1", name)
|
||||
|
||||
var resName string
|
||||
@@ -125,6 +182,9 @@ func (ds *PostgresDatastore) GetApp(name string) (*models.App, error) {
|
||||
json.Unmarshal([]byte(config), &res.Config)
|
||||
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, models.ErrAppsNotFound
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -132,10 +192,19 @@ func (ds *PostgresDatastore) GetApp(name string) (*models.App, error) {
|
||||
}
|
||||
|
||||
func scanApp(scanner rowScanner, app *models.App) error {
|
||||
var configStr string
|
||||
|
||||
err := scanner.Scan(
|
||||
&app.Name,
|
||||
&configStr,
|
||||
)
|
||||
|
||||
if configStr == "" {
|
||||
return models.ErrAppsNotFound
|
||||
}
|
||||
|
||||
json.Unmarshal([]byte(configStr), &app.Config)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -156,18 +225,25 @@ func (ds *PostgresDatastore) GetApps(filter *models.AppFilter) ([]*models.App, e
|
||||
err := scanApp(rows, &app)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err == sql.ErrNoRows {
|
||||
return res, nil
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
res = append(res, &app)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
return res, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (ds *PostgresDatastore) StoreRoute(route *models.Route) (*models.Route, error) {
|
||||
func (ds *PostgresDatastore) InsertRoute(route *models.Route) (*models.Route, error) {
|
||||
if route == nil {
|
||||
return nil, models.ErrDatastoreEmptyRoute
|
||||
}
|
||||
|
||||
hbyte, err := json.Marshal(route.Headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -187,14 +263,47 @@ func (ds *PostgresDatastore) StoreRoute(route *models.Route) (*models.Route, err
|
||||
headers,
|
||||
config
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
ON CONFLICT (app_name, path) DO UPDATE SET
|
||||
path = $2,
|
||||
VALUES ($1, $2, $3, $4, $5, $6);`,
|
||||
route.AppName,
|
||||
route.Path,
|
||||
route.Image,
|
||||
route.Memory,
|
||||
string(hbyte),
|
||||
string(cbyte),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
pqErr := err.(*pq.Error)
|
||||
if pqErr.Code == "23505" {
|
||||
return nil, models.ErrRoutesAlreadyExists
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return route, nil
|
||||
}
|
||||
|
||||
func (ds *PostgresDatastore) UpdateRoute(route *models.Route) (*models.Route, error) {
|
||||
if route == nil {
|
||||
return nil, models.ErrDatastoreEmptyRoute
|
||||
}
|
||||
|
||||
hbyte, err := json.Marshal(route.Headers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cbyte, err := json.Marshal(route.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := ds.db.Exec(`
|
||||
UPDATE routes SET
|
||||
image = $3,
|
||||
memory = $4,
|
||||
headers = $5,
|
||||
config = $6;
|
||||
`,
|
||||
config = $6
|
||||
WHERE app_name = $1 AND path = $2;`,
|
||||
route.AppName,
|
||||
route.Path,
|
||||
route.Image,
|
||||
@@ -206,11 +315,29 @@ func (ds *PostgresDatastore) StoreRoute(route *models.Route) (*models.Route, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
return nil, models.ErrRoutesNotFound
|
||||
}
|
||||
|
||||
return route, nil
|
||||
}
|
||||
|
||||
func (ds *PostgresDatastore) RemoveRoute(appName, routePath string) error {
|
||||
_, err := ds.db.Exec(`
|
||||
if appName == "" {
|
||||
return models.ErrDatastoreEmptyAppName
|
||||
}
|
||||
|
||||
if routePath == "" {
|
||||
return models.ErrDatastoreEmptyRoutePath
|
||||
}
|
||||
|
||||
res, err := ds.db.Exec(`
|
||||
DELETE FROM routes
|
||||
WHERE path = $1 AND app_name = $2
|
||||
`, routePath, appName)
|
||||
@@ -218,6 +345,16 @@ func (ds *PostgresDatastore) RemoveRoute(appName, routePath string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
return models.ErrRoutesRemoving
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -244,10 +381,18 @@ func scanRoute(scanner rowScanner, route *models.Route) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func getRoute(qr rowQuerier, routePath string) (*models.Route, error) {
|
||||
func (ds *PostgresDatastore) GetRoute(appName, routePath string) (*models.Route, error) {
|
||||
if appName == "" {
|
||||
return nil, models.ErrDatastoreEmptyAppName
|
||||
}
|
||||
|
||||
if routePath == "" {
|
||||
return nil, models.ErrDatastoreEmptyRoutePath
|
||||
}
|
||||
|
||||
var route models.Route
|
||||
|
||||
row := qr.QueryRow(fmt.Sprintf("%s WHERE path=$1", routeSelector), routePath)
|
||||
row := ds.db.QueryRow(fmt.Sprintf("%s WHERE app_name=$1 AND path=$2", routeSelector), appName, routePath)
|
||||
err := scanRoute(row, &route)
|
||||
|
||||
if err == sql.ErrNoRows {
|
||||
@@ -258,10 +403,6 @@ func getRoute(qr rowQuerier, routePath string) (*models.Route, error) {
|
||||
return &route, nil
|
||||
}
|
||||
|
||||
func (ds *PostgresDatastore) GetRoute(appName, routePath string) (*models.Route, error) {
|
||||
return getRoute(ds.db, routePath)
|
||||
}
|
||||
|
||||
func (ds *PostgresDatastore) GetRoutes(filter *models.RouteFilter) ([]*models.Route, error) {
|
||||
res := []*models.Route{}
|
||||
filterQuery := buildFilterQuery(filter)
|
||||
|
||||
277
api/datastore/postgres_test.go
Normal file
277
api/datastore/postgres_test.go
Normal file
@@ -0,0 +1,277 @@
|
||||
package datastore
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/iron-io/functions/api/models"
|
||||
)
|
||||
|
||||
const tmpPostgres = "postgres://postgres@127.0.0.1:15432/funcs?sslmode=disable"
|
||||
|
||||
func preparePostgresTest() func() {
|
||||
fmt.Println("initializing postgres for test")
|
||||
exec.Command("docker", "rm", "-f", "iron-postgres-test").Run()
|
||||
exec.Command("docker", "run", "--name", "iron-postgres-test", "-p", "15432:5432", "-d", "postgres").Run()
|
||||
for {
|
||||
db, err := sql.Open("postgres", "postgres://postgres@127.0.0.1:15432?sslmode=disable")
|
||||
if err != nil {
|
||||
time.Sleep(1 * time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
db.Exec(`CREATE DATABASE funcs;`)
|
||||
_, err = db.Exec(`GRANT ALL PRIVILEGES ON DATABASE funcs TO postgres;`)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
fmt.Println("postgres for test ready")
|
||||
return func() {
|
||||
exec.Command("docker", "rm", "-f", "iron-postgres-test").Run()
|
||||
}
|
||||
}
|
||||
|
||||
func TestPostgres(t *testing.T) {
|
||||
close := preparePostgresTest()
|
||||
defer close()
|
||||
buf := setLogBuffer()
|
||||
|
||||
ds, err := New(tmpPostgres)
|
||||
if err != nil {
|
||||
t.Fatalf("Error when creating datastore: %v", err)
|
||||
}
|
||||
|
||||
testApp := &models.App{
|
||||
Name: "Test",
|
||||
}
|
||||
|
||||
testRoute := &models.Route{
|
||||
AppName: testApp.Name,
|
||||
Path: "/test",
|
||||
Image: "iron/hello",
|
||||
}
|
||||
|
||||
// Testing insert app
|
||||
_, err = ds.InsertApp(nil)
|
||||
if err != models.ErrDatastoreEmptyApp {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test InsertApp(nil): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyApp, err)
|
||||
}
|
||||
|
||||
_, err = ds.InsertApp(&models.App{})
|
||||
if err != models.ErrDatastoreEmptyAppName {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test InsertApp(nil): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyAppName, err)
|
||||
}
|
||||
|
||||
_, err = ds.InsertApp(testApp)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test InsertApp: error when storing new app: %s", err)
|
||||
}
|
||||
|
||||
_, err = ds.InsertApp(testApp)
|
||||
if err != models.ErrAppsAlreadyExists {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test InsertApp duplicated: expected error `%v`, but it was `%v`", models.ErrAppsAlreadyExists, err)
|
||||
}
|
||||
|
||||
_, err = ds.UpdateApp(&models.App{
|
||||
Name: testApp.Name,
|
||||
Config: map[string]string{
|
||||
"TEST": "1",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test UpdateApp: error when updating app: %v", err)
|
||||
}
|
||||
|
||||
// Testing get app
|
||||
_, err = ds.GetApp("")
|
||||
if err != models.ErrDatastoreEmptyAppName {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetApp: expected error to be %v, but it was %s", models.ErrDatastoreEmptyAppName, err)
|
||||
}
|
||||
|
||||
app, err := ds.GetApp(testApp.Name)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetApp: error: %s", err)
|
||||
}
|
||||
if app.Name != testApp.Name {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetApp: expected `app.Name` to be `%s` but it was `%s`", app.Name, testApp.Name)
|
||||
}
|
||||
|
||||
// Testing list apps
|
||||
apps, err := ds.GetApps(&models.AppFilter{})
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetApps: unexpected error %v", err)
|
||||
}
|
||||
if len(apps) == 0 {
|
||||
t.Fatal("Test GetApps: expected result count to be greater than 0")
|
||||
}
|
||||
if apps[0].Name != testApp.Name {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetApps: expected `app.Name` to be `%s` but it was `%s`", app.Name, testApp.Name)
|
||||
}
|
||||
|
||||
// Testing app delete
|
||||
err = ds.RemoveApp("")
|
||||
if err != models.ErrDatastoreEmptyAppName {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test RemoveApp: expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyAppName, err)
|
||||
}
|
||||
|
||||
err = ds.RemoveApp(testApp.Name)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test RemoveApp: error: %s", err)
|
||||
}
|
||||
app, err = ds.GetApp(testApp.Name)
|
||||
if err != models.ErrAppsNotFound {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetApp(removed): expected error `%v`, but it was `%v`", models.ErrAppsNotFound, err)
|
||||
}
|
||||
if app != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test RemoveApp: failed to remove the app")
|
||||
}
|
||||
|
||||
// Test update inexistent app
|
||||
_, err = ds.UpdateApp(&models.App{
|
||||
Name: testApp.Name,
|
||||
Config: map[string]string{
|
||||
"TEST": "1",
|
||||
},
|
||||
})
|
||||
if err != models.ErrAppsNotFound {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test UpdateApp(inexistent): expected error `%v`, but it was `%v`", models.ErrAppsNotFound, err)
|
||||
}
|
||||
|
||||
// Insert app again to test routes
|
||||
ds.InsertApp(testApp)
|
||||
|
||||
// Testing insert route
|
||||
_, err = ds.InsertRoute(nil)
|
||||
if err != models.ErrDatastoreEmptyRoute {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test InsertRoute(nil): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyRoute, err)
|
||||
}
|
||||
|
||||
_, err = ds.InsertRoute(testRoute)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test InsertRoute: error when storing new route: %s", err)
|
||||
}
|
||||
|
||||
_, err = ds.InsertRoute(testRoute)
|
||||
if err != models.ErrRoutesAlreadyExists {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test InsertRoute duplicated: expected error to be `%v`, but it was `%v`", models.ErrRoutesAlreadyExists, err)
|
||||
}
|
||||
|
||||
_, err = ds.UpdateRoute(testRoute)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test UpdateRoute: unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Testing get
|
||||
_, err = ds.GetRoute("a", "")
|
||||
if err != models.ErrDatastoreEmptyRoutePath {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoute(empty route path): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyRoutePath, err)
|
||||
}
|
||||
|
||||
_, err = ds.GetRoute("", "a")
|
||||
if err != models.ErrDatastoreEmptyAppName {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoute(empty app name): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyAppName, err)
|
||||
}
|
||||
|
||||
route, err := ds.GetRoute(testApp.Name, testRoute.Path)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoute: unexpected error %v", err)
|
||||
}
|
||||
if route.Path != testRoute.Path {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoute: expected `route.Path` to be `%s` but it was `%s`", route.Path, testRoute.Path)
|
||||
}
|
||||
|
||||
// Testing list routes
|
||||
routes, err := ds.GetRoutesByApp(testApp.Name, &models.RouteFilter{})
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoutes: unexpected error %v", err)
|
||||
}
|
||||
if len(routes) == 0 {
|
||||
t.Fatal("Test GetRoutes: expected result count to be greater than 0")
|
||||
}
|
||||
if routes[0].Path != testRoute.Path {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoutes: expected `app.Name` to be `%s` but it was `%s`", testRoute.Path, routes[0].Path)
|
||||
}
|
||||
|
||||
// Testing list routes
|
||||
routes, err = ds.GetRoutes(&models.RouteFilter{Image: testRoute.Image})
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoutes: error: %s", err)
|
||||
}
|
||||
if len(routes) == 0 {
|
||||
t.Fatal("Test GetRoutes: expected result count to be greater than 0")
|
||||
}
|
||||
if routes[0].Path != testRoute.Path {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoutes: expected `app.Name` to be `%s` but it was `%s`", testRoute.Path, routes[0].Path)
|
||||
}
|
||||
|
||||
// Testing app delete
|
||||
err = ds.RemoveRoute("", "")
|
||||
if err != models.ErrDatastoreEmptyAppName {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test RemoveRoute(empty app name): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyAppName, err)
|
||||
}
|
||||
|
||||
err = ds.RemoveRoute("a", "")
|
||||
if err != models.ErrDatastoreEmptyRoutePath {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test RemoveRoute(empty route path): expected error `%v`, but it was `%v`", models.ErrDatastoreEmptyRoutePath, err)
|
||||
}
|
||||
|
||||
err = ds.RemoveRoute(testRoute.AppName, testRoute.Path)
|
||||
if err != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test RemoveApp: unexpected error: %v", err)
|
||||
}
|
||||
|
||||
_, err = ds.UpdateRoute(&models.Route{
|
||||
AppName: testRoute.AppName,
|
||||
Path: testRoute.Path,
|
||||
Image: "test",
|
||||
})
|
||||
if err != models.ErrRoutesNotFound {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test UpdateRoute inexistent: expected error to be `%v`, but it was `%v`", models.ErrRoutesNotFound, err)
|
||||
}
|
||||
|
||||
route, err = ds.GetRoute(testRoute.AppName, testRoute.Path)
|
||||
if err != models.ErrRoutesNotFound {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test GetRoute: expected error `%v`, but it was `%v`", models.ErrRoutesNotFound, err)
|
||||
}
|
||||
if route != nil {
|
||||
t.Log(buf.String())
|
||||
t.Fatalf("Test RemoveApp: failed to remove the route")
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ var (
|
||||
ErrAppsRemoving = errors.New("Could not remove app from datastore")
|
||||
ErrAppsGet = errors.New("Could not get app from datastore")
|
||||
ErrAppsList = errors.New("Could not list apps from datastore")
|
||||
ErrAppsAlreadyExists = errors.New("App already exists")
|
||||
ErrAppsNotFound = errors.New("App not found")
|
||||
ErrAppsNothingToUpdate = errors.New("Nothing to update")
|
||||
ErrAppsMissingNew = errors.New("Missing new application")
|
||||
|
||||
@@ -5,13 +5,15 @@ import "errors"
|
||||
type Datastore interface {
|
||||
GetApp(appName string) (*App, error)
|
||||
GetApps(*AppFilter) ([]*App, error)
|
||||
StoreApp(*App) (*App, error)
|
||||
InsertApp(app *App) (*App, error)
|
||||
UpdateApp(app *App) (*App, error)
|
||||
RemoveApp(appName string) error
|
||||
|
||||
GetRoute(appName, routePath string) (*Route, error)
|
||||
GetRoutes(*RouteFilter) (routes []*Route, err error)
|
||||
GetRoutesByApp(string, *RouteFilter) (routes []*Route, err error)
|
||||
StoreRoute(*Route) (*Route, error)
|
||||
InsertRoute(route *Route) (*Route, error)
|
||||
UpdateRoute(route *Route) (*Route, error)
|
||||
RemoveRoute(appName, routePath string) error
|
||||
|
||||
// The following provide a generic key value store for arbitrary data, can be used by extensions to store extra data
|
||||
|
||||
@@ -11,14 +11,15 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrRoutesCreate = errors.New("Could not create route")
|
||||
ErrRoutesUpdate = errors.New("Could not update route")
|
||||
ErrRoutesRemoving = errors.New("Could not remove route from datastore")
|
||||
ErrRoutesGet = errors.New("Could not get route from datastore")
|
||||
ErrRoutesList = errors.New("Could not list routes from datastore")
|
||||
ErrRoutesNotFound = errors.New("Route not found")
|
||||
ErrRoutesMissingNew = errors.New("Missing new route")
|
||||
ErrInvalidPayload = errors.New("Invalid payload")
|
||||
ErrRoutesCreate = errors.New("Could not create route")
|
||||
ErrRoutesUpdate = errors.New("Could not update route")
|
||||
ErrRoutesRemoving = errors.New("Could not remove route from datastore")
|
||||
ErrRoutesGet = errors.New("Could not get route from datastore")
|
||||
ErrRoutesList = errors.New("Could not list routes from datastore")
|
||||
ErrRoutesAlreadyExists = errors.New("Route already exists")
|
||||
ErrRoutesNotFound = errors.New("Route not found")
|
||||
ErrRoutesMissingNew = errors.New("Missing new route")
|
||||
ErrInvalidPayload = errors.New("Invalid payload")
|
||||
)
|
||||
|
||||
type Routes []*Route
|
||||
|
||||
@@ -41,7 +41,7 @@ func handleAppCreate(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = Api.Datastore.StoreApp(wapp.App)
|
||||
_, err = Api.Datastore.InsertApp(wapp.App)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate))
|
||||
|
||||
@@ -26,28 +26,29 @@ func setLogBuffer() *bytes.Buffer {
|
||||
|
||||
func TestAppCreate(t *testing.T) {
|
||||
buf := setLogBuffer()
|
||||
New(&datastore.Mock{}, &mqs.Mock{}, testRunner(t))
|
||||
s := New(&datastore.Mock{}, &mqs.Mock{}, testRunner(t))
|
||||
router := testRouter(s)
|
||||
|
||||
for i, test := range []struct {
|
||||
mock *datastore.Mock
|
||||
path string
|
||||
body string
|
||||
expectedCode int
|
||||
expectedError error
|
||||
}{
|
||||
// errors
|
||||
{"/v1/apps", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
||||
{"/v1/apps", `{}`, http.StatusBadRequest, models.ErrAppsMissingNew},
|
||||
{"/v1/apps", `{ "name": "Test" }`, http.StatusBadRequest, models.ErrAppsMissingNew},
|
||||
{"/v1/apps", `{ "app": { "name": "" } }`, http.StatusInternalServerError, models.ErrAppsValidationMissingName},
|
||||
{"/v1/apps", `{ "app": { "name": "1234567890123456789012345678901" } }`, http.StatusInternalServerError, models.ErrAppsValidationTooLongName},
|
||||
{"/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName},
|
||||
{"/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName},
|
||||
{&datastore.Mock{}, "/v1/apps", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
||||
{&datastore.Mock{}, "/v1/apps", `{}`, http.StatusBadRequest, models.ErrAppsMissingNew},
|
||||
{&datastore.Mock{}, "/v1/apps", `{ "name": "Test" }`, http.StatusBadRequest, models.ErrAppsMissingNew},
|
||||
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "" } }`, http.StatusInternalServerError, models.ErrAppsValidationMissingName},
|
||||
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "1234567890123456789012345678901" } }`, http.StatusInternalServerError, models.ErrAppsValidationTooLongName},
|
||||
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName},
|
||||
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "&&%@!#$#@$" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName},
|
||||
|
||||
// success
|
||||
{"/v1/apps", `{ "app": { "name": "teste" } }`, http.StatusCreated, nil},
|
||||
{&datastore.Mock{}, "/v1/apps", `{ "app": { "name": "teste" } }`, http.StatusCreated, nil},
|
||||
} {
|
||||
s := New(test.mock, &mqs.Mock{}, testRunner(t))
|
||||
router := testRouter(s)
|
||||
|
||||
body := bytes.NewBuffer([]byte(test.body))
|
||||
_, rec := routerRequest(t, router, "POST", test.path, body)
|
||||
|
||||
@@ -171,21 +172,27 @@ func TestAppGet(t *testing.T) {
|
||||
|
||||
func TestAppUpdate(t *testing.T) {
|
||||
buf := setLogBuffer()
|
||||
s := New(&datastore.Mock{}, &mqs.Mock{}, testRunner(t))
|
||||
router := testRouter(s)
|
||||
|
||||
for i, test := range []struct {
|
||||
mock *datastore.Mock
|
||||
path string
|
||||
body string
|
||||
expectedCode int
|
||||
expectedError error
|
||||
}{
|
||||
// errors
|
||||
{"/v1/apps/myapp", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
||||
{&datastore.Mock{}, "/v1/apps/myapp", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
||||
|
||||
// success
|
||||
{"/v1/apps/myapp", `{ "app": { "config": { "test": "1" } } }`, http.StatusOK, nil},
|
||||
{&datastore.Mock{
|
||||
FakeApp: &models.App{
|
||||
Name: "myapp",
|
||||
},
|
||||
}, "/v1/apps/myapp", `{ "app": { "config": { "test": "1" } } }`, http.StatusOK, nil},
|
||||
} {
|
||||
s := New(test.mock, &mqs.Mock{}, testRunner(t))
|
||||
router := testRouter(s)
|
||||
|
||||
body := bytes.NewBuffer([]byte(test.body))
|
||||
_, rec := routerRequest(t, router, "PUT", test.path, body)
|
||||
|
||||
|
||||
@@ -28,10 +28,10 @@ func handleAppUpdate(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
app, err := Api.Datastore.StoreApp(wapp.App)
|
||||
app, err := Api.Datastore.UpdateApp(wapp.App)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate))
|
||||
log.WithError(err).Debug(models.ErrAppsUpdate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsUpdate))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ func handleRouteCreate(c *gin.Context) {
|
||||
}
|
||||
|
||||
if app == nil {
|
||||
// Create a new application and add the route to that new application
|
||||
newapp := &models.App{Name: wroute.Route.AppName}
|
||||
if err := newapp.Validate(); err != nil {
|
||||
log.Error(err)
|
||||
@@ -60,7 +61,7 @@ func handleRouteCreate(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
app, err = Api.Datastore.StoreApp(newapp)
|
||||
app, err = Api.Datastore.InsertApp(newapp)
|
||||
if err != nil {
|
||||
log.WithError(err).Error(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate))
|
||||
@@ -68,7 +69,7 @@ func handleRouteCreate(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
_, err = Api.Datastore.StoreRoute(wroute.Route)
|
||||
_, err = Api.Datastore.InsertRoute(wroute.Route)
|
||||
if err != nil {
|
||||
log.WithError(err).Error(models.ErrRoutesCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesCreate))
|
||||
|
||||
@@ -13,27 +13,29 @@ import (
|
||||
|
||||
func TestRouteCreate(t *testing.T) {
|
||||
buf := setLogBuffer()
|
||||
s := New(&datastore.Mock{}, &mqs.Mock{}, testRunner(t))
|
||||
router := testRouter(s)
|
||||
|
||||
for i, test := range []struct {
|
||||
mock *datastore.Mock
|
||||
path string
|
||||
body string
|
||||
expectedCode int
|
||||
expectedError error
|
||||
}{
|
||||
// errors
|
||||
{"/v1/apps/a/routes", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
||||
{"/v1/apps/a/routes", `{ }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
||||
{"/v1/apps/a/routes", `{ "path": "/myroute" }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
||||
{"/v1/apps/a/routes", `{ "route": { } }`, http.StatusInternalServerError, models.ErrRoutesValidationMissingImage},
|
||||
{"/v1/apps/a/routes", `{ "route": { "image": "iron/hello" } }`, http.StatusInternalServerError, models.ErrRoutesValidationMissingPath},
|
||||
{"/v1/apps/a/routes", `{ "route": { "image": "iron/hello", "path": "myroute" } }`, http.StatusInternalServerError, models.ErrRoutesValidationInvalidPath},
|
||||
{"/v1/apps/$/routes", `{ "route": { "image": "iron/hello", "path": "/myroute" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", ``, http.StatusBadRequest, models.ErrInvalidJSON},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "path": "/myroute" }`, http.StatusBadRequest, models.ErrRoutesMissingNew},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { } }`, http.StatusInternalServerError, models.ErrRoutesValidationMissingImage},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { "image": "iron/hello" } }`, http.StatusInternalServerError, models.ErrRoutesValidationMissingPath},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { "image": "iron/hello", "path": "myroute" } }`, http.StatusInternalServerError, models.ErrRoutesValidationInvalidPath},
|
||||
{&datastore.Mock{}, "/v1/apps/$/routes", `{ "route": { "image": "iron/hello", "path": "/myroute" } }`, http.StatusInternalServerError, models.ErrAppsValidationInvalidName},
|
||||
|
||||
// success
|
||||
{"/v1/apps/a/routes", `{ "route": { "name": "myroute", "image": "iron/hello", "path": "/myroute" } }`, http.StatusCreated, nil},
|
||||
{&datastore.Mock{}, "/v1/apps/a/routes", `{ "route": { "image": "iron/hello", "path": "/myroute" } }`, http.StatusCreated, nil},
|
||||
} {
|
||||
s := New(test.mock, &mqs.Mock{}, testRunner(t))
|
||||
router := testRouter(s)
|
||||
|
||||
body := bytes.NewBuffer([]byte(test.body))
|
||||
_, rec := routerRequest(t, router, "POST", test.path, body)
|
||||
|
||||
|
||||
@@ -37,10 +37,10 @@ func handleRouteUpdate(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = Api.Datastore.StoreRoute(wroute.Route)
|
||||
_, err = Api.Datastore.UpdateRoute(wroute.Route)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate))
|
||||
log.WithError(err).Debug(models.ErrRoutesUpdate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrRoutesUpdate))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@ package server
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -92,7 +91,6 @@ func TestRouteRunnerPost(t *testing.T) {
|
||||
resp := getErrorResponse(t, rec)
|
||||
respMsg := resp.Error.Message
|
||||
expMsg := test.expectedError.Error()
|
||||
fmt.Println(respMsg == expMsg)
|
||||
if respMsg != expMsg && !strings.Contains(respMsg, expMsg) {
|
||||
t.Log(buf.String())
|
||||
t.Errorf("Test %d: Expected error message to have `%s`",
|
||||
@@ -165,7 +163,6 @@ func TestMatchRoute(t *testing.T) {
|
||||
for j, param := range test.expectedParams {
|
||||
if params[j].Key != param.Key || params[j].Value != param.Value {
|
||||
t.Log(buf.String())
|
||||
fmt.Println(params[j])
|
||||
t.Errorf("Test %d: expected param %d, key = %s, value = %s", i, j, param.Key, param.Value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package server
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"path"
|
||||
@@ -185,6 +186,8 @@ func (s *Server) bindHandlers() {
|
||||
engine.NoRoute(handleSpecial)
|
||||
}
|
||||
|
||||
var ErrInternalServerError = errors.New("Something unexpected happened on the server")
|
||||
|
||||
func simpleError(err error) *models.Error {
|
||||
return &models.Error{&models.ErrorBody{Message: err.Error()}}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ func getErrorResponse(t *testing.T, rec *httptest.ResponseRecorder) models.Error
|
||||
}
|
||||
|
||||
func prepareBolt(t *testing.T) (models.Datastore, func()) {
|
||||
os.Remove(tmpBolt)
|
||||
ds, err := datastore.New("bolt://" + tmpBolt)
|
||||
if err != nil {
|
||||
t.Fatal("Error when creating datastore: %s", err)
|
||||
|
||||
Reference in New Issue
Block a user