diff --git a/.gitignore b/.gitignore index 9ff6ed9..ab482f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,2 @@ .* -/go.sum +go.sum diff --git a/file/file.go b/file/file.go index 7ce072e..12fb8b0 100644 --- a/file/file.go +++ b/file/file.go @@ -1,9 +1,9 @@ package file import ( + "apigo.cloud/git/apigo/plugin" "bufio" "errors" - "apigo.cloud/git/apigo/plugin" "github.com/ssgo/u" "gopkg.in/yaml.v3" "os" @@ -545,7 +545,7 @@ func getAllowExtensions() []string { fileConfigLock.RLock() defer fileConfigLock.RUnlock() allowExtensions := make([]string, len(_allowExtensions)) - for i, v := range _allowPaths { + for i, v := range _allowExtensions { allowExtensions[i] = v } return allowExtensions @@ -556,6 +556,7 @@ func checkDirAllow(filename string) bool { if len(allowPaths) > 0 { ok := false for _, allowPath := range allowPaths { + //fmt.Println(">>>", filename, allowPath, strings.HasPrefix(filename, allowPath)) if strings.HasPrefix(filename, allowPath) { ok = true break @@ -577,6 +578,7 @@ func checkFileAllow(filename string) bool { if len(allowExtensions) > 0 { ok := false for _, allowExtension := range allowExtensions { + //fmt.Println(">>>", filename, allowExtension, strings.HasSuffix(filename, allowExtension)) if strings.HasSuffix(filename, allowExtension) { ok = true break diff --git a/redis/redis.go b/redis/redis.go index 0c8c8e7..e8ceb5e 100644 --- a/redis/redis.go +++ b/redis/redis.go @@ -1,8 +1,8 @@ package redis import ( - "encoding/json" "apigo.cloud/git/apigo/plugin" + "encoding/json" "github.com/ssgo/log" "github.com/ssgo/redis" "github.com/ssgo/u" diff --git a/tests/crypto_test.go b/tests/crypto_test.go new file mode 100644 index 0000000..dfa59b2 --- /dev/null +++ b/tests/crypto_test.go @@ -0,0 +1,68 @@ +package tests + +import ( + "apigo.cloud/git/apigo/gojs" + _ "apigo.cloud/git/apigo/plugins/crypto" + "testing" +) + +func TestHash(t *testing.T) { + r, err, _ := gojs.Run(` + if(crypto.md5('hello 123') != '1bb45824de71b2f6476d800f427cb2ab') throw new Error('md5 error') + if(crypto.sm3('hello 123') != '4e1f46e2350250d20df71c360852751c8aed29753e6058969602cea8639f7737') throw new Error('sm3 error') + if(crypto.sha256(new Uint8Array([1,2,3,0,254])) != '39a55ea4bd5dd2fd3818501a1fff9bde99573465a2a5b82c9731f8efd2f0c814') throw new Error('sha256 error') + return true +`, nil, nil) + Test(t, "Hash", r == true && err == nil, err) +} + +func TestAes(t *testing.T) { + r, err, _ := gojs.Run(` + key = "?GQ$0K0GgLdO=f+~L68PLm$uhKr4'=tV" + iv = new Uint8Array([86,70,115,55,64,115,75,54,49,99,106,94,102,63,72,90]) + s1 = crypto.aes.encryptBytes('hello 123', key, iv) + if( crypto.urlBase64.encodeBytes(s1) != 't2fsWsWbCDjMBqV_5WLgfQ==') throw new Error('urlBase64 encode error') + s2 = crypto.aes.decrypt(crypto.hex.encodeBytes(s1), crypto.hex.encodeBytes(key), crypto.hex.encodeBytes(iv)) + if( s2 != 'hello 123') throw new Error('aes decrypt') + return true +`, nil, nil) + Test(t, "AES", r == true && err == nil, err) +} + +func TestSM4(t *testing.T) { + r, err, _ := gojs.Run(` + key = "?GQ$0K0GgLdO=f+~L68PLm$uhKr4'=tV" + iv = new Uint8Array([86,70,115,55,64,115,75,54,49,99,106,94,102,63,72,90]) + s1 = crypto.sm4.encryptBytes('hello 123', key, iv) + s2 = crypto.sm4.decrypt(crypto.hex.encodeBytes(s1), crypto.hex.encodeBytes(key), crypto.hex.encodeBytes(iv)) + if( s2 != 'hello 123') throw new Error('sm4 decrypt error') + return true +`, nil, nil) + Test(t, "SM4", r == true && err == nil, err) +} + +func TestECDSA(t *testing.T) { + r, err, _ := gojs.Run(` + [priKey, pubKey] = crypto.ecdsa.genKey() + s1 = crypto.ecdsa.sign('hello 123', priKey) + if(!crypto.ecdsa.verify('hello 123', s1, pubKey)) throw new Error('') + s2 = crypto.ecdsa.encrypt('hello 123', pubKey) + s3 = crypto.ecdsa.decrypt(s2, priKey) + if( s3 != 'hello 123') throw new Error('ecdsa decrypt error') + return true +`, nil, nil) + Test(t, "ECDSA", r == true && err == nil, err) +} + +func TestSM2(t *testing.T) { + r, err, _ := gojs.Run(` + [priKey, pubKey] = crypto.sm2.genKey() + s1 = crypto.sm2.sign('hello 123', priKey) + if(!crypto.sm2.verify('hello 123', s1, pubKey)) throw new Error('') + s2 = crypto.sm2.encrypt('hello 123', pubKey) + s3 = crypto.sm2.decrypt(s2, priKey) + if( s3 != 'hello 123') throw new Error('sm2 decrypt error') + return true +`, nil, nil) + Test(t, "SM2", r == true && err == nil, err) +} diff --git a/tests/db_test.go b/tests/db_test.go new file mode 100644 index 0000000..6858b79 --- /dev/null +++ b/tests/db_test.go @@ -0,0 +1,56 @@ +package tests + +import ( + "apigo.cloud/git/apigo/gojs" + "apigo.cloud/git/apigo/plugin" + _ "apigo.cloud/git/apigo/plugins/db" + _ "github.com/mattn/go-sqlite3" + "github.com/ssgo/u" + "os" + "testing" +) + +func TestSqlite(t *testing.T) { + rt := gojs.New(nil, nil) + defer rt.Close() + + gojs.SetPluginsConfig(map[string]plugin.Config{ + "db": { + "default": "sqlite3://test.db", + }, + }) + + defer os.Remove("test.db") + r, err, _ := rt.Run(` + db.exec('CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(30))') + id1 = db.insert('test', {name:'Tom'}) + id2 = db.replace('test', {name:'Kitty'}) + id3 = db.insert('test', {name:'Lucy'}) + return id1 + id2 + id3 + `) + Test(t, "create and insert", u.Int(r) == 6, r, err) + + r, err, _ = rt.Run(` + changes = db.fetch().update('test', {name:'Lucy Wang'}, 'id=?', 3) + return changes + `) + Test(t, "update", u.Int(r) == 1, r, err) + + r, err, _ = rt.Run(` + changes = db.fetch().delete('test', 'id=?', 2) + return changes + `) + Test(t, "update", u.Int(r) == 1, r, err) + + r, err, _ = rt.Run(` + list = db.fetch().query('select id,name from test where id > ?', 1) + return list + `) + list := make([]struct{ + Id int + Name string + }, 0) + u.Convert(r, &list) + Test(t, "list", len(list) == 1 && list[0].Name == "Lucy Wang", r, err) + +} diff --git a/tests/discover_test.go b/tests/discover_test.go new file mode 100644 index 0000000..eb9f50a --- /dev/null +++ b/tests/discover_test.go @@ -0,0 +1,46 @@ +package tests + +import ( + "apigo.cloud/git/apigo/gojs" + _ "apigo.cloud/git/apigo/plugins/discover" + "github.com/ssgo/discover" + "github.com/ssgo/redis" + "github.com/ssgo/s" + "testing" +) + +func TestDiscover(t *testing.T) { + rdServer := StartRedis("16378") + defer rdServer.Close() + rd := redis.GetRedis("redis://localhost:16378", nil) + rd.HSET("echo", "localhost:11223", 100) + + s.Register(0, "/echo", func(in map[string]interface{}) map[string]interface{} { + return in + }, "") + s.Config.Listen = "11223,h2c" + discover.Config.Registry = "redis://localhost:16378" + discover.Config.Calls = map[string]string{"echo":""} + as := s.AsyncStart() + defer as.Stop() + // discover.Start("") // if not use ssgo/s, manual start discover + + rt := gojs.New(nil, nil) + defer rt.Close() + + r, err, _ := rt.Run(` + echoSrv = discover.fetch('echo') + r = echoSrv.get('/echo?aaa=111') + if(r.aaa != 111) throw new Error('aaa is '+r.aaa+' not 111') + return true +`) + Test(t, "get", r == true && err == nil, r, err) + + r, err, _ = rt.Run(` + r = echoSrv.post('/echo', {aaa:111}) + if(r.aaa != 111) throw new Error('aaa is '+r.aaa+' not 111') + return true +`) + Test(t, "post", r == true && err == nil, r, err) + +} diff --git a/tests/file_test.go b/tests/file_test.go new file mode 100644 index 0000000..b550cd1 --- /dev/null +++ b/tests/file_test.go @@ -0,0 +1,55 @@ +package tests + +import ( + "apigo.cloud/git/apigo/gojs" + "apigo.cloud/git/apigo/plugin" + _ "apigo.cloud/git/apigo/plugins/file" + "testing" +) + +func TestFile(t *testing.T) { + rt := gojs.New(nil, nil) + defer rt.Close() + + gojs.SetPluginsConfig(map[string]plugin.Config{ + "file": { + "allowPaths": []string{ + "testData", + }, + "allowExtensions": []string{ + ".txt", + }, + }, + }) + + r, err, _ := rt.Run(` + try{ + file.write('testData/aaa.txt', '123') + if(file.read('testData/aaa.txt')!=='123') throw new Error('write and read file') + + let f = file.open('testData/aaa.txt') + try{ + f.write('22') + f.seekStart() + if(f.read(20)!=='223') throw new Error('write file by seek') + }catch(ex){ + throw ex + }finally{ + f.close() + } + + file.saveJson('testData/bbb.txt', {bbb:234}) + if(file.loadJson('testData/bbb.txt').bbb!==234) throw new Error('write and read json') + + files = file.list('testData', 'name') + if( files.length !== 2 || files[1].name !== 'bbb.txt' ) throw new Error('list file, count: '+files.length+' name: '+files[1].name) + }catch(ex){ + throw ex + }finally{ + file.remove('testData') + } + + return true + `) + Test(t, "file", r == true && err == nil, r, err) +} diff --git a/tests/go.mod b/tests/go.mod new file mode 100644 index 0000000..28f9bc0 --- /dev/null +++ b/tests/go.mod @@ -0,0 +1,47 @@ +module tests + +go 1.17 + +require ( + apigo.cloud/git/apigo/gojs v0.0.2 + apigo.cloud/git/apigo/plugin v1.0.1 + apigo.cloud/git/apigo/plugins v0.0.0 + github.com/mattn/go-sqlite3 v1.14.18 + github.com/ssgo/discover v0.6.11 + github.com/ssgo/redis v0.6.11 + github.com/ssgo/s v1.6.11 + github.com/ssgo/u v0.6.11 + github.com/tidwall/redcon v1.6.2 +) + +require ( + apigo.cloud/git/apigo/qjs v0.0.1 // indirect + github.com/ZZMarquis/gm v1.3.2 // indirect + github.com/emmansun/gmsm v0.21.1 // indirect + github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-sql-driver/mysql v1.5.0 // indirect + github.com/gomodule/redigo v1.8.8 // indirect + github.com/gorilla/websocket v1.5.1 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/obscuren/ecies v0.0.0-20150213224233-7c0f4a9b18d9 // indirect + github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/shirou/gopsutil/v3 v3.22.10 // indirect + github.com/ssgo/config v0.6.11 // indirect + github.com/ssgo/db v0.6.11 // indirect + github.com/ssgo/httpclient v0.6.11 // indirect + github.com/ssgo/log v0.6.11 // indirect + github.com/ssgo/standard v0.6.11 // indirect + github.com/tidwall/btree v1.1.0 // indirect + github.com/tidwall/match v1.1.1 // indirect + github.com/tklauser/go-sysconf v0.3.10 // indirect + github.com/tklauser/numcpus v0.4.0 // indirect + github.com/yusufpapurcu/wmi v1.2.2 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/text v0.13.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) + +replace apigo.cloud/git/apigo/plugins v0.0.0 => ../ diff --git a/tests/http_test.go b/tests/http_test.go new file mode 100644 index 0000000..0828661 --- /dev/null +++ b/tests/http_test.go @@ -0,0 +1,71 @@ +package tests + +import ( + "apigo.cloud/git/apigo/gojs" + _ "apigo.cloud/git/apigo/plugins/http" + "github.com/ssgo/s" + "strings" + "testing" +) + +func TestHttp(t *testing.T) { + s.Register(0, "/echo", func(in map[string]interface{}) map[string]interface{} { + return in + }, "") + s.Register(0, "/jump", func(response *s.Response) { + response.Location("/echo?aaa=222") + }, "") + s.Config.Listen = "10803" + as := s.AsyncStart() + defer as.Stop() + + rt := gojs.New(nil, nil) + defer rt.Close() + + r, err, _ := rt.Run(` + r = http.get('http://127.0.0.1:10803/echo?aaa=111') + if(r.aaa != 111) throw new Error('aaa is '+r.aaa+' not 111') + return true +`) + Test(t, "get", r == true && err == nil, r, err) + + r, err, _ = rt.Run(` + r = http.post('http://127.0.0.1:10803/echo', {aaa:111}) + if(r.aaa != 111) throw new Error('aaa is '+r.aaa+' not 111') + return true +`) + Test(t, "post", r == true && err == nil, r, err) + + r, err, _ = rt.Run(` + r = http.get('http://127.0.0.1:10803/jump') + if(r.aaa != 222) throw new Error('aaa is '+r.aaa+' not 222') + return true +`) + Test(t, "jump", r == true && err == nil, r, err) +} + +func TestH2C(t *testing.T) { + s.Register(0, "/echo", func(in map[string]interface{}) map[string]interface{} { + return in + }, "") + s.Config.Listen = "" + as := s.AsyncStart() + defer as.Stop() + + rt := gojs.New(nil, nil) + defer rt.Close() + + rt.JsCtx.Globals().Set("server", rt.JsCtx.String(as.Addr)) + _, err, _ := rt.Run(` + http.get('http://'+server+'/echo?aaa=111') +`) + Test(t, "get for h2c", err != nil && strings.Contains(err.Error(), "transport connection broken")) + + r, err, _ := rt.Run(` + let c = http.newH2C(10) + r = c.post('http://'+server+'/echo', {aaa:111}) + if(r.aaa != 111) throw new Error('aaa is '+r.aaa+' not 111') + return true +`) + Test(t, "post for h2c", r == true && err == nil, r, err) +} diff --git a/tests/redis_test.go b/tests/redis_test.go new file mode 100644 index 0000000..d380d53 --- /dev/null +++ b/tests/redis_test.go @@ -0,0 +1,29 @@ +package tests + +import ( + "apigo.cloud/git/apigo/gojs" + "apigo.cloud/git/apigo/plugin" + _ "apigo.cloud/git/apigo/plugins/redis" + "testing" +) + +func TestRedis(t *testing.T) { + rdServer := StartRedis("16379") + defer rdServer.Close() + + rt := gojs.New(nil, nil) + defer rt.Close() + + gojs.SetPluginsConfig(map[string]plugin.Config{ + "redis": { + "default": "redis://localhost:16379", + }, + }) + r, err, _ := rt.Run(` + redis.set('aaa', 111) + let aaa = redis.get('aaa') + if(aaa != 111) throw new Error('aaa is '+aaa+' not 111') + return true + `) + Test(t, "get", r == true && err == nil, r, err) +} diff --git a/tests/test.go b/tests/test.go new file mode 100644 index 0000000..8cc31aa --- /dev/null +++ b/tests/test.go @@ -0,0 +1,69 @@ +package tests + +import ( + "fmt" + "github.com/ssgo/u" + "github.com/tidwall/redcon" + "strings" + "testing" +) + +var testIndex = 0 + +func Test(t *testing.T, title string, ok bool, info ...interface{}) { + testIndex++ + if ok { + fmt.Println(u.Cyan(fmt.Sprint("#", testIndex)), title, u.BGreen("Succeed")) + } else { + t.Fatal(append([]interface{}{u.Cyan(fmt.Sprintln("#", testIndex)), title, u.BRed("Failed")}, info...)...) + } +} + +var _rdData = map[string][]byte{} +var _rdMData = map[string]map[string][]byte{} + +func StartRedis(port string) *redcon.Server { + rdServer := redcon.NewServer(":"+port, func(conn redcon.Conn, cmd redcon.Command) { + //fmt.Println(u.BCyan("redis command " + string(cmd.Raw))) + switch strings.ToUpper(string(cmd.Args[0])) { + case "SET": + _rdData[string(cmd.Args[1])] = cmd.Args[2] + conn.WriteString("OK") + case "GET": + conn.WriteBulk(_rdData[string(cmd.Args[1])]) + case "HSET": + data := _rdMData[string(cmd.Args[1])] + if data == nil { + data = map[string][]byte{} + _rdMData[string(cmd.Args[1])] = data + } + data[string(cmd.Args[2])] = cmd.Args[3] + conn.WriteString("OK") + case "HGETALL": + data := _rdMData[string(cmd.Args[1])] + if data != nil { + conn.WriteArray(len(data)*2) + for k, v := range data { + conn.WriteBulkString(k) + conn.WriteBulk(v) + } + } else { + conn.WriteArray(0) + } + default: + //fmt.Println(u.BYellow("unknown redis command " + string(cmd.Raw))) + conn.WriteString("OK") + } + }, func(conn redcon.Conn) bool { + return true + }, func(conn redcon.Conn, err error) { + }) + go func() { + err := rdServer.ListenAndServe() + if err != nil { + fmt.Println(err.Error()) + } + }() + + return rdServer +}