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 })