[add] migrate widgets.table api

This commit is contained in:
Max 2023-03-25 17:46:57 +08:00
parent 5de550781c
commit f1f58cc99f
4 changed files with 460 additions and 162 deletions

View file

@ -9,7 +9,7 @@ COMMIT := $(shell git log | head -n 1 | awk '{print substr($$2, 0, 12)}')
NOW := $(shell date +"%FT%T%z") NOW := $(shell date +"%FT%T%z")
# ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) # ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
TESTFOLDER := $(shell $(GO) list ./... | grep -E 'api|model|flow|script|fs|i18n|connector|query|plugin|cert|crypto|task|schedule|runtime|helper|utils|widget|importer|store|widgets/app|widgets/login|widgets/table' | grep -vE 'examples|tests*|config|widgets') TESTFOLDER := $(shell $(GO) list ./... | grep -E 'api|model|flow|script|fs|i18n|connector|query|plugin|cert|crypto|task|schedule|runtime|helper|utils|widget|importer|store' | grep -vE 'examples|tests*|config|widgets')
TESTTAGS ?= "" TESTTAGS ?= ""
# TESTWIDGETS := $(shell $(GO) list ./widgets/...) # TESTWIDGETS := $(shell $(GO) list ./widgets/...)

225
test/request.go Normal file
View file

@ -0,0 +1,225 @@
package test
import (
"bytes"
"context"
"fmt"
"io"
"net/http"
"time"
jsoniter "github.com/json-iterator/go"
"github.com/yaoapp/gou/model"
"github.com/yaoapp/gou/process"
"github.com/yaoapp/gou/session"
"github.com/yaoapp/yao/helper"
)
// Request request
type Request struct {
host string
port int
route string
method string
data map[string]interface{}
params map[string]string
headers map[string]string
}
// Response response
type Response struct {
status int
body []byte
}
// NewRequest create a new request
func NewRequest(port int) *Request {
return &Request{
host: "127.0.0.1",
port: port,
data: map[string]interface{}{},
params: map[string]string{},
headers: map[string]string{},
}
}
// Token set token
func (r *Request) Token(token string) *Request {
r.headers["Authorization"] = fmt.Sprintf("Bearer %s", token)
return r
}
// Header set header
func (r *Request) Header(key string, value string) *Request {
r.headers[key] = value
return r
}
// Param set saram
func (r *Request) Param(key string, value string) *Request {
r.params[key] = value
return r
}
// Data set data
func (r *Request) Data(data map[string]interface{}) *Request {
r.data = data
return r
}
// Route set the route
func (r *Request) Route(route string) *Request {
r.route = route
return r
}
// Get request
func (r *Request) Get() (*Response, error) {
r.method = "GET"
return r.Send()
}
// Post request
func (r *Request) Post() (*Response, error) {
r.method = "POST"
return r.Send()
}
// Send request
func (r *Request) Send() (*Response, error) {
client := http.Client{}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// set body
var data io.Reader = nil
if len(r.data) > 0 {
content, err := jsoniter.Marshal(r.data)
if err != nil {
return nil, err
}
data = bytes.NewBuffer(content)
}
url := fmt.Sprintf("http://%s:%d%s", r.host, r.port, r.route)
req, err := http.NewRequestWithContext(ctx, r.method, url, data)
if err != nil {
return nil, err
}
// Set header
for key, value := range r.headers {
req.Header.Add(key, value)
}
if _, has := r.headers["Content-Type"]; !has {
req.Header.Add("Content-Type", "application/json")
}
// Set Parms
if len(r.params) > 0 {
q := req.URL.Query()
for key, value := range r.params {
q.Add(key, value)
}
req.URL.RawQuery = q.Encode()
}
// Send Request
res, err := client.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
// response body
body, err := io.ReadAll(res.Body)
if err != nil {
return nil, err
}
p := &Response{
status: res.StatusCode,
body: body,
}
return p, nil
}
// Map to map
func (p *Response) Map() (map[string]interface{}, error) {
v := map[string]interface{}{}
err := jsoniter.Unmarshal(p.body, &v)
if err != nil {
return nil, err
}
return v, nil
}
// Int to int
func (p *Response) Int() (int, error) {
v := 0
err := jsoniter.Unmarshal(p.body, &v)
if err != nil {
return 0, err
}
return v, nil
}
// Status get the reaponse status
func (p *Response) Status() int {
return p.status
}
// Body get the reaponse body
func (p *Response) Body() string {
return string(p.body)
}
// To cast to custom sturct
func (p *Response) To(v interface{}) error {
err := jsoniter.Unmarshal(p.body, v)
if err != nil {
return err
}
return nil
}
// AutoLogin auto login
func AutoLogin(id int) (map[string]interface{}, error) {
user := model.Select("admin.user")
row, err := user.Find(id, model.QueryParam(model.QueryParam{Select: []interface{}{"id", "name", "type", "email", "mobile", "extra", "status"}}))
if err != nil {
return nil, err
}
expiresAt := time.Now().Unix() + 3600
sid := session.ID()
token := helper.JwtMake(id, map[string]interface{}{}, map[string]interface{}{
"expires_at": expiresAt,
"sid": sid,
"issuer": "admin",
})
session.Global().Expire(time.Duration(token.ExpiresAt)*time.Second).ID(sid).Set("user_id", id)
session.Global().ID(sid).Set("user", row)
session.Global().ID(sid).Set("issuer", "admin")
p, err := process.Of("yao.app.menu")
if err != nil {
return nil, err
}
menus, err := p.Exec()
if err != nil {
return nil, err
}
return map[string]interface{}{
"expires_at": token.ExpiresAt,
"token": token.Token,
"user": row,
"menus": menus,
}, nil
}

View file

@ -3,21 +3,29 @@ package test
import ( import (
"fmt" "fmt"
"os" "os"
"strings"
"testing" "testing"
"time"
"github.com/gin-gonic/gin"
"github.com/yaoapp/gou/api"
"github.com/yaoapp/gou/application" "github.com/yaoapp/gou/application"
"github.com/yaoapp/gou/model" "github.com/yaoapp/gou/model"
"github.com/yaoapp/gou/query" "github.com/yaoapp/gou/query"
"github.com/yaoapp/gou/query/gou" "github.com/yaoapp/gou/query/gou"
v8 "github.com/yaoapp/gou/runtime/v8" v8 "github.com/yaoapp/gou/runtime/v8"
"github.com/yaoapp/gou/server/http"
"github.com/yaoapp/kun/exception" "github.com/yaoapp/kun/exception"
"github.com/yaoapp/xun/capsule" "github.com/yaoapp/xun/capsule"
"github.com/yaoapp/yao/config" "github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/fs" "github.com/yaoapp/yao/fs"
"github.com/yaoapp/yao/helper"
"github.com/yaoapp/yao/runtime" "github.com/yaoapp/yao/runtime"
"github.com/yaoapp/yao/share" "github.com/yaoapp/yao/share"
) )
var testServer *http.Server = nil
// Prepare test environment // Prepare test environment
func Prepare(t *testing.T, cfg config.Config) { func Prepare(t *testing.T, cfg config.Config) {
root := os.Getenv("YAO_TEST_APPLICATION") root := os.Getenv("YAO_TEST_APPLICATION")
@ -42,7 +50,7 @@ func Prepare(t *testing.T, cfg config.Config) {
dbconnect(t, cfg) dbconnect(t, cfg)
load(t, cfg) load(t, cfg)
start(t, cfg) startRuntime(t, cfg)
} }
// Clean the test environment // Clean the test environment
@ -51,6 +59,49 @@ func Clean() {
runtime.Stop() runtime.Stop()
} }
// Start the test server
func Start(t *testing.T, guards map[string]gin.HandlerFunc, cfg config.Config) {
var err error
option := http.Option{Port: 0, Root: "/", Timeout: 2 * time.Second}
gin.SetMode(gin.ReleaseMode)
router := gin.New()
api.SetGuards(guards)
api.SetRoutes(router, "api")
testServer = http.New(router, option)
go func() { err = testServer.Start() }()
<-testServer.Event()
if err != nil {
t.Fatal(err)
}
}
// Stop the test server
func Stop() {
if testServer != nil {
testServer.Stop()
<-testServer.Event()
}
dbclose()
runtime.Stop()
}
// Port Get the test server port
func Port(t *testing.T) int {
if testServer == nil {
t.Fatal(fmt.Errorf("server not started"))
}
port, err := testServer.Port()
if err != nil {
t.Fatal(err)
}
return port
}
func dbclose() { func dbclose() {
if capsule.Global != nil { if capsule.Global != nil {
capsule.Global.Connections.Range(func(key, value any) bool { capsule.Global.Connections.Range(func(key, value any) bool {
@ -76,7 +127,7 @@ func dbconnect(t *testing.T, cfg config.Config) {
} }
func start(t *testing.T, cfg config.Config) { func startRuntime(t *testing.T, cfg config.Config) {
err := runtime.Start(cfg) err := runtime.Start(cfg)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -145,3 +196,18 @@ func loadQuery(t *testing.T, cfg config.Config) {
AESKey: cfg.DB.AESKey, AESKey: cfg.DB.AESKey,
}) })
} }
// GuardBearerJWT test guard
func GuardBearerJWT(c *gin.Context) {
tokenString := c.Request.Header.Get("Authorization")
tokenString = strings.TrimSpace(strings.TrimPrefix(tokenString, "Bearer "))
if tokenString == "" {
c.JSON(403, gin.H{"code": 403, "message": "No permission"})
c.Abort()
return
}
claims := helper.JwtValidate(tokenString)
c.Set("__sid", claims.SID)
}

View file

@ -1,8 +1,15 @@
package table package table
import ( import (
"fmt"
"net/url"
"testing"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/yaoapp/yao/widgets/test" "github.com/stretchr/testify/assert"
"github.com/yaoapp/kun/any"
"github.com/yaoapp/yao/config"
"github.com/yaoapp/yao/test"
) )
var guards = map[string]gin.HandlerFunc{ var guards = map[string]gin.HandlerFunc{
@ -10,194 +17,194 @@ var guards = map[string]gin.HandlerFunc{
"widget-table": Guard, "widget-table": Guard,
} }
// func TestAPISetting(t *testing.T) { func TestAPISetting(t *testing.T) {
// gtest.Prepare(t, config.Conf) port := start(t)
// defer gtest.Clean() defer stop()
// prepare(t) req := test.NewRequest(port).Route("/api/__yao/table/pet/setting")
// clear(t) res, err := req.Get()
// testData(t) if err != nil {
t.Fatal(err)
}
assert.Equal(t, 403, res.Status())
// port := start(t) req = test.NewRequest(port).Route("/api/__yao/table/pet/setting").Token(token(t))
// defer test.Stop(func() {}) res, err = req.Get()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 200, res.Status())
// req := test.NewRequest(port).Route("/api/__yao/table/pet/setting") v, err := res.Map()
// res, err := req.Get() if err != nil {
// if err != nil { t.Fatal(err)
// t.Fatal(err) }
// }
// assert.Equal(t, 403, res.Status())
// req = test.NewRequest(port).Route("/api/__yao/table/pet/setting").Token(token(t)) data := any.Of(v).MapStr().Dot()
// res, err = req.Get() assert.Equal(t, "/api/xiang/import/pet", data.Get("header.preset.import.api.import"))
// if err != nil { // assert.Equal(t, "跳转", data.Get("header.preset.import.operation.0.title"))
// t.Fatal(err) assert.Equal(t, "/api/__yao/table/pet/component/fields.table."+url.QueryEscape("入院状态")+".view.props.xProps/remote", data.Get("fields.table.入院状态.view.props.xProps.remote.api"))
// } assert.Equal(t, "/api/__yao/table/pet/component/fields.table."+url.QueryEscape("入院状态")+".edit.props.xProps/remote", data.Get("fields.table.入院状态.edit.props.xProps.remote.api"))
// assert.Equal(t, 200, res.Status()) }
// v, err := res.Map() func TestAPISearch(t *testing.T) {
// if err != nil { port := start(t)
// t.Fatal(err) defer test.Stop()
// }
// data := any.Of(v).MapStr().Dot()
// assert.Equal(t, "/api/xiang/import/pet", data.Get("header.preset.import.api.import"))
// // assert.Equal(t, "跳转", data.Get("header.preset.import.operation.0.title"))
// assert.Equal(t, "/api/__yao/table/pet/component/fields.table."+url.QueryEscape("入院状态")+".view.props.xProps/remote", data.Get("fields.table.入院状态.view.props.xProps.remote.api"))
// assert.Equal(t, "/api/__yao/table/pet/component/fields.table."+url.QueryEscape("入院状态")+".edit.props.xProps/remote", data.Get("fields.table.入院状态.edit.props.xProps.remote.api"))
// }
// func TestAPISearch(t *testing.T) { req := test.NewRequest(port).Route("/api/__yao/table/session/search")
// port := start(t) res, err := req.Get()
// defer test.Stop(func() {}) if err != nil {
t.Fatal(err)
}
assert.Equal(t, 403, res.Status())
// req := test.NewRequest(port).Route("/api/__yao/table/session/search") req = test.NewRequest(port).Route("/api/__yao/table/session/search").Token(token(t))
// res, err := req.Get() res, err = req.Get()
// if err != nil { if err != nil {
// t.Fatal(err) t.Fatal(err)
// } }
// assert.Equal(t, 403, res.Status()) assert.Equal(t, 200, res.Status())
resp, err := res.Map()
if err != nil {
t.Fatal(err)
}
// req = test.NewRequest(port).Route("/api/__yao/table/session/search").Token(token(t)) data := any.Of(resp).MapStr().Dot()
// res, err = req.Get() assert.Equal(t, "1", fmt.Sprintf("%v", data.Get("pagesize")))
// if err != nil { assert.Equal(t, "3", fmt.Sprintf("%v", data.Get("total")))
// t.Fatal(err) assert.Equal(t, "checked", data.Get("data.0.status"))
// } assert.Equal(t, "enabled", data.Get("data.0.mode"))
// assert.Equal(t, 200, res.Status()) assert.Equal(t, "1", fmt.Sprintf("%v", data.Get("data.0.doctor_id")))
// resp, err := res.Map()
// if err != nil {
// t.Fatal(err)
// }
// data := any.Of(resp).MapStr().Dot() }
// assert.Equal(t, "1", fmt.Sprintf("%v", data.Get("pagesize")))
// assert.Equal(t, "3", fmt.Sprintf("%v", data.Get("total")))
// assert.Equal(t, "checked", data.Get("data.0.status"))
// assert.Equal(t, "enabled", data.Get("data.0.mode"))
// assert.Equal(t, "1", fmt.Sprintf("%v", data.Get("data.0.doctor_id")))
// } func TestAPISave(t *testing.T) {
port := start(t)
defer test.Stop()
// func TestAPISave(t *testing.T) { payload := map[string]interface{}{
// port := start(t) "name": "New Pet",
// defer test.Stop(func() {}) "type": "cat",
"status": "checked",
"mode": "enabled",
"stay": 66,
"cost": 24,
"doctor_id": 1,
}
// payload := map[string]interface{}{ req := test.NewRequest(port).Route("/api/__yao/table/pet/save").Data(payload)
// "name": "New Pet", res, err := req.Post()
// "type": "cat", if err != nil {
// "status": "checked", t.Fatal(err)
// "mode": "enabled", }
// "stay": 66, assert.Equal(t, 403, res.Status())
// "cost": 24,
// "doctor_id": 1,
// }
// req := test.NewRequest(port).Route("/api/__yao/table/pet/save").Data(payload) req = test.NewRequest(port).Route("/api/__yao/table/pet/save").Data(payload).Token(token(t))
// res, err := req.Post() res, err = req.Post()
// if err != nil { if err != nil {
// t.Fatal(err) t.Fatal(err)
// } }
// assert.Equal(t, 403, res.Status()) assert.Equal(t, 200, res.Status())
// req = test.NewRequest(port).Route("/api/__yao/table/pet/save").Data(payload).Token(token(t)) v, err := res.Int()
// res, err = req.Post() if err != nil {
// if err != nil { t.Fatal(err)
// t.Fatal(err) }
// }
// assert.Equal(t, 200, res.Status())
// v, err := res.Int() assert.Equal(t, 4, v)
// if err != nil { }
// t.Fatal(err)
// }
// assert.Equal(t, 4, v) func TestAPICustomGuard(t *testing.T) {
// }
// func TestAPICustomGuard(t *testing.T) { port := start(t)
defer test.Stop()
// port := start(t) req := test.NewRequest(port).Route("/api/__yao/table/pet/find/1")
// defer test.Stop(func() {}) res, err := req.Get()
if err != nil {
t.Fatal(err)
}
// req := test.NewRequest(port).Route("/api/__yao/table/pet/find/1") req = test.NewRequest(port).Route("/api/__yao/table/pet/get")
// res, err := req.Get() res, err = req.Get()
// if err != nil { if err != nil {
// t.Fatal(err) t.Fatal(err)
// } }
assert.Equal(t, 403, res.Status())
// req = test.NewRequest(port).Route("/api/__yao/table/pet/get") req = test.NewRequest(port).Route("/api/__yao/table/pet/get").Token(token(t)).Header("Unit-Test", "yes")
// res, err = req.Get() res, err = req.Get()
// if err != nil { if err != nil {
// t.Fatal(err) t.Fatal(err)
// } }
// assert.Equal(t, 403, res.Status()) assert.Equal(t, 418, res.Status())
// req = test.NewRequest(port).Route("/api/__yao/table/pet/get").Token(token(t)).Header("Unit-Test", "yes") req = test.NewRequest(port).Route("/api/__yao/table/pet/get").Token(token(t))
// res, err = req.Get() res, err = req.Get()
// if err != nil { if err != nil {
// t.Fatal(err) t.Fatal(err)
// } }
// assert.Equal(t, 418, res.Status()) assert.Equal(t, 200, res.Status())
}
// req = test.NewRequest(port).Route("/api/__yao/table/pet/get").Token(token(t)) func TestAPIGlobalCustomGuard(t *testing.T) {
// res, err = req.Get()
// if err != nil {
// t.Fatal(err)
// }
// assert.Equal(t, 200, res.Status())
// }
// func TestAPIGlobalCustomGuard(t *testing.T) { port := start(t)
defer test.Stop()
// port := start(t) req := test.NewRequest(port).Route("/api/__yao/table/guard/find/1")
// defer test.Stop(func() {}) res, err := req.Get()
if err != nil {
t.Fatal(err)
}
assert.Equal(t, 403, res.Status())
// req := test.NewRequest(port).Route("/api/__yao/table/guard/find/1") req = test.NewRequest(port).Route("/api/__yao/table/guard/get")
// res, err := req.Get() res, err = req.Get()
// if err != nil { if err != nil {
// t.Fatal(err) t.Fatal(err)
// } }
// assert.Equal(t, 403, res.Status()) assert.Equal(t, 403, res.Status())
// req = test.NewRequest(port).Route("/api/__yao/table/guard/get") req = test.NewRequest(port).Route("/api/__yao/table/guard/get").Token(token(t)).Header("Unit-Test", "yes")
// res, err = req.Get() res, err = req.Get()
// if err != nil { if err != nil {
// t.Fatal(err) t.Fatal(err)
// } }
// assert.Equal(t, 403, res.Status()) assert.Equal(t, 418, res.Status())
// req = test.NewRequest(port).Route("/api/__yao/table/guard/get").Token(token(t)).Header("Unit-Test", "yes") req = test.NewRequest(port).Route("/api/__yao/table/guard/get").Token(token(t))
// res, err = req.Get() res, err = req.Get()
// if err != nil { if err != nil {
// t.Fatal(err) t.Fatal(err)
// } }
// assert.Equal(t, 418, res.Status()) assert.Equal(t, 200, res.Status())
}
// req = test.NewRequest(port).Route("/api/__yao/table/guard/get").Token(token(t)) func start(t *testing.T) int {
// res, err = req.Get() test.Prepare(t, config.Conf)
// if err != nil { prepare(t)
// t.Fatal(err) clear(t)
// } testData(t)
// assert.Equal(t, 200, res.Status()) test.Start(t, guards, config.Conf)
// }
// func start(t *testing.T) int { return test.Port(t)
// port := 0 }
// go test.Start(t, guards, port) func stop() {
// time.Sleep(200 * time.Millisecond) test.Stop()
// return port }
// }
// func token(t *testing.T) string { func token(t *testing.T) string {
// res, err := test.AutoLogin(1) res, err := test.AutoLogin(1)
// if err != nil { if err != nil {
// t.Fatal(err) t.Fatal(err)
// } }
// token, ok := res["token"].(string) token, ok := res["token"].(string)
// if !ok { if !ok {
// t.Fatal(fmt.Errorf("get token error %v", res)) t.Fatal(fmt.Errorf("get token error %v", res))
// } }
// return token return token
// } }