mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-09 22:44:05 +08:00
refactor: plugin structure
This commit is contained in:
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/httprunner/hrp/internal/boomer"
|
"github.com/httprunner/hrp/internal/boomer"
|
||||||
"github.com/httprunner/hrp/internal/ga"
|
"github.com/httprunner/hrp/internal/ga"
|
||||||
"github.com/httprunner/hrp/plugin/common"
|
pluginInternal "github.com/httprunner/hrp/plugin/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewBoomer(spawnCount int, spawnRate float64) *HRPBoomer {
|
func NewBoomer(spawnCount int, spawnRate float64) *HRPBoomer {
|
||||||
@@ -22,8 +22,8 @@ func NewBoomer(spawnCount int, spawnRate float64) *HRPBoomer {
|
|||||||
|
|
||||||
type HRPBoomer struct {
|
type HRPBoomer struct {
|
||||||
*boomer.Boomer
|
*boomer.Boomer
|
||||||
plugins []common.Plugin // each task has its own plugin process
|
plugins []pluginInternal.IPlugin // each task has its own plugin process
|
||||||
pluginsMutex *sync.RWMutex // avoid data race
|
pluginsMutex *sync.RWMutex // avoid data race
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run starts to run load test for one or multiple testcases.
|
// Run starts to run load test for one or multiple testcases.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/httprunner/hrp/internal/builtin"
|
"github.com/httprunner/hrp/internal/builtin"
|
||||||
"github.com/httprunner/hrp/plugin/common"
|
pluginInternal "github.com/httprunner/hrp/plugin/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
func newParser() *parser {
|
func newParser() *parser {
|
||||||
@@ -21,7 +21,7 @@ func newParser() *parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type parser struct {
|
type parser struct {
|
||||||
plugin common.Plugin // plugin is used to call functions
|
plugin pluginInternal.IPlugin // plugin is used to call functions
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildURL(baseURL, stepURL string) string {
|
func buildURL(baseURL, stepURL string) string {
|
||||||
@@ -252,7 +252,7 @@ func (p *parser) callFunc(funcName string, arguments ...interface{}) (interface{
|
|||||||
fn := reflect.ValueOf(function)
|
fn := reflect.ValueOf(function)
|
||||||
|
|
||||||
// call with builtin function
|
// call with builtin function
|
||||||
return common.CallFunc(fn, arguments...)
|
return pluginInternal.CallFunc(fn, arguments...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// merge two variables mapping, the first variables have higher priority
|
// merge two variables mapping, the first variables have higher priority
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package common
|
package pluginInternal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package common
|
package pluginInternal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package shared
|
package pluginInternal
|
||||||
|
|
||||||
import "github.com/hashicorp/go-plugin"
|
import "github.com/hashicorp/go-plugin"
|
||||||
|
|
||||||
const Name = "debugtalk"
|
const PluginName = "debugtalk"
|
||||||
|
|
||||||
// handshakeConfigs are used to just do a basic handshake between
|
// handshakeConfigs are used to just do a basic handshake between
|
||||||
// a plugin and host. If the handshake fails, a user friendly error is shown.
|
// a plugin and host. If the handshake fails, a user friendly error is shown.
|
||||||
@@ -11,5 +11,5 @@ const Name = "debugtalk"
|
|||||||
var HandshakeConfig = plugin.HandshakeConfig{
|
var HandshakeConfig = plugin.HandshakeConfig{
|
||||||
ProtocolVersion: 1,
|
ProtocolVersion: 1,
|
||||||
MagicCookieKey: "HttpRunnerPlus",
|
MagicCookieKey: "HttpRunnerPlus",
|
||||||
MagicCookieValue: Name,
|
MagicCookieValue: PluginName,
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package common
|
package pluginInternal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
// +build linux freebsd darwin
|
// +build linux freebsd darwin
|
||||||
// go plugin doesn't support windows
|
// go plugin doesn't support windows
|
||||||
|
|
||||||
package common
|
package pluginInternal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package common
|
package pluginInternal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
@@ -6,8 +6,6 @@ import (
|
|||||||
|
|
||||||
"github.com/hashicorp/go-hclog"
|
"github.com/hashicorp/go-hclog"
|
||||||
"github.com/hashicorp/go-plugin"
|
"github.com/hashicorp/go-plugin"
|
||||||
"github.com/httprunner/hrp/plugin/shared"
|
|
||||||
pluginShared "github.com/httprunner/hrp/plugin/shared"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -16,13 +14,13 @@ var client *plugin.Client
|
|||||||
// HashicorpPlugin implements hashicorp/go-plugin
|
// HashicorpPlugin implements hashicorp/go-plugin
|
||||||
type HashicorpPlugin struct {
|
type HashicorpPlugin struct {
|
||||||
logOn bool // turn on plugin log
|
logOn bool // turn on plugin log
|
||||||
pluginShared.FuncCaller
|
FuncCaller
|
||||||
cachedFunctions map[string]bool // cache loaded functions to improve performance
|
cachedFunctions map[string]bool // cache loaded functions to improve performance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *HashicorpPlugin) Init(path string) error {
|
func (p *HashicorpPlugin) Init(path string) error {
|
||||||
loggerOptions := &hclog.LoggerOptions{
|
loggerOptions := &hclog.LoggerOptions{
|
||||||
Name: shared.Name,
|
Name: PluginName,
|
||||||
Output: os.Stdout,
|
Output: os.Stdout,
|
||||||
}
|
}
|
||||||
if p.logOn {
|
if p.logOn {
|
||||||
@@ -32,9 +30,9 @@ func (p *HashicorpPlugin) Init(path string) error {
|
|||||||
}
|
}
|
||||||
// launch the plugin process
|
// launch the plugin process
|
||||||
client = plugin.NewClient(&plugin.ClientConfig{
|
client = plugin.NewClient(&plugin.ClientConfig{
|
||||||
HandshakeConfig: shared.HandshakeConfig,
|
HandshakeConfig: HandshakeConfig,
|
||||||
Plugins: map[string]plugin.Plugin{
|
Plugins: map[string]plugin.Plugin{
|
||||||
shared.Name: &shared.HashicorpPlugin{},
|
PluginName: &HRPPlugin{},
|
||||||
},
|
},
|
||||||
Cmd: exec.Command(path),
|
Cmd: exec.Command(path),
|
||||||
Logger: hclog.New(loggerOptions),
|
Logger: hclog.New(loggerOptions),
|
||||||
@@ -48,7 +46,7 @@ func (p *HashicorpPlugin) Init(path string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Request the plugin
|
// Request the plugin
|
||||||
raw, err := rpcClient.Dispense(shared.Name)
|
raw, err := rpcClient.Dispense(PluginName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("request plugin failed")
|
log.Error().Err(err).Msg("request plugin failed")
|
||||||
return err
|
return err
|
||||||
@@ -56,7 +54,7 @@ func (p *HashicorpPlugin) Init(path string) error {
|
|||||||
|
|
||||||
// We should have a Function now! This feels like a normal interface
|
// We should have a Function now! This feels like a normal interface
|
||||||
// implementation but is in fact over an RPC connection.
|
// implementation but is in fact over an RPC connection.
|
||||||
p.FuncCaller = raw.(shared.FuncCaller)
|
p.FuncCaller = raw.(FuncCaller)
|
||||||
|
|
||||||
p.cachedFunctions = make(map[string]bool)
|
p.cachedFunctions = make(map[string]bool)
|
||||||
log.Info().Str("path", path).Msg("load hashicorp go plugin success")
|
log.Info().Str("path", path).Msg("load hashicorp go plugin success")
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package common
|
package pluginInternal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package shared
|
package pluginInternal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
@@ -89,15 +89,22 @@ func (s *functionRPCServer) Call(args interface{}, resp *interface{}) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashicorpPlugin implements hashicorp's plugin.Plugin.
|
// HRPPlugin implements hashicorp's plugin.Plugin.
|
||||||
type HashicorpPlugin struct {
|
type HRPPlugin struct {
|
||||||
Impl FuncCaller
|
Impl FuncCaller
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *HashicorpPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
|
func (p *HRPPlugin) Server(*plugin.MuxBroker) (interface{}, error) {
|
||||||
return &functionRPCServer{Impl: p.Impl}, nil
|
return &functionRPCServer{Impl: p.Impl}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (HashicorpPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
|
func (HRPPlugin) Client(b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
|
||||||
return &functionRPC{client: c}, nil
|
return &functionRPC{client: c}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IPlugin interface {
|
||||||
|
Init(path string) error // init plugin
|
||||||
|
Has(funcName string) bool // check if plugin has function
|
||||||
|
Call(funcName string, args ...interface{}) (interface{}, error) // call function
|
||||||
|
Quit() error // quit plugin
|
||||||
|
}
|
||||||
@@ -1,33 +1,24 @@
|
|||||||
package common
|
package pluginInternal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
pluginShared "github.com/httprunner/hrp/plugin/shared"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type pluginFile string
|
type pluginFile string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
goPluginFile pluginFile = pluginShared.Name + ".so" // built from go plugin
|
goPluginFile pluginFile = PluginName + ".so" // built from go plugin
|
||||||
hashicorpGoPluginFile pluginFile = pluginShared.Name + ".bin" // built from hashicorp go plugin
|
hashicorpGoPluginFile pluginFile = PluginName + ".bin" // built from hashicorp go plugin
|
||||||
hashicorpPyPluginFile pluginFile = pluginShared.Name + ".py"
|
hashicorpPyPluginFile pluginFile = PluginName + ".py"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Plugin interface {
|
func Init(path string, logOn bool) (IPlugin, error) {
|
||||||
Init(path string) error // init plugin
|
|
||||||
Has(funcName string) bool // check if plugin has function
|
|
||||||
Call(funcName string, args ...interface{}) (interface{}, error) // call function
|
|
||||||
Quit() error // quit plugin
|
|
||||||
}
|
|
||||||
|
|
||||||
func Init(path string, logOn bool) (Plugin, error) {
|
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
var plugin Plugin
|
var plugin IPlugin
|
||||||
|
|
||||||
// priority: hashicorp plugin > go plugin
|
// priority: hashicorp plugin > go plugin
|
||||||
// locate hashicorp plugin file
|
// locate hashicorp plugin file
|
||||||
@@ -8,8 +8,7 @@ import (
|
|||||||
hclog "github.com/hashicorp/go-hclog"
|
hclog "github.com/hashicorp/go-hclog"
|
||||||
"github.com/hashicorp/go-plugin"
|
"github.com/hashicorp/go-plugin"
|
||||||
|
|
||||||
"github.com/httprunner/hrp/plugin/common"
|
pluginInternal "github.com/httprunner/hrp/plugin/internal"
|
||||||
pluginShared "github.com/httprunner/hrp/plugin/shared"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// functionsMap stores plugin functions
|
// functionsMap stores plugin functions
|
||||||
@@ -37,7 +36,7 @@ func (p *functionPlugin) Call(funcName string, args ...interface{}) (interface{}
|
|||||||
return nil, fmt.Errorf("function %s not found", funcName)
|
return nil, fmt.Errorf("function %s not found", funcName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return common.CallFunc(fn, args...)
|
return pluginInternal.CallFunc(fn, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
var functions = make(functionsMap)
|
var functions = make(functionsMap)
|
||||||
@@ -55,17 +54,17 @@ func Register(funcName string, fn interface{}) {
|
|||||||
func Serve() {
|
func Serve() {
|
||||||
funcPlugin := &functionPlugin{
|
funcPlugin := &functionPlugin{
|
||||||
logger: hclog.New(&hclog.LoggerOptions{
|
logger: hclog.New(&hclog.LoggerOptions{
|
||||||
Name: pluginShared.Name,
|
Name: pluginInternal.PluginName,
|
||||||
Output: os.Stdout,
|
Output: os.Stdout,
|
||||||
Level: hclog.Info,
|
Level: hclog.Info,
|
||||||
}),
|
}),
|
||||||
functions: functions,
|
functions: functions,
|
||||||
}
|
}
|
||||||
var pluginMap = map[string]plugin.Plugin{
|
var pluginMap = map[string]plugin.Plugin{
|
||||||
pluginShared.Name: &pluginShared.HashicorpPlugin{Impl: funcPlugin},
|
pluginInternal.PluginName: &pluginInternal.HRPPlugin{Impl: funcPlugin},
|
||||||
}
|
}
|
||||||
plugin.Serve(&plugin.ServeConfig{
|
plugin.Serve(&plugin.ServeConfig{
|
||||||
HandshakeConfig: pluginShared.HandshakeConfig,
|
HandshakeConfig: pluginInternal.HandshakeConfig,
|
||||||
Plugins: pluginMap,
|
Plugins: pluginMap,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import (
|
|||||||
|
|
||||||
"github.com/httprunner/hrp/internal/builtin"
|
"github.com/httprunner/hrp/internal/builtin"
|
||||||
"github.com/httprunner/hrp/internal/ga"
|
"github.com/httprunner/hrp/internal/ga"
|
||||||
"github.com/httprunner/hrp/plugin/common"
|
pluginInternal "github.com/httprunner/hrp/plugin/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -282,8 +282,8 @@ func (r *caseRunner) run() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func initPlugin(path string, logOn bool) (plugin common.Plugin, err error) {
|
func initPlugin(path string, logOn bool) (plugin pluginInternal.IPlugin, err error) {
|
||||||
plugin, err = common.Init(path, logOn)
|
plugin, err = pluginInternal.Init(path, logOn)
|
||||||
if plugin == nil {
|
if plugin == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -299,7 +299,7 @@ func initPlugin(path string, logOn bool) (plugin common.Plugin, err error) {
|
|||||||
|
|
||||||
// report event for initializing plugin
|
// report event for initializing plugin
|
||||||
var pluginType string
|
var pluginType string
|
||||||
if _, ok := plugin.(*common.GoPlugin); ok {
|
if _, ok := plugin.(*pluginInternal.GoPlugin); ok {
|
||||||
pluginType = "go"
|
pluginType = "go"
|
||||||
} else {
|
} else {
|
||||||
pluginType = "hashicorp"
|
pluginType = "hashicorp"
|
||||||
|
|||||||
Reference in New Issue
Block a user