[add] studio server unit-tests

This commit is contained in:
Max 2022-10-14 12:25:03 +08:00
parent d71443fd00
commit ecee5d73db
4 changed files with 205 additions and 23 deletions

View file

@ -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
} }

View file

@ -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

View file

@ -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)
} }

View file

@ -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;
}