Skip to content

Commit

Permalink
text-explorer: add test flags
Browse files Browse the repository at this point in the history
  • Loading branch information
xhd2015 committed May 21, 2024
1 parent 110daef commit b56122c
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 84 deletions.
4 changes: 2 additions & 2 deletions cmd/xgo/runtime_gen/core/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
)

const VERSION = "1.0.36"
const REVISION = "b1fa6d6f3a19df8888bf2c0eb103ddff88257582+1"
const NUMBER = 226
const REVISION = "110daef2be989ffe0f7a2111e4a8e75272a4b6d3+1"
const NUMBER = 227

// these fields will be filled by compiler
const XGO_VERSION = ""
Expand Down
131 changes: 125 additions & 6 deletions cmd/xgo/test-explorer/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,39 @@ package test_explorer

import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"strings"

"github.com/xhd2015/xgo/support/goinfo"
)

type TestConfig struct {
Go *GoConfig
GoCmd string
Exclude []string
Env map[string]interface{}

// test flags passed to go test
// common usages:
// -p=12 parallel programs
// -parallel=12 parallel test cases within the same test
// according to our test, -p is more useful than -parallel
Flags []string
}

func (c *TestConfig) CmdEnv() []string {
if c == nil || len(c.Env) == 0 {
return nil
}
var env []string
env = append(env, os.Environ()...)
for k, v := range c.Env {
env = append(env, fmt.Sprintf("%s=%s", k, fmt.Sprint(v)))
}
return env
}

type GoConfig struct {
Expand Down Expand Up @@ -71,17 +96,111 @@ func parseTestConfig(config string) (*TestConfig, error) {
conf.Exclude = []string{e}
}
case []interface{}:
for _, x := range e {
s, ok := x.(string)
if !ok {
return nil, fmt.Errorf("exclude requires string, actual: %T", x)
}
conf.Exclude = append(conf.Exclude, s)
list, err := toStringList(e)
if err != nil {
return nil, fmt.Errorf("exclude: %w", err)
}
conf.Exclude = list
default:
return nil, fmt.Errorf("exclude requires string or list, actual: %T", e)
}
}
e, ok = m["flags"]
if ok {
list, err := toStringList(e)
if err != nil {
return nil, fmt.Errorf("flags: %w", err)
}
conf.Flags = list
}

return conf, nil
}

func parseConfigAndMergeOptions(configFile string, opts *Options) (*TestConfig, error) {
data, readErr := ioutil.ReadFile(configFile)
if readErr != nil {
if !errors.Is(readErr, os.ErrNotExist) {
return nil, readErr
}
readErr = nil
}
var testConfig *TestConfig
if len(data) > 0 {
var err error
testConfig, err = parseTestConfig(string(data))
if err != nil {
return nil, fmt.Errorf("parse test.config.json: %w", err)
}
}
if testConfig == nil {
testConfig = &TestConfig{}
}
if opts.GoCommand != "" {
testConfig.GoCmd = opts.GoCommand
} else if testConfig.GoCmd == "" {
testConfig.GoCmd = opts.DefaultGoCommand
}
testConfig.Exclude = append(testConfig.Exclude, opts.Exclude...)
testConfig.Flags = append(testConfig.Flags, opts.Flags...)
return testConfig, nil
}

func validateGoVersion(testConfig *TestConfig) error {
if testConfig.Go != nil || (testConfig.Go.Min == "" && testConfig.Go.Max == "") {
return nil
}
// check go version
goVersionStr, err := goinfo.GetGoVersionOutput("go")
if err != nil {
return err
}
goVersion, err := goinfo.ParseGoVersion(goVersionStr)
if err != nil {
return err
}
if testConfig.Go.Min != "" {
minVer, _ := goinfo.ParseGoVersionNumber(strings.TrimPrefix(testConfig.Go.Min, "go"))
if minVer != nil {
if compareGoVersion(goVersion, minVer, true) < 0 {
return fmt.Errorf("go version %s < %s", strings.TrimPrefix(goVersionStr, "go version "), testConfig.Go.Min)
}
}
}
if testConfig.Go.Max != "" {
maxVer, _ := goinfo.ParseGoVersionNumber(strings.TrimPrefix(testConfig.Go.Max, "go"))
if maxVer != nil {
if compareGoVersion(goVersion, maxVer, true) > 0 {
return fmt.Errorf("go version %s > %s", strings.TrimPrefix(goVersionStr, "go version "), testConfig.Go.Max)
}
}
}
return nil
}

func parseConfigAndValidate(configFile string, opts *Options) error {
testConfig, err := parseConfigAndMergeOptions(configFile, opts)
if err != nil {
return err
}
return validateGoVersion(testConfig)
}

func toStringList(e interface{}) ([]string, error) {
if e == nil {
return nil, nil
}
list, ok := e.([]interface{})
if !ok {
return nil, fmt.Errorf("requires []string, actual: %T", e)
}
strList := make([]string, 0, len(list))
for _, x := range list {
s, ok := x.(string)
if !ok {
return nil, fmt.Errorf("elements requires string, actual: %T", x)
}
strList = append(strList, s)
}
return strList, nil
}
32 changes: 20 additions & 12 deletions cmd/xgo/test-explorer/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,11 @@ type PollSessionResult struct {
}

type session struct {
dir string
goCmd string
exclude []string
env []string
dir string
goCmd string
exclude []string
env []string
testFlags []string

item *TestingItem

Expand Down Expand Up @@ -266,7 +267,8 @@ func (c *session) Start() error {
if c.goCmd != "" {
goCmd = c.goCmd
}
testFlags := append([]string{"test", "-json"}, testArgs...)
testFlags := append([]string{"test", "-json"}, c.testFlags...)
testFlags = append(testFlags, testArgs...)
fmt.Printf("%s %v\n", goCmd, testFlags)

err := cmd.Env(c.env).Dir(c.dir).
Expand Down Expand Up @@ -393,8 +395,7 @@ func (c *session) sendEvent(event *TestingItemEvent) {
}

// TODO: add /session/destroy
func setupSessionHandler(server *http.ServeMux, projectDir string, config *TestConfig, env []string) {

func setupSessionHandler(server *http.ServeMux, projectDir string, getTestConfig func() (*TestConfig, error)) {
var nextID int64 = 0
var sessionMapping sync.Map

Expand All @@ -410,14 +411,21 @@ func setupSessionHandler(server *http.ServeMux, projectDir string, config *TestC
return nil, netutil.ParamErrorf("requires file")
}

config, err := getTestConfig()
if err != nil {
return nil, err
}

idInt := atomic.AddInt64(&nextID, 1)
id := fmt.Sprintf("session_%d", idInt)
// to avoid stale requests from older pages
id := fmt.Sprintf("session_%s_%d", time.Now().Format("2006-01-02_15:04:05"), idInt)

sess := &session{
dir: projectDir,
goCmd: config.GoCmd,
exclude: config.Exclude,
env: env,
dir: projectDir,
goCmd: config.GoCmd,
exclude: config.Exclude,
env: config.CmdEnv(),
testFlags: config.Flags,

eventCh: make(chan *TestingItemEvent, 100),
item: req.TestingItem,
Expand Down
85 changes: 25 additions & 60 deletions cmd/xgo/test-explorer/test_explorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"context"
_ "embed"
"encoding/json"
"errors"
"fmt"
"go/ast"
"go/parser"
Expand Down Expand Up @@ -33,6 +32,7 @@ type Options struct {
GoCommand string
ProjectDir string
Exclude []string
Flags []string
}

func Main(args []string, opts *Options) error {
Expand Down Expand Up @@ -69,6 +69,15 @@ func Main(args []string, opts *Options) error {
i++
continue
}
if arg == "--flag" || arg == "--flags" {
// e.g. -parallel
if i+1 >= n {
return fmt.Errorf("%s requires value", arg)
}
opts.Flags = append(opts.Flags, args[i+1])
i++
continue
}
if !strings.HasPrefix(arg, "-") {
continue
}
Expand Down Expand Up @@ -162,66 +171,17 @@ func handle(opts *Options) error {
}

configFile := filepath.Join(opts.ProjectDir, "test.config.json")

data, readErr := ioutil.ReadFile(configFile)
if readErr != nil {
if !errors.Is(readErr, os.ErrNotExist) {
return readErr
}
readErr = nil
}
var testConfig *TestConfig
if len(data) > 0 {
var err error
testConfig, err = parseTestConfig(string(data))
if err != nil {
return fmt.Errorf("parse test.config.json: %w", err)
}
}
if testConfig == nil {
testConfig = &TestConfig{}
}
if opts.GoCommand != "" {
testConfig.GoCmd = opts.GoCommand
} else if testConfig.GoCmd == "" {
testConfig.GoCmd = opts.DefaultGoCommand
err := parseConfigAndValidate(configFile, opts)
if err != nil {
return err
}
testConfig.Exclude = append(testConfig.Exclude, opts.Exclude...)

// check go version
if testConfig.Go != nil && (testConfig.Go.Min != "" || testConfig.Go.Max != "") {
goVersionStr, err := goinfo.GetGoVersionOutput("go")
getTestConfig := func() (*TestConfig, error) {
conf, err := parseConfigAndMergeOptions(configFile, opts)
if err != nil {
return err
}
goVersion, err := goinfo.ParseGoVersion(goVersionStr)
if err != nil {
return err
}
if testConfig.Go.Min != "" {
minVer, _ := goinfo.ParseGoVersionNumber(strings.TrimPrefix(testConfig.Go.Min, "go"))
if minVer != nil {
if compareGoVersion(goVersion, minVer, true) < 0 {
return fmt.Errorf("go version %s < %s", strings.TrimPrefix(goVersionStr, "go version "), testConfig.Go.Min)
}
}
}
if testConfig.Go.Max != "" {
maxVer, _ := goinfo.ParseGoVersionNumber(strings.TrimPrefix(testConfig.Go.Max, "go"))
if maxVer != nil {
if compareGoVersion(goVersion, maxVer, true) > 0 {
return fmt.Errorf("go version %s > %s", strings.TrimPrefix(goVersionStr, "go version "), testConfig.Go.Max)
}
}
}
}

var env []string
if len(testConfig.Env) > 0 {
env = append(env, os.Environ()...)
for k, v := range testConfig.Env {
env = append(env, fmt.Sprintf("%s=%s", k, fmt.Sprint(v)))
return nil, fmt.Errorf("read test config:%w", err)
}
return conf, nil
}

server := &http.ServeMux{}
Expand Down Expand Up @@ -289,12 +249,16 @@ func handle(opts *Options) error {
if err != nil {
return nil, err
}
config, err := getTestConfig()
if err != nil {
return nil, err
}

return run(req, testConfig.GoCmd, env)
return run(req, config.GoCmd, config.CmdEnv(), config.Flags)
})
})

setupSessionHandler(server, opts.ProjectDir, testConfig, env)
setupSessionHandler(server, opts.ProjectDir, getTestConfig)

server.HandleFunc("/openVscode", func(w http.ResponseWriter, r *http.Request) {
netutil.SetCORSHeaders(w)
Expand Down Expand Up @@ -485,7 +449,7 @@ func getDetail(req *DetailRequest) (*DetailResponse, error) {
Content: string(content)[i:j],
}, nil
}
func run(req *RunRequest, goCmd string, env []string) (*RunResult, error) {
func run(req *RunRequest, goCmd string, env []string, testFlags []string) (*RunResult, error) {
if req == nil || req.BaseRequest == nil || req.File == "" {
return nil, fmt.Errorf("requires file")
}
Expand All @@ -498,6 +462,7 @@ func run(req *RunRequest, goCmd string, env []string) (*RunResult, error) {
if req.Verbose {
args = append(args, "-v")
}
args = append(args, testFlags...)
if goCmd == "" {
goCmd = "go"
}
Expand Down
4 changes: 2 additions & 2 deletions cmd/xgo/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package main
import "fmt"

const VERSION = "1.0.36"
const REVISION = "b1fa6d6f3a19df8888bf2c0eb103ddff88257582+1"
const NUMBER = 226
const REVISION = "110daef2be989ffe0f7a2111e4a8e75272a4b6d3+1"
const NUMBER = 227

func getRevision() string {
revSuffix := ""
Expand Down
4 changes: 2 additions & 2 deletions runtime/core/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
)

const VERSION = "1.0.36"
const REVISION = "b1fa6d6f3a19df8888bf2c0eb103ddff88257582+1"
const NUMBER = 226
const REVISION = "110daef2be989ffe0f7a2111e4a8e75272a4b6d3+1"
const NUMBER = 227

// these fields will be filled by compiler
const XGO_VERSION = ""
Expand Down

0 comments on commit b56122c

Please sign in to comment.