refactor: hashicorp tests

This commit is contained in:
debugtalk
2022-01-14 17:53:06 +08:00
parent a0de8106d7
commit 875f2fadd3
7 changed files with 161 additions and 90 deletions

View File

@@ -9,26 +9,49 @@ func init() {
log.Println("plugin init function called")
}
func SumInt(args ...interface{}) (interface{}, error) {
func SumTwoInt(a, b int) int {
return a + b
}
func SumInts(args ...int) int {
var sum int
for _, arg := range args {
v, ok := arg.(int)
if !ok {
sum += arg
}
return sum
}
func Sum(args ...interface{}) (interface{}, error) {
var sum float64
for _, arg := range args {
switch v := arg.(type) {
case int:
sum += float64(v)
case float64:
sum += v
default:
return nil, fmt.Errorf("unexpected type: %T", arg)
}
sum += v
}
return sum, nil
}
func ConcatenateString(args ...interface{}) (interface{}, error) {
func SumTwoString(a, b string) string {
return a + b
}
func SumStrings(s ...string) string {
var sum string
for _, arg := range s {
sum += arg
}
return sum
}
func Concatenate(args ...interface{}) (interface{}, error) {
var result string
for _, arg := range args {
v, ok := arg.(string)
if !ok {
return nil, fmt.Errorf("unexpected type: %T", arg)
}
result += v
result += fmt.Sprintf("%v", arg)
}
return result, nil
}

View File

@@ -0,0 +1,14 @@
package main
import "github.com/httprunner/hrp/plugin"
// register functions and build to plugin binary
func main() {
plugin.Register("sum_ints", SumInts)
plugin.Register("sum_two_int", SumTwoInt)
plugin.Register("sum", Sum)
plugin.Register("sum_two_string", SumTwoString)
plugin.Register("sum_strings", SumStrings)
plugin.Register("concatenate", Concatenate)
plugin.Serve()
}

View File

@@ -15,7 +15,8 @@ import (
func buildGoPlugin() {
fmt.Println("[setup] build go plugin")
// flag -race is necessary in order to be consistent with go test
cmd := exec.Command("go", "build", "-buildmode=plugin", "-race", "-o=examples/debugtalk.so", "examples/plugin/debugtalk.go")
cmd := exec.Command("go", "build", "-buildmode=plugin", "-race",
"-o=examples/debugtalk.so", "examples/plugin/debugtalk.go")
if err := cmd.Run(); err != nil {
panic(err)
}
@@ -78,10 +79,13 @@ func TestCallPluginFunction(t *testing.T) {
defer removeGoPlugin()
parser := newParser()
parser.initPlugin("examples/debugtalk.so")
err := parser.initPlugin("examples/debugtalk.so")
if err != nil {
t.Fatal(err)
}
// call function without arguments
result, err := parser.callFunc("ConcatenateString", "1", "2", "3.14")
result, err := parser.callFunc("Concatenate", "1", 2, "3.14")
if !assert.NoError(t, err) {
t.Fail()
}

View File

@@ -1,4 +1,4 @@
package main
package hrp
import (
"fmt"
@@ -6,22 +6,30 @@ import (
"os/exec"
"testing"
"github.com/stretchr/testify/assert"
"github.com/httprunner/hrp/plugin/host"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
fmt.Println("[TestMain] build go plugin")
cmd := exec.Command("go", "build", "-o=debugtalk.bin", "./debugtalk.go")
func buildHashicorpPlugin() {
fmt.Println("[init] build hashicorp go plugin")
cmd := exec.Command("go", "build",
"-o=examples/debugtalk.bin",
"examples/plugin/hashicorp.go", "examples/plugin/debugtalk.go")
if err := cmd.Run(); err != nil {
panic(err)
}
os.Exit(m.Run())
}
func removeHashicorpPlugin() {
fmt.Println("[teardown] remove hashicorp plugin")
os.Remove("examples/debugtalk.bin")
}
func TestInitHashicorpPlugin(t *testing.T) {
f, err := host.Init("./debugtalk.bin")
buildHashicorpPlugin()
defer removeHashicorpPlugin()
f, err := host.Init("examples/debugtalk.bin")
if err != nil {
t.Fatal(err)
}

View File

@@ -1,65 +0,0 @@
package main
import (
"fmt"
"github.com/httprunner/hrp/plugin"
)
func SumTwoInt(a, b int) int {
return a + b
}
func SumInts(args ...int) int {
var sum int
for _, arg := range args {
sum += arg
}
return sum
}
func Sum(args ...interface{}) (interface{}, error) {
var sum float64
for _, arg := range args {
switch v := arg.(type) {
case int:
sum += float64(v)
case float64:
sum += v
default:
return nil, fmt.Errorf("unexpected type: %T", arg)
}
}
return sum, nil
}
func SumTwoString(a, b string) string {
return a + b
}
func SumStrings(s ...string) string {
var sum string
for _, arg := range s {
sum += arg
}
return sum
}
func Concatenate(args ...interface{}) (interface{}, error) {
var result string
for _, arg := range args {
result += fmt.Sprintf("%v", arg)
}
return result, nil
}
// register functions and build to plugin binary
func main() {
plugin.Register("sum_ints", SumInts)
plugin.Register("sum_two_int", SumTwoInt)
plugin.Register("sum", Sum)
plugin.Register("sum_two_string", SumTwoString)
plugin.Register("sum_strings", SumStrings)
plugin.Register("concatenate", Concatenate)
plugin.Serve()
}

View File

@@ -23,9 +23,28 @@ func CallFunc(fn reflect.Value, args ...interface{}) (interface{}, error) {
for index, argument := range args {
if argument == nil {
argumentsValue[index] = reflect.Zero(fn.Type().In(index))
} else {
argumentsValue[index] = reflect.ValueOf(args[index])
continue
}
argumentValue := reflect.ValueOf(argument)
expectArgumentType := fn.Type().In(index)
actualArgumentType := reflect.TypeOf(argument)
// type match
if expectArgumentType == actualArgumentType {
argumentsValue[index] = argumentValue
continue
}
// type not match, check if convertible
if !actualArgumentType.ConvertibleTo(expectArgumentType) {
// function argument type not match and not convertible
err := fmt.Errorf("function argument %d's type is neither match nor convertible, expect %v, actual %v",
index, expectArgumentType, actualArgumentType)
return nil, err
}
// convert argument to expect type
argumentsValue[index] = argumentValue.Convert(expectArgumentType)
}
resultValues := fn.Call(argumentsValue)
@@ -40,8 +59,14 @@ func CallFunc(fn reflect.Value, args ...interface{}) (interface{}, error) {
return resultValues[0].Interface(), nil
}
} else if len(resultValues) == 1 {
// return one arguments: interface{}
return resultValues[0].Interface(), nil
// return one argument
if err, ok := resultValues[0].Interface().(error); ok {
// return error
return nil, err
} else {
// return interface{}
return resultValues[0].Interface(), nil
}
} else {
// return more than 2 arguments, unexpected
err := fmt.Errorf("function should return at most 2 arguments")

View File

@@ -0,0 +1,62 @@
package shared
import (
"errors"
"fmt"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
)
func TestCallFunc(t *testing.T) {
type data struct {
f interface{}
args []interface{}
expVal interface{}
expErr error
}
params := []data{
// zero argument, zero return
{f: func() {}, args: []interface{}{}, expVal: nil, expErr: nil},
// zero argument, return one value
{f: func() int { return 1 }, args: []interface{}{}, expVal: 1, expErr: nil},
{f: func() string { return "a" }, args: []interface{}{}, expVal: "a", expErr: nil},
{f: func() interface{} { return 1.23 }, args: []interface{}{}, expVal: 1.23, expErr: nil},
// zero argument, return error
{f: func() error { return errors.New("xxx") }, args: []interface{}{}, expVal: nil, expErr: errors.New("xxx")},
// zero argument, return one value and error
{f: func() (int, error) { return 1, errors.New("xxx") }, args: []interface{}{}, expVal: 1, expErr: errors.New("xxx")},
{f: func() (interface{}, error) { return 1.23, errors.New("xxx") }, args: []interface{}{}, expVal: 1.23, expErr: errors.New("xxx")},
// one argument, return one value
{f: func(n int) int { return n * n }, args: []interface{}{2}, expVal: 4},
{f: func(c string) string { return c + c }, args: []interface{}{"p"}, expVal: "pp"},
{f: func(arg interface{}) interface{} { return fmt.Sprintf("%v", arg) }, args: []interface{}{1.23}, expVal: "1.23"},
// two arguments in same type
{f: func(a, b int) int { return a * b }, args: []interface{}{2, 3}, expVal: 6},
// two arguments in different type
{
f: func(n int, c string) string {
var s string
for i := 0; i < n; i++ {
s += c
}
return s
},
args: []interface{}{3, "p"},
expVal: "ppp",
},
}
for _, p := range params {
fn := reflect.ValueOf(p.f)
val, err := CallFunc(fn, p.args...)
if !assert.Equal(t, p.expErr, err) {
t.Fatal(err)
}
if !assert.Equal(t, p.expVal, val) {
t.Fatal()
}
}
}