diff --git a/data/user_workspaces/admin/src/gotest/example1_test.go b/data/user_workspaces/admin/src/gotest/example1_test.go new file mode 100644 index 0000000..8c9c857 --- /dev/null +++ b/data/user_workspaces/admin/src/gotest/example1_test.go @@ -0,0 +1,16 @@ +package test + +import ( + "testing" +) + +func Test_Division_1(t *testing.T) { + if i, e := Division(6, 2); i != 3 || e != nil { //try a unit test on function + t.Error("除法函数测试没通过") // 如果不是如预期的那么就报错 + } else { + t.Log("第一个测试通过了") //记录一些你期望记录的信息 + } +} + +func Test_Division_2(t *testing.T) { +} diff --git a/data/user_workspaces/admin/src/gotest/example2_test.go b/data/user_workspaces/admin/src/gotest/example2_test.go new file mode 100644 index 0000000..ebdfe2b --- /dev/null +++ b/data/user_workspaces/admin/src/gotest/example2_test.go @@ -0,0 +1,17 @@ +package test + +import ( + "testing" +) + +func Test_Division_3(t *testing.T) { + if i, e := Division(6, 2); i != 3 || e != nil { //try a unit test on function + t.Error("除法函数测试没通过") // 如果不是如预期的那么就报错 + } else { + t.Log("第一个测试通过了") //记录一些你期望记录的信息 + } +} + +func Test_Division_4(t *testing.T) { + t.Error("就是不通过") +} diff --git a/data/user_workspaces/admin/src/gotest/test.go b/data/user_workspaces/admin/src/gotest/test.go new file mode 100644 index 0000000..8394003 --- /dev/null +++ b/data/user_workspaces/admin/src/gotest/test.go @@ -0,0 +1,13 @@ +package test + +import ( + "errors" +) + +func Division(a, b float64) (float64, error) { + if b == 0 { + return 0, errors.New("除数不能为0") + } + + return a / b, nil +} diff --git a/data/user_workspaces/admin/src/mytest/hello/main.go b/data/user_workspaces/admin/src/hello/main.go similarity index 100% rename from data/user_workspaces/admin/src/mytest/hello/main.go rename to data/user_workspaces/admin/src/hello/main.go diff --git a/data/user_workspaces/admin/src/mytest/time/index.html b/data/user_workspaces/admin/src/mytest/time/index.html deleted file mode 100644 index 3d0944b..0000000 --- a/data/user_workspaces/admin/src/mytest/time/index.html +++ /dev/null @@ -1,411 +0,0 @@ - - - - - - {{.i18n.wide}} - - - - - - - - - - - - - - - - - - -
-
- - -
-
- - {{.i18n.file}} - - -
-
-
-
-
    -
- -
-
    -
  • - {{.i18n.create_file}} - -
  • -
  • - {{.i18n.create_dir}} - -
  • -
  • - {{.i18n.delete}} - -
  • -
-
- -
-
    -
  • - {{.i18n.delete}} - -
  • -
-
-
-
-
-
-
- - - - - - - - -
-
-
-
-
-
-
- - -
-
- - {{.i18n.output}} - - -
-
- - {{.i18n.search}} - - -
-
- - {{.i18n.notification}} - - -
-
-
-
- -
-
- -
-
-
- -
-
-
-
-
-
- -
- {{.i18n.isDelete}} - - - - ? - -
-
-
-
- -
-
- -
-
- -
-
- - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/data/user_workspaces/admin/src/mytest/time/main.go b/data/user_workspaces/admin/src/time/main.go similarity index 100% rename from data/user_workspaces/admin/src/mytest/time/main.go rename to data/user_workspaces/admin/src/time/main.go diff --git a/data/user_workspaces/admin/src/mytest/time/pkg/time.go b/data/user_workspaces/admin/src/time/pkg/time.go similarity index 100% rename from data/user_workspaces/admin/src/mytest/time/pkg/time.go rename to data/user_workspaces/admin/src/time/pkg/time.go diff --git a/i18n/en_US.json b/i18n/en_US.json index bac7c64..d89595a 100644 --- a/i18n/en_US.json +++ b/i18n/en_US.json @@ -86,13 +86,16 @@ "focus_notification": "Focus to Notification", "start-build": "START [go build]", "build-succ": "[go build] SUCCESS", - "build-failed": "[go build] Failed", + "build-failed": "[go build] ERROR", + "start-test": "START [go test]", + "test-succ": "[go test] SUCCESS", + "test-failed": "[go test] ERROR", "start-install": "START [go install]", "install-succ": "[go install] SUCCESS", - "install-failed": "[go install] Fialed", + "install-failed": "[go install] ERROR", "start-get": "START [go get]", "get-succ": "[go get] SUCCESS", - "get-failed": "[go get] Failed", + "get-failed": "[go get] ERROR", "check_version": "Checking update", "new_version_available": "new version available", "go_env": "Go", @@ -101,5 +104,6 @@ "license": "License", "credits": "Credits", "uptodate": "it is up to date", + "test": "Test", "colon": ": " } \ No newline at end of file diff --git a/i18n/zh_CN.json b/i18n/zh_CN.json index e66384d..54cc172 100644 --- a/i18n/zh_CN.json +++ b/i18n/zh_CN.json @@ -87,6 +87,9 @@ "start-build": "开始 [go build]", "build-succ": "[go build] 成功", "build-failed": "[go build] 失败", + "start-test": "开始 [go test]", + "test-succ": "[go test] 成功", + "test-failed": "[go test] 失败", "start-install": "开始 [go install]", "install-succ": "[go install] 成功", "install-failed": "[go install] 失败", @@ -101,5 +104,6 @@ "license": "许可协议", "credits": "致谢", "uptodate": "已是最新版本", + "test": "测试", "colon": ":" } \ No newline at end of file diff --git a/main.go b/main.go index c526665..e8f344a 100644 --- a/main.go +++ b/main.go @@ -294,6 +294,7 @@ func main() { http.HandleFunc("/build", handlerWrapper(output.BuildHandler)) http.HandleFunc("/run", handlerWrapper(output.RunHandler)) http.HandleFunc("/stop", handlerWrapper(output.StopHandler)) + http.HandleFunc("/go/test", handlerWrapper(output.GoTestHandler)) http.HandleFunc("/go/get", handlerWrapper(output.GoGetHandler)) http.HandleFunc("/go/install", handlerWrapper(output.GoInstallHandler)) http.HandleFunc("/output/ws", handlerWrapper(output.WSHandler)) diff --git a/output/outputs.go b/output/outputs.go index c1038ed..5ba81b0 100644 --- a/output/outputs.go +++ b/output/outputs.go @@ -56,11 +56,9 @@ func RunHandler(w http.ResponseWriter, r *http.Request) { data := map[string]interface{}{"succ": true} defer util.RetJSON(w, r, data) - decoder := json.NewDecoder(r.Body) - var args map[string]interface{} - if err := decoder.Decode(&args); err != nil { + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { glog.Error(err) data["succ"] = false @@ -188,11 +186,9 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) { username := httpSession.Values["username"].(string) locale := conf.Wide.GetUser(username).Locale - decoder := json.NewDecoder(r.Body) - var args map[string]interface{} - if err := decoder.Decode(&args); err != nil { + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { glog.Error(err) data["succ"] = false @@ -390,8 +386,8 @@ func BuildHandler(w http.ResponseWriter, r *http.Request) { }(rand.Int()) } -// go install. -func GoInstallHandler(w http.ResponseWriter, r *http.Request) { +// go test. +func GoTestHandler(w http.ResponseWriter, r *http.Request) { data := map[string]interface{}{"succ": true} defer util.RetJSON(w, r, data) @@ -399,11 +395,9 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) { username := httpSession.Values["username"].(string) locale := conf.Wide.GetUser(username).Locale - decoder := json.NewDecoder(r.Body) - var args map[string]interface{} - if err := decoder.Decode(&args); err != nil { + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { glog.Error(err) data["succ"] = false @@ -415,8 +409,12 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) { filePath := args["file"].(string) curDir := filePath[:strings.LastIndex(filePath, conf.PathSeparator)] - fout, err := os.Create(filePath) + cmd := exec.Command("go", "test", "-v") + cmd.Dir = curDir + setCmdEnv(cmd, username) + + stdout, err := cmd.StdoutPipe() if nil != err { glog.Error(err) data["succ"] = false @@ -424,17 +422,108 @@ func GoInstallHandler(w http.ResponseWriter, r *http.Request) { return } - code := args["code"].(string) - - fout.WriteString(code) - - if err := fout.Close(); nil != err { + stderr, err := cmd.StderrPipe() + if nil != err { glog.Error(err) data["succ"] = false return } + if !data["succ"].(bool) { + return + } + + channelRet := map[string]interface{}{} + + if nil != session.OutputWS[sid] { + // 在前端 output 中显示“开始 go test + + channelRet["output"] = "" + i18n.Get(locale, "start-test").(string) + "\n" + channelRet["cmd"] = "start-test" + + wsChannel := session.OutputWS[sid] + + err := wsChannel.Conn.WriteJSON(&channelRet) + if nil != err { + glog.Error(err) + return + } + + // 更新通道最近使用时间 + wsChannel.Time = time.Now() + } + + reader := bufio.NewReader(io.MultiReader(stdout, stderr)) + + if err := cmd.Start(); nil != err { + glog.Error(err) + data["succ"] = false + + return + } + + go func(runningId int) { + defer util.Recover() + + glog.V(3).Infof("Session [%s] is running [go test] [runningId=%d]", sid, runningId) + + channelRet := map[string]interface{}{} + channelRet["cmd"] = "go test" + + // 一次性读取 + buf, _ := ioutil.ReadAll(reader) + + // 同步点,等待 go test 执行完成 + cmd.Wait() + + if !cmd.ProcessState.Success() { + glog.V(3).Infof("Session [%s] 's running [go test] [runningId=%d] has done (with error)", sid, runningId) + + channelRet["output"] = "" + i18n.Get(locale, "test-failed").(string) + "\n" + string(buf) + } else { + glog.V(3).Infof("Session [%s] 's running [go test] [runningId=%d] has done", sid, runningId) + + channelRet["output"] = "" + i18n.Get(locale, "test-succ").(string) + "\n" + string(buf) + } + + if nil != session.OutputWS[sid] { + wsChannel := session.OutputWS[sid] + + err := wsChannel.Conn.WriteJSON(&channelRet) + if nil != err { + glog.Error(err) + } + + // 更新通道最近使用时间 + wsChannel.Time = time.Now() + } + }(rand.Int()) +} + +// go install. +func GoInstallHandler(w http.ResponseWriter, r *http.Request) { + data := map[string]interface{}{"succ": true} + defer util.RetJSON(w, r, data) + + httpSession, _ := session.HTTPSession.Get(r, "wide-session") + username := httpSession.Values["username"].(string) + locale := conf.Wide.GetUser(username).Locale + + var args map[string]interface{} + + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { + glog.Error(err) + data["succ"] = false + + return + } + + sid := args["sid"].(string) + + filePath := args["file"].(string) + curDir := filePath[:strings.LastIndex(filePath, conf.PathSeparator)] + cmd := exec.Command("go", "install") cmd.Dir = curDir @@ -577,11 +666,9 @@ func GoGetHandler(w http.ResponseWriter, r *http.Request) { username := httpSession.Values["username"].(string) locale := conf.Wide.GetUser(username).Locale - decoder := json.NewDecoder(r.Body) - var args map[string]interface{} - if err := decoder.Decode(&args); err != nil { + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { glog.Error(err) data["succ"] = false diff --git a/static/css/wide.css b/static/css/wide.css index d7eb7c8..ceba9d3 100644 --- a/static/css/wide.css +++ b/static/css/wide.css @@ -281,18 +281,21 @@ } .bottom-window-group .output .start-build, +.bottom-window-group .output .start-test, .bottom-window-group .output .start-install, .bottom-window-group .output .start-get { color: #999; } -.bottom-window-group .output .build-succ, +.bottom-window-group .output .build-succ, +.bottom-window-group .output .test-succ, .bottom-window-group .output .install-succ, .bottom-window-group .output .get-succ { color: rgb(0,153,0); } -.bottom-window-group .output .build-failed, +.bottom-window-group .output .build-failed, +.bottom-window-group .output .test-failed, .bottom-window-group .output .install-failed, .bottom-window-group .output .get-failed { color: red; diff --git a/static/js/editors.js b/static/js/editors.js index 031b577..d2e13a0 100644 --- a/static/js/editors.js +++ b/static/js/editors.js @@ -24,7 +24,7 @@ var editors = { wide.curEditor.focus(); }, removeAfter: function (id, nextId) { - if (id === 'startPage') { + if (id === 'startPage') { // 当前关闭的 tab 是起始页 return false; } @@ -35,6 +35,10 @@ var editors = { break; } } + if (editors.data.length === 0) { // 起始页可能存在,所以用编辑器数据判断 + menu.disabled(['save-all', 'close-all', 'build', 'run', 'go-test', 'go-get', 'go-install']); + $(".toolbars").hide(); + } if (!nextId) { // 不存在打开的编辑器 @@ -43,9 +47,6 @@ var editors = { wide.curNode = undefined; wide.curEditor = undefined; - - menu.disabled(['save-all', 'close-all', 'run', 'go-get', 'go-install']); - $(".toolbars").hide(); return false; } @@ -440,7 +441,7 @@ var editors = { content: '' }); - menu.undisabled(['save-all', 'close-all', 'run', 'go-get', 'go-install']); + menu.undisabled(['save-all', 'close-all', 'build', 'run', 'go-test', 'go-get', 'go-install']); var rulers = []; rulers.push({color: "#ccc", column: 120, lineStyle: "dashed"}); diff --git a/static/js/wide.js b/static/js/wide.js index f4a3d48..751174b 100644 --- a/static/js/wide.js +++ b/static/js/wide.js @@ -351,11 +351,13 @@ var wide = { break; case 'start-build': + case 'start-test': case 'start-install': case 'start-get': wide.fillOutput(data.output); break; + case 'go test': case 'go install': case 'go get': wide.fillOutput($('.bottom-window-group .output > div').html() + data.output); @@ -541,6 +543,10 @@ var wide = { if (!currentPath) { return false; } + + if ($(".menu li.build").hasClass("disabled")) { + return false; + } var request = newWideRequest(); request.file = currentPath; @@ -600,6 +606,36 @@ var wide = { } }); }, + // 测试. + test: function () { + wide.saveAllFiles(); + + var currentPath = editors.getCurrentPath(); + if (!currentPath) { + return false; + } + + if ($(".menu li.test").hasClass("disabled")) { + return false; + } + + var request = newWideRequest(); + request.file = currentPath; + + $.ajax({ + type: 'POST', + url: '/go/test', + data: JSON.stringify(request), + dataType: "json", + beforeSend: function (data) { + $('.bottom-window-group .output > div').text(''); + wide.bottomWindowTab.setCurrent("output"); + windows.flowBottom(); + }, + success: function (data) { + } + }); + }, goget: function () { wide.saveAllFiles(); @@ -643,7 +679,6 @@ var wide = { var request = newWideRequest(); request.file = currentPath; - request.code = wide.curEditor.getValue(); $.ajax({ type: 'POST', diff --git a/views/index.html b/views/index.html index b49e5f1..597c2e4 100644 --- a/views/index.html +++ b/views/index.html @@ -46,13 +46,17 @@ {{.i18n.run}}