Skip to content

Commit

Permalink
add --mock-rules option
Browse files Browse the repository at this point in the history
  • Loading branch information
xhd2015 committed Jul 6, 2024
1 parent d3ecb6a commit 5a3329d
Show file tree
Hide file tree
Showing 17 changed files with 315 additions and 29 deletions.
3 changes: 2 additions & 1 deletion cmd/xgo/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import (
"io/ioutil"
"strings"

"github.com/xhd2015/xgo/support/fileutil"
"github.com/xhd2015/xgo/support/strutil"
)

func editFile(file string, callback func(content string) (string, error)) error {
bytes, err := ioutil.ReadFile(file)
bytes, err := fileutil.ReadFile(file)
if err != nil {
return err
}
Expand Down
22 changes: 9 additions & 13 deletions cmd/xgo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -150,8 +149,6 @@ func handleBuild(cmd string, args []string) error {
resetInstrument := opts.resetInstrument
noSetup := opts.noSetup

optionsFromFile := opts.optionsFromFile

debugWithDlv := opts.debugWithDlv
xgoHome := opts.xgoHome
syncXgoOnly := opts.syncXgoOnly
Expand Down Expand Up @@ -200,6 +197,11 @@ func handleBuild(cmd string, args []string) error {
}
defer os.RemoveAll(tmpDir)

optionsFromFile, optionsFromFileContent, err := mergeOptionFiles(tmpDir, opts.optionsFromFile, opts.mockRules)
if err != nil {
return err
}

var vscodeDebugFile string
var vscodeDebugFileSuffix string
if !noInstrument && debugTarget != "" {
Expand Down Expand Up @@ -265,16 +267,10 @@ func handleBuild(cmd string, args []string) error {
if len(gcflags) > 0 || debug != nil {
buildCacheSuffix += "-gcflags"
}
if optionsFromFile != "" {
data, err := ioutil.ReadFile(optionsFromFile)
if err != nil {
return err
}
if len(data) > 0 {
h := md5.New()
h.Write(data)
buildCacheSuffix += "-" + hex.EncodeToString(h.Sum(nil))
}
if optionsFromFile != "" && len(optionsFromFileContent) > 0 {
h := md5.New()
h.Write(optionsFromFileContent)
buildCacheSuffix += "-" + hex.EncodeToString(h.Sum(nil))
}
buildCacheDir := filepath.Join(instrumentDir, "build-cache"+buildCacheSuffix)
revisionFile := filepath.Join(instrumentDir, "xgo-revision.txt")
Expand Down
12 changes: 12 additions & 0 deletions cmd/xgo/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ type options struct {
resetInstrument bool
noSetup bool

// --options-from-file file
optionsFromFile string

// rules from command line will take higher priorities
mockRules []string

// dev only
debugWithDlv bool
xgoHome string
Expand Down Expand Up @@ -87,6 +91,7 @@ func parseOptions(cmd string, args []string) (*options, error) {
var noSetup bool

var optionsFromFile string
var mockRules []string

var debugWithDlv bool
var xgoHome string
Expand Down Expand Up @@ -155,6 +160,12 @@ func parseOptions(cmd string, args []string) (*options, error) {
Flags: []string{"--options-from-file"},
Value: &optionsFromFile,
},
{
Flags: []string{"--mock-rule"},
Set: func(v string) {
mockRules = append(mockRules, v)
},
},
{
Flags: []string{"--dump-ir"},
Value: &dumpIR,
Expand Down Expand Up @@ -395,6 +406,7 @@ func parseOptions(cmd string, args []string) (*options, error) {
noSetup: noSetup,

optionsFromFile: optionsFromFile,
mockRules: mockRules,

debugWithDlv: debugWithDlv,
xgoHome: xgoHome,
Expand Down
3 changes: 2 additions & 1 deletion cmd/xgo/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"time"

"github.com/xhd2015/xgo/support/filecopy"
"github.com/xhd2015/xgo/support/fileutil"
"github.com/xhd2015/xgo/support/goinfo"
"github.com/xhd2015/xgo/support/osinfo"
)
Expand Down Expand Up @@ -315,7 +316,7 @@ func buildCompiler(goroot string, output string) error {
}

func compareAndUpdateCompilerID(compilerFile string, compilerIDFile string) (changed bool, err error) {
prevData, statErr := ioutil.ReadFile(compilerIDFile)
prevData, statErr := fileutil.ReadFile(compilerIDFile)
if statErr != nil {
if !errors.Is(statErr, os.ErrNotExist) {
return false, statErr
Expand Down
75 changes: 75 additions & 0 deletions cmd/xgo/rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package main

import (
"encoding/json"
"fmt"
"path/filepath"

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

// TODO: use generate to ensure options sync
// see patch/match/match.go, patch/ctxt/match_options.go

type Rule struct {
Any bool `json:"any"`
Kind *string `json:"kind"`
Pkg *string `json:"pkg"`
Name *string `json:"name"`
Stdlib *bool `json:"stdlib"`
MainModule *bool `json:"main_module"`
Generic *bool `json:"generic"`
Exported *bool `json:"exported"`
Action string `json:"action"` // include,exclude or empty
}

type FileOptions struct {
FilterRules []Rule `json:"filter_rules"`
}

func mergeOptionFiles(tmpDir string, optionFromFile string, mockRules []string) (newFile string, content []byte, err error) {
if len(mockRules) == 0 {
if optionFromFile != "" {
content, err = fileutil.ReadFile(optionFromFile)
}
return optionFromFile, content, err
}
var opts FileOptions
if optionFromFile != "" {
optionFromFileContent, err := fileutil.ReadFile(optionFromFile)
if err != nil {
return "", nil, err
}

if len(optionFromFileContent) > 0 {
err := json.Unmarshal(optionFromFileContent, &opts)
if err != nil {
return "", nil, fmt.Errorf("parse %s: %w", optionFromFile, err)
}
}
}

rulesFromFiles := opts.FilterRules
mergedRules := make([]Rule, 0, len(rulesFromFiles)+len(mockRules))
for _, mockRule := range mockRules {
if mockRule == "" {
continue
}
var rule Rule
err := json.Unmarshal([]byte(mockRule), &rule)
if err != nil {
return "", nil, fmt.Errorf("parse mock rule: %s %w", mockRule, err)
}
mergedRules = append(mergedRules, rule)
}

mergedRules = append(mergedRules, rulesFromFiles...)

newOptionFile, err := json.Marshal(FileOptions{FilterRules: mergedRules})
if err != nil {
return "", nil, err
}
newFile = filepath.Join(tmpDir, "options-from-file.json")
err = fileutil.WriteFile(newFile, newOptionFile)
return newFile, newOptionFile, err
}
75 changes: 70 additions & 5 deletions cmd/xgo/test-explorer/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"

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

Expand All @@ -24,6 +26,8 @@ type TestConfig struct {
// according to our test, -p is more useful than -parallel
Flags []string `json:"flags"`
Args []string `json:"args"`

MockRules []string `json:"mock_rules"`
}

func (c *TestConfig) CmdEnv() []string {
Expand Down Expand Up @@ -129,14 +133,23 @@ func parseTestConfig(config string) (*TestConfig, error) {
conf.Args = list
}

e, ok = m["mock_rules"]
if ok {
list, err := toMarshaledStrings(e)
if err != nil {
return nil, fmt.Errorf("mock_rules: %w", err)
}
conf.MockRules = list
}

return conf, nil
}

func parseConfigAndMergeOptions(configFile string, opts *Options, configFileRequired bool) (*TestConfig, error) {
var data []byte
if configFile != "" {
var readErr error
data, readErr = ioutil.ReadFile(configFile)
data, readErr = fileutil.ReadFile(configFile)
if readErr != nil {
if configFileRequired || !errors.Is(readErr, os.ErrNotExist) {
return nil, readErr
Expand All @@ -155,17 +168,44 @@ func parseConfigAndMergeOptions(configFile string, opts *Options, configFileRequ
if testConfig == nil {
testConfig = &TestConfig{}
}
var goCmd string
if opts.GoCommand != "" {
testConfig.GoCmd = opts.GoCommand
} else if testConfig.GoCmd == "" {
testConfig.GoCmd = opts.DefaultGoCommand
goCmd = opts.GoCommand
} else if testConfig.GoCmd != "" {
goCmd = testConfig.GoCmd
} else {
goCmd = opts.DefaultGoCommand
}
testConfig.GoCmd = goCmd
testConfig.Exclude = append(testConfig.Exclude, opts.Exclude...)
testConfig.Flags = append(testConfig.Flags, opts.Flags...)
if goCmd == "xgo" && len(testConfig.MockRules) > 0 && getXgoSupportsMockRule() {
for _, mockRule := range testConfig.MockRules {
testConfig.Flags = append(testConfig.Flags, "--mock-rule", mockRule)
}
}
testConfig.Args = append(testConfig.Args, opts.Args...)
return testConfig, nil
}

// check if xgo version > 1.0.44
func getXgoSupportsMockRule() bool {
xgoVersion, err := cmd.Output("xgo", "version")
if err != nil {
return false
}
// not 1.0., so must after 1.0.44
if !strings.HasPrefix(xgoVersion, "1.0.") {
return true
}
last := strings.TrimPrefix(xgoVersion, "1.0.")
lastNum, err := strconv.ParseInt(last, 10, 64)
if err != nil {
return false
}
return lastNum > 44
}

func validateGoVersion(testConfig *TestConfig) error {
if testConfig == nil || testConfig.Go == nil || (testConfig.Go.Min == "" && testConfig.Go.Max == "") {
return nil
Expand Down Expand Up @@ -224,3 +264,28 @@ func toStringList(e interface{}) ([]string, error) {
}
return strList, nil
}

func toMarshaledStrings(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 {
if x == nil {
continue
}
if s, ok := x.(string); ok {
return nil, fmt.Errorf("elements requires non string, actual: %q", s)
}
data, err := json.Marshal(x)
if err != nil {
return nil, fmt.Errorf("elements to json failed: %w", err)
}
strList = append(strList, string(data))
}
return strList, nil
}
2 changes: 1 addition & 1 deletion cmd/xgo/test-explorer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ func getDetail(req *DetailRequest) (*DetailResponse, error) {
if found == nil {
return nil, netutil.ParamErrorf("not found: %s", req.Name)
}
content, err := ioutil.ReadFile(req.File)
content, err := fileutil.ReadFile(req.File)
if err != nil {
return nil, err
}
Expand Down
5 changes: 5 additions & 0 deletions cmd/xgo/test-explorer/testdata/mock_rules/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/xhd2015/xgo/cmd/xgo/test-explorer/testdata/mock_rules

go 1.14

require github.com/xhd2015/xgo/runtime v1.0.43
2 changes: 2 additions & 0 deletions cmd/xgo/test-explorer/testdata/mock_rules/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/xhd2015/xgo/runtime v1.0.43 h1:Nv8jJiboLQz3436f8DX7lEYZ2I90IkqcJY3UhXxRbAk=
github.com/xhd2015/xgo/runtime v1.0.43/go.mod h1:9GBQ2SzJCzpD3T+HRN+2C0TUOGv7qIz4s0mad1xJ8Jo=
34 changes: 34 additions & 0 deletions cmd/xgo/test-explorer/testdata/mock_rules/mock_rules_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package prog_arg

import (
"fmt"
"net/http"
"testing"

"github.com/xhd2015/xgo/runtime/mock"
)

// run example:
//
// go run -tags dev ./cmd/xgo e --project-dir cmd/xgo/test-explorer/testdata/mock_rules
func TestProgArg(t *testing.T) {
var panicErr interface{}
func() {
defer func() {
panicErr = recover()
}()
mock.Patch(http.Get, func(url string) (*http.Response, error) {
return nil, nil
})
}()

if panicErr == nil {
t.Fatalf("expect mock http.Get panic, actually not")
}

msg := fmt.Sprint(panicErr)
expect := "failed to setup mock for: net/http.Get"
if msg != expect {
t.Fatalf("expect panic %q, actual: %q", expect, msg)
}
}
8 changes: 8 additions & 0 deletions cmd/xgo/test-explorer/testdata/mock_rules/test.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"mock_rules": [
{
"stdlib": true,
"action": "exclude"
}
]
}
4 changes: 2 additions & 2 deletions cmd/xgo/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import "fmt"

// auto updated
const VERSION = "1.0.44"
const REVISION = "7ff3bd301202f9d81cfeeb72c34dfd8c46f7d36e+1"
const NUMBER = 286
const REVISION = "d3ecb6a09079e9459de6090e6fb1acba13a83150+1"
const NUMBER = 287

// manually updated
const CORE_VERSION = "1.0.43"
Expand Down
Loading

0 comments on commit 5a3329d

Please sign in to comment.