You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

715 lines
21 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 pstest
  15. import (
  16. "context"
  17. "fmt"
  18. "io"
  19. "sync"
  20. "testing"
  21. "time"
  22. "cloud.google.com/go/internal/testutil"
  23. "github.com/golang/protobuf/ptypes"
  24. pb "google.golang.org/genproto/googleapis/pubsub/v1"
  25. "google.golang.org/grpc"
  26. "google.golang.org/grpc/codes"
  27. "google.golang.org/grpc/status"
  28. )
  29. func TestTopics(t *testing.T) {
  30. pclient, _, server, cleanup := newFake(context.TODO(), t)
  31. defer cleanup()
  32. ctx := context.Background()
  33. var topics []*pb.Topic
  34. for i := 1; i < 3; i++ {
  35. topics = append(topics, mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{
  36. Name: fmt.Sprintf("projects/P/topics/T%d", i),
  37. Labels: map[string]string{"num": fmt.Sprintf("%d", i)},
  38. }))
  39. }
  40. if got, want := len(server.GServer.topics), len(topics); got != want {
  41. t.Fatalf("got %d topics, want %d", got, want)
  42. }
  43. for _, top := range topics {
  44. got, err := pclient.GetTopic(ctx, &pb.GetTopicRequest{Topic: top.Name})
  45. if err != nil {
  46. t.Fatal(err)
  47. }
  48. if !testutil.Equal(got, top) {
  49. t.Errorf("\ngot %+v\nwant %+v", got, top)
  50. }
  51. }
  52. res, err := pclient.ListTopics(ctx, &pb.ListTopicsRequest{Project: "projects/P"})
  53. if err != nil {
  54. t.Fatal(err)
  55. }
  56. if got, want := res.Topics, topics; !testutil.Equal(got, want) {
  57. t.Errorf("\ngot %+v\nwant %+v", got, want)
  58. }
  59. for _, top := range topics {
  60. if _, err := pclient.DeleteTopic(ctx, &pb.DeleteTopicRequest{Topic: top.Name}); err != nil {
  61. t.Fatal(err)
  62. }
  63. }
  64. if got, want := len(server.GServer.topics), 0; got != want {
  65. t.Fatalf("got %d topics, want %d", got, want)
  66. }
  67. }
  68. func TestSubscriptions(t *testing.T) {
  69. pclient, sclient, server, cleanup := newFake(context.TODO(), t)
  70. defer cleanup()
  71. ctx := context.Background()
  72. topic := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  73. var subs []*pb.Subscription
  74. for i := 0; i < 3; i++ {
  75. subs = append(subs, mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
  76. Name: fmt.Sprintf("projects/P/subscriptions/S%d", i),
  77. Topic: topic.Name,
  78. AckDeadlineSeconds: int32(10 * (i + 1)),
  79. }))
  80. }
  81. if got, want := len(server.GServer.subs), len(subs); got != want {
  82. t.Fatalf("got %d subscriptions, want %d", got, want)
  83. }
  84. for _, s := range subs {
  85. got, err := sclient.GetSubscription(ctx, &pb.GetSubscriptionRequest{Subscription: s.Name})
  86. if err != nil {
  87. t.Fatal(err)
  88. }
  89. if !testutil.Equal(got, s) {
  90. t.Errorf("\ngot %+v\nwant %+v", got, s)
  91. }
  92. }
  93. res, err := sclient.ListSubscriptions(ctx, &pb.ListSubscriptionsRequest{Project: "projects/P"})
  94. if err != nil {
  95. t.Fatal(err)
  96. }
  97. if got, want := res.Subscriptions, subs; !testutil.Equal(got, want) {
  98. t.Errorf("\ngot %+v\nwant %+v", got, want)
  99. }
  100. res2, err := pclient.ListTopicSubscriptions(ctx, &pb.ListTopicSubscriptionsRequest{Topic: topic.Name})
  101. if err != nil {
  102. t.Fatal(err)
  103. }
  104. if got, want := len(res2.Subscriptions), len(subs); got != want {
  105. t.Fatalf("got %d subs, want %d", got, want)
  106. }
  107. for i, got := range res2.Subscriptions {
  108. want := subs[i].Name
  109. if !testutil.Equal(got, want) {
  110. t.Errorf("\ngot %+v\nwant %+v", got, want)
  111. }
  112. }
  113. for _, s := range subs {
  114. if _, err := sclient.DeleteSubscription(ctx, &pb.DeleteSubscriptionRequest{Subscription: s.Name}); err != nil {
  115. t.Fatal(err)
  116. }
  117. }
  118. if got, want := len(server.GServer.subs), 0; got != want {
  119. t.Fatalf("got %d subscriptions, want %d", got, want)
  120. }
  121. }
  122. func TestSubscriptionErrors(t *testing.T) {
  123. _, sclient, _, cleanup := newFake(context.TODO(), t)
  124. defer cleanup()
  125. ctx := context.Background()
  126. checkCode := func(err error, want codes.Code) {
  127. t.Helper()
  128. if status.Code(err) != want {
  129. t.Errorf("got %v, want code %s", err, want)
  130. }
  131. }
  132. _, err := sclient.GetSubscription(ctx, &pb.GetSubscriptionRequest{})
  133. checkCode(err, codes.InvalidArgument)
  134. _, err = sclient.GetSubscription(ctx, &pb.GetSubscriptionRequest{Subscription: "s"})
  135. checkCode(err, codes.NotFound)
  136. _, err = sclient.UpdateSubscription(ctx, &pb.UpdateSubscriptionRequest{})
  137. checkCode(err, codes.InvalidArgument)
  138. _, err = sclient.UpdateSubscription(ctx, &pb.UpdateSubscriptionRequest{Subscription: &pb.Subscription{}})
  139. checkCode(err, codes.InvalidArgument)
  140. _, err = sclient.UpdateSubscription(ctx, &pb.UpdateSubscriptionRequest{Subscription: &pb.Subscription{Name: "s"}})
  141. checkCode(err, codes.NotFound)
  142. _, err = sclient.DeleteSubscription(ctx, &pb.DeleteSubscriptionRequest{})
  143. checkCode(err, codes.InvalidArgument)
  144. _, err = sclient.DeleteSubscription(ctx, &pb.DeleteSubscriptionRequest{Subscription: "s"})
  145. checkCode(err, codes.NotFound)
  146. _, err = sclient.Acknowledge(ctx, &pb.AcknowledgeRequest{})
  147. checkCode(err, codes.InvalidArgument)
  148. _, err = sclient.Acknowledge(ctx, &pb.AcknowledgeRequest{Subscription: "s"})
  149. checkCode(err, codes.NotFound)
  150. _, err = sclient.ModifyAckDeadline(ctx, &pb.ModifyAckDeadlineRequest{})
  151. checkCode(err, codes.InvalidArgument)
  152. _, err = sclient.ModifyAckDeadline(ctx, &pb.ModifyAckDeadlineRequest{Subscription: "s"})
  153. checkCode(err, codes.NotFound)
  154. _, err = sclient.Pull(ctx, &pb.PullRequest{})
  155. checkCode(err, codes.InvalidArgument)
  156. _, err = sclient.Pull(ctx, &pb.PullRequest{Subscription: "s"})
  157. checkCode(err, codes.NotFound)
  158. _, err = sclient.Seek(ctx, &pb.SeekRequest{})
  159. checkCode(err, codes.InvalidArgument)
  160. srt := &pb.SeekRequest_Time{Time: ptypes.TimestampNow()}
  161. _, err = sclient.Seek(ctx, &pb.SeekRequest{Target: srt})
  162. checkCode(err, codes.InvalidArgument)
  163. _, err = sclient.Seek(ctx, &pb.SeekRequest{Target: srt, Subscription: "s"})
  164. checkCode(err, codes.NotFound)
  165. }
  166. func TestPublish(t *testing.T) {
  167. s := NewServer()
  168. defer s.Close()
  169. var ids []string
  170. for i := 0; i < 3; i++ {
  171. ids = append(ids, s.Publish("projects/p/topics/t", []byte("hello"), nil))
  172. }
  173. s.Wait()
  174. ms := s.Messages()
  175. if got, want := len(ms), len(ids); got != want {
  176. t.Errorf("got %d messages, want %d", got, want)
  177. }
  178. for i, id := range ids {
  179. if got, want := ms[i].ID, id; got != want {
  180. t.Errorf("got %s, want %s", got, want)
  181. }
  182. }
  183. m := s.Message(ids[1])
  184. if m == nil {
  185. t.Error("got nil, want a message")
  186. }
  187. }
  188. // Note: this sets the fake's "now" time, so it is sensitive to concurrent changes to "now".
  189. func publish(t *testing.T, pclient pb.PublisherClient, topic *pb.Topic, messages []*pb.PubsubMessage) map[string]*pb.PubsubMessage {
  190. pubTime := time.Now()
  191. now.Store(func() time.Time { return pubTime })
  192. defer func() { now.Store(time.Now) }()
  193. res, err := pclient.Publish(context.Background(), &pb.PublishRequest{
  194. Topic: topic.Name,
  195. Messages: messages,
  196. })
  197. if err != nil {
  198. t.Fatal(err)
  199. }
  200. tsPubTime, err := ptypes.TimestampProto(pubTime)
  201. if err != nil {
  202. t.Fatal(err)
  203. }
  204. want := map[string]*pb.PubsubMessage{}
  205. for i, id := range res.MessageIds {
  206. want[id] = &pb.PubsubMessage{
  207. Data: messages[i].Data,
  208. Attributes: messages[i].Attributes,
  209. MessageId: id,
  210. PublishTime: tsPubTime,
  211. }
  212. }
  213. return want
  214. }
  215. func TestPull(t *testing.T) {
  216. pclient, sclient, _, cleanup := newFake(context.TODO(), t)
  217. defer cleanup()
  218. top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  219. sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
  220. Name: "projects/P/subscriptions/S",
  221. Topic: top.Name,
  222. AckDeadlineSeconds: 10,
  223. })
  224. want := publish(t, pclient, top, []*pb.PubsubMessage{
  225. {Data: []byte("d1")},
  226. {Data: []byte("d2")},
  227. {Data: []byte("d3")},
  228. })
  229. got := pubsubMessages(pullN(context.TODO(), t, len(want), sclient, sub))
  230. if diff := testutil.Diff(got, want); diff != "" {
  231. t.Error(diff)
  232. }
  233. res, err := sclient.Pull(context.Background(), &pb.PullRequest{Subscription: sub.Name})
  234. if err != nil {
  235. t.Fatal(err)
  236. }
  237. if len(res.ReceivedMessages) != 0 {
  238. t.Errorf("got %d messages, want zero", len(res.ReceivedMessages))
  239. }
  240. }
  241. func TestStreamingPull(t *testing.T) {
  242. // A simple test of streaming pull.
  243. pclient, sclient, _, cleanup := newFake(context.TODO(), t)
  244. defer cleanup()
  245. top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  246. sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
  247. Name: "projects/P/subscriptions/S",
  248. Topic: top.Name,
  249. AckDeadlineSeconds: 10,
  250. })
  251. want := publish(t, pclient, top, []*pb.PubsubMessage{
  252. {Data: []byte("d1")},
  253. {Data: []byte("d2")},
  254. {Data: []byte("d3")},
  255. })
  256. got := pubsubMessages(streamingPullN(context.TODO(), t, len(want), sclient, sub))
  257. if diff := testutil.Diff(got, want); diff != "" {
  258. t.Error(diff)
  259. }
  260. }
  261. // This test acks each message as it arrives and makes sure we don't see dups.
  262. func TestStreamingPullAck(t *testing.T) {
  263. minAckDeadlineSecs = 1
  264. pclient, sclient, _, cleanup := newFake(context.TODO(), t)
  265. defer cleanup()
  266. top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  267. sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
  268. Name: "projects/P/subscriptions/S",
  269. Topic: top.Name,
  270. AckDeadlineSeconds: 1,
  271. })
  272. _ = publish(t, pclient, top, []*pb.PubsubMessage{
  273. {Data: []byte("d1")},
  274. {Data: []byte("d2")},
  275. {Data: []byte("d3")},
  276. })
  277. got := map[string]bool{}
  278. ctx, cancel := context.WithCancel(context.Background())
  279. spc := mustStartStreamingPull(ctx, t, sclient, sub)
  280. time.AfterFunc(time.Duration(2*minAckDeadlineSecs)*time.Second, cancel)
  281. for i := 0; i < 4; i++ {
  282. res, err := spc.Recv()
  283. if err == io.EOF {
  284. break
  285. }
  286. if err != nil {
  287. if status.Code(err) == codes.Canceled {
  288. break
  289. }
  290. t.Fatal(err)
  291. }
  292. if i == 3 {
  293. t.Fatal("expected to only see 3 messages, got 4")
  294. }
  295. req := &pb.StreamingPullRequest{}
  296. for _, m := range res.ReceivedMessages {
  297. if got[m.Message.MessageId] {
  298. t.Fatal("duplicate message")
  299. }
  300. got[m.Message.MessageId] = true
  301. req.AckIds = append(req.AckIds, m.AckId)
  302. }
  303. if err := spc.Send(req); err != nil {
  304. t.Fatal(err)
  305. }
  306. }
  307. }
  308. func TestAcknowledge(t *testing.T) {
  309. ctx := context.Background()
  310. pclient, sclient, srv, cleanup := newFake(context.TODO(), t)
  311. defer cleanup()
  312. top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  313. sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
  314. Name: "projects/P/subscriptions/S",
  315. Topic: top.Name,
  316. AckDeadlineSeconds: 10,
  317. })
  318. publish(t, pclient, top, []*pb.PubsubMessage{
  319. {Data: []byte("d1")},
  320. {Data: []byte("d2")},
  321. {Data: []byte("d3")},
  322. })
  323. msgs := streamingPullN(context.TODO(), t, 3, sclient, sub)
  324. var ackIDs []string
  325. for _, m := range msgs {
  326. ackIDs = append(ackIDs, m.AckId)
  327. }
  328. if _, err := sclient.Acknowledge(ctx, &pb.AcknowledgeRequest{
  329. Subscription: sub.Name,
  330. AckIds: ackIDs,
  331. }); err != nil {
  332. t.Fatal(err)
  333. }
  334. smsgs := srv.Messages()
  335. if got, want := len(smsgs), 3; got != want {
  336. t.Fatalf("got %d messages, want %d", got, want)
  337. }
  338. for _, sm := range smsgs {
  339. if sm.Acks != 1 {
  340. t.Errorf("message %s: got %d acks, want 1", sm.ID, sm.Acks)
  341. }
  342. }
  343. }
  344. func TestModAck(t *testing.T) {
  345. ctx := context.Background()
  346. pclient, sclient, _, cleanup := newFake(context.TODO(), t)
  347. defer cleanup()
  348. top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  349. sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
  350. Name: "projects/P/subscriptions/S",
  351. Topic: top.Name,
  352. AckDeadlineSeconds: 10,
  353. })
  354. publish(t, pclient, top, []*pb.PubsubMessage{
  355. {Data: []byte("d1")},
  356. {Data: []byte("d2")},
  357. {Data: []byte("d3")},
  358. })
  359. msgs := streamingPullN(context.TODO(), t, 3, sclient, sub)
  360. var ackIDs []string
  361. for _, m := range msgs {
  362. ackIDs = append(ackIDs, m.AckId)
  363. }
  364. if _, err := sclient.ModifyAckDeadline(ctx, &pb.ModifyAckDeadlineRequest{
  365. Subscription: sub.Name,
  366. AckIds: ackIDs,
  367. AckDeadlineSeconds: 0,
  368. }); err != nil {
  369. t.Fatal(err)
  370. }
  371. // Having nacked all three messages, we should see them again.
  372. msgs = streamingPullN(context.TODO(), t, 3, sclient, sub)
  373. if got, want := len(msgs), 3; got != want {
  374. t.Errorf("got %d messages, want %d", got, want)
  375. }
  376. }
  377. func TestAckDeadline(t *testing.T) {
  378. // Messages should be resent after they expire.
  379. pclient, sclient, _, cleanup := newFake(context.TODO(), t)
  380. defer cleanup()
  381. minAckDeadlineSecs = 2
  382. top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  383. sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
  384. Name: "projects/P/subscriptions/S",
  385. Topic: top.Name,
  386. AckDeadlineSeconds: minAckDeadlineSecs,
  387. })
  388. _ = publish(t, pclient, top, []*pb.PubsubMessage{
  389. {Data: []byte("d1")},
  390. {Data: []byte("d2")},
  391. {Data: []byte("d3")},
  392. })
  393. got := map[string]int{}
  394. spc := mustStartStreamingPull(context.TODO(), t, sclient, sub)
  395. // In 5 seconds the ack deadline will expire twice, so we should see each message
  396. // exactly three times.
  397. time.AfterFunc(5*time.Second, func() {
  398. if err := spc.CloseSend(); err != nil {
  399. t.Errorf("CloseSend: %v", err)
  400. }
  401. })
  402. for {
  403. res, err := spc.Recv()
  404. if err == io.EOF {
  405. break
  406. }
  407. if err != nil {
  408. t.Fatal(err)
  409. }
  410. for _, m := range res.ReceivedMessages {
  411. got[m.Message.MessageId]++
  412. }
  413. }
  414. for id, n := range got {
  415. if n != 3 {
  416. t.Errorf("message %s: saw %d times, want 3", id, n)
  417. }
  418. }
  419. }
  420. func TestMultiSubs(t *testing.T) {
  421. // Each subscription gets every message.
  422. pclient, sclient, _, cleanup := newFake(context.TODO(), t)
  423. defer cleanup()
  424. top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  425. sub1 := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
  426. Name: "projects/P/subscriptions/S1",
  427. Topic: top.Name,
  428. AckDeadlineSeconds: 10,
  429. })
  430. sub2 := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
  431. Name: "projects/P/subscriptions/S2",
  432. Topic: top.Name,
  433. AckDeadlineSeconds: 10,
  434. })
  435. want := publish(t, pclient, top, []*pb.PubsubMessage{
  436. {Data: []byte("d1")},
  437. {Data: []byte("d2")},
  438. {Data: []byte("d3")},
  439. })
  440. got1 := pubsubMessages(streamingPullN(context.TODO(), t, len(want), sclient, sub1))
  441. got2 := pubsubMessages(streamingPullN(context.TODO(), t, len(want), sclient, sub2))
  442. if diff := testutil.Diff(got1, want); diff != "" {
  443. t.Error(diff)
  444. }
  445. if diff := testutil.Diff(got2, want); diff != "" {
  446. t.Error(diff)
  447. }
  448. }
  449. // Messages are handed out to all streams of a subscription in a best-effort
  450. // round-robin behavior. The fake server prefers to fail-fast onto another
  451. // stream when one stream is already busy, though, so we're unable to test
  452. // strict round robin behavior.
  453. func TestMultiStreams(t *testing.T) {
  454. ctx, cancel := context.WithCancel(context.Background())
  455. defer cancel()
  456. pclient, sclient, _, cleanup := newFake(ctx, t)
  457. defer cleanup()
  458. top := mustCreateTopic(ctx, t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  459. sub := mustCreateSubscription(ctx, t, sclient, &pb.Subscription{
  460. Name: "projects/P/subscriptions/S",
  461. Topic: top.Name,
  462. AckDeadlineSeconds: 10,
  463. })
  464. st1 := mustStartStreamingPull(ctx, t, sclient, sub)
  465. defer st1.CloseSend()
  466. st1Received := make(chan struct{})
  467. go func() {
  468. _, err := st1.Recv()
  469. if err != nil {
  470. t.Error(err)
  471. }
  472. close(st1Received)
  473. }()
  474. st2 := mustStartStreamingPull(ctx, t, sclient, sub)
  475. defer st2.CloseSend()
  476. st2Received := make(chan struct{})
  477. go func() {
  478. _, err := st2.Recv()
  479. if err != nil {
  480. t.Error(err)
  481. }
  482. close(st2Received)
  483. }()
  484. publish(t, pclient, top, []*pb.PubsubMessage{
  485. {Data: []byte("d1")},
  486. {Data: []byte("d2")},
  487. })
  488. timeout := time.After(5 * time.Second)
  489. select {
  490. case <-timeout:
  491. t.Fatal("timed out waiting for stream 1 to receive any message")
  492. case <-st1Received:
  493. }
  494. select {
  495. case <-timeout:
  496. t.Fatal("timed out waiting for stream 1 to receive any message")
  497. case <-st2Received:
  498. }
  499. }
  500. func TestStreamingPullTimeout(t *testing.T) {
  501. pclient, sclient, srv, cleanup := newFake(context.TODO(), t)
  502. defer cleanup()
  503. timeout := 200 * time.Millisecond
  504. srv.SetStreamTimeout(timeout)
  505. top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  506. sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
  507. Name: "projects/P/subscriptions/S",
  508. Topic: top.Name,
  509. AckDeadlineSeconds: 10,
  510. })
  511. stream := mustStartStreamingPull(context.TODO(), t, sclient, sub)
  512. time.Sleep(2 * timeout)
  513. _, err := stream.Recv()
  514. if err != io.EOF {
  515. t.Errorf("got %v, want io.EOF", err)
  516. }
  517. }
  518. func TestSeek(t *testing.T) {
  519. pclient, sclient, _, cleanup := newFake(context.TODO(), t)
  520. defer cleanup()
  521. top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  522. sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
  523. Name: "projects/P/subscriptions/S",
  524. Topic: top.Name,
  525. AckDeadlineSeconds: 10,
  526. })
  527. ts := ptypes.TimestampNow()
  528. _, err := sclient.Seek(context.Background(), &pb.SeekRequest{
  529. Subscription: sub.Name,
  530. Target: &pb.SeekRequest_Time{Time: ts},
  531. })
  532. if err != nil {
  533. t.Errorf("Seeking: %v", err)
  534. }
  535. }
  536. func TestTryDeliverMessage(t *testing.T) {
  537. for _, test := range []struct {
  538. availStreamIdx int
  539. expectedOutIdx int
  540. }{
  541. {availStreamIdx: 0, expectedOutIdx: 0},
  542. // Stream 1 will always be marked for deletion.
  543. {availStreamIdx: 2, expectedOutIdx: 1}, // s0, s1 (deleted), s2, s3 becomes s0, s2, s3. So we expect outIdx=1.
  544. {availStreamIdx: 3, expectedOutIdx: 2}, // s0, s1 (deleted), s2, s3 becomes s0, s2, s3. So we expect outIdx=2.
  545. } {
  546. top := newTopic(&pb.Topic{Name: "some-topic"})
  547. sub := newSubscription(top, &sync.Mutex{}, &pb.Subscription{Name: "some-sub", Topic: "some-topic"})
  548. done := make(chan struct{}, 1)
  549. done <- struct{}{}
  550. sub.streams = []*stream{{}, {done: done}, {}, {}}
  551. msgc := make(chan *pb.ReceivedMessage, 1)
  552. sub.streams[test.availStreamIdx].msgc = msgc
  553. var d int
  554. idx, ok := sub.tryDeliverMessage(&message{deliveries: &d}, 0, time.Now())
  555. if !ok {
  556. t.Fatalf("[avail=%d]: expected msg to be put on stream %d's channel, but it was not", test.availStreamIdx, test.expectedOutIdx)
  557. }
  558. if idx != test.expectedOutIdx {
  559. t.Fatalf("[avail=%d]: expected msg to be put on stream %d, but it was put on %d", test.availStreamIdx, test.expectedOutIdx, idx)
  560. }
  561. select {
  562. case <-msgc:
  563. default:
  564. t.Fatalf("[avail=%d]: expected msg to be put on stream %d's channel, but it was not", test.availStreamIdx, idx)
  565. }
  566. }
  567. }
  568. func mustStartStreamingPull(ctx context.Context, t *testing.T, sc pb.SubscriberClient, sub *pb.Subscription) pb.Subscriber_StreamingPullClient {
  569. spc, err := sc.StreamingPull(ctx)
  570. if err != nil {
  571. t.Fatal(err)
  572. }
  573. if err := spc.Send(&pb.StreamingPullRequest{Subscription: sub.Name}); err != nil {
  574. t.Fatal(err)
  575. }
  576. return spc
  577. }
  578. func pullN(ctx context.Context, t *testing.T, n int, sc pb.SubscriberClient, sub *pb.Subscription) map[string]*pb.ReceivedMessage {
  579. got := map[string]*pb.ReceivedMessage{}
  580. for i := 0; len(got) < n; i++ {
  581. res, err := sc.Pull(ctx, &pb.PullRequest{Subscription: sub.Name, MaxMessages: int32(n - len(got))})
  582. if err != nil {
  583. t.Fatal(err)
  584. }
  585. for _, m := range res.ReceivedMessages {
  586. got[m.Message.MessageId] = m
  587. }
  588. }
  589. return got
  590. }
  591. func streamingPullN(ctx context.Context, t *testing.T, n int, sc pb.SubscriberClient, sub *pb.Subscription) map[string]*pb.ReceivedMessage {
  592. spc := mustStartStreamingPull(ctx, t, sc, sub)
  593. got := map[string]*pb.ReceivedMessage{}
  594. for i := 0; i < n; i++ {
  595. res, err := spc.Recv()
  596. if err != nil {
  597. t.Fatal(err)
  598. }
  599. for _, m := range res.ReceivedMessages {
  600. got[m.Message.MessageId] = m
  601. }
  602. }
  603. if err := spc.CloseSend(); err != nil {
  604. t.Fatal(err)
  605. }
  606. res, err := spc.Recv()
  607. if err != io.EOF {
  608. t.Fatalf("Recv returned <%v> instead of EOF; res = %v", err, res)
  609. }
  610. return got
  611. }
  612. func pubsubMessages(rms map[string]*pb.ReceivedMessage) map[string]*pb.PubsubMessage {
  613. ms := map[string]*pb.PubsubMessage{}
  614. for k, rm := range rms {
  615. ms[k] = rm.Message
  616. }
  617. return ms
  618. }
  619. func mustCreateTopic(ctx context.Context, t *testing.T, pc pb.PublisherClient, topic *pb.Topic) *pb.Topic {
  620. top, err := pc.CreateTopic(ctx, topic)
  621. if err != nil {
  622. t.Fatal(err)
  623. }
  624. return top
  625. }
  626. func mustCreateSubscription(ctx context.Context, t *testing.T, sc pb.SubscriberClient, sub *pb.Subscription) *pb.Subscription {
  627. sub, err := sc.CreateSubscription(ctx, sub)
  628. if err != nil {
  629. t.Fatal(err)
  630. }
  631. return sub
  632. }
  633. // newFake creates a new fake server along with a publisher and subscriber
  634. // client. Its final return is a cleanup function.
  635. //
  636. // Note: be sure to call cleanup!
  637. func newFake(ctx context.Context, t *testing.T) (pb.PublisherClient, pb.SubscriberClient, *Server, func()) {
  638. srv := NewServer()
  639. conn, err := grpc.DialContext(ctx, srv.Addr, grpc.WithInsecure())
  640. if err != nil {
  641. t.Fatal(err)
  642. }
  643. return pb.NewPublisherClient(conn), pb.NewSubscriberClient(conn), srv, func() {
  644. srv.Close()
  645. conn.Close()
  646. }
  647. }