Skip to content

Commit

Permalink
Merge pull request #124 from nettorta/develop
Browse files Browse the repository at this point in the history
Enchanced custom gun tutorial
  • Loading branch information
direvius authored May 16, 2019
2 parents ab0f91c + 4ad1e32 commit babf755
Showing 1 changed file with 192 additions and 41 deletions.
233 changes: 192 additions & 41 deletions docs/custom.rst
Original file line number Diff line number Diff line change
@@ -1,12 +1,60 @@
Custom guns
===========


Basic tutorial
--------------
You can create you own Golang-based gun with `pandora`.

There is an example of custom gun shooting via gRPC.

We create a new gun and define ```shoot``` method for it w/ our test logic.

You can find examples of custom guns' code below:
- `gRPC <#gRPC>`_
- `Websockets <#Websockets>`_

Now it's time to compile our gun. Install deps and compile your custom gun file (```go build my_custom_gun.go```).

After that step you'll get ```my_custom_gun``` binary file, it is compiled pandora with your custom gun inside.

Now its time to create ```load.yaml```:

.. code-block:: yaml
pools:
- id: HTTP pool
gun:
type: my_custom_gun_name # custom gun name (specified at `register.Gun("my_custom_gun_name", ...`)
target: "your_grpc_host:your_grpc_port"
ammo:
type: custom_provider
source:
type: file
path: ./json.ammo
result:
type: phout
destination: ./phout.log
rps: {duration: 30s, type: line, from: 1, to: 2}
startup:
type: once
times: 10
log:
level: error
And create ammofile ```./json.ammo```:

.. code-block:: yaml
{"tag": "/MyCase1", "Param1": "146837693,146837692,146837691"}
{"tag": "/MyCase2", "Param2": "555", "Param1": "500002"}
We are ready to shoot. Try it.


gRPC
----

.. code-block:: go
Expand All @@ -18,22 +66,24 @@ We create a new gun and define ```shoot``` method for it w/ our test logic.
// and protobuf contracts for your grpc service
import (
"log"
"context"
"strconv"
"strings"
"time"
"github.com/golang/protobuf/ptypes/timestamp"
"github.com/satori/go.uuid"
"github.com/spf13/afero"
"google.golang.org/grpc"
pb "my_package/my_protobuf_contracts"
"github.com/yandex/pandora/cli"
"github.com/yandex/pandora/components/phttp/import"
"github.com/yandex/pandora/core"
"github.com/yandex/pandora/core/aggregator/netsample"
"github.com/yandex/pandora/core/import"
"github.com/yandex/pandora/core/register"
"google.golang.org/grpc"
"log"
"context"
"strconv"
"strings"
"time"
pb "my_package/my_contracts"
)
type Ammo struct {
Expand Down Expand Up @@ -191,7 +241,7 @@ We create a new gun and define ```shoot``` method for it w/ our test logic.
// Custom imports. Integrate your custom types into configuration system.
coreimport.RegisterCustomJSONProvider("custom_provider", func() core.Ammo { return &Ammo{} })
register.Gun("My_custom_gun_name", NewGun, func() GunConfig {
register.Gun("my_custom_gun_name", NewGun, func() GunConfig {
return GunConfig{
Target: "default target",
}
Expand All @@ -200,39 +250,140 @@ We create a new gun and define ```shoot``` method for it w/ our test logic.
cli.Run()
}
Now it's time to compile our gun. Install deps and compile your custom gun file (```go build my_custom_gun.go```).
After that step you'll get ```my_custom_gun``` binary file, it is compiled pandora with your custom gun inside.

Now its time to create ```load.yaml```:
.. code-block:: yaml
pools:
- id: HTTP pool
gun:
type: My_custom_gun_name # custom gun name specified
target: "your_grpc_host:your_grpc_port"
ammo:
type: custom_provider
source:
type: file
path: ./json.ammo
result:
type: phout
destination: ./phout.log
rps: {duration: 30s, type: line, from: 1, to: 2}
startup:
type: once
times: 10
log:
level: error
And create ammofile ```./json.ammo```:

.. code-block:: yaml
{"tag": "/MyCase1", "Param1": "146837693,146837692,146837691"}
{"tag": "/MyCase2", "Param2": "555", "Param1": "500002"}
Websockets
----------

.. code-block:: go
We are ready to shoot. Try it.
package main
import (
"bytes"
"encoding/json"
"io/ioutil"
"log"
"math/rand"
"mime/multipart"
"net/http"
"net/url"
"strconv"
"time"
"github.com/gorilla/websocket"
"github.com/spf13/afero"
"github.com/yandex/pandora/cli"
"github.com/yandex/pandora/components/phttp/import"
"github.com/yandex/pandora/core"
"github.com/yandex/pandora/core/aggregator/netsample"
"github.com/yandex/pandora/core/import"
"github.com/yandex/pandora/core/register"
)
type Ammo struct {
Tag string
}
type Sample struct {
URL string
ShootTimeSeconds float64
}
type GunConfig struct {
Target string `validate:"required"`
Handler string `validate:"required"`// Configuration will fail, without target defined
}
type Gun struct {
// Configured on construction.
client websocket.Conn
conf GunConfig
// Configured on Bind, before shooting
aggr core.Aggregator // May be your custom Aggregator.
core.GunDeps
}
func NewGun(conf GunConfig) *Gun {
return &Gun{conf: conf}
}
func (g *Gun) Bind(aggr core.Aggregator, deps core.GunDeps) error {
targetPath := url.URL{Scheme: "ws", Host: g.conf.Target, Path: g.conf.Handler}
sample := netsample.Acquire("connection")
code := 0
rand.Seed(time.Now().Unix())
conn, _, err := websocket.DefaultDialer.Dial(
targetPath.String(),
nil,
)
if err != nil {
log.Fatalf("dial err FATAL %s:", err)
code = 500
} else {
code = 200
}
g.client = *conn
g.aggr = aggr
g.GunDeps = deps
defer func() {
sample.SetProtoCode(code)
g.aggr.Report(sample)
}()
go func() {
for {
_, message, err := conn.ReadMessage()
if err != nil {
log.Println("read:", err)
code = 400
return
}
log.Printf("recv: %s", message)
}
}()
err = conn.WriteMessage(websocket.TextMessage, []byte("some websocket connection initialization text, e.g. token"))
if err != nil {
log.Println("write:", err)
}
return nil
}
func (g *Gun) Shoot(ammo core.Ammo) {
sample := netsample.Acquire("message")
code := 0
conn := g.client
err := conn.WriteMessage(websocket.TextMessage, []byte("test_message"))
if err != nil {
log.Println("connection closed", err)
code = 600
} else {
code = 200
}
defer func() {
sample.SetProtoCode(code)
g.aggr.Report(sample)
}()
}
func main() {
//debug.SetGCPercent(-1)
// Standard imports.
fs := afero.NewOsFs()
coreimport.Import(fs)
// May not be imported, if you don't need http guns and etc.
phttp.Import(fs)
// Custom imports. Integrate your custom types into configuration system.
coreimport.RegisterCustomJSONProvider("ammo_provider", func() core.Ammo { return &Ammo{} })
register.Gun("my_custom_gun_name", NewGun, func() GunConfig {
return GunConfig{
Target: "default target",
}
})
cli.Run()
}

0 comments on commit babf755

Please sign in to comment.