diff options
author | Valery Piashchynski <[email protected]> | 2020-12-26 00:47:21 +0300 |
---|---|---|
committer | GitHub <[email protected]> | 2020-12-26 00:47:21 +0300 |
commit | 566d7f4c95eb5dedcb2da5afcda4bbea8eba077f (patch) | |
tree | 0007a6b8c8ac9e7d31b8a5f3f7f27669c860d261 /tests/plugins/rpc | |
parent | 1bc3db2ea9b95edd0101676d7bfd75df3782c3bd (diff) | |
parent | 7a0dee1a416705c621edbf50e1f43fb39845348f (diff) |
Merge pull request #463 from spiral/experiment/core_pluginsv2.0.0-beta1
[RR2] Plugins
Diffstat (limited to 'tests/plugins/rpc')
-rwxr-xr-x | tests/plugins/rpc/config_test.go | 135 | ||||
-rw-r--r-- | tests/plugins/rpc/configs/.rr-rpc-disabled.yaml | 6 | ||||
-rw-r--r-- | tests/plugins/rpc/configs/.rr.yaml | 6 | ||||
-rw-r--r-- | tests/plugins/rpc/plugin1.go | 42 | ||||
-rw-r--r-- | tests/plugins/rpc/plugin2.go | 53 | ||||
-rw-r--r-- | tests/plugins/rpc/rpc_test.go | 188 |
6 files changed, 430 insertions, 0 deletions
diff --git a/tests/plugins/rpc/config_test.go b/tests/plugins/rpc/config_test.go new file mode 100755 index 00000000..df5fa391 --- /dev/null +++ b/tests/plugins/rpc/config_test.go @@ -0,0 +1,135 @@ +package rpc + +import ( + "runtime" + "testing" + + "github.com/spiral/roadrunner/v2/plugins/rpc" + "github.com/stretchr/testify/assert" +) + +func TestConfig_Listener(t *testing.T) { + cfg := &rpc.Config{Listen: "tcp://:18001"} + + ln, err := cfg.Listener() + assert.NoError(t, err) + assert.NotNil(t, ln) + defer func() { + err := ln.Close() + if err != nil { + t.Errorf("error closing the listener: error %v", err) + } + }() + + assert.Equal(t, "tcp", ln.Addr().Network()) + if runtime.GOOS == "windows" { + assert.Equal(t, "[::]:18001", ln.Addr().String()) + } else { + assert.Equal(t, "0.0.0.0:18001", ln.Addr().String()) + } +} + +func TestConfig_ListenerUnix(t *testing.T) { + cfg := &rpc.Config{Listen: "unix://file.sock"} + + ln, err := cfg.Listener() + assert.NoError(t, err) + assert.NotNil(t, ln) + defer func() { + err := ln.Close() + if err != nil { + t.Errorf("error closing the listener: error %v", err) + } + }() + + assert.Equal(t, "unix", ln.Addr().Network()) + assert.Equal(t, "file.sock", ln.Addr().String()) +} + +func Test_Config_Error(t *testing.T) { + cfg := &rpc.Config{Listen: "uni:unix.sock"} + ln, err := cfg.Listener() + assert.Nil(t, ln) + assert.Error(t, err) + assert.Equal(t, "invalid DSN (tcp://:6001, unix://file.sock)", err.Error()) +} + +func Test_Config_ErrorMethod(t *testing.T) { + cfg := &rpc.Config{Listen: "xinu://unix.sock"} + + ln, err := cfg.Listener() + assert.Nil(t, ln) + assert.Error(t, err) +} + +func TestConfig_Dialer(t *testing.T) { + cfg := &rpc.Config{Listen: "tcp://:18001"} + + ln, _ := cfg.Listener() + defer func() { + err := ln.Close() + if err != nil { + t.Errorf("error closing the listener: error %v", err) + } + }() + + conn, err := cfg.Dialer() + assert.NoError(t, err) + assert.NotNil(t, conn) + defer func() { + err := conn.Close() + if err != nil { + t.Errorf("error closing the connection: error %v", err) + } + }() + + assert.Equal(t, "tcp", conn.RemoteAddr().Network()) + assert.Equal(t, "127.0.0.1:18001", conn.RemoteAddr().String()) +} + +func TestConfig_DialerUnix(t *testing.T) { + cfg := &rpc.Config{Listen: "unix://file.sock"} + + ln, _ := cfg.Listener() + defer func() { + err := ln.Close() + if err != nil { + t.Errorf("error closing the listener: error %v", err) + } + }() + + conn, err := cfg.Dialer() + assert.NoError(t, err) + assert.NotNil(t, conn) + defer func() { + err := conn.Close() + if err != nil { + t.Errorf("error closing the connection: error %v", err) + } + }() + + assert.Equal(t, "unix", conn.RemoteAddr().Network()) + assert.Equal(t, "file.sock", conn.RemoteAddr().String()) +} + +func Test_Config_DialerError(t *testing.T) { + cfg := &rpc.Config{Listen: "uni:unix.sock"} + ln, err := cfg.Dialer() + assert.Nil(t, ln) + assert.Error(t, err) + assert.Equal(t, "invalid socket DSN (tcp://:6001, unix://file.sock)", err.Error()) +} + +func Test_Config_DialerErrorMethod(t *testing.T) { + cfg := &rpc.Config{Listen: "xinu://unix.sock"} + + ln, err := cfg.Dialer() + assert.Nil(t, ln) + assert.Error(t, err) +} + +func Test_Config_Defaults(t *testing.T) { + c := &rpc.Config{} + c.InitDefaults() + assert.Equal(t, "tcp://127.0.0.1:6001", c.Listen) +} diff --git a/tests/plugins/rpc/configs/.rr-rpc-disabled.yaml b/tests/plugins/rpc/configs/.rr-rpc-disabled.yaml new file mode 100644 index 00000000..d5c185e7 --- /dev/null +++ b/tests/plugins/rpc/configs/.rr-rpc-disabled.yaml @@ -0,0 +1,6 @@ +rpc: + listen: tcp://127.0.0.1:6001 + disabled: true +logs: + mode: development + level: error
\ No newline at end of file diff --git a/tests/plugins/rpc/configs/.rr.yaml b/tests/plugins/rpc/configs/.rr.yaml new file mode 100644 index 00000000..d2cb6c70 --- /dev/null +++ b/tests/plugins/rpc/configs/.rr.yaml @@ -0,0 +1,6 @@ +rpc: + listen: tcp://127.0.0.1:6001 + disabled: false +logs: + mode: development + level: error
\ No newline at end of file diff --git a/tests/plugins/rpc/plugin1.go b/tests/plugins/rpc/plugin1.go new file mode 100644 index 00000000..6843b396 --- /dev/null +++ b/tests/plugins/rpc/plugin1.go @@ -0,0 +1,42 @@ +package rpc + +import ( + "fmt" + + "github.com/spiral/roadrunner/v2/plugins/config" +) + +type Plugin1 struct { + config config.Configurer +} + +func (p1 *Plugin1) Init(cfg config.Configurer) error { + p1.config = cfg + return nil +} + +func (p1 *Plugin1) Serve() chan error { + errCh := make(chan error, 1) + return errCh +} + +func (p1 *Plugin1) Stop() error { + return nil +} + +func (p1 *Plugin1) Name() string { + return "rpc_test.plugin1" +} + +func (p1 *Plugin1) RPC() interface{} { + return &PluginRPC{srv: p1} +} + +type PluginRPC struct { + srv *Plugin1 +} + +func (r *PluginRPC) Hello(in string, out *string) error { + *out = fmt.Sprintf("Hello, username: %s", in) + return nil +} diff --git a/tests/plugins/rpc/plugin2.go b/tests/plugins/rpc/plugin2.go new file mode 100644 index 00000000..2c47158f --- /dev/null +++ b/tests/plugins/rpc/plugin2.go @@ -0,0 +1,53 @@ +package rpc + +import ( + "net" + "net/rpc" + "time" + + "github.com/spiral/errors" + goridgeRpc "github.com/spiral/goridge/v3/pkg/rpc" +) + +// plugin2 makes a call to the plugin1 via RPC +// this is just a simulation of external call FOR TEST +// you don't need to do such things :) +type Plugin2 struct { +} + +func (p2 *Plugin2) Init() error { + return nil +} + +func (p2 *Plugin2) Serve() chan error { + errCh := make(chan error, 1) + + go func() { + time.Sleep(time.Second * 3) + + conn, err := net.Dial("tcp", "127.0.0.1:6001") + if err != nil { + errCh <- errors.E(errors.Serve, err) + return + } + client := rpc.NewClientWithCodec(goridgeRpc.NewClientCodec(conn)) + var ret string + err = client.Call("rpc_test.plugin1.Hello", "Valery", &ret) + if err != nil { + errCh <- err + return + } + if ret != "Hello, username: Valery" { + errCh <- errors.E("wrong response") + return + } + // to stop exec + errCh <- errors.E(errors.Disabled) + }() + + return errCh +} + +func (p2 *Plugin2) Stop() error { + return nil +} diff --git a/tests/plugins/rpc/rpc_test.go b/tests/plugins/rpc/rpc_test.go new file mode 100644 index 00000000..98959b28 --- /dev/null +++ b/tests/plugins/rpc/rpc_test.go @@ -0,0 +1,188 @@ +package rpc + +import ( + "os" + "os/signal" + "sync" + "syscall" + "testing" + "time" + + "github.com/spiral/endure" + "github.com/spiral/errors" + "github.com/spiral/roadrunner/v2/plugins/config" + "github.com/spiral/roadrunner/v2/plugins/logger" + "github.com/spiral/roadrunner/v2/plugins/rpc" + "github.com/stretchr/testify/assert" +) + +// graph https://bit.ly/3ensdNb +func TestRpcInit(t *testing.T) { + cont, err := endure.NewContainer(nil, endure.SetLogLevel(endure.ErrorLevel)) + if err != nil { + t.Fatal(err) + } + + err = cont.Register(&Plugin1{}) + if err != nil { + t.Fatal(err) + } + + err = cont.Register(&Plugin2{}) + if err != nil { + t.Fatal(err) + } + + v := &config.Viper{} + v.Path = "configs/.rr.yaml" + v.Prefix = "rr" + err = cont.Register(v) + if err != nil { + t.Fatal(err) + } + + err = cont.Register(&rpc.Plugin{}) + if err != nil { + t.Fatal(err) + } + + err = cont.Register(&logger.ZapLogger{}) + if err != nil { + t.Fatal(err) + } + + err = cont.Init() + if err != nil { + t.Fatal(err) + } + + ch, err := cont.Serve() + if err != nil { + t.Fatal(err) + } + + sig := make(chan os.Signal, 1) + + signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + wg := &sync.WaitGroup{} + wg.Add(1) + + tt := time.NewTimer(time.Second * 10) + + go func() { + defer wg.Done() + defer tt.Stop() + for { + select { + case e := <-ch: + // just stop, this is ok + if errors.Is(errors.Disabled, e.Error) { + return + } + assert.Fail(t, "error", e.Error.Error()) + err = cont.Stop() + if err != nil { + assert.FailNow(t, "error", err.Error()) + } + case <-sig: + err = cont.Stop() + if err != nil { + assert.FailNow(t, "error", err.Error()) + } + return + case <-tt.C: + // timeout + err = cont.Stop() + if err != nil { + assert.FailNow(t, "error", err.Error()) + } + assert.Fail(t, "timeout") + } + } + }() + + wg.Wait() +} + +// graph https://bit.ly/3ensdNb +func TestRpcDisabled(t *testing.T) { + cont, err := endure.NewContainer(nil, endure.SetLogLevel(endure.ErrorLevel)) + if err != nil { + t.Fatal(err) + } + + err = cont.Register(&Plugin1{}) + if err != nil { + t.Fatal(err) + } + + err = cont.Register(&Plugin2{}) + if err != nil { + t.Fatal(err) + } + + v := &config.Viper{} + v.Path = "configs/.rr-rpc-disabled.yaml" + v.Prefix = "rr" + err = cont.Register(v) + if err != nil { + t.Fatal(err) + } + + err = cont.Register(&rpc.Plugin{}) + if err != nil { + t.Fatal(err) + } + + err = cont.Register(&logger.ZapLogger{}) + if err != nil { + t.Fatal(err) + } + + err = cont.Init() + if err != nil { + t.Fatal(err) + } + + ch, err := cont.Serve() + if err != nil { + t.Fatal(err) + } + + sig := make(chan os.Signal, 1) + + signal.Notify(sig, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) + tt := time.NewTimer(time.Second * 20) + + wg := &sync.WaitGroup{} + wg.Add(1) + + go func() { + defer wg.Done() + defer tt.Stop() + for { + select { + case e := <-ch: + // RPC is turned off, should be and dial error + if errors.Is(errors.Disabled, e.Error) { + assert.FailNow(t, "should not be disabled error") + } + assert.Error(t, e.Error) + err = cont.Stop() + assert.Error(t, err) + return + case <-sig: + err = cont.Stop() + if err != nil { + assert.FailNow(t, "error", err.Error()) + } + return + case <-tt.C: + // timeout + return + } + } + }() + + wg.Wait() +} |