github.com/philippseith/signalr@v0.6.3/serveroptions_test.go (about)

     1  package signalr
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/go-kit/log"
    11  	"github.com/google/uuid"
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  )
    15  
    16  type singleHub struct {
    17  	Hub
    18  	id string
    19  }
    20  
    21  func (s *singleHub) OnConnected(string) {
    22  	s.initUUID()
    23  	singleHubMsg <- s.id
    24  }
    25  
    26  func (s *singleHub) GetUUID() string {
    27  	s.initUUID()
    28  	singleHubMsg <- s.id
    29  	return s.id
    30  }
    31  
    32  func (s *singleHub) initUUID() {
    33  	if s.id == "" {
    34  		s.id = uuid.New().String()
    35  	}
    36  }
    37  
    38  var singleHubMsg = make(chan string, 100)
    39  
    40  var _ = Describe("Server options", func() {
    41  
    42  	Describe("UseHub option", func() {
    43  		Context("When the UseHub option is used", func() {
    44  			It("should use the same hub instance on all invocations", func(done Done) {
    45  				server, err := NewServer(context.TODO(), UseHub(&singleHub{}))
    46  				Expect(server).NotTo(BeNil())
    47  				Expect(err).To(BeNil())
    48  				conn1 := newTestingConnectionForServer()
    49  				Expect(conn1).NotTo(BeNil())
    50  				go func() { _ = server.Serve(conn1) }()
    51  				<-singleHubMsg
    52  				conn2 := newTestingConnectionForServer()
    53  				Expect(conn2).NotTo(BeNil())
    54  				go func() { _ = server.Serve(conn2) }()
    55  				<-singleHubMsg
    56  				// Call GetId twice. If different instances used the results are different
    57  				var uuid string
    58  				conn1.ClientSend(`{"type":1,"invocationId": "123","target":"getuuid"}`)
    59  				<-singleHubMsg
    60  				select {
    61  				case message := <-conn1.received:
    62  					Expect(message).To(BeAssignableToTypeOf(completionMessage{}))
    63  					uuid = fmt.Sprint(message.(completionMessage).Result)
    64  				case <-time.After(1000 * time.Millisecond):
    65  					Fail("timed out")
    66  				}
    67  				conn1.ClientSend(`{"type":1,"invocationId": "456","target":"getuuid"}`)
    68  				<-singleHubMsg
    69  				select {
    70  				case message := <-conn1.received:
    71  					Expect(message).To(BeAssignableToTypeOf(completionMessage{}))
    72  					Expect(fmt.Sprint(message.(completionMessage).Result)).To(Equal(uuid))
    73  				case <-time.After(1000 * time.Millisecond):
    74  					Fail("timed out")
    75  				}
    76  				// Even on another connection, the uuid should be the same
    77  				conn2.ClientSend(`{"type":1,"invocationId": "456","target":"getuuid"}`)
    78  				<-singleHubMsg
    79  				select {
    80  				case message := <-conn2.received:
    81  					Expect(message).To(BeAssignableToTypeOf(completionMessage{}))
    82  					Expect(fmt.Sprint(message.(completionMessage).Result)).To(Equal(uuid))
    83  				case <-time.After(1000 * time.Millisecond):
    84  					Fail("timed out")
    85  				}
    86  				close(done)
    87  			}, 3.0)
    88  		})
    89  		Context("When UseHub is used on a client", func() {
    90  			It("should return an error", func(done Done) {
    91  				_, err := NewClient(context.TODO(), WithConnection(newTestingConnection()), testLoggerOption(), UseHub(&singleHub{}))
    92  				Expect(err).To(HaveOccurred())
    93  				close(done)
    94  			})
    95  		})
    96  	})
    97  
    98  	Describe("SimpleHubFactory option", func() {
    99  		Context("When the SimpleHubFactory option is used", func() {
   100  			It("should call the hub factory on each hub method invocation", func(done Done) {
   101  				server, err := NewServer(context.TODO(), SimpleHubFactory(&singleHub{}), testLoggerOption())
   102  				Expect(server).NotTo(BeNil())
   103  				Expect(err).To(BeNil())
   104  				conn := newTestingConnectionForServer()
   105  				Expect(conn).NotTo(BeNil())
   106  				go func() { _ = server.Serve(conn) }()
   107  				uuids := make(map[string]interface{})
   108  				uuid := <-singleHubMsg
   109  				if _, ok := uuids[uuid]; ok {
   110  					Fail("same hub called twice")
   111  				} else {
   112  					uuids[uuid] = nil
   113  				}
   114  				conn.ClientSend(`{"type":1,"invocationId": "123","target":"getuuid"}`)
   115  				select {
   116  				case uuid = <-singleHubMsg:
   117  					if _, ok := uuids[uuid]; ok {
   118  						Fail("same hub called twice")
   119  					} else {
   120  						uuids[uuid] = nil
   121  					}
   122  				case <-time.After(1000 * time.Millisecond):
   123  					Fail("timed out")
   124  				}
   125  				conn.ClientSend(`{"type":1,"invocationId": "456","target":"getuuid"}`)
   126  				select {
   127  				case uuid = <-singleHubMsg:
   128  					if _, ok := uuids[uuid]; ok {
   129  						Fail("same hub called twice")
   130  					} else {
   131  						uuids[uuid] = nil
   132  					}
   133  				case <-time.After(1000 * time.Millisecond):
   134  					Fail("timed out")
   135  				}
   136  				close(done)
   137  			}, 2.0)
   138  		})
   139  		Context("When SimpleHubFactory is used on a client", func() {
   140  			It("should return an error", func(done Done) {
   141  				_, err := NewClient(context.TODO(), WithConnection(newTestingConnection()), testLoggerOption(), SimpleHubFactory(&singleHub{}))
   142  				Expect(err).To(HaveOccurred())
   143  				close(done)
   144  			})
   145  		})
   146  	})
   147  
   148  	Describe("Logger option", func() {
   149  		Context("When the Logger option with debug false is used", func() {
   150  			It("calling a method correctly should log no events", func(done Done) {
   151  				cw := newChannelWriter()
   152  				server, err := NewServer(context.TODO(), UseHub(&invocationHub{}), Logger(log.NewLogfmtLogger(cw), false))
   153  				Expect(server).NotTo(BeNil())
   154  				Expect(err).To(BeNil())
   155  				conn := newTestingConnectionForServer()
   156  				Expect(conn).NotTo(BeNil())
   157  				go func() { _ = server.Serve(conn) }()
   158  				conn.ClientSend(`{"type":1,"invocationId": "123","target":"simple"}`)
   159  				<-invocationQueue
   160  				select {
   161  				case logEntry := <-cw.Chan():
   162  					Fail(fmt.Sprintf("log entry written: %v", string(logEntry)))
   163  				case <-time.After(1000 * time.Millisecond):
   164  					break
   165  				}
   166  				close(done)
   167  			}, 2.0)
   168  		})
   169  		Context("When the Logger option with debug true is used", func() {
   170  			It("calling a method correctly should log events", func(done Done) {
   171  				cw := newChannelWriter()
   172  				server, err := NewServer(context.TODO(), UseHub(&invocationHub{}), Logger(log.NewLogfmtLogger(cw), true))
   173  				Expect(server).NotTo(BeNil())
   174  				Expect(err).To(BeNil())
   175  				conn := newTestingConnectionForServer()
   176  				Expect(conn).NotTo(BeNil())
   177  				go func() { _ = server.Serve(conn) }()
   178  				conn.ClientSend(`{"type":1,"invocationId": "123","target":"simple"}`)
   179  				<-invocationQueue
   180  				select {
   181  				case <-cw.Chan():
   182  					break
   183  				case <-time.After(1000 * time.Millisecond):
   184  					Fail("timed out")
   185  				}
   186  				close(done)
   187  			}, 2.0)
   188  		})
   189  		Context("When the Logger option with debug false is used", func() {
   190  			It("calling a method incorrectly should log events", func(done Done) {
   191  				cw := newChannelWriter()
   192  				server, err := NewServer(context.TODO(), UseHub(&invocationHub{}), Logger(log.NewLogfmtLogger(cw), false))
   193  				Expect(server).NotTo(BeNil())
   194  				Expect(err).To(BeNil())
   195  				conn := newTestingConnectionForServer()
   196  				Expect(conn).NotTo(BeNil())
   197  				go func() { _ = server.Serve(conn) }()
   198  				conn.ClientSend(`{"type":1,"invocationId": "123","target":"sumple is simple with typo"}`)
   199  				select {
   200  				case <-cw.Chan():
   201  					break
   202  				case <-time.After(1000 * time.Millisecond):
   203  					Fail("timed out")
   204  				}
   205  				close(done)
   206  			}, 2.0)
   207  		})
   208  		Context("When no option which sets the hub type is used, NewServer", func() {
   209  			It("should return an error", func(done Done) {
   210  				_, err := NewServer(context.TODO(), testLoggerOption())
   211  				Expect(err).NotTo(BeNil())
   212  				close(done)
   213  			})
   214  		})
   215  		Context("When an option returns an error, NewServer", func() {
   216  			It("should return an error", func(done Done) {
   217  				_, err := NewServer(context.TODO(), func(Party) error { return errors.New("bad option") })
   218  				Expect(err).NotTo(BeNil())
   219  				close(done)
   220  			})
   221  		})
   222  	})
   223  
   224  	Describe("EnableDetailedErrors option", func() {
   225  		Context("When the EnableDetailedErrors option false is used, calling a method which panics", func() {
   226  			It("should return a completion, which contains only the panic", func(done Done) {
   227  				server, err := NewServer(context.TODO(), UseHub(&invocationHub{}), testLoggerOption())
   228  				Expect(server).NotTo(BeNil())
   229  				Expect(err).To(BeNil())
   230  				conn := newTestingConnectionForServer()
   231  				Expect(conn).NotTo(BeNil())
   232  				go func() { _ = server.Serve(conn) }()
   233  				conn.ClientSend(`{"type":1,"invocationId": "ppp","target":"Panic"}`)
   234  				<-invocationQueue
   235  				select {
   236  				case m := <-conn.ReceiveChan():
   237  					Expect(m).To(BeAssignableToTypeOf(completionMessage{}))
   238  					cm := m.(completionMessage)
   239  					Expect(cm.Error).To(Equal("Don't panic!\n"))
   240  				case <-time.After(100 * time.Millisecond):
   241  					Fail("timed out")
   242  				}
   243  				close(done)
   244  			}, 1.0)
   245  		})
   246  		Context("When the EnableDetailedErrors option true is used, calling a method which panics", func() {
   247  			It("should return a completion, which contains only the panic", func(done Done) {
   248  				server, err := NewServer(context.TODO(), UseHub(&invocationHub{}), EnableDetailedErrors(true), testLoggerOption())
   249  				Expect(server).NotTo(BeNil())
   250  				Expect(err).To(BeNil())
   251  				conn := newTestingConnectionForServer()
   252  				Expect(conn).NotTo(BeNil())
   253  				go func() { _ = server.Serve(conn) }()
   254  				conn.ClientSend(`{"type":1,"invocationId": "ppp","target":"Panic"}`)
   255  				<-invocationQueue
   256  				select {
   257  				case m := <-conn.ReceiveChan():
   258  					Expect(m).To(BeAssignableToTypeOf(completionMessage{}))
   259  					cm := m.(completionMessage)
   260  					Expect(cm.Error).NotTo(Equal("Don't panic!\n"))
   261  				case <-time.After(100 * time.Millisecond):
   262  					Fail("timed out")
   263  				}
   264  				close(done)
   265  			}, 1.0)
   266  		})
   267  	})
   268  
   269  	Describe("TimeoutInterval option", func() {
   270  		Context("When the TimeoutInterval has expired without any client message", func() {
   271  			It("the connection should be closed", func(done Done) {
   272  				server, err := NewServer(context.TODO(), UseHub(&invocationHub{}), TimeoutInterval(100*time.Millisecond), testLoggerOption())
   273  				Expect(server).NotTo(BeNil())
   274  				Expect(err).To(BeNil())
   275  				conn := newTestingConnectionForServer()
   276  				Expect(conn).NotTo(BeNil())
   277  				go func() { _ = server.Serve(conn) }()
   278  				time.Sleep(200 * time.Millisecond)
   279  				conn.ClientSend(`{"type":1,"invocationId": "timeout100","target":"Simple"}`)
   280  				select {
   281  				case m := <-conn.ReceiveChan():
   282  					Expect(m).To(BeAssignableToTypeOf(closeMessage{}))
   283  					cm := m.(closeMessage)
   284  					Expect(cm.Error).NotTo(BeNil())
   285  				case <-time.After(200 * time.Millisecond):
   286  					Fail("timed out")
   287  				case <-invocationQueue:
   288  					Fail("hub method invoked")
   289  				}
   290  				close(done)
   291  			}, 2.0)
   292  		})
   293  	})
   294  
   295  	Describe("KeepAliveInterval option", func() {
   296  		Context("When the KeepAliveInterval has expired without any server message", func() {
   297  			It("a ping should have been sent", func(done Done) {
   298  				server, err := NewServer(context.TODO(), UseHub(&invocationHub{}), KeepAliveInterval(200*time.Millisecond), testLoggerOption())
   299  				Expect(server).NotTo(BeNil())
   300  				Expect(err).To(BeNil())
   301  				conn := newTestingConnection()
   302  				go func() { _ = server.Serve(conn) }()
   303  				// Send initial Handshake
   304  				conn.ClientSend(`{"protocol": "json","version": 1}`)
   305  				// Handshake response
   306  				hr, _ := conn.ClientReceive()
   307  				Expect(hr).To(Equal("{}"))
   308  				for i := 0; i < 5; i++ {
   309  					// Wait for ping
   310  					hmc := make(chan interface{}, 1)
   311  					go func() {
   312  						m, _ := conn.ClientReceive()
   313  						hmc <- m
   314  					}()
   315  					select {
   316  					case m := <-hmc:
   317  						Expect(strings.TrimRight(m.(string), "\n")).To(Equal("{\"type\":6}"))
   318  					case <-time.After(600 * time.Millisecond):
   319  						Fail("timed out")
   320  					}
   321  				}
   322  				server.cancel()
   323  				close(done)
   324  			}, 2.0)
   325  		})
   326  	})
   327  
   328  	Describe("StreamBufferCapacity option", func() {
   329  		Context("When the StreamBufferCapacity is 0", func() {
   330  			It("should return an error", func(done Done) {
   331  				_, err := NewServer(context.TODO(), UseHub(&singleHub{}), StreamBufferCapacity(0), testLoggerOption())
   332  				Expect(err).NotTo(BeNil())
   333  				close(done)
   334  			})
   335  		})
   336  	})
   337  
   338  	Describe("MaximumReceiveMessageSize option", func() {
   339  		Context("When the MaximumReceiveMessageSize is 0", func() {
   340  			It("should return an error", func(done Done) {
   341  				_, err := NewServer(context.TODO(), UseHub(&singleHub{}), MaximumReceiveMessageSize(0), testLoggerOption())
   342  				Expect(err).NotTo(BeNil())
   343  				close(done)
   344  			})
   345  		})
   346  	})
   347  	Describe("HTTPTransports option", func() {
   348  		Context("When HTTPTransports is one of WebSockets, ServerSentEvents or both", func() {
   349  			It("should set these transports", func(done Done) {
   350  				s, err := NewServer(context.TODO(), UseHub(&singleHub{}), HTTPTransports(TransportWebSockets), testLoggerOption())
   351  				Expect(err).NotTo(HaveOccurred())
   352  				Expect(s.availableTransports()).To(ContainElement(TransportWebSockets))
   353  				close(done)
   354  			})
   355  			It("should set these transports", func(done Done) {
   356  				s, err := NewServer(context.TODO(), UseHub(&singleHub{}), HTTPTransports(TransportServerSentEvents), testLoggerOption())
   357  				Expect(err).NotTo(HaveOccurred())
   358  				Expect(s.availableTransports()).To(ContainElement(TransportServerSentEvents))
   359  				close(done)
   360  			})
   361  			It("should set these transports", func(done Done) {
   362  				s, err := NewServer(context.TODO(), UseHub(&singleHub{}), HTTPTransports(TransportServerSentEvents, TransportWebSockets), testLoggerOption())
   363  				Expect(err).NotTo(HaveOccurred())
   364  				Expect(s.availableTransports()).To(ContainElement(TransportWebSockets))
   365  				Expect(s.availableTransports()).To(ContainElement(TransportServerSentEvents))
   366  				close(done)
   367  			})
   368  		})
   369  		Context("When HTTPTransports is none of WebSockets, ServerSentEvents", func() {
   370  			It("should return an error", func(done Done) {
   371  				_, err := NewServer(context.TODO(), UseHub(&singleHub{}), HTTPTransports("WebTransport"), testLoggerOption())
   372  				Expect(err).To(HaveOccurred())
   373  				close(done)
   374  			})
   375  		})
   376  		Context("When HTTPTransports is used on a client", func() {
   377  			It("should return an error", func(done Done) {
   378  				_, err := NewClient(context.TODO(), WithConnection(newTestingConnection()), HTTPTransports(TransportServerSentEvents), testLoggerOption())
   379  				Expect(err).To(HaveOccurred())
   380  				close(done)
   381  			})
   382  		})
   383  
   384  	})
   385  })
   386  
   387  type channelWriter struct {
   388  	channel chan []byte
   389  }
   390  
   391  func (c *channelWriter) Write(p []byte) (n int, err error) {
   392  	c.channel <- p
   393  	return len(p), nil
   394  }
   395  
   396  func (c *channelWriter) Chan() chan []byte {
   397  	return c.channel
   398  }
   399  
   400  func newChannelWriter() *channelWriter {
   401  	return &channelWriter{make(chan []byte, 100)}
   402  }
   403  
   404  // type mapLogger struct {
   405  //	c chan bool
   406  //	m map[string]string
   407  // }
   408  //
   409  // func (m *mapLogger) Log(keyvals ...interface{}) error {
   410  //	m.m = make(map[string]string)
   411  //	for i := 0; i < len(keyvals); i += 2 {
   412  //		m.m[keyvals[i].(string)] = keyvals[i+1].(string)
   413  //	}
   414  //	m.c <- true
   415  //	return nil
   416  // }