diff options
| author | Shulhan <ms@kilabit.info> | 2024-11-16 15:12:48 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2024-11-16 16:50:51 +0700 |
| commit | a465d718b8ab7d8530e59586a60b11349f1ccc04 (patch) | |
| tree | 6ba3beeb5fec02cd7a9a060052022f671fb37c76 | |
| parent | 20fdd17d5202a356f1581345e73c15eb8ce1a42a (diff) | |
| download | pakakeh.go-a465d718b8ab7d8530e59586a60b11349f1ccc04.tar.xz | |
lib/play: add option to Run with specific Go version and without race
The idea is to allow testing Go code on specific Go version.
For example, before Go 1.22, the for loop with variable is shared
among block statements, which cause every use of that variable is run
with the last value.
| -rw-r--r-- | lib/play/command.go | 8 | ||||
| -rw-r--r-- | lib/play/play.go | 21 | ||||
| -rw-r--r-- | lib/play/play_test.go | 19 | ||||
| -rw-r--r-- | lib/play/request.go | 10 | ||||
| -rw-r--r-- | lib/play/testdata/httpHandleRun_test.txt | 29 |
5 files changed, 72 insertions, 15 deletions
diff --git a/lib/play/command.go b/lib/play/command.go index f3812dbe..4413b9ff 100644 --- a/lib/play/command.go +++ b/lib/play/command.go @@ -37,7 +37,13 @@ func newCommand(req *Request, workingDir string) (cmd *command, err error) { return nil, fmt.Errorf(`newCommand: %w`, err) } - cmd.execGoRun = exec.CommandContext(cmd.ctx, `go`, `run`, `-race`, `.`) + var listArg = []string{`run`} + if !req.WithoutRace { + listArg = append(listArg, `-race`) + } + listArg = append(listArg, `.`) + + cmd.execGoRun = exec.CommandContext(cmd.ctx, `go`, listArg...) cmd.execGoRun.Env = append(cmd.execGoRun.Env, `CGO_ENABLED=1`) cmd.execGoRun.Env = append(cmd.execGoRun.Env, `HOME=`+userHomeDir) cmd.execGoRun.Env = append(cmd.execGoRun.Env, `PATH=/usr/bin:/usr/local/bin`) diff --git a/lib/play/play.go b/lib/play/play.go index 6abd79a8..068a52c2 100644 --- a/lib/play/play.go +++ b/lib/play/play.go @@ -11,10 +11,19 @@ // format, // // { -// "body":<string> +// "goversion": <string>, // For run only. +// "without_race": <boolean>, // For run only. +// "body": <string> // } // -// where "body" field contains the Go code to be formatted or run. +// The "goversion" field define the Go tools and toolchain version to be +// used to compile the code. +// The default "goversion" is defined as global variable [GoVersion] in this +// package. +// If "without_race" is false, the Run command will not run with "-race" +// option. +// The "body" field contains the Go code to be formatted or run. +// // Both have the following response format, // // { @@ -54,12 +63,6 @@ var GoVersion = `1.23.2` // terminated. var Timeout = 10 * time.Second -var gomodTemplate = ` -module play.local - -go ` + GoVersion + ` -` - var now = func() int64 { return time.Now().Unix() } @@ -269,6 +272,8 @@ func Run(req *Request) (out []byte, err error) { var gomod = filepath.Join(tempdir, `go.mod`) + var gomodTemplate = "module play.local\n\ngo " + req.GoVersion + "\n" + err = os.WriteFile(gomod, []byte(gomodTemplate), 0600) if err != nil { return nil, fmt.Errorf(`%s: WriteFile %q: %w`, logp, gomod, err) diff --git a/lib/play/play_test.go b/lib/play/play_test.go index 4e95fb44..4172c506 100644 --- a/lib/play/play_test.go +++ b/lib/play/play_test.go @@ -128,6 +128,7 @@ func TestHTTPHandleRun(t *testing.T) { type testCase struct { tag string contentType string + req Request } var ( @@ -150,32 +151,38 @@ func TestHTTPHandleRun(t *testing.T) { }, { tag: `nopackage`, contentType: libhttp.ContentTypeJSON, + }, { + tag: `go121_for`, + contentType: libhttp.ContentTypeJSON, + req: Request{ + GoVersion: `1.21.13`, + WithoutRace: true, + }, }} var ( withBody = true - req Request tcase testCase rawb []byte body bytes.Buffer ) for _, tcase = range listCase { - req.Body = string(tdata.Input[tcase.tag]) + tcase.req.Body = string(tdata.Input[tcase.tag]) - rawb, err = json.Marshal(&req) + rawb, err = json.Marshal(&tcase.req) if err != nil { t.Fatal(err) } body.Reset() body.Write(rawb) - var req *http.Request = httptest.NewRequest(`POST`, `/`, &body) - req.Header.Set(libhttp.HeaderContentType, tcase.contentType) + var httpReq *http.Request = httptest.NewRequest(`POST`, `/`, &body) + httpReq.Header.Set(libhttp.HeaderContentType, tcase.contentType) var writer *httptest.ResponseRecorder = httptest.NewRecorder() - HTTPHandleRun(writer, req) + HTTPHandleRun(writer, httpReq) var result *http.Response = writer.Result() rawb, err = httputil.DumpResponse(result, withBody) diff --git a/lib/play/request.go b/lib/play/request.go index 2b479325..18c210bd 100644 --- a/lib/play/request.go +++ b/lib/play/request.go @@ -23,8 +23,14 @@ type Request struct { // In the HTTP request, the sid is read from cookie named "sid". cookieSid *http.Cookie + // The Go version that will be used in go.mod. + GoVersion string `json:"goversion"` + // Body contains the Go code to be Format-ed or Run. Body string `json:"body"` + + // WithoutRace define option opt out "-race" when running Go code. + WithoutRace bool `json:"without_race"` } func (req *Request) init() { @@ -37,6 +43,10 @@ func (req *Request) init() { req.cookieSid.Path = `/` req.cookieSid.MaxAge = 604800 // Seven days. req.cookieSid.SameSite = http.SameSiteStrictMode + + if req.GoVersion == `` { + req.GoVersion = GoVersion + } } // generateSid generate session ID from the first 16 hex of SHA256 hash of diff --git a/lib/play/testdata/httpHandleRun_test.txt b/lib/play/testdata/httpHandleRun_test.txt index 10997d47..bbea0f91 100644 --- a/lib/play/testdata/httpHandleRun_test.txt +++ b/lib/play/testdata/httpHandleRun_test.txt @@ -59,3 +59,32 @@ func main() { <<< noimport +>>> go121_for +package main + +import ( + "fmt" + "sync" +) + +func main() { + var wg sync.WaitGroup + for x := 1; x < 5; x++ { + wg.Add(1) + go func() { + fmt.Println(`x =`, x) + wg.Done() + }() + } + wg.Wait() +} + +<<< go121_for +HTTP/1.1 200 OK +Connection: close +Content-Type: application/json +Set-Cookie: sid=d964b22e8f2e75d9; Path=/; Max-Age=604800; SameSite=Strict + +{"data":"x = 5\nx = 5\nx = 5\nx = 5\n","code":200} + +>>> noop |
