From 2516d1055a7a24e17ba953a5e8791690a51c29c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Fri, 8 Feb 2019 20:36:50 +0100 Subject: [PATCH 1/2] fix concurrency --- client.go | 12 +++++++++++- client_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/client.go b/client.go index 0028ddc..e555a6d 100644 --- a/client.go +++ b/client.go @@ -7,6 +7,7 @@ import ( "net" "regexp" "strings" + "sync" "time" ) @@ -57,6 +58,7 @@ type Client struct { notify chan Notification disconnect chan struct{} res []string + mutex sync.Mutex Server *ServerMethods } @@ -234,7 +236,15 @@ func (c *Client) ExecCmd(cmd *Cmd) ([]string, error) { return nil, ErrNotConnected } - c.work <- cmd.String() + c.mutex.Lock() + defer c.mutex.Unlock() + + select { + case c.work <- cmd.String(): + // continue + case <-time.After(c.timeout): + return nil, ErrTimeout + } select { case err := <-c.err: diff --git a/client_test.go b/client_test.go index cdc028d..e50c438 100644 --- a/client_test.go +++ b/client_test.go @@ -230,3 +230,36 @@ func TestClientBadHeader(t *testing.T) { // Should never get here assert.NoError(t, c.Close()) } + +func TestConcurrency(t *testing.T) { + s := newServer(t) + if s == nil { + return + } + defer func() { + assert.NoError(t, s.Close()) + }() + + c, err := NewClient(s.Addr, Timeout(time.Millisecond*100)) + if !assert.NoError(t, err) { + return + } + + wait := make(chan struct{}) + + go func() { + for i := 0; i <= 10; i++ { + _, err = c.Server.GroupList() + assert.NoError(t, err) + } + wait <- struct{}{} + }() + + for i := 0; i <= 10; i++ { + _, err = c.Server.GroupList() + assert.NoError(t, err) + } + + // wait for go routine to finish + <-wait +} From 94d0c84d7ba3ffa6a4306867e9708bf372c47e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20B=C3=B6gle?= Date: Sun, 10 Feb 2019 15:38:56 +0100 Subject: [PATCH 2/2] fixed TestConcurrency --- client_test.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/client_test.go b/client_test.go index e50c438..a02d826 100644 --- a/client_test.go +++ b/client_test.go @@ -245,21 +245,26 @@ func TestConcurrency(t *testing.T) { return } - wait := make(chan struct{}) + const iterations = 10 + errors := make(chan error) go func() { - for i := 0; i <= 10; i++ { - _, err = c.Server.GroupList() - assert.NoError(t, err) + defer close(errors) + + for i := 0; i <= iterations; i++ { + if _, err2 := c.Server.GroupList(); err2 != nil { + errors <- err2 + } } - wait <- struct{}{} }() - for i := 0; i <= 10; i++ { + for i := 0; i <= iterations; i++ { _, err = c.Server.GroupList() assert.NoError(t, err) } - // wait for go routine to finish - <-wait + // receive errors from go-routine and wait for completion + for err := range errors { + assert.NoError(t, err) + } }