diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/config_test.go | 40 | ||||
-rw-r--r-- | ext/errors_test.go | 11 | ||||
-rw-r--r-- | ext/pipe_factory_test.go | 133 | ||||
-rw-r--r-- | ext/protocol_test.go | 46 | ||||
-rw-r--r-- | ext/socket_factory_test.go | 427 |
5 files changed, 657 insertions, 0 deletions
diff --git a/ext/config_test.go b/ext/config_test.go new file mode 100644 index 00000000..fbdde223 --- /dev/null +++ b/ext/config_test.go @@ -0,0 +1,40 @@ +package ext + +import ( + "github.com/stretchr/testify/assert" + "testing" + "time" +) + +func Test_NumWorkers(t *testing.T) { + cfg := Config{ + AllocateTimeout: time.Second, + DestroyTimeout: time.Second * 10, + } + err := cfg.Valid() + + assert.NotNil(t, err) + assert.Equal(t, "cfg.NumWorkers must be set", err.Error()) +} + +func Test_AllocateTimeout(t *testing.T) { + cfg := Config{ + NumWorkers: 10, + DestroyTimeout: time.Second * 10, + } + err := cfg.Valid() + + assert.NotNil(t, err) + assert.Equal(t, "cfg.AllocateTimeout must be set", err.Error()) +} + +func Test_DestroyTimeout(t *testing.T) { + cfg := Config{ + NumWorkers: 10, + AllocateTimeout: time.Second, + } + err := cfg.Valid() + + assert.NotNil(t, err) + assert.Equal(t, "cfg.DestroyTimeout must be set", err.Error()) +} diff --git a/ext/errors_test.go b/ext/errors_test.go new file mode 100644 index 00000000..7c9d7a5b --- /dev/null +++ b/ext/errors_test.go @@ -0,0 +1,11 @@ +package ext + +import ( + "github.com/stretchr/testify/assert" + "testing" +) + +func Test_JobError_Error(t *testing.T) { + e := JobError([]byte("error")) + assert.Equal(t, "error", e.Error()) +} diff --git a/ext/pipe_factory_test.go b/ext/pipe_factory_test.go new file mode 100644 index 00000000..434c31b0 --- /dev/null +++ b/ext/pipe_factory_test.go @@ -0,0 +1,133 @@ +package ext + +import ( + "github.com/stretchr/testify/assert" + "os/exec" + "testing" +) + +func Test_Pipe_Start(t *testing.T) { + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "pipes") + + w, err := NewPipeFactory().SpawnWorker(cmd) + assert.NoError(t, err) + assert.NotNil(t, w) + + go func() { + assert.NoError(t, w.Wait()) + }() + + w.Stop() +} + +func Test_Pipe_StartError(t *testing.T) { + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "pipes") + cmd.Start() + + w, err := NewPipeFactory().SpawnWorker(cmd) + assert.Error(t, err) + assert.Nil(t, w) +} + +func Test_Pipe_PipeError(t *testing.T) { + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "pipes") + cmd.StdinPipe() + + w, err := NewPipeFactory().SpawnWorker(cmd) + assert.Error(t, err) + assert.Nil(t, w) +} + +func Test_Pipe_PipeError2(t *testing.T) { + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "pipes") + cmd.StdoutPipe() + + w, err := NewPipeFactory().SpawnWorker(cmd) + assert.Error(t, err) + assert.Nil(t, w) +} + +func Test_Pipe_Failboot(t *testing.T) { + cmd := exec.Command("php", "php-src/tests/failboot.php") + w, err := NewPipeFactory().SpawnWorker(cmd) + + assert.Nil(t, w) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failboot") +} + +func Test_Pipe_Invalid(t *testing.T) { + cmd := exec.Command("php", "php-src/tests/invalid.php") + + w, err := NewPipeFactory().SpawnWorker(cmd) + assert.Error(t, err) + assert.Nil(t, w) +} + +func Test_Pipe_Echo(t *testing.T) { + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "pipes") + + w, _ := NewPipeFactory().SpawnWorker(cmd) + go func() { + assert.NoError(t, w.Wait()) + }() + defer w.Stop() + + res, err := w.Exec(&Payload{Body: []byte("hello")}) + + assert.NoError(t, err) + assert.NotNil(t, res) + assert.NotNil(t, res.Body) + assert.Nil(t, res.Context) + + assert.Equal(t, "hello", res.String()) +} + +func Test_Pipe_Broken(t *testing.T) { + cmd := exec.Command("php", "php-src/tests/client.php", "broken", "pipes") + + w, _ := NewPipeFactory().SpawnWorker(cmd) + go func() { + err := w.Wait() + + assert.Error(t, err) + assert.Contains(t, err.Error(), "undefined_function()") + }() + defer w.Stop() + + res, err := w.Exec(&Payload{Body: []byte("hello")}) + + assert.Error(t, err) + assert.Nil(t, res) +} + +func Benchmark_Pipe_SpawnWorker_Stop(b *testing.B) { + f := NewPipeFactory() + for n := 0; n < b.N; n++ { + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "pipes") + w, _ := f.SpawnWorker(cmd) + go func() { + if w.Wait() != nil { + b.Fail() + } + }() + + w.Stop() + } +} + +func Benchmark_Pipe_Worker_ExecEcho(b *testing.B) { + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "pipes") + + w, _ := NewPipeFactory().SpawnWorker(cmd) + go func() { + w.Wait() + }() + defer w.Stop() + + for n := 0; n < b.N; n++ { + if _, err := w.Exec(&Payload{Body: []byte("hello")}); err != nil { + b.Fail() + } + } +} diff --git a/ext/protocol_test.go b/ext/protocol_test.go new file mode 100644 index 00000000..f6410ef5 --- /dev/null +++ b/ext/protocol_test.go @@ -0,0 +1,46 @@ +package ext + +import ( + "github.com/pkg/errors" + "github.com/spiral/goridge" + "github.com/stretchr/testify/assert" + "testing" +) + +type relayMock struct { + error bool + payload string +} + +func (r *relayMock) Send(data []byte, flags byte) (err error) { + if r.error { + return errors.New("send error") + } + + return nil +} + +func (r *relayMock) Receive() (data []byte, p goridge.Prefix, err error) { + return []byte(r.payload), goridge.NewPrefix().WithFlag(goridge.PayloadControl), nil +} + +func (r *relayMock) Close() error { + return nil +} + +func Test_Protocol_Errors(t *testing.T) { + err := sendPayload(&relayMock{}, make(chan int)) + assert.Error(t, err) +} + +func Test_Protocol_FetchPID(t *testing.T) { + pid, err := fetchPID(&relayMock{error: false, payload: "{\"pid\":100}"}) + assert.NoError(t, err) + assert.Equal(t, 100, pid) + + _, err = fetchPID(&relayMock{error: true, payload: "{\"pid\":100}"}) + assert.Error(t, err) + + _, err = fetchPID(&relayMock{error: false, payload: "{\"pid:100"}) + assert.Error(t, err) +} diff --git a/ext/socket_factory_test.go b/ext/socket_factory_test.go new file mode 100644 index 00000000..2d6108bc --- /dev/null +++ b/ext/socket_factory_test.go @@ -0,0 +1,427 @@ +package ext + +import ( + "github.com/stretchr/testify/assert" + "net" + "os/exec" + "runtime" + "testing" + "time" +) + +func Test_Tcp_Start(t *testing.T) { + time.Sleep(time.Millisecond * 10) // to ensure free socket + + ls, err := net.Listen("tcp", "localhost:9007") + if assert.NoError(t, err) { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "tcp") + + w, err := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + assert.NoError(t, err) + assert.NotNil(t, w) + + go func() { + assert.NoError(t, w.Wait()) + }() + + w.Stop() +} + +func Test_Tcp_StartCloseFactory(t *testing.T) { + time.Sleep(time.Millisecond * 10) // to ensure free socket + + ls, err := net.Listen("tcp", "localhost:9007") + if assert.NoError(t, err) { + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "tcp") + + f := NewSocketFactory(ls, time.Minute) + defer f.Close() + + w, err := f.SpawnWorker(cmd) + assert.NoError(t, err) + assert.NotNil(t, w) + + go func() { + assert.NoError(t, w.Wait()) + }() + + w.Stop() +} + +func Test_Tcp_StartError(t *testing.T) { + time.Sleep(time.Millisecond * 10) // to ensure free socket + + ls, err := net.Listen("tcp", "localhost:9007") + if assert.NoError(t, err) { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "pipes") + cmd.Start() + + w, err := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + assert.Error(t, err) + assert.Nil(t, w) +} + +func Test_Tcp_Failboot(t *testing.T) { + time.Sleep(time.Millisecond * 10) // to ensure free socket + + ls, err := net.Listen("tcp", "localhost:9007") + if assert.NoError(t, err) { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/failboot.php") + + w, err := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + assert.Nil(t, w) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failboot") +} + +func Test_Tcp_Timeout(t *testing.T) { + time.Sleep(time.Millisecond * 10) // to ensure free socket + + ls, err := net.Listen("tcp", "localhost:9007") + if assert.NoError(t, err) { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/slow-client.php", "echo", "tcp", "200", "0") + + w, err := NewSocketFactory(ls, time.Millisecond*100).SpawnWorker(cmd) + assert.Nil(t, w) + assert.Error(t, err) + assert.Contains(t, err.Error(), "relay timeout") +} + +func Test_Tcp_Invalid(t *testing.T) { + time.Sleep(time.Millisecond * 10) // to ensure free socket + + ls, err := net.Listen("tcp", "localhost:9007") + if assert.NoError(t, err) { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/invalid.php") + + w, err := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + assert.Error(t, err) + assert.Nil(t, w) +} + +func Test_Tcp_Broken(t *testing.T) { + time.Sleep(time.Millisecond * 10) // to ensure free socket + + ls, err := net.Listen("tcp", "localhost:9007") + if assert.NoError(t, err) { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/client.php", "broken", "tcp") + + w, err := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + go func() { + err := w.Wait() + + assert.Error(t, err) + assert.Contains(t, err.Error(), "undefined_function()") + }() + defer w.Stop() + + res, err := w.Exec(&Payload{Body: []byte("hello")}) + + assert.Error(t, err) + assert.Nil(t, res) +} + +func Test_Tcp_Echo(t *testing.T) { + time.Sleep(time.Millisecond * 10) // to ensure free socket + + ls, err := net.Listen("tcp", "localhost:9007") + if assert.NoError(t, err) { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "tcp") + + w, err := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + go func() { + assert.NoError(t, w.Wait()) + }() + defer w.Stop() + + res, err := w.Exec(&Payload{Body: []byte("hello")}) + + assert.NoError(t, err) + assert.NotNil(t, res) + assert.NotNil(t, res.Body) + assert.Nil(t, res.Context) + + assert.Equal(t, "hello", res.String()) +} + +func Test_Unix_Start(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("not supported on " + runtime.GOOS) + } + + ls, err := net.Listen("unix", "sock.unix") + if err == nil { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "unix") + + w, err := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + assert.NoError(t, err) + assert.NotNil(t, w) + + go func() { + assert.NoError(t, w.Wait()) + }() + + w.Stop() +} + +func Test_Unix_Failboot(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("not supported on " + runtime.GOOS) + } + + ls, err := net.Listen("unix", "sock.unix") + if err == nil { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/failboot.php") + + w, err := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + assert.Nil(t, w) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failboot") +} + +func Test_Unix_Timeout(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("not supported on " + runtime.GOOS) + } + + ls, err := net.Listen("unix", "sock.unix") + if err == nil { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/slow-client.php", "echo", "unix", "200", "0") + + w, err := NewSocketFactory(ls, time.Millisecond*100).SpawnWorker(cmd) + assert.Nil(t, w) + assert.Error(t, err) + assert.Contains(t, err.Error(), "relay timeout") +} + +func Test_Unix_Invalid(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("not supported on " + runtime.GOOS) + } + + ls, err := net.Listen("unix", "sock.unix") + if err == nil { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/invalid.php") + + w, err := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + assert.Error(t, err) + assert.Nil(t, w) +} + +func Test_Unix_Broken(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("not supported on " + runtime.GOOS) + } + + ls, err := net.Listen("unix", "sock.unix") + if err == nil { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/client.php", "broken", "unix") + + w, err := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + go func() { + err := w.Wait() + + assert.Error(t, err) + assert.Contains(t, err.Error(), "undefined_function()") + }() + defer w.Stop() + + res, err := w.Exec(&Payload{Body: []byte("hello")}) + + assert.Error(t, err) + assert.Nil(t, res) +} + +func Test_Unix_Echo(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("not supported on " + runtime.GOOS) + } + + ls, err := net.Listen("unix", "sock.unix") + if err == nil { + defer ls.Close() + } else { + t.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "unix") + + w, err := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + go func() { + assert.NoError(t, w.Wait()) + }() + defer w.Stop() + + res, err := w.Exec(&Payload{Body: []byte("hello")}) + + assert.NoError(t, err) + assert.NotNil(t, res) + assert.NotNil(t, res.Body) + assert.Nil(t, res.Context) + + assert.Equal(t, "hello", res.String()) +} + +func Benchmark_Tcp_SpawnWorker_Stop(b *testing.B) { + ls, err := net.Listen("tcp", "localhost:9007") + if err == nil { + defer ls.Close() + } else { + b.Skip("socket is busy") + } + + f := NewSocketFactory(ls, time.Minute) + for n := 0; n < b.N; n++ { + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "tcp") + + w, _ := f.SpawnWorker(cmd) + go func() { + if w.Wait() != nil { + b.Fail() + } + }() + + w.Stop() + } +} + +func Benchmark_Tcp_Worker_ExecEcho(b *testing.B) { + ls, err := net.Listen("tcp", "localhost:9007") + if err == nil { + defer ls.Close() + } else { + b.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "tcp") + + w, _ := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + go func() { + w.Wait() + }() + defer w.Stop() + + for n := 0; n < b.N; n++ { + if _, err := w.Exec(&Payload{Body: []byte("hello")}); err != nil { + b.Fail() + } + } +} + +func Benchmark_Unix_SpawnWorker_Stop(b *testing.B) { + if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { + b.Skip("not supported on " + runtime.GOOS) + } + + ls, err := net.Listen("unix", "sock.unix") + if err == nil { + defer ls.Close() + } else { + b.Skip("socket is busy") + } + + f := NewSocketFactory(ls, time.Minute) + for n := 0; n < b.N; n++ { + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "unix") + + w, _ := f.SpawnWorker(cmd) + go func() { + if w.Wait() != nil { + b.Fail() + } + }() + + w.Stop() + } +} + +func Benchmark_Unix_Worker_ExecEcho(b *testing.B) { + if runtime.GOOS == "windows" || runtime.GOOS == "darwin" { + b.Skip("not supported on " + runtime.GOOS) + } + + ls, err := net.Listen("unix", "sock.unix") + if err == nil { + defer ls.Close() + } else { + b.Skip("socket is busy") + } + + cmd := exec.Command("php", "php-src/tests/client.php", "echo", "unix") + + w, _ := NewSocketFactory(ls, time.Minute).SpawnWorker(cmd) + go func() { + w.Wait() + }() + defer w.Stop() + + for n := 0; n < b.N; n++ { + if _, err := w.Exec(&Payload{Body: []byte("hello")}); err != nil { + b.Fail() + } + } +} |