Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

text-explorer: add test flags #130

Merged
merged 1 commit into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading