Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

326 linhas
9.4 KiB

  1. // Copyright 2017 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package pubsub
  15. // TODO(jba): test keepalive
  16. // TODO(jba): test that expired messages are not kept alive
  17. // TODO(jba): test that when all messages expire, Stop returns.
  18. import (
  19. "io"
  20. "strconv"
  21. "sync"
  22. "sync/atomic"
  23. "testing"
  24. "time"
  25. "cloud.google.com/go/internal/testutil"
  26. "google.golang.org/grpc/status"
  27. tspb "github.com/golang/protobuf/ptypes/timestamp"
  28. "github.com/google/go-cmp/cmp"
  29. "github.com/google/go-cmp/cmp/cmpopts"
  30. "golang.org/x/net/context"
  31. "google.golang.org/api/option"
  32. pb "google.golang.org/genproto/googleapis/pubsub/v1"
  33. "google.golang.org/grpc"
  34. "google.golang.org/grpc/codes"
  35. )
  36. var (
  37. timestamp = &tspb.Timestamp{}
  38. testMessages = []*pb.ReceivedMessage{
  39. {AckId: "0", Message: &pb.PubsubMessage{Data: []byte{1}, PublishTime: timestamp}},
  40. {AckId: "1", Message: &pb.PubsubMessage{Data: []byte{2}, PublishTime: timestamp}},
  41. {AckId: "2", Message: &pb.PubsubMessage{Data: []byte{3}, PublishTime: timestamp}},
  42. }
  43. )
  44. func TestStreamingPullBasic(t *testing.T) {
  45. client, server := newFake(t)
  46. server.addStreamingPullMessages(testMessages)
  47. testStreamingPullIteration(t, client, server, testMessages)
  48. }
  49. func TestStreamingPullMultipleFetches(t *testing.T) {
  50. client, server := newFake(t)
  51. server.addStreamingPullMessages(testMessages[:1])
  52. server.addStreamingPullMessages(testMessages[1:])
  53. testStreamingPullIteration(t, client, server, testMessages)
  54. }
  55. func newTestSubscription(t *testing.T, client *Client, name string) *Subscription {
  56. topic := client.Topic("t")
  57. sub, err := client.CreateSubscription(context.Background(), name,
  58. SubscriptionConfig{Topic: topic})
  59. if err != nil {
  60. t.Fatalf("CreateSubscription: %v", err)
  61. }
  62. return sub
  63. }
  64. func testStreamingPullIteration(t *testing.T, client *Client, server *fakeServer, msgs []*pb.ReceivedMessage) {
  65. sub := newTestSubscription(t, client, "s")
  66. gotMsgs, err := pullN(context.Background(), sub, len(msgs), func(_ context.Context, m *Message) {
  67. id, err := strconv.Atoi(m.ackID)
  68. if err != nil {
  69. panic(err)
  70. }
  71. // ack evens, nack odds
  72. if id%2 == 0 {
  73. m.Ack()
  74. } else {
  75. m.Nack()
  76. }
  77. })
  78. if err != nil {
  79. t.Fatalf("Pull: %v", err)
  80. }
  81. gotMap := map[string]*Message{}
  82. for _, m := range gotMsgs {
  83. gotMap[m.ackID] = m
  84. }
  85. for i, msg := range msgs {
  86. want, err := toMessage(msg)
  87. if err != nil {
  88. t.Fatal(err)
  89. }
  90. want.calledDone = true
  91. got := gotMap[want.ackID]
  92. if got == nil {
  93. t.Errorf("%d: no message for ackID %q", i, want.ackID)
  94. continue
  95. }
  96. if !testutil.Equal(got, want, cmp.AllowUnexported(Message{}), cmpopts.IgnoreTypes(time.Time{}, func(string, bool, time.Time) {})) {
  97. t.Errorf("%d: got\n%#v\nwant\n%#v", i, got, want)
  98. }
  99. }
  100. server.wait()
  101. for i := 0; i < len(msgs); i++ {
  102. id := msgs[i].AckId
  103. if i%2 == 0 {
  104. if !server.Acked[id] {
  105. t.Errorf("msg %q should have been acked but wasn't", id)
  106. }
  107. } else {
  108. if dl, ok := server.Deadlines[id]; !ok || dl != 0 {
  109. t.Errorf("msg %q should have been nacked but wasn't", id)
  110. }
  111. }
  112. }
  113. }
  114. func TestStreamingPullError(t *testing.T) {
  115. // If an RPC to the service returns a non-retryable error, Pull should
  116. // return after all callbacks return, without waiting for messages to be
  117. // acked.
  118. client, server := newFake(t)
  119. server.addStreamingPullMessages(testMessages[:1])
  120. server.addStreamingPullError(status.Errorf(codes.Unknown, ""))
  121. sub := newTestSubscription(t, client, "s")
  122. // Use only one goroutine, since the fake server is configured to
  123. // return only one error.
  124. sub.ReceiveSettings.NumGoroutines = 1
  125. callbackDone := make(chan struct{})
  126. ctx, _ := context.WithTimeout(context.Background(), time.Second)
  127. err := sub.Receive(ctx, func(ctx context.Context, m *Message) {
  128. defer close(callbackDone)
  129. select {
  130. case <-ctx.Done():
  131. return
  132. }
  133. })
  134. select {
  135. case <-callbackDone:
  136. default:
  137. t.Fatal("Receive returned but callback was not done")
  138. }
  139. if want := codes.Unknown; grpc.Code(err) != want {
  140. t.Fatalf("got <%v>, want code %v", err, want)
  141. }
  142. }
  143. func TestStreamingPullCancel(t *testing.T) {
  144. // If Receive's context is canceled, it should return after all callbacks
  145. // return and all messages have been acked.
  146. client, server := newFake(t)
  147. server.addStreamingPullMessages(testMessages)
  148. sub := newTestSubscription(t, client, "s")
  149. ctx, cancel := context.WithTimeout(context.Background(), time.Second)
  150. var n int32
  151. err := sub.Receive(ctx, func(ctx2 context.Context, m *Message) {
  152. atomic.AddInt32(&n, 1)
  153. defer atomic.AddInt32(&n, -1)
  154. cancel()
  155. m.Ack()
  156. })
  157. if got := atomic.LoadInt32(&n); got != 0 {
  158. t.Errorf("Receive returned with %d callbacks still running", got)
  159. }
  160. if err != nil {
  161. t.Fatalf("Receive got <%v>, want nil", err)
  162. }
  163. }
  164. func TestStreamingPullRetry(t *testing.T) {
  165. // Check that we retry on io.EOF or Unavailable.
  166. client, server := newFake(t)
  167. server.addStreamingPullMessages(testMessages[:1])
  168. server.addStreamingPullError(io.EOF)
  169. server.addStreamingPullError(io.EOF)
  170. server.addStreamingPullMessages(testMessages[1:2])
  171. server.addStreamingPullError(status.Errorf(codes.Unavailable, ""))
  172. server.addStreamingPullError(status.Errorf(codes.Unavailable, ""))
  173. server.addStreamingPullMessages(testMessages[2:])
  174. testStreamingPullIteration(t, client, server, testMessages)
  175. }
  176. func TestStreamingPullOneActive(t *testing.T) {
  177. // Only one call to Pull can be active at a time.
  178. client, srv := newFake(t)
  179. srv.addStreamingPullMessages(testMessages[:1])
  180. sub := newTestSubscription(t, client, "s")
  181. ctx, cancel := context.WithCancel(context.Background())
  182. err := sub.Receive(ctx, func(ctx context.Context, m *Message) {
  183. m.Ack()
  184. err := sub.Receive(ctx, func(context.Context, *Message) {})
  185. if err != errReceiveInProgress {
  186. t.Errorf("got <%v>, want <%v>", err, errReceiveInProgress)
  187. }
  188. cancel()
  189. })
  190. if err != nil {
  191. t.Fatalf("got <%v>, want nil", err)
  192. }
  193. }
  194. func TestStreamingPullConcurrent(t *testing.T) {
  195. newMsg := func(i int) *pb.ReceivedMessage {
  196. return &pb.ReceivedMessage{
  197. AckId: strconv.Itoa(i),
  198. Message: &pb.PubsubMessage{Data: []byte{byte(i)}, PublishTime: timestamp},
  199. }
  200. }
  201. // Multiple goroutines should be able to read from the same iterator.
  202. client, server := newFake(t)
  203. // Add a lot of messages, a few at a time, to make sure both threads get a chance.
  204. nMessages := 100
  205. for i := 0; i < nMessages; i += 2 {
  206. server.addStreamingPullMessages([]*pb.ReceivedMessage{newMsg(i), newMsg(i + 1)})
  207. }
  208. sub := newTestSubscription(t, client, "s")
  209. ctx, _ := context.WithTimeout(context.Background(), time.Second)
  210. gotMsgs, err := pullN(ctx, sub, nMessages, func(ctx context.Context, m *Message) {
  211. m.Ack()
  212. })
  213. if err != nil {
  214. t.Fatalf("Receive: %v", err)
  215. }
  216. seen := map[string]bool{}
  217. for _, gm := range gotMsgs {
  218. if seen[gm.ackID] {
  219. t.Fatalf("duplicate ID %q", gm.ackID)
  220. }
  221. seen[gm.ackID] = true
  222. }
  223. if len(seen) != nMessages {
  224. t.Fatalf("got %d messages, want %d", len(seen), nMessages)
  225. }
  226. }
  227. func TestStreamingPullFlowControl(t *testing.T) {
  228. // Callback invocations should not occur if flow control limits are exceeded.
  229. client, server := newFake(t)
  230. server.addStreamingPullMessages(testMessages)
  231. sub := newTestSubscription(t, client, "s")
  232. sub.ReceiveSettings.MaxOutstandingMessages = 2
  233. ctx, cancel := context.WithCancel(context.Background())
  234. activec := make(chan int)
  235. waitc := make(chan int)
  236. errc := make(chan error)
  237. go func() {
  238. errc <- sub.Receive(ctx, func(_ context.Context, m *Message) {
  239. activec <- 1
  240. <-waitc
  241. m.Ack()
  242. })
  243. }()
  244. // Here, two callbacks are active. Receive should be blocked in the flow
  245. // control acquire method on the third message.
  246. <-activec
  247. <-activec
  248. select {
  249. case <-activec:
  250. t.Fatal("third callback in progress")
  251. case <-time.After(100 * time.Millisecond):
  252. }
  253. cancel()
  254. // Receive still has not returned, because both callbacks are still blocked on waitc.
  255. select {
  256. case err := <-errc:
  257. t.Fatalf("Receive returned early with error %v", err)
  258. case <-time.After(100 * time.Millisecond):
  259. }
  260. // Let both callbacks proceed.
  261. waitc <- 1
  262. waitc <- 1
  263. // The third callback will never run, because acquire returned a non-nil
  264. // error, causing Receive to return. So now Receive should end.
  265. if err := <-errc; err != nil {
  266. t.Fatalf("got %v from Receive, want nil", err)
  267. }
  268. }
  269. func newFake(t *testing.T) (*Client, *fakeServer) {
  270. srv, err := newFakeServer()
  271. if err != nil {
  272. t.Fatal(err)
  273. }
  274. conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure())
  275. if err != nil {
  276. t.Fatal(err)
  277. }
  278. client, err := NewClient(context.Background(), "projectID", option.WithGRPCConn(conn))
  279. if err != nil {
  280. t.Fatal(err)
  281. }
  282. return client, srv
  283. }
  284. // pullN calls sub.Receive until at least n messages are received.
  285. func pullN(ctx context.Context, sub *Subscription, n int, f func(context.Context, *Message)) ([]*Message, error) {
  286. var (
  287. mu sync.Mutex
  288. msgs []*Message
  289. )
  290. cctx, cancel := context.WithCancel(ctx)
  291. err := sub.Receive(cctx, func(ctx context.Context, m *Message) {
  292. mu.Lock()
  293. msgs = append(msgs, m)
  294. nSeen := len(msgs)
  295. mu.Unlock()
  296. f(ctx, m)
  297. if nSeen >= n {
  298. cancel()
  299. }
  300. })
  301. if err != nil {
  302. return nil, err
  303. }
  304. return msgs, nil
  305. }