summaryrefslogtreecommitdiff
path: root/xgb_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'xgb_test.go')
-rw-r--r--xgb_test.go225
1 files changed, 225 insertions, 0 deletions
diff --git a/xgb_test.go b/xgb_test.go
new file mode 100644
index 0000000..19ed307
--- /dev/null
+++ b/xgb_test.go
@@ -0,0 +1,225 @@
+package xgb
+
+import (
+ "errors"
+ "fmt"
+ "testing"
+ "time"
+)
+
+func TestConnOnNonBlockingDummyXServer(t *testing.T) {
+ timeout := 10 * time.Millisecond
+ checkedReply := func(wantError bool) func(*Conn) error {
+ request := "reply"
+ if wantError {
+ request = "error"
+ }
+ return func(c *Conn) error {
+ cookie := c.NewCookie(true, true)
+ c.NewRequest([]byte(request), cookie)
+ _, err := cookie.Reply()
+ if wantError && err == nil {
+ return errors.New(fmt.Sprintf("checked request \"%v\" with reply resulted in nil error, want some error", request))
+ }
+ if !wantError && err != nil {
+ return errors.New(fmt.Sprintf("checked request \"%v\" with reply resulted in error %v, want nil error", request, err))
+ }
+ return nil
+ }
+ }
+ checkedNoreply := func(wantError bool) func(*Conn) error {
+ request := "noreply"
+ if wantError {
+ request = "error"
+ }
+ return func(c *Conn) error {
+ cookie := c.NewCookie(true, false)
+ c.NewRequest([]byte(request), cookie)
+ err := cookie.Check()
+ if wantError && err == nil {
+ return errors.New(fmt.Sprintf("checked request \"%v\" with no reply resulted in nil error, want some error", request))
+ }
+ if !wantError && err != nil {
+ return errors.New(fmt.Sprintf("checked request \"%v\" with no reply resulted in error %v, want nil error", request, err))
+ }
+ return nil
+ }
+ }
+ uncheckedReply := func(wantError bool) func(*Conn) error {
+ request := "reply"
+ if wantError {
+ request = "error"
+ }
+ return func(c *Conn) error {
+ cookie := c.NewCookie(false, true)
+ c.NewRequest([]byte(request), cookie)
+ _, err := cookie.Reply()
+ if err != nil {
+ return errors.New(fmt.Sprintf("unchecked request \"%v\" with reply resulted in %v, want nil", request, err))
+ }
+ return nil
+ }
+ }
+ uncheckedNoreply := func(wantError bool) func(*Conn) error {
+ request := "noreply"
+ if wantError {
+ request = "error"
+ }
+ return func(c *Conn) error {
+ cookie := c.NewCookie(false, false)
+ c.NewRequest([]byte(request), cookie)
+ return nil
+ }
+ }
+ event := func() func(*Conn) error {
+ return func(c *Conn) error {
+ _, err := c.conn.Write([]byte("event"))
+ if err != nil {
+ return errors.New(fmt.Sprintf("asked dummy server to send event, but resulted in error: %v\n", err))
+ }
+ return err
+ }
+ }
+ waitEvent := func(wantError bool) func(*Conn) error {
+ return func(c *Conn) error {
+ _, err := c.WaitForEvent()
+ if wantError && err == nil {
+ return errors.New(fmt.Sprintf("wait for event resulted in nil error, want some error"))
+ }
+ if !wantError && err != nil {
+ return errors.New(fmt.Sprintf("wait for event resulted in error %v, want nil error", err))
+ }
+ return nil
+ }
+ }
+ checkClosed := func(c *Conn) error {
+ select {
+ case eoe, ok := <-c.eventChan:
+ if ok {
+ return fmt.Errorf("(*Conn).eventChan should be closed, but is not and returns %v", eoe)
+ }
+ case <-time.After(timeout):
+ return fmt.Errorf("(*Conn).eventChan should be closed, but is not and was blocking for %v", timeout)
+ }
+ return nil
+ }
+
+ testCases := []struct {
+ description string
+ actions []func(*Conn) error
+ }{
+ {"close",
+ []func(*Conn) error{},
+ },
+ {"double close",
+ []func(*Conn) error{
+ func(c *Conn) error {
+ c.Close()
+ return nil
+ },
+ },
+ },
+ {"checked requests with reply",
+ []func(*Conn) error{
+ checkedReply(false),
+ checkedReply(true),
+ checkedReply(false),
+ checkedReply(true),
+ },
+ },
+ {"checked requests no reply",
+ []func(*Conn) error{
+ checkedNoreply(false),
+ checkedNoreply(true),
+ checkedNoreply(false),
+ checkedNoreply(true),
+ },
+ },
+ {"unchecked requests with reply",
+ []func(*Conn) error{
+ uncheckedReply(false),
+ uncheckedReply(true),
+ waitEvent(true),
+ uncheckedReply(false),
+ event(),
+ waitEvent(false),
+ },
+ },
+ {"unchecked requests no reply",
+ []func(*Conn) error{
+ uncheckedNoreply(false),
+ uncheckedNoreply(true),
+ waitEvent(true),
+ uncheckedNoreply(false),
+ event(),
+ waitEvent(false),
+ },
+ },
+ {"close with pending requests",
+ []func(*Conn) error{
+ func(c *Conn) error {
+ c.conn.(*dNC).ReadLock()
+ defer c.conn.(*dNC).ReadUnlock()
+ c.NewRequest([]byte("reply"), c.NewCookie(false, true))
+ c.Close()
+ return nil
+ },
+ checkClosed,
+ },
+ },
+ {"unexpected conn close",
+ []func(*Conn) error{
+ func(c *Conn) error {
+ c.conn.Close()
+ if ev, err := c.WaitForEvent(); ev != nil || err != nil {
+ return fmt.Errorf("WaitForEvent() = (%v, %v), want (nil, nil)", ev, err)
+ }
+ return nil
+ },
+ checkClosed,
+ },
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.description, func(t *testing.T) {
+ sclm := leaksMonitor("after server close, before testcase exit")
+ defer sclm.checkTesting(t)
+
+ s := newDummyNetConn("dummyX", newDummyXServerReplier())
+ defer s.Close()
+
+ c, err := postNewConn(&Conn{conn: s})
+ if err != nil {
+ t.Errorf("connect to dummy server error: %v", err)
+ return
+ }
+
+ defer leaksMonitor("after actions end", sclm).checkTesting(t)
+
+ for _, action := range tc.actions {
+ if err := action(c); err != nil {
+ t.Error(err)
+ break
+ }
+ }
+
+ recovered := false
+ func() {
+ defer func() {
+ if err := recover(); err != nil {
+ t.Errorf("(*Conn).Close() panic recover: %v", err)
+ recovered = true
+ }
+ }()
+
+ c.Close()
+ }()
+ if !recovered {
+ if err := checkClosed(c); err != nil {
+ t.Error(err)
+ }
+ }
+
+ })
+ }
+}