|
- // Copyright 2017 Google LLC
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- package pstest
-
- import (
- "context"
- "fmt"
- "io"
- "sync"
- "testing"
- "time"
-
- "cloud.google.com/go/internal/testutil"
- "github.com/golang/protobuf/ptypes"
- pb "google.golang.org/genproto/googleapis/pubsub/v1"
- "google.golang.org/grpc"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/status"
- )
-
- func TestTopics(t *testing.T) {
- pclient, _, server, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- ctx := context.Background()
- var topics []*pb.Topic
- for i := 1; i < 3; i++ {
- topics = append(topics, mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{
- Name: fmt.Sprintf("projects/P/topics/T%d", i),
- Labels: map[string]string{"num": fmt.Sprintf("%d", i)},
- }))
- }
- if got, want := len(server.GServer.topics), len(topics); got != want {
- t.Fatalf("got %d topics, want %d", got, want)
- }
- for _, top := range topics {
- got, err := pclient.GetTopic(ctx, &pb.GetTopicRequest{Topic: top.Name})
- if err != nil {
- t.Fatal(err)
- }
- if !testutil.Equal(got, top) {
- t.Errorf("\ngot %+v\nwant %+v", got, top)
- }
- }
-
- res, err := pclient.ListTopics(ctx, &pb.ListTopicsRequest{Project: "projects/P"})
- if err != nil {
- t.Fatal(err)
- }
- if got, want := res.Topics, topics; !testutil.Equal(got, want) {
- t.Errorf("\ngot %+v\nwant %+v", got, want)
- }
-
- for _, top := range topics {
- if _, err := pclient.DeleteTopic(ctx, &pb.DeleteTopicRequest{Topic: top.Name}); err != nil {
- t.Fatal(err)
- }
- }
- if got, want := len(server.GServer.topics), 0; got != want {
- t.Fatalf("got %d topics, want %d", got, want)
- }
- }
-
- func TestSubscriptions(t *testing.T) {
- pclient, sclient, server, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- ctx := context.Background()
- topic := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
- var subs []*pb.Subscription
- for i := 0; i < 3; i++ {
- subs = append(subs, mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
- Name: fmt.Sprintf("projects/P/subscriptions/S%d", i),
- Topic: topic.Name,
- AckDeadlineSeconds: int32(10 * (i + 1)),
- }))
- }
-
- if got, want := len(server.GServer.subs), len(subs); got != want {
- t.Fatalf("got %d subscriptions, want %d", got, want)
- }
- for _, s := range subs {
- got, err := sclient.GetSubscription(ctx, &pb.GetSubscriptionRequest{Subscription: s.Name})
- if err != nil {
- t.Fatal(err)
- }
- if !testutil.Equal(got, s) {
- t.Errorf("\ngot %+v\nwant %+v", got, s)
- }
- }
-
- res, err := sclient.ListSubscriptions(ctx, &pb.ListSubscriptionsRequest{Project: "projects/P"})
- if err != nil {
- t.Fatal(err)
- }
- if got, want := res.Subscriptions, subs; !testutil.Equal(got, want) {
- t.Errorf("\ngot %+v\nwant %+v", got, want)
- }
-
- res2, err := pclient.ListTopicSubscriptions(ctx, &pb.ListTopicSubscriptionsRequest{Topic: topic.Name})
- if err != nil {
- t.Fatal(err)
- }
- if got, want := len(res2.Subscriptions), len(subs); got != want {
- t.Fatalf("got %d subs, want %d", got, want)
- }
- for i, got := range res2.Subscriptions {
- want := subs[i].Name
- if !testutil.Equal(got, want) {
- t.Errorf("\ngot %+v\nwant %+v", got, want)
- }
- }
-
- for _, s := range subs {
- if _, err := sclient.DeleteSubscription(ctx, &pb.DeleteSubscriptionRequest{Subscription: s.Name}); err != nil {
- t.Fatal(err)
- }
- }
- if got, want := len(server.GServer.subs), 0; got != want {
- t.Fatalf("got %d subscriptions, want %d", got, want)
- }
- }
-
- func TestSubscriptionErrors(t *testing.T) {
- _, sclient, _, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- ctx := context.Background()
-
- checkCode := func(err error, want codes.Code) {
- t.Helper()
- if status.Code(err) != want {
- t.Errorf("got %v, want code %s", err, want)
- }
- }
-
- _, err := sclient.GetSubscription(ctx, &pb.GetSubscriptionRequest{})
- checkCode(err, codes.InvalidArgument)
- _, err = sclient.GetSubscription(ctx, &pb.GetSubscriptionRequest{Subscription: "s"})
- checkCode(err, codes.NotFound)
- _, err = sclient.UpdateSubscription(ctx, &pb.UpdateSubscriptionRequest{})
- checkCode(err, codes.InvalidArgument)
- _, err = sclient.UpdateSubscription(ctx, &pb.UpdateSubscriptionRequest{Subscription: &pb.Subscription{}})
- checkCode(err, codes.InvalidArgument)
- _, err = sclient.UpdateSubscription(ctx, &pb.UpdateSubscriptionRequest{Subscription: &pb.Subscription{Name: "s"}})
- checkCode(err, codes.NotFound)
- _, err = sclient.DeleteSubscription(ctx, &pb.DeleteSubscriptionRequest{})
- checkCode(err, codes.InvalidArgument)
- _, err = sclient.DeleteSubscription(ctx, &pb.DeleteSubscriptionRequest{Subscription: "s"})
- checkCode(err, codes.NotFound)
- _, err = sclient.Acknowledge(ctx, &pb.AcknowledgeRequest{})
- checkCode(err, codes.InvalidArgument)
- _, err = sclient.Acknowledge(ctx, &pb.AcknowledgeRequest{Subscription: "s"})
- checkCode(err, codes.NotFound)
- _, err = sclient.ModifyAckDeadline(ctx, &pb.ModifyAckDeadlineRequest{})
- checkCode(err, codes.InvalidArgument)
- _, err = sclient.ModifyAckDeadline(ctx, &pb.ModifyAckDeadlineRequest{Subscription: "s"})
- checkCode(err, codes.NotFound)
- _, err = sclient.Pull(ctx, &pb.PullRequest{})
- checkCode(err, codes.InvalidArgument)
- _, err = sclient.Pull(ctx, &pb.PullRequest{Subscription: "s"})
- checkCode(err, codes.NotFound)
- _, err = sclient.Seek(ctx, &pb.SeekRequest{})
- checkCode(err, codes.InvalidArgument)
- srt := &pb.SeekRequest_Time{Time: ptypes.TimestampNow()}
- _, err = sclient.Seek(ctx, &pb.SeekRequest{Target: srt})
- checkCode(err, codes.InvalidArgument)
- _, err = sclient.Seek(ctx, &pb.SeekRequest{Target: srt, Subscription: "s"})
- checkCode(err, codes.NotFound)
- }
-
- func TestPublish(t *testing.T) {
- s := NewServer()
- defer s.Close()
-
- var ids []string
- for i := 0; i < 3; i++ {
- ids = append(ids, s.Publish("projects/p/topics/t", []byte("hello"), nil))
- }
- s.Wait()
- ms := s.Messages()
- if got, want := len(ms), len(ids); got != want {
- t.Errorf("got %d messages, want %d", got, want)
- }
- for i, id := range ids {
- if got, want := ms[i].ID, id; got != want {
- t.Errorf("got %s, want %s", got, want)
- }
- }
-
- m := s.Message(ids[1])
- if m == nil {
- t.Error("got nil, want a message")
- }
- }
-
- // Note: this sets the fake's "now" time, so it is sensitive to concurrent changes to "now".
- func publish(t *testing.T, pclient pb.PublisherClient, topic *pb.Topic, messages []*pb.PubsubMessage) map[string]*pb.PubsubMessage {
- pubTime := time.Now()
- now.Store(func() time.Time { return pubTime })
- defer func() { now.Store(time.Now) }()
-
- res, err := pclient.Publish(context.Background(), &pb.PublishRequest{
- Topic: topic.Name,
- Messages: messages,
- })
- if err != nil {
- t.Fatal(err)
- }
- tsPubTime, err := ptypes.TimestampProto(pubTime)
- if err != nil {
- t.Fatal(err)
- }
- want := map[string]*pb.PubsubMessage{}
- for i, id := range res.MessageIds {
- want[id] = &pb.PubsubMessage{
- Data: messages[i].Data,
- Attributes: messages[i].Attributes,
- MessageId: id,
- PublishTime: tsPubTime,
- }
- }
- return want
- }
-
- func TestPull(t *testing.T) {
- pclient, sclient, _, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
- sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
- Name: "projects/P/subscriptions/S",
- Topic: top.Name,
- AckDeadlineSeconds: 10,
- })
-
- want := publish(t, pclient, top, []*pb.PubsubMessage{
- {Data: []byte("d1")},
- {Data: []byte("d2")},
- {Data: []byte("d3")},
- })
- got := pubsubMessages(pullN(context.TODO(), t, len(want), sclient, sub))
- if diff := testutil.Diff(got, want); diff != "" {
- t.Error(diff)
- }
-
- res, err := sclient.Pull(context.Background(), &pb.PullRequest{Subscription: sub.Name})
- if err != nil {
- t.Fatal(err)
- }
- if len(res.ReceivedMessages) != 0 {
- t.Errorf("got %d messages, want zero", len(res.ReceivedMessages))
- }
- }
-
- func TestStreamingPull(t *testing.T) {
- // A simple test of streaming pull.
- pclient, sclient, _, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
- sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
- Name: "projects/P/subscriptions/S",
- Topic: top.Name,
- AckDeadlineSeconds: 10,
- })
-
- want := publish(t, pclient, top, []*pb.PubsubMessage{
- {Data: []byte("d1")},
- {Data: []byte("d2")},
- {Data: []byte("d3")},
- })
- got := pubsubMessages(streamingPullN(context.TODO(), t, len(want), sclient, sub))
- if diff := testutil.Diff(got, want); diff != "" {
- t.Error(diff)
- }
- }
-
- // This test acks each message as it arrives and makes sure we don't see dups.
- func TestStreamingPullAck(t *testing.T) {
- minAckDeadlineSecs = 1
- pclient, sclient, _, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
- sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
- Name: "projects/P/subscriptions/S",
- Topic: top.Name,
- AckDeadlineSeconds: 1,
- })
-
- _ = publish(t, pclient, top, []*pb.PubsubMessage{
- {Data: []byte("d1")},
- {Data: []byte("d2")},
- {Data: []byte("d3")},
- })
-
- got := map[string]bool{}
- ctx, cancel := context.WithCancel(context.Background())
- spc := mustStartStreamingPull(ctx, t, sclient, sub)
- time.AfterFunc(time.Duration(2*minAckDeadlineSecs)*time.Second, cancel)
-
- for i := 0; i < 4; i++ {
- res, err := spc.Recv()
- if err == io.EOF {
- break
- }
- if err != nil {
- if status.Code(err) == codes.Canceled {
- break
- }
- t.Fatal(err)
- }
- if i == 3 {
- t.Fatal("expected to only see 3 messages, got 4")
- }
- req := &pb.StreamingPullRequest{}
- for _, m := range res.ReceivedMessages {
- if got[m.Message.MessageId] {
- t.Fatal("duplicate message")
- }
- got[m.Message.MessageId] = true
- req.AckIds = append(req.AckIds, m.AckId)
- }
- if err := spc.Send(req); err != nil {
- t.Fatal(err)
- }
- }
- }
-
- func TestAcknowledge(t *testing.T) {
- ctx := context.Background()
- pclient, sclient, srv, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
- sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
- Name: "projects/P/subscriptions/S",
- Topic: top.Name,
- AckDeadlineSeconds: 10,
- })
-
- publish(t, pclient, top, []*pb.PubsubMessage{
- {Data: []byte("d1")},
- {Data: []byte("d2")},
- {Data: []byte("d3")},
- })
- msgs := streamingPullN(context.TODO(), t, 3, sclient, sub)
- var ackIDs []string
- for _, m := range msgs {
- ackIDs = append(ackIDs, m.AckId)
- }
- if _, err := sclient.Acknowledge(ctx, &pb.AcknowledgeRequest{
- Subscription: sub.Name,
- AckIds: ackIDs,
- }); err != nil {
- t.Fatal(err)
- }
- smsgs := srv.Messages()
- if got, want := len(smsgs), 3; got != want {
- t.Fatalf("got %d messages, want %d", got, want)
- }
- for _, sm := range smsgs {
- if sm.Acks != 1 {
- t.Errorf("message %s: got %d acks, want 1", sm.ID, sm.Acks)
- }
- }
- }
-
- func TestModAck(t *testing.T) {
- ctx := context.Background()
- pclient, sclient, _, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
- sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
- Name: "projects/P/subscriptions/S",
- Topic: top.Name,
- AckDeadlineSeconds: 10,
- })
-
- publish(t, pclient, top, []*pb.PubsubMessage{
- {Data: []byte("d1")},
- {Data: []byte("d2")},
- {Data: []byte("d3")},
- })
- msgs := streamingPullN(context.TODO(), t, 3, sclient, sub)
- var ackIDs []string
- for _, m := range msgs {
- ackIDs = append(ackIDs, m.AckId)
- }
- if _, err := sclient.ModifyAckDeadline(ctx, &pb.ModifyAckDeadlineRequest{
- Subscription: sub.Name,
- AckIds: ackIDs,
- AckDeadlineSeconds: 0,
- }); err != nil {
- t.Fatal(err)
- }
- // Having nacked all three messages, we should see them again.
- msgs = streamingPullN(context.TODO(), t, 3, sclient, sub)
- if got, want := len(msgs), 3; got != want {
- t.Errorf("got %d messages, want %d", got, want)
- }
- }
-
- func TestAckDeadline(t *testing.T) {
- // Messages should be resent after they expire.
- pclient, sclient, _, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- minAckDeadlineSecs = 2
- top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
- sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
- Name: "projects/P/subscriptions/S",
- Topic: top.Name,
- AckDeadlineSeconds: minAckDeadlineSecs,
- })
-
- _ = publish(t, pclient, top, []*pb.PubsubMessage{
- {Data: []byte("d1")},
- {Data: []byte("d2")},
- {Data: []byte("d3")},
- })
-
- got := map[string]int{}
- spc := mustStartStreamingPull(context.TODO(), t, sclient, sub)
- // In 5 seconds the ack deadline will expire twice, so we should see each message
- // exactly three times.
- time.AfterFunc(5*time.Second, func() {
- if err := spc.CloseSend(); err != nil {
- t.Errorf("CloseSend: %v", err)
- }
- })
- for {
- res, err := spc.Recv()
- if err == io.EOF {
- break
- }
- if err != nil {
- t.Fatal(err)
- }
- for _, m := range res.ReceivedMessages {
- got[m.Message.MessageId]++
- }
- }
- for id, n := range got {
- if n != 3 {
- t.Errorf("message %s: saw %d times, want 3", id, n)
- }
- }
- }
-
- func TestMultiSubs(t *testing.T) {
- // Each subscription gets every message.
- pclient, sclient, _, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
- sub1 := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
- Name: "projects/P/subscriptions/S1",
- Topic: top.Name,
- AckDeadlineSeconds: 10,
- })
- sub2 := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
- Name: "projects/P/subscriptions/S2",
- Topic: top.Name,
- AckDeadlineSeconds: 10,
- })
-
- want := publish(t, pclient, top, []*pb.PubsubMessage{
- {Data: []byte("d1")},
- {Data: []byte("d2")},
- {Data: []byte("d3")},
- })
- got1 := pubsubMessages(streamingPullN(context.TODO(), t, len(want), sclient, sub1))
- got2 := pubsubMessages(streamingPullN(context.TODO(), t, len(want), sclient, sub2))
- if diff := testutil.Diff(got1, want); diff != "" {
- t.Error(diff)
- }
- if diff := testutil.Diff(got2, want); diff != "" {
- t.Error(diff)
- }
- }
-
- // Messages are handed out to all streams of a subscription in a best-effort
- // round-robin behavior. The fake server prefers to fail-fast onto another
- // stream when one stream is already busy, though, so we're unable to test
- // strict round robin behavior.
- func TestMultiStreams(t *testing.T) {
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
- pclient, sclient, _, cleanup := newFake(ctx, t)
- defer cleanup()
-
- top := mustCreateTopic(ctx, t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
- sub := mustCreateSubscription(ctx, t, sclient, &pb.Subscription{
- Name: "projects/P/subscriptions/S",
- Topic: top.Name,
- AckDeadlineSeconds: 10,
- })
- st1 := mustStartStreamingPull(ctx, t, sclient, sub)
- defer st1.CloseSend()
- st1Received := make(chan struct{})
- go func() {
- _, err := st1.Recv()
- if err != nil {
- t.Error(err)
- }
- close(st1Received)
- }()
-
- st2 := mustStartStreamingPull(ctx, t, sclient, sub)
- defer st2.CloseSend()
- st2Received := make(chan struct{})
- go func() {
- _, err := st2.Recv()
- if err != nil {
- t.Error(err)
- }
- close(st2Received)
- }()
-
- publish(t, pclient, top, []*pb.PubsubMessage{
- {Data: []byte("d1")},
- {Data: []byte("d2")},
- })
-
- timeout := time.After(5 * time.Second)
- select {
- case <-timeout:
- t.Fatal("timed out waiting for stream 1 to receive any message")
- case <-st1Received:
- }
- select {
- case <-timeout:
- t.Fatal("timed out waiting for stream 1 to receive any message")
- case <-st2Received:
- }
- }
-
- func TestStreamingPullTimeout(t *testing.T) {
- pclient, sclient, srv, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- timeout := 200 * time.Millisecond
- srv.SetStreamTimeout(timeout)
- top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
- sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
- Name: "projects/P/subscriptions/S",
- Topic: top.Name,
- AckDeadlineSeconds: 10,
- })
- stream := mustStartStreamingPull(context.TODO(), t, sclient, sub)
- time.Sleep(2 * timeout)
- _, err := stream.Recv()
- if err != io.EOF {
- t.Errorf("got %v, want io.EOF", err)
- }
- }
-
- func TestSeek(t *testing.T) {
- pclient, sclient, _, cleanup := newFake(context.TODO(), t)
- defer cleanup()
-
- top := mustCreateTopic(context.TODO(), t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
- sub := mustCreateSubscription(context.TODO(), t, sclient, &pb.Subscription{
- Name: "projects/P/subscriptions/S",
- Topic: top.Name,
- AckDeadlineSeconds: 10,
- })
- ts := ptypes.TimestampNow()
- _, err := sclient.Seek(context.Background(), &pb.SeekRequest{
- Subscription: sub.Name,
- Target: &pb.SeekRequest_Time{Time: ts},
- })
- if err != nil {
- t.Errorf("Seeking: %v", err)
- }
- }
-
- func TestTryDeliverMessage(t *testing.T) {
- for _, test := range []struct {
- availStreamIdx int
- expectedOutIdx int
- }{
- {availStreamIdx: 0, expectedOutIdx: 0},
- // Stream 1 will always be marked for deletion.
- {availStreamIdx: 2, expectedOutIdx: 1}, // s0, s1 (deleted), s2, s3 becomes s0, s2, s3. So we expect outIdx=1.
- {availStreamIdx: 3, expectedOutIdx: 2}, // s0, s1 (deleted), s2, s3 becomes s0, s2, s3. So we expect outIdx=2.
- } {
- top := newTopic(&pb.Topic{Name: "some-topic"})
- sub := newSubscription(top, &sync.Mutex{}, &pb.Subscription{Name: "some-sub", Topic: "some-topic"})
-
- done := make(chan struct{}, 1)
- done <- struct{}{}
- sub.streams = []*stream{{}, {done: done}, {}, {}}
-
- msgc := make(chan *pb.ReceivedMessage, 1)
- sub.streams[test.availStreamIdx].msgc = msgc
-
- var d int
- idx, ok := sub.tryDeliverMessage(&message{deliveries: &d}, 0, time.Now())
- if !ok {
- t.Fatalf("[avail=%d]: expected msg to be put on stream %d's channel, but it was not", test.availStreamIdx, test.expectedOutIdx)
- }
- if idx != test.expectedOutIdx {
- t.Fatalf("[avail=%d]: expected msg to be put on stream %d, but it was put on %d", test.availStreamIdx, test.expectedOutIdx, idx)
- }
- select {
- case <-msgc:
- default:
- t.Fatalf("[avail=%d]: expected msg to be put on stream %d's channel, but it was not", test.availStreamIdx, idx)
- }
- }
- }
-
- func mustStartStreamingPull(ctx context.Context, t *testing.T, sc pb.SubscriberClient, sub *pb.Subscription) pb.Subscriber_StreamingPullClient {
- spc, err := sc.StreamingPull(ctx)
- if err != nil {
- t.Fatal(err)
- }
- if err := spc.Send(&pb.StreamingPullRequest{Subscription: sub.Name}); err != nil {
- t.Fatal(err)
- }
- return spc
- }
-
- func pullN(ctx context.Context, t *testing.T, n int, sc pb.SubscriberClient, sub *pb.Subscription) map[string]*pb.ReceivedMessage {
- got := map[string]*pb.ReceivedMessage{}
- for i := 0; len(got) < n; i++ {
- res, err := sc.Pull(ctx, &pb.PullRequest{Subscription: sub.Name, MaxMessages: int32(n - len(got))})
- if err != nil {
- t.Fatal(err)
- }
- for _, m := range res.ReceivedMessages {
- got[m.Message.MessageId] = m
- }
- }
- return got
- }
-
- func streamingPullN(ctx context.Context, t *testing.T, n int, sc pb.SubscriberClient, sub *pb.Subscription) map[string]*pb.ReceivedMessage {
- spc := mustStartStreamingPull(ctx, t, sc, sub)
- got := map[string]*pb.ReceivedMessage{}
- for i := 0; i < n; i++ {
- res, err := spc.Recv()
- if err != nil {
- t.Fatal(err)
- }
- for _, m := range res.ReceivedMessages {
- got[m.Message.MessageId] = m
- }
- }
- if err := spc.CloseSend(); err != nil {
- t.Fatal(err)
- }
- res, err := spc.Recv()
- if err != io.EOF {
- t.Fatalf("Recv returned <%v> instead of EOF; res = %v", err, res)
- }
- return got
- }
-
- func pubsubMessages(rms map[string]*pb.ReceivedMessage) map[string]*pb.PubsubMessage {
- ms := map[string]*pb.PubsubMessage{}
- for k, rm := range rms {
- ms[k] = rm.Message
- }
- return ms
- }
-
- func mustCreateTopic(ctx context.Context, t *testing.T, pc pb.PublisherClient, topic *pb.Topic) *pb.Topic {
- top, err := pc.CreateTopic(ctx, topic)
- if err != nil {
- t.Fatal(err)
- }
- return top
- }
-
- func mustCreateSubscription(ctx context.Context, t *testing.T, sc pb.SubscriberClient, sub *pb.Subscription) *pb.Subscription {
- sub, err := sc.CreateSubscription(ctx, sub)
- if err != nil {
- t.Fatal(err)
- }
- return sub
- }
-
- // newFake creates a new fake server along with a publisher and subscriber
- // client. Its final return is a cleanup function.
- //
- // Note: be sure to call cleanup!
- func newFake(ctx context.Context, t *testing.T) (pb.PublisherClient, pb.SubscriberClient, *Server, func()) {
- srv := NewServer()
- conn, err := grpc.DialContext(ctx, srv.Addr, grpc.WithInsecure())
- if err != nil {
- t.Fatal(err)
- }
- return pb.NewPublisherClient(conn), pb.NewSubscriberClient(conn), srv, func() {
- srv.Close()
- conn.Close()
- }
- }
|