mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-13 08:19:44 +08:00
docs: add plugin docs
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
- [x] Testcases can be described in multiple formats, `YAML`/`JSON`/`Golang`, and they are interchangeable.
|
||||
- [x] With [`HAR`][HAR] support, you can use Charles/Fiddler/Chrome/etc as a script recording generator.
|
||||
- [x] Supports `variables`/`extract`/`validate`/`hooks` mechanisms to create extremely complex test scenarios.
|
||||
- [ ] Built-in integration of rich functions, and you can also use [`go plugin`][plugin] to create and call custom functions.
|
||||
- [x] Built-in integration of rich functions, and you can also use [hashicorp/plugin] or [go plugin] to create and call custom functions.
|
||||
- [x] Inherit all powerful features of [`Boomer`][Boomer] and [`locust`][locust], you can run `load test` without extra work.
|
||||
- [x] Using it as a `CLI tool` or a `library` are both supported.
|
||||
|
||||
@@ -272,7 +272,8 @@ func TestCaseDemo(t *testing.T) {
|
||||
[jmespath]: https://jmespath.org/
|
||||
[allure]: https://docs.qameta.io/allure/
|
||||
[HAR]: http://httparchive.org/
|
||||
[plugin]: https://pkg.go.dev/plugin
|
||||
[hashicorp/plugin]: https://github.com/hashicorp/go-plugin
|
||||
[go plugin]: https://pkg.go.dev/plugin
|
||||
[demo.json]: https://github.com/httprunner/hrp/blob/main/examples/demo.json
|
||||
[examples]: https://github.com/httprunner/hrp/blob/main/examples/
|
||||
[CHANGELOG]: docs/CHANGELOG.md
|
||||
190
plugin/README.md
Normal file
190
plugin/README.md
Normal file
@@ -0,0 +1,190 @@
|
||||
# plugin
|
||||
|
||||
When you need to do some dynamic calculations or custom logic processing in testcases, you need to use the plugin function mechanism.
|
||||
|
||||
HttpRunner+ supports both [hashicorp/plugin] and [go plugin] to create and call custom functions.
|
||||
|
||||
## hashicorp/plugin
|
||||
|
||||
It is recommended to use [hashicorp/plugin] in most cases.
|
||||
|
||||
### create plugin functions
|
||||
|
||||
Firstly, you need to define your plugin functions. The functions can be very flexible, only the following restrictions should be complied with.
|
||||
|
||||
- function should return at most one value and one error.
|
||||
- `Register()` and `Serve()` must be called to register plugin functions and start a plugin server process in `main()`.
|
||||
|
||||
Here is some plugin functions as example.
|
||||
|
||||
```go
|
||||
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 main() {
|
||||
plugin.Register("sum_ints", SumInts)
|
||||
plugin.Register("sum_two_int", SumTwoInt)
|
||||
plugin.Register("sum", Sum)
|
||||
plugin.Serve()
|
||||
}
|
||||
```
|
||||
|
||||
You can get more examples at [examples/plugin/]
|
||||
|
||||
### build plugin
|
||||
|
||||
Secondly, you can build your hashicorp plugin to binary file `debugtalk.bin`. The name of `debugtalk.bin` is by convention and should not be changed.
|
||||
|
||||
```bash
|
||||
$ go build -o examples/debugtalk.bin examples/plugin/hashicorp.go examples/plugin/debugtalk.go
|
||||
```
|
||||
|
||||
It is recommended to place the `debugtalk.bin` file in your project root folder, or you can put it in the parent folder of the target testcase file. HttpRunner+ will search `debugtalk.bin` upward recursively until current working directory or system root dir.
|
||||
|
||||
### use plugin functions
|
||||
|
||||
Then, you can call your defined plugin function in your `YAML/JSON` testcase at any position.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "get with params",
|
||||
"variables": {
|
||||
"a": "${sum_two_int(1,6)}",
|
||||
"b": "${sum_ints(1,2,3)}",
|
||||
"c": "${sum(1, 2.3, 4)}",
|
||||
},
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "/get",
|
||||
"params": {
|
||||
"foo1": "$c",
|
||||
"foo2": "${max($a, $b)}"
|
||||
},
|
||||
"headers": {
|
||||
"User-Agent": "HttpRunnerPlus"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## go plugin
|
||||
|
||||
The golang official plugin is only supported on Linux, FreeBSD, and macOS. And this solution also has many drawbacks.
|
||||
|
||||
### create plugin functions
|
||||
|
||||
Firstly, you need to define your plugin functions. The functions can be very flexible, only the following restrictions should be complied with.
|
||||
|
||||
- plugin package name must be `main`.
|
||||
- function names must be capitalized.
|
||||
- function should return at most one value and one error.
|
||||
|
||||
Here is some plugin functions as example.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
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
|
||||
}
|
||||
```
|
||||
|
||||
You can get more examples at [examples/plugin/debugtalk.go]
|
||||
|
||||
### build plugin
|
||||
|
||||
Then you can build your go plugin with `-buildmode=plugin` flag to binary file `debugtalk.so`. The name of `debugtalk.so` is by convention and should not be changed.
|
||||
|
||||
```bash
|
||||
$ go build -buildmode=plugin -o=examples/debugtalk.so examples/plugin/debugtalk.go
|
||||
```
|
||||
|
||||
It is recommended to place the `debugtalk.so` file in your project root folder, or you can put it in the parent folder of the target testcase file. HttpRunner+ will search `debugtalk.so` upward recursively until current working directory or system root dir.
|
||||
|
||||
### use plugin functions
|
||||
|
||||
Then, you can call your defined plugin function in your `YAML/JSON` testcase at any position.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "get with params",
|
||||
"variables": {
|
||||
"a": "${SumTwoInt(1,6)}",
|
||||
"b": "${SumInts(1,2,3)}",
|
||||
"c": "${Sum(1, 2.3, 4)}",
|
||||
},
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"url": "/get",
|
||||
"params": {
|
||||
"foo1": "$c",
|
||||
"foo2": "${max($a, $b)}"
|
||||
},
|
||||
"headers": {
|
||||
"User-Agent": "HttpRunnerPlus"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Notice: you should use the original function name.
|
||||
|
||||
[hashicorp/plugin]: https://github.com/hashicorp/go-plugin
|
||||
[go plugin]: https://pkg.go.dev/plugin
|
||||
[examples/plugin/]: ../examples/plugin/
|
||||
[examples/plugin/debugtalk.go]: ../examples/plugin/debugtalk.go
|
||||
@@ -42,6 +42,8 @@ func (p *functionPlugin) Call(funcName string, args ...interface{}) (interface{}
|
||||
|
||||
var functions = make(functionsMap)
|
||||
|
||||
// Register registers a plugin function.
|
||||
// Every plugin function must be registered before Serve() is called.
|
||||
func Register(funcName string, fn interface{}) {
|
||||
if _, ok := functions[funcName]; ok {
|
||||
return
|
||||
@@ -49,6 +51,7 @@ func Register(funcName string, fn interface{}) {
|
||||
functions[funcName] = reflect.ValueOf(fn)
|
||||
}
|
||||
|
||||
// Serve starts a plugin server process.
|
||||
func Serve() {
|
||||
funcPlugin := &functionPlugin{
|
||||
logger: hclog.New(&hclog.LoggerOptions{
|
||||
|
||||
Reference in New Issue
Block a user