[add] studio server unit-tests
This commit is contained in:
parent
d71443fd00
commit
ecee5d73db
4 changed files with 205 additions and 23 deletions
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
@ -11,6 +13,8 @@ import (
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var regExcp = regexp.MustCompile("^Exception\\|([0-9]+):(.+)$")
|
||||||
|
|
||||||
// Serve start the api server
|
// Serve start the api server
|
||||||
func setRouter(router *gin.Engine) {
|
func setRouter(router *gin.Engine) {
|
||||||
|
|
||||||
|
|
@ -42,7 +46,7 @@ func setRouter(router *gin.Engine) {
|
||||||
}
|
}
|
||||||
c.JSON(200, res)
|
c.JSON(200, res)
|
||||||
c.Done()
|
c.Done()
|
||||||
break
|
return
|
||||||
|
|
||||||
case "readdir":
|
case "readdir":
|
||||||
name := c.Query("name")
|
name := c.Query("name")
|
||||||
|
|
@ -62,11 +66,13 @@ func setRouter(router *gin.Engine) {
|
||||||
}
|
}
|
||||||
c.JSON(200, data)
|
c.JSON(200, data)
|
||||||
c.Done()
|
c.Done()
|
||||||
break
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw(c, 404, fmt.Sprintf("%s method does not found", c.Param("method")))
|
||||||
})
|
})
|
||||||
|
|
||||||
// DSL WriteFile, Mkdir, MkdirAll ...
|
// DSL WriteFile, Mkdir, MkdirAll, Remove, RemoveAll ...
|
||||||
router.POST("/dsl/:method", func(c *gin.Context) {
|
router.POST("/dsl/:method", func(c *gin.Context) {
|
||||||
|
|
||||||
method := strings.ToLower(c.Param("method"))
|
method := strings.ToLower(c.Param("method"))
|
||||||
|
|
@ -97,7 +103,7 @@ func setRouter(router *gin.Engine) {
|
||||||
|
|
||||||
c.JSON(200, length)
|
c.JSON(200, length)
|
||||||
c.Done()
|
c.Done()
|
||||||
break
|
return
|
||||||
|
|
||||||
case "mkdir":
|
case "mkdir":
|
||||||
name := c.Query("name")
|
name := c.Query("name")
|
||||||
|
|
@ -113,7 +119,7 @@ func setRouter(router *gin.Engine) {
|
||||||
}
|
}
|
||||||
c.Status(200)
|
c.Status(200)
|
||||||
c.Done()
|
c.Done()
|
||||||
break
|
return
|
||||||
|
|
||||||
case "mkdirall":
|
case "mkdirall":
|
||||||
name := c.Query("name")
|
name := c.Query("name")
|
||||||
|
|
@ -129,9 +135,42 @@ func setRouter(router *gin.Engine) {
|
||||||
}
|
}
|
||||||
c.Status(200)
|
c.Status(200)
|
||||||
c.Done()
|
c.Done()
|
||||||
break
|
return
|
||||||
|
|
||||||
|
case "remove":
|
||||||
|
name := c.Query("name")
|
||||||
|
if name == "" {
|
||||||
|
throw(c, 400, "name is required")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := dfs.Remove(name)
|
||||||
|
if err != nil {
|
||||||
|
throw(c, 500, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Status(200)
|
||||||
|
c.Done()
|
||||||
|
return
|
||||||
|
|
||||||
|
case "removeall":
|
||||||
|
name := c.Query("name")
|
||||||
|
if name == "" {
|
||||||
|
throw(c, 400, "name is required")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err := dfs.RemoveAll(name)
|
||||||
|
if err != nil {
|
||||||
|
throw(c, 500, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Status(200)
|
||||||
|
c.Done()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw(c, 404, fmt.Sprintf("%s method does not found", c.Param("method")))
|
||||||
})
|
})
|
||||||
|
|
||||||
// Cloud Functions
|
// Cloud Functions
|
||||||
|
|
@ -151,21 +190,31 @@ func setRouter(router *gin.Engine) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if payload == nil || len(payload) > 0 {
|
if payload == nil || len(payload) == 0 {
|
||||||
throw(c, 400, "file content is required")
|
throw(c, 400, "file content is required")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var call cloudCall
|
var fun cfunc
|
||||||
err = jsoniter.Unmarshal(payload, &call)
|
err = jsoniter.Unmarshal(payload, &fun)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
throw(c, 500, err.Error())
|
throw(c, 500, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := gou.Yao.Engine.Call(map[string]interface{}{}, service, call.Method, call.Args...)
|
res, err := gou.Yao.Engine.Call(map[string]interface{}{}, service, fun.Method, fun.Args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
throw(c, 500, err.Error())
|
// parse Exception
|
||||||
|
code := 500
|
||||||
|
message := err.Error()
|
||||||
|
match := regExcp.FindStringSubmatch(message)
|
||||||
|
if len(match) > 0 {
|
||||||
|
code, err = strconv.Atoi(match[1])
|
||||||
|
if err == nil {
|
||||||
|
message = strings.TrimSpace(match[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw(c, code, message)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ var shutdownSignal = make(chan bool, 1)
|
||||||
var dfs fs.FileSystem
|
var dfs fs.FileSystem
|
||||||
var scripts = map[string][]byte{}
|
var scripts = map[string][]byte{}
|
||||||
|
|
||||||
type cloudCall struct {
|
type cfunc struct {
|
||||||
Method string `json:"method"`
|
Method string `json:"method"`
|
||||||
Args []interface{} `json:"args,omitempty"`
|
Args []interface{} `json:"args,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
@ -38,7 +38,7 @@ func Start(cfg config.Config) (err error) {
|
||||||
errCh := make(chan error, 1)
|
errCh := make(chan error, 1)
|
||||||
|
|
||||||
// Set router
|
// Set router
|
||||||
router := gin.Default()
|
router := gin.New()
|
||||||
setRouter(router)
|
setRouter(router)
|
||||||
|
|
||||||
// Server setting
|
// Server setting
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,22 @@
|
||||||
package studio
|
package studio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
jsoniter "github.com/json-iterator/go"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
"github.com/yaoapp/yao/config"
|
"github.com/yaoapp/yao/config"
|
||||||
"github.com/yaoapp/yao/network"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type kv map[string]interface{}
|
||||||
|
type arr []interface{}
|
||||||
|
|
||||||
func TestLoad(t *testing.T) {
|
func TestLoad(t *testing.T) {
|
||||||
err := Load(config.Conf)
|
err := Load(config.Conf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -63,16 +69,131 @@ func TestGetAPI(t *testing.T) {
|
||||||
defer Stop()
|
defer Stop()
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
|
|
||||||
url := fmt.Sprintf("http://127.0.0.1:%d/dsl/readfile?name=/models/user.json", config.Conf.Studio.Port)
|
code, row := httpGet[kv]("/dsl/ReadFile?name=/models/user.json", t)
|
||||||
res := network.RequestGet(url, nil, nil)
|
assert.Equal(t, 200, code)
|
||||||
assert.Equal(t, "用户", res.Data.(map[string]interface{})["name"])
|
assert.Equal(t, "用户", row["name"])
|
||||||
|
|
||||||
url = fmt.Sprintf("http://127.0.0.1:%d/dsl/readdir?name=/models", config.Conf.Studio.Port)
|
code, rows := httpGet[arr]("/dsl/ReadDir?name=/models", t)
|
||||||
res = network.RequestGet(url, nil, nil)
|
assert.Equal(t, 200, code)
|
||||||
assert.Equal(t, 11, len(res.Data.([]interface{})))
|
assert.Equal(t, 11, len(rows))
|
||||||
|
|
||||||
url = fmt.Sprintf("http://127.0.0.1:%d/dsl/readdir?name=/models&recursive=1", config.Conf.Studio.Port)
|
code, rows = httpGet[arr]("/dsl/ReadDir?name=/models&recursive=1", t)
|
||||||
res = network.RequestGet(url, nil, nil)
|
assert.Equal(t, 200, code)
|
||||||
assert.Equal(t, 12, len(res.Data.([]interface{})))
|
assert.Equal(t, 12, len(rows))
|
||||||
|
|
||||||
|
code, length := httpPost[int]("/dsl/WriteFile?name=/models/foo.mod.json", []byte(`{"name":"foo"}`), t)
|
||||||
|
assert.Equal(t, 200, code)
|
||||||
|
assert.Equal(t, 19, length)
|
||||||
|
|
||||||
|
code, _ = httpPost[kv]("/dsl/Remove?name=/models/foo.mod.json", nil, t)
|
||||||
|
assert.Equal(t, 200, code)
|
||||||
|
|
||||||
|
code, _ = httpPost[kv]("/dsl/Mkdir?name=/models/bar", nil, t)
|
||||||
|
assert.Equal(t, 200, code)
|
||||||
|
|
||||||
|
code, _ = httpPost[kv]("/dsl/Remove?name=/models/bar", nil, t)
|
||||||
|
assert.Equal(t, 200, code)
|
||||||
|
|
||||||
|
code, _ = httpPost[kv]("/dsl/MkdirAll?name=/models/bar/hi", nil, t)
|
||||||
|
assert.Equal(t, 200, code)
|
||||||
|
|
||||||
|
code, _ = httpPost[kv]("/dsl/RemoveAll?name=/models/bar", nil, t)
|
||||||
|
assert.Equal(t, 200, code)
|
||||||
|
|
||||||
|
code, res := httpPostJSON[arr](
|
||||||
|
"/service/table",
|
||||||
|
kv{
|
||||||
|
"method": "UnitTest",
|
||||||
|
"args": []interface{}{
|
||||||
|
"foo", 1, 0.618,
|
||||||
|
kv{"string": "world", "int": 1, "float": 0.618},
|
||||||
|
arr{"foo", 1, 0.618},
|
||||||
|
},
|
||||||
|
}, t)
|
||||||
|
|
||||||
|
assert.Equal(t, 200, code)
|
||||||
|
assert.Equal(t, "foo", res[0])
|
||||||
|
assert.Equal(t, float64(1), res[1])
|
||||||
|
assert.Equal(t, 0.618, res[2])
|
||||||
|
assert.Equal(t, "world", res[3].(map[string]interface{})["string"])
|
||||||
|
assert.Equal(t, float64(1), res[3].(map[string]interface{})["int"])
|
||||||
|
assert.Equal(t, 0.618, res[3].(map[string]interface{})["float"])
|
||||||
|
assert.Equal(t, "foo", res[4].([]interface{})[0])
|
||||||
|
assert.Equal(t, float64(1), res[4].([]interface{})[1])
|
||||||
|
assert.Equal(t, 0.618, res[4].([]interface{})[2])
|
||||||
|
|
||||||
|
code, excp := httpPostJSON[kv]("/service/table", kv{"method": "UnitTest", "args": []interface{}{"throw-test"}}, t)
|
||||||
|
assert.Equal(t, 418, code)
|
||||||
|
assert.Equal(t, float64(418), excp["code"])
|
||||||
|
assert.Equal(t, "I'm a teapot", excp["message"])
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpGet[T kv | arr | interface{} | map[string]interface{} | int | []interface{}](url string, t *testing.T) (int, T) {
|
||||||
|
|
||||||
|
var data T
|
||||||
|
url = fmt.Sprintf("http://127.0.0.1:%d%s", config.Conf.Studio.Port, url)
|
||||||
|
res, err := http.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Body != nil {
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if body != nil {
|
||||||
|
err = jsoniter.Unmarshal(body, &data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.StatusCode, data
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpPost[T kv | arr | interface{} | map[string]interface{} | int | []interface{}](url string, payload []byte, t *testing.T) (int, T) {
|
||||||
|
|
||||||
|
var data T
|
||||||
|
var buff *bytes.Buffer = bytes.NewBuffer([]byte{})
|
||||||
|
|
||||||
|
if payload != nil {
|
||||||
|
buff = bytes.NewBuffer(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
url = fmt.Sprintf("http://127.0.0.1:%d%s", config.Conf.Studio.Port, url)
|
||||||
|
res, err := http.Post(url, "application/json", buff)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.Body != nil {
|
||||||
|
body, err := io.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if body != nil && string(body) != "" {
|
||||||
|
err = jsoniter.Unmarshal(body, &data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.StatusCode, data
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpPostJSON[T kv | arr | interface{} | map[string]interface{} | int | []interface{}](url string, payload interface{}, t *testing.T) (int, T) {
|
||||||
|
var data []byte
|
||||||
|
var err error
|
||||||
|
if payload != nil {
|
||||||
|
data, err = jsoniter.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return httpPost[T](url, data, t)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,3 +31,15 @@ function Model(name) {
|
||||||
function Ping() {
|
function Ping() {
|
||||||
return "PONG";
|
return "PONG";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* for unit tests
|
||||||
|
* @param {...any} args
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function UnitTest(...args) {
|
||||||
|
if (args.length > 0 && args[0] == "throw-test") {
|
||||||
|
throw new Exception("I'm a teapot", 418);
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue