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

     1  package signalr
     2  
     3  import (
     4  	"time"
     5  
     6  	. "github.com/onsi/ginkgo"
     7  	. "github.com/onsi/gomega"
     8  )
     9  
    10  var streamInvocationQueue = make(chan string, 20)
    11  
    12  type streamHub struct {
    13  	Hub
    14  }
    15  
    16  func (s *streamHub) SimpleStream() <-chan int {
    17  	r := make(chan int)
    18  	go func() {
    19  		defer close(r)
    20  		for i := 1; i < 4; i++ {
    21  			r <- i
    22  		}
    23  	}()
    24  	streamInvocationQueue <- "SimpleStream()"
    25  	return r
    26  }
    27  
    28  func (s *streamHub) EndlessStream() <-chan int {
    29  	r := make(chan int)
    30  	go func() {
    31  		defer close(r)
    32  		for i := 1; ; i++ {
    33  			r <- i
    34  		}
    35  	}()
    36  	streamInvocationQueue <- "EndlessStream()"
    37  	return r
    38  }
    39  
    40  func (s *streamHub) SliceStream() <-chan []int {
    41  	r := make(chan []int)
    42  	go func() {
    43  		defer close(r)
    44  		for i := 1; i < 4; i++ {
    45  			s := make([]int, 2)
    46  			s[0] = i
    47  			s[1] = i * 2
    48  			r <- s
    49  		}
    50  	}()
    51  	streamInvocationQueue <- "SliceStream()"
    52  	return r
    53  }
    54  
    55  func (s *streamHub) SimpleInt() int {
    56  	streamInvocationQueue <- "SimpleInt()"
    57  	return -1
    58  }
    59  
    60  var _ = Describe("StreamInvocation", func() {
    61  
    62  	Describe("Simple stream invocation", func() {
    63  		var server Server
    64  		var conn *testingConnection
    65  		BeforeEach(func(done Done) {
    66  			server, conn = connect(&streamHub{})
    67  			close(done)
    68  		})
    69  		AfterEach(func(done Done) {
    70  			server.cancel()
    71  			close(done)
    72  		})
    73  		Context("When invoked by the client", func() {
    74  			It("should be invoked on the server, return stream items and a final completion without result", func(done Done) {
    75  				p := &jsonHubProtocol{dbg: testLogger()}
    76  				conn.ClientSend(`{"type":4,"invocationId": "zzz","target":"simplestream"}`)
    77  				Expect(<-streamInvocationQueue).To(Equal("SimpleStream()"))
    78  				for i := 1; i < 4; i++ {
    79  					recv := (<-conn.received).(streamItemMessage)
    80  					Expect(recv).NotTo(BeNil())
    81  					Expect(recv.InvocationID).To(Equal("zzz"))
    82  					var f float64
    83  					Expect(p.UnmarshalArgument(recv.Item, &f)).NotTo(HaveOccurred())
    84  					Expect(f).To(Equal(float64(i)))
    85  				}
    86  				recv := (<-conn.received).(completionMessage)
    87  				Expect(recv).NotTo(BeNil())
    88  				Expect(recv.InvocationID).To(Equal("zzz"))
    89  				Expect(recv.Result).To(BeNil())
    90  				Expect(recv.Error).To(Equal(""))
    91  				close(done)
    92  			})
    93  		})
    94  	})
    95  
    96  	Describe("Slice stream invocation", func() {
    97  		var server Server
    98  		var conn *testingConnection
    99  		BeforeEach(func(done Done) {
   100  			server, conn = connect(&streamHub{})
   101  			close(done)
   102  		})
   103  		AfterEach(func(done Done) {
   104  			server.cancel()
   105  			close(done)
   106  		})
   107  		Context("When invoked by the client", func() {
   108  			It("should be invoked on the server, return stream items and a final completion without result", func(done Done) {
   109  				protocol := jsonHubProtocol{dbg: testLogger()}
   110  				conn.ClientSend(`{"type":4,"invocationId": "slice","target":"slicestream"}`)
   111  				Expect(<-streamInvocationQueue).To(Equal("SliceStream()"))
   112  				for i := 1; i < 4; i++ {
   113  					recv := (<-conn.received).(streamItemMessage)
   114  					Expect(recv).NotTo(BeNil())
   115  					Expect(recv.InvocationID).To(Equal("slice"))
   116  					exp := make([]int, 0, 2)
   117  					exp = append(exp, i)
   118  					exp = append(exp, i*2)
   119  					var got []int
   120  					Expect(protocol.UnmarshalArgument(recv.Item, &got)).NotTo(HaveOccurred())
   121  					Expect(got).To(Equal(exp))
   122  				}
   123  				recv := (<-conn.received).(completionMessage)
   124  				Expect(recv).NotTo(BeNil())
   125  				Expect(recv.InvocationID).To(Equal("slice"))
   126  				Expect(recv.Result).To(BeNil())
   127  				Expect(recv.Error).To(Equal(""))
   128  				close(done)
   129  			})
   130  		})
   131  	})
   132  
   133  	Describe("Stop simple stream invocation", func() {
   134  		var server Server
   135  		var conn *testingConnection
   136  		BeforeEach(func(done Done) {
   137  			server, conn = connect(&streamHub{})
   138  			close(done)
   139  		})
   140  		AfterEach(func(done Done) {
   141  			server.cancel()
   142  			close(done)
   143  		})
   144  		Context("When invoked by the client and stop after one result", func() {
   145  			It("should be invoked on the server, return stream one item and a final completion without result", func(done Done) {
   146  				protocol := jsonHubProtocol{dbg: testLogger()}
   147  				conn.ClientSend(`{"type":4,"invocationId": "xxx","target":"endlessstream"}`)
   148  				Expect(<-streamInvocationQueue).To(Equal("EndlessStream()"))
   149  				recv := (<-conn.received).(streamItemMessage)
   150  				Expect(recv).NotTo(BeNil())
   151  				Expect(recv.InvocationID).To(Equal("xxx"))
   152  				var got int
   153  				Expect(protocol.UnmarshalArgument(recv.Item, &got)).NotTo(HaveOccurred())
   154  				Expect(got).To(Equal(1))
   155  				// stop it
   156  				conn.ClientSend(`{"type":5,"invocationId": "xxx"}`)
   157  			loop:
   158  				for {
   159  					recv := <-conn.received
   160  					Expect(recv).NotTo(BeNil())
   161  					switch recv := recv.(type) {
   162  					case streamItemMessage:
   163  						Expect(recv.InvocationID).To(Equal("xxx"))
   164  					case completionMessage:
   165  						Expect(recv.InvocationID).To(Equal("xxx"))
   166  						Expect(recv.Result).To(BeNil())
   167  						Expect(recv.Error).To(Equal(""))
   168  						break loop
   169  					}
   170  				}
   171  				close(done)
   172  			})
   173  		})
   174  	})
   175  
   176  	Describe("Invalid CancelInvocation", func() {
   177  		var server Server
   178  		var conn *testingConnection
   179  		BeforeEach(func(done Done) {
   180  			server, conn = connect(&streamHub{})
   181  			close(done)
   182  		})
   183  		AfterEach(func(done Done) {
   184  			server.cancel()
   185  			close(done)
   186  		})
   187  		Context("When invoked by the client and receiving an invalid CancelInvocation", func() {
   188  			It("should close the connection with an error", func(done Done) {
   189  				protocol := &jsonHubProtocol{dbg: testLogger()}
   190  				conn.ClientSend(`{"type":4,"invocationId": "xyz","target":"endlessstream"}`)
   191  				Expect(<-streamInvocationQueue).To(Equal("EndlessStream()"))
   192  				recv := (<-conn.received).(streamItemMessage)
   193  				Expect(recv).NotTo(BeNil())
   194  				Expect(recv.InvocationID).To(Equal("xyz"))
   195  				var got int
   196  				Expect(protocol.UnmarshalArgument(recv.Item, &got)).NotTo(HaveOccurred())
   197  				Expect(got).To(Equal(1))
   198  				// try to stop it, but do not get it right
   199  				conn.ClientSend(`{"type":5,"invocationId":1}`)
   200  			loop:
   201  				for {
   202  					message := <-conn.received
   203  					switch message := message.(type) {
   204  					case closeMessage:
   205  						Expect(message.Error).NotTo(BeNil())
   206  						break loop
   207  					default:
   208  					}
   209  				}
   210  				close(done)
   211  			})
   212  		})
   213  	})
   214  
   215  	Describe("Stream invocation of method with no stream result", func() {
   216  		var server Server
   217  		var conn *testingConnection
   218  		BeforeEach(func(done Done) {
   219  			server, conn = connect(&streamHub{})
   220  			close(done)
   221  		})
   222  		AfterEach(func(done Done) {
   223  			server.cancel()
   224  			close(done)
   225  		})
   226  		Context("When invoked by the client", func() {
   227  			It("should be invoked on the server, return one stream item with the \"no stream\" result and a final completion without result", func(done Done) {
   228  				protocol := &jsonHubProtocol{dbg: testLogger()}
   229  				conn.ClientSend(`{"type":4,"invocationId": "yyy","target":"simpleint"}`)
   230  				Expect(<-streamInvocationQueue).To(Equal("SimpleInt()"))
   231  				sRecv := (<-conn.received).(streamItemMessage)
   232  				Expect(sRecv).NotTo(BeNil())
   233  				Expect(sRecv.InvocationID).To(Equal("yyy"))
   234  				var got int
   235  				Expect(protocol.UnmarshalArgument(sRecv.Item, &got)).NotTo(HaveOccurred())
   236  				Expect(got).To(Equal(-1))
   237  				cRecv := (<-conn.received).(completionMessage)
   238  				Expect(cRecv).NotTo(BeNil())
   239  				Expect(cRecv.InvocationID).To(Equal("yyy"))
   240  				Expect(cRecv.Result).To(BeNil())
   241  				Expect(cRecv.Error).To(Equal(""))
   242  				close(done)
   243  			})
   244  		})
   245  	})
   246  
   247  	Describe("invalid messages", func() {
   248  		var server Server
   249  		var conn *testingConnection
   250  		BeforeEach(func(done Done) {
   251  			server, conn = connect(&streamHub{})
   252  			close(done)
   253  		})
   254  		AfterEach(func(done Done) {
   255  			server.cancel()
   256  			close(done)
   257  		})
   258  		Context("When an invalid stream invocation message is sent", func() {
   259  			It("should return a completion with error", func(done Done) {
   260  				conn.ClientSend(`{"type":4}`)
   261  				select {
   262  				case message := <-conn.received:
   263  					completionMessage := message.(completionMessage)
   264  					Expect(completionMessage).NotTo(BeNil())
   265  					Expect(completionMessage.Error).NotTo(BeNil())
   266  				case <-time.After(100 * time.Millisecond):
   267  				}
   268  				close(done)
   269  			})
   270  		})
   271  	})
   272  
   273  })