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

     1  package signalr
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"time"
     7  
     8  	. "github.com/onsi/ginkgo"
     9  	. "github.com/onsi/gomega"
    10  )
    11  
    12  var invocationQueue = make(chan string, 20)
    13  
    14  type invocationHub struct {
    15  	Hub
    16  }
    17  
    18  func (i *invocationHub) Simple() {
    19  	invocationQueue <- "Simple()"
    20  }
    21  
    22  func (i *invocationHub) SimpleInt(value int) int {
    23  	invocationQueue <- fmt.Sprintf("SimpleInt(%v)", value)
    24  	return value + 1
    25  }
    26  
    27  func (i *invocationHub) SimpleFloat(value float64) (float64, float64) {
    28  	invocationQueue <- fmt.Sprintf("SimpleFloat(%v)", value)
    29  	return value * 10.0, value * 100.0
    30  }
    31  
    32  func (i *invocationHub) SimpleString(value1 string, value2 string) string {
    33  	invocationQueue <- fmt.Sprintf("SimpleString(%v, %v)", value1, value2)
    34  	return strings.ToLower(value1 + value2)
    35  }
    36  
    37  func (i *invocationHub) Async() chan bool {
    38  	r := make(chan bool)
    39  	go func() {
    40  		defer close(r)
    41  		r <- true
    42  	}()
    43  	invocationQueue <- "Async()"
    44  	return r
    45  }
    46  
    47  func (i *invocationHub) AsyncClosedChan() chan bool {
    48  	r := make(chan bool)
    49  	close(r)
    50  	invocationQueue <- "AsyncClosedChan()"
    51  	return r
    52  }
    53  
    54  func (i *invocationHub) Panic() {
    55  	invocationQueue <- "Panic()"
    56  	panic("Don't panic!")
    57  }
    58  
    59  var _ = Describe("Invocation", func() {
    60  
    61  	Describe("Simple invocation", func() {
    62  		var server Server
    63  		var conn *testingConnection
    64  		BeforeEach(func(done Done) {
    65  			server, conn = connect(&invocationHub{})
    66  			close(done)
    67  		})
    68  		AfterEach(func(done Done) {
    69  			server.cancel()
    70  			close(done)
    71  		})
    72  		Context("When invoked by the client", func() {
    73  			It("should be invoked and return a completion", func(done Done) {
    74  				conn.ClientSend(`{"type":1,"invocationId": "123","target":"simple"}`)
    75  				Expect(<-invocationQueue).To(Equal("Simple()"))
    76  				recv := (<-conn.received).(completionMessage)
    77  				Expect(recv).NotTo(BeNil())
    78  				Expect(recv.InvocationID).To(Equal("123"))
    79  				Expect(recv.Result).To(BeNil())
    80  				Expect(recv.Error).To(Equal(""))
    81  				close(done)
    82  			}, 2.0)
    83  		})
    84  		Context("When invoked by the client two times in one frame", func() {
    85  			It("should be invoked and return a completion", func(done Done) {
    86  				conn.ClientSend(`{"type":1,"invocationId": "123","target":"simple"}`)
    87  				conn.ClientSend(`{"type":1,"invocationId": "123","target":"simple"}`)
    88  				Expect(<-invocationQueue).To(Equal("Simple()"))
    89  				Expect(<-invocationQueue).To(Equal("Simple()"))
    90  				recv := (<-conn.received).(completionMessage)
    91  				Expect(recv).NotTo(BeNil())
    92  				Expect(recv.InvocationID).To(Equal("123"))
    93  				Expect(recv.Result).To(BeNil())
    94  				Expect(recv.Error).To(Equal(""))
    95  				close(done)
    96  			}, 2.0)
    97  		})
    98  	})
    99  
   100  	Describe("Non blocking invocation", func() {
   101  		var server Server
   102  		var conn *testingConnection
   103  		BeforeEach(func(done Done) {
   104  			server, conn = connect(&invocationHub{})
   105  			close(done)
   106  		})
   107  		AfterEach(func(done Done) {
   108  			server.cancel()
   109  			close(done)
   110  		})
   111  		Context("When invoked by the client", func() {
   112  			It("should be invoked and return no completion", func(done Done) {
   113  				conn.ClientSend(`{"type":1,"target":"simple"}`)
   114  				Expect(<-invocationQueue).To(Equal("Simple()"))
   115  				select {
   116  				case message := <-conn.received:
   117  					if _, ok := message.(completionMessage); ok {
   118  						Fail("received completion ")
   119  					}
   120  				case <-time.After(1000 * time.Millisecond):
   121  				}
   122  				close(done)
   123  			}, 2.0)
   124  		})
   125  	})
   126  
   127  	Describe("Invalid invocation", func() {
   128  		var server Server
   129  		var conn *testingConnection
   130  		BeforeEach(func(done Done) {
   131  			server, conn = connect(&invocationHub{})
   132  			close(done)
   133  		})
   134  		AfterEach(func(done Done) {
   135  			server.cancel()
   136  			close(done)
   137  		})
   138  		Context("When an invalid invocation message is sent", func() {
   139  			It("close the connection with error", func(done Done) {
   140  				// Invalid. invocationId should be a string
   141  				conn.ClientSend(`{"type":1,"invocationId":1}`)
   142  				select {
   143  				case message := <-conn.received:
   144  					Expect(message).To(BeAssignableToTypeOf(closeMessage{}))
   145  					Expect(message.(closeMessage).Error).NotTo(BeNil())
   146  				case <-time.After(1000 * time.Millisecond):
   147  					Fail("timed out")
   148  				}
   149  				close(done)
   150  			}, 2.0)
   151  		})
   152  	})
   153  
   154  	Describe("Invalid json", func() {
   155  		var server Server
   156  		var conn *testingConnection
   157  		BeforeEach(func(done Done) {
   158  			server, conn = connect(&invocationHub{})
   159  			close(done)
   160  		})
   161  		AfterEach(func(done Done) {
   162  			server.cancel()
   163  			close(done)
   164  		})
   165  		Context("when invalid json is received", func() {
   166  			It("should close the connection with an error", func(done Done) {
   167  				conn.ClientSend(`{"type":1,"invocationId": "4444","target":"simpleint", arguments[CanNotParse]}`)
   168  				select {
   169  				case message := <-conn.received:
   170  					Expect(message).To(BeAssignableToTypeOf(closeMessage{}))
   171  					Expect(message.(closeMessage).Error).NotTo(BeNil())
   172  				case <-time.After(1000 * time.Millisecond):
   173  					Fail("timed out")
   174  				}
   175  				close(done)
   176  			}, 2.0)
   177  		})
   178  	})
   179  
   180  	Describe("SimpleInt invocation", func() {
   181  		var server Server
   182  		var conn *testingConnection
   183  		BeforeEach(func(done Done) {
   184  			server, conn = connect(&invocationHub{})
   185  			close(done)
   186  		})
   187  		AfterEach(func(done Done) {
   188  			server.cancel()
   189  			close(done)
   190  		})
   191  		Context("When invoked by the client", func() {
   192  			It("should be invoked on the server, get an int and return an int", func(done Done) {
   193  				var value = 314
   194  				conn.ClientSend(fmt.Sprintf(
   195  					`{"type":1,"invocationId": "666","target":"simpleint","arguments":[%v]}`, value))
   196  				Expect(<-invocationQueue).To(Equal(fmt.Sprintf("SimpleInt(%v)", value)))
   197  				recv := (<-conn.received).(completionMessage)
   198  				Expect(recv).NotTo(BeNil())
   199  				Expect(recv.InvocationID).To(Equal("666"))
   200  				Expect(recv.Result).To(Equal(float64(value + 1))) // json  makes all numbers float64
   201  				Expect(recv.Error).To(Equal(""))
   202  				close(done)
   203  			}, 2.0)
   204  		})
   205  	})
   206  
   207  	Describe("SimpleInt invocation with invalid argument", func() {
   208  		var server Server
   209  		var conn *testingConnection
   210  		BeforeEach(func(done Done) {
   211  			server, conn = connect(&invocationHub{})
   212  			close(done)
   213  		})
   214  		AfterEach(func(done Done) {
   215  			server.cancel()
   216  			close(done)
   217  		})
   218  		Context("When invoked by the client with an invalid argument", func() {
   219  			It("should not be invoked on the server and return an error", func(done Done) {
   220  				conn.ClientSend(
   221  					`{"type":1,"invocationId": "555","target":"simpleint","arguments":["CantParse"]}`)
   222  				recv := (<-conn.received).(completionMessage)
   223  				Expect(recv).NotTo(BeNil())
   224  				Expect(recv.Error).NotTo(Equal(""))
   225  				Expect(recv.InvocationID).To(Equal("555"))
   226  				close(done)
   227  			}, 2.0)
   228  		})
   229  	})
   230  
   231  	Describe("SimpleFloat invocation", func() {
   232  		var server Server
   233  		var conn *testingConnection
   234  		BeforeEach(func(done Done) {
   235  			server, conn = connect(&invocationHub{})
   236  			close(done)
   237  		})
   238  		AfterEach(func(done Done) {
   239  			server.cancel()
   240  			close(done)
   241  		})
   242  		Context("When invoked by the client", func() {
   243  			It("should be invoked on the server, get a float and return a two floats", func(done Done) {
   244  				var value = 3.1415
   245  				conn.ClientSend(fmt.Sprintf(
   246  					`{"type":1,"invocationId": "8087","target":"simplefloat","arguments":[%v]}`, value))
   247  				Expect(<-invocationQueue).To(Equal(fmt.Sprintf("SimpleFloat(%v)", value)))
   248  				recv := (<-conn.received).(completionMessage)
   249  				Expect(recv).NotTo(BeNil())
   250  				Expect(recv.InvocationID).To(Equal("8087"))
   251  				Expect(recv.Result).To(Equal([]interface{}{value * 10.0, value * 100.0}))
   252  				Expect(recv.Error).To(Equal(""))
   253  				close(done)
   254  			}, 2.0)
   255  		})
   256  	})
   257  
   258  	Describe("SimpleString invocation", func() {
   259  		var server Server
   260  		var conn *testingConnection
   261  		BeforeEach(func(done Done) {
   262  			server, conn = connect(&invocationHub{})
   263  			close(done)
   264  		})
   265  		AfterEach(func(done Done) {
   266  			server.cancel()
   267  			close(done)
   268  		})
   269  		Context("When invoked by the client", func() {
   270  			It("should be invoked on the server, get two strings and return a string", func(done Done) {
   271  				value1 := "Camel"
   272  				value2 := "Cased"
   273  				conn.ClientSend(fmt.Sprintf(
   274  					`{"type":1,"invocationId": "6502","target":"simplestring","arguments":["%v", "%v"]}`, value1, value2))
   275  				Expect(<-invocationQueue).To(Equal(fmt.Sprintf("SimpleString(%v, %v)", value1, value2)))
   276  				recv := (<-conn.received).(completionMessage)
   277  				Expect(recv).NotTo(BeNil())
   278  				Expect(recv.InvocationID).To(Equal("6502"))
   279  				Expect(recv.Result).To(Equal(strings.ToLower(value1 + value2)))
   280  				Expect(recv.Error).To(Equal(""))
   281  				close(done)
   282  			}, 2.0)
   283  		})
   284  	})
   285  
   286  	Describe("Async invocation", func() {
   287  		var server Server
   288  		var conn *testingConnection
   289  		BeforeEach(func(done Done) {
   290  			server, conn = connect(&invocationHub{})
   291  			close(done)
   292  		})
   293  		AfterEach(func(done Done) {
   294  			server.cancel()
   295  			close(done)
   296  		})
   297  		Context("When invoked by the client", func() {
   298  			It("should be invoked on the server and return true asynchronously", func(done Done) {
   299  				conn.ClientSend(`{"type":1,"invocationId": "mfg","target":"async"}`)
   300  				Expect(<-invocationQueue).To(Equal("Async()"))
   301  				recv := (<-conn.received).(completionMessage)
   302  				Expect(recv).NotTo(BeNil())
   303  				Expect(recv.InvocationID).To(Equal("mfg"))
   304  				Expect(recv.Result).To(Equal(true))
   305  				Expect(recv.Error).To(Equal(""))
   306  				close(done)
   307  			}, 2.0)
   308  		})
   309  	})
   310  
   311  	Describe("Async invocation with buggy server method which returns a closed channel", func() {
   312  		var server Server
   313  		var conn *testingConnection
   314  		BeforeEach(func(done Done) {
   315  			server, conn = connect(&invocationHub{})
   316  			close(done)
   317  		})
   318  		AfterEach(func(done Done) {
   319  			server.cancel()
   320  			close(done)
   321  		})
   322  		Context("When invoked by the client", func() {
   323  			It("should be invoked on the server and return an error", func(done Done) {
   324  				conn.ClientSend(`{"type":1,"invocationId": "ouch","target":"asyncclosedchan"}`)
   325  				Expect(<-invocationQueue).To(Equal("AsyncClosedChan()"))
   326  				recv := (<-conn.received).(completionMessage)
   327  				Expect(recv).NotTo(BeNil())
   328  				Expect(recv.InvocationID).To(Equal("ouch"))
   329  				Expect(recv.Result).To(BeNil())
   330  				Expect(recv.Error).NotTo(BeNil())
   331  				close(done)
   332  			}, 2.0)
   333  		})
   334  	})
   335  
   336  	Describe("Panic in invoked func", func() {
   337  		var server Server
   338  		var conn *testingConnection
   339  		BeforeEach(func(done Done) {
   340  			server, conn = connect(&invocationHub{})
   341  			close(done)
   342  		})
   343  		AfterEach(func(done Done) {
   344  			server.cancel()
   345  			close(done)
   346  		})
   347  
   348  		Context("When a func is invoked by the client and panics", func() {
   349  			It("should be invoked on the server and return an error but no result", func(done Done) {
   350  				conn.ClientSend(`{"type":1,"invocationId": "???","target":"panic"}`)
   351  				Expect(<-invocationQueue).To(Equal("Panic()"))
   352  				recv := (<-conn.received).(completionMessage)
   353  				Expect(recv).NotTo(BeNil())
   354  				Expect(recv.InvocationID).To(Equal("???"))
   355  				Expect(recv.Result).To(BeNil())
   356  				Expect(recv.Error).NotTo(Equal(""))
   357  				close(done)
   358  			}, 2.0)
   359  		})
   360  	})
   361  
   362  	Describe("Missing method invocation", func() {
   363  		var server Server
   364  		var conn *testingConnection
   365  		BeforeEach(func(done Done) {
   366  			server, conn = connect(&invocationHub{})
   367  			close(done)
   368  		})
   369  		AfterEach(func(done Done) {
   370  			server.cancel()
   371  			close(done)
   372  		})
   373  		Context("When a missing server method invoked by the client", func() {
   374  			It("should return an error", func(done Done) {
   375  				conn.ClientSend(`{"type":1,"invocationId": "0000","target":"missing"}`)
   376  				recv := (<-conn.received).(completionMessage)
   377  				Expect(recv).NotTo(BeNil())
   378  				Expect(recv.InvocationID).To(Equal("0000"))
   379  				Expect(recv.Result).To(BeNil())
   380  				Expect(recv.Error).NotTo(BeNil())
   381  				Expect(len(recv.Error)).To(BeNumerically(">", 0))
   382  				close(done)
   383  			}, 2.0)
   384  		})
   385  	})
   386  
   387  })