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.
 
 
 

514 lines
14 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. "fmt"
  17. "io"
  18. "testing"
  19. "time"
  20. "github.com/golang/protobuf/ptypes"
  21. "cloud.google.com/go/internal/testutil"
  22. "golang.org/x/net/context"
  23. pb "google.golang.org/genproto/googleapis/pubsub/v1"
  24. "google.golang.org/grpc"
  25. )
  26. func TestTopics(t *testing.T) {
  27. pclient, _, server := newFake(t)
  28. ctx := context.Background()
  29. var topics []*pb.Topic
  30. for i := 1; i < 3; i++ {
  31. topics = append(topics, mustCreateTopic(t, pclient, &pb.Topic{
  32. Name: fmt.Sprintf("projects/P/topics/T%d", i),
  33. Labels: map[string]string{"num": fmt.Sprintf("%d", i)},
  34. }))
  35. }
  36. if got, want := len(server.gServer.topics), len(topics); got != want {
  37. t.Fatalf("got %d topics, want %d", got, want)
  38. }
  39. for _, top := range topics {
  40. got, err := pclient.GetTopic(ctx, &pb.GetTopicRequest{Topic: top.Name})
  41. if err != nil {
  42. t.Fatal(err)
  43. }
  44. if !testutil.Equal(got, top) {
  45. t.Errorf("\ngot %+v\nwant %+v", got, top)
  46. }
  47. }
  48. res, err := pclient.ListTopics(ctx, &pb.ListTopicsRequest{Project: "projects/P"})
  49. if err != nil {
  50. t.Fatal(err)
  51. }
  52. if got, want := res.Topics, topics; !testutil.Equal(got, want) {
  53. t.Errorf("\ngot %+v\nwant %+v", got, want)
  54. }
  55. for _, top := range topics {
  56. if _, err := pclient.DeleteTopic(ctx, &pb.DeleteTopicRequest{Topic: top.Name}); err != nil {
  57. t.Fatal(err)
  58. }
  59. }
  60. if got, want := len(server.gServer.topics), 0; got != want {
  61. t.Fatalf("got %d topics, want %d", got, want)
  62. }
  63. }
  64. func TestSubscriptions(t *testing.T) {
  65. pclient, sclient, server := newFake(t)
  66. ctx := context.Background()
  67. topic := mustCreateTopic(t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  68. var subs []*pb.Subscription
  69. for i := 0; i < 3; i++ {
  70. subs = append(subs, mustCreateSubscription(t, sclient, &pb.Subscription{
  71. Name: fmt.Sprintf("projects/P/subscriptions/S%d", i),
  72. Topic: topic.Name,
  73. AckDeadlineSeconds: int32(10 * (i + 1)),
  74. }))
  75. }
  76. if got, want := len(server.gServer.subs), len(subs); got != want {
  77. t.Fatalf("got %d subscriptions, want %d", got, want)
  78. }
  79. for _, s := range subs {
  80. got, err := sclient.GetSubscription(ctx, &pb.GetSubscriptionRequest{Subscription: s.Name})
  81. if err != nil {
  82. t.Fatal(err)
  83. }
  84. if !testutil.Equal(got, s) {
  85. t.Errorf("\ngot %+v\nwant %+v", got, s)
  86. }
  87. }
  88. res, err := sclient.ListSubscriptions(ctx, &pb.ListSubscriptionsRequest{Project: "projects/P"})
  89. if err != nil {
  90. t.Fatal(err)
  91. }
  92. if got, want := res.Subscriptions, subs; !testutil.Equal(got, want) {
  93. t.Errorf("\ngot %+v\nwant %+v", got, want)
  94. }
  95. res2, err := pclient.ListTopicSubscriptions(ctx, &pb.ListTopicSubscriptionsRequest{Topic: topic.Name})
  96. if err != nil {
  97. t.Fatal(err)
  98. }
  99. if got, want := len(res2.Subscriptions), len(subs); got != want {
  100. t.Fatalf("got %d subs, want %d", got, want)
  101. }
  102. for i, got := range res2.Subscriptions {
  103. want := subs[i].Name
  104. if !testutil.Equal(got, want) {
  105. t.Errorf("\ngot %+v\nwant %+v", got, want)
  106. }
  107. }
  108. for _, s := range subs {
  109. if _, err := sclient.DeleteSubscription(ctx, &pb.DeleteSubscriptionRequest{Subscription: s.Name}); err != nil {
  110. t.Fatal(err)
  111. }
  112. }
  113. if got, want := len(server.gServer.subs), 0; got != want {
  114. t.Fatalf("got %d subscriptions, want %d", got, want)
  115. }
  116. }
  117. func TestPublish(t *testing.T) {
  118. s := NewServer()
  119. var ids []string
  120. for i := 0; i < 3; i++ {
  121. ids = append(ids, s.Publish("projects/p/topics/t", []byte("hello"), nil))
  122. }
  123. s.Wait()
  124. ms := s.Messages()
  125. if got, want := len(ms), len(ids); got != want {
  126. t.Errorf("got %d messages, want %d", got, want)
  127. }
  128. for i, id := range ids {
  129. if got, want := ms[i].ID, id; got != want {
  130. t.Errorf("got %s, want %s", got, want)
  131. }
  132. }
  133. m := s.Message(ids[1])
  134. if m == nil {
  135. t.Error("got nil, want a message")
  136. }
  137. }
  138. // Note: this sets the fake's "now" time, so it is senstive to concurrent changes to "now".
  139. func publish(t *testing.T, pclient pb.PublisherClient, topic *pb.Topic, messages []*pb.PubsubMessage) map[string]*pb.PubsubMessage {
  140. pubTime := time.Now()
  141. now.Store(func() time.Time { return pubTime })
  142. defer func() { now.Store(time.Now) }()
  143. res, err := pclient.Publish(context.Background(), &pb.PublishRequest{
  144. Topic: topic.Name,
  145. Messages: messages,
  146. })
  147. if err != nil {
  148. t.Fatal(err)
  149. }
  150. tsPubTime, err := ptypes.TimestampProto(pubTime)
  151. if err != nil {
  152. t.Fatal(err)
  153. }
  154. want := map[string]*pb.PubsubMessage{}
  155. for i, id := range res.MessageIds {
  156. want[id] = &pb.PubsubMessage{
  157. Data: messages[i].Data,
  158. Attributes: messages[i].Attributes,
  159. MessageId: id,
  160. PublishTime: tsPubTime,
  161. }
  162. }
  163. return want
  164. }
  165. func TestStreamingPull(t *testing.T) {
  166. // A simple test of streaming pull.
  167. pclient, sclient, _ := newFake(t)
  168. top := mustCreateTopic(t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  169. sub := mustCreateSubscription(t, sclient, &pb.Subscription{
  170. Name: "projects/P/subscriptions/S",
  171. Topic: top.Name,
  172. AckDeadlineSeconds: 10,
  173. })
  174. want := publish(t, pclient, top, []*pb.PubsubMessage{
  175. {Data: []byte("d1")},
  176. {Data: []byte("d2")},
  177. {Data: []byte("d3")},
  178. })
  179. got := pubsubMessages(pullN(t, len(want), sclient, sub))
  180. if diff := testutil.Diff(got, want); diff != "" {
  181. t.Error(diff)
  182. }
  183. }
  184. func TestStreamingPullAck(t *testing.T) {
  185. // Ack each message as it arrives. Make sure we don't see dups.
  186. minAckDeadlineSecs = 1
  187. pclient, sclient, _ := newFake(t)
  188. top := mustCreateTopic(t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  189. sub := mustCreateSubscription(t, sclient, &pb.Subscription{
  190. Name: "projects/P/subscriptions/S",
  191. Topic: top.Name,
  192. AckDeadlineSeconds: 1,
  193. })
  194. _ = publish(t, pclient, top, []*pb.PubsubMessage{
  195. {Data: []byte("d1")},
  196. {Data: []byte("d2")},
  197. {Data: []byte("d3")},
  198. })
  199. got := map[string]bool{}
  200. spc := mustStartPull(t, sclient, sub)
  201. time.AfterFunc(time.Duration(3*minAckDeadlineSecs)*time.Second, func() {
  202. if err := spc.CloseSend(); err != nil {
  203. t.Errorf("CloseSend: %v", err)
  204. }
  205. })
  206. for {
  207. res, err := spc.Recv()
  208. if err == io.EOF {
  209. break
  210. }
  211. if err != nil {
  212. t.Fatal(err)
  213. }
  214. req := &pb.StreamingPullRequest{}
  215. for _, m := range res.ReceivedMessages {
  216. if got[m.Message.MessageId] {
  217. t.Fatal("duplicate message")
  218. }
  219. got[m.Message.MessageId] = true
  220. req.AckIds = append(req.AckIds, m.AckId)
  221. }
  222. if err := spc.Send(req); err != nil {
  223. t.Fatal(err)
  224. }
  225. }
  226. }
  227. func TestAcknowledge(t *testing.T) {
  228. ctx := context.Background()
  229. pclient, sclient, srv := newFake(t)
  230. top := mustCreateTopic(t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  231. sub := mustCreateSubscription(t, sclient, &pb.Subscription{
  232. Name: "projects/P/subscriptions/S",
  233. Topic: top.Name,
  234. AckDeadlineSeconds: 10,
  235. })
  236. publish(t, pclient, top, []*pb.PubsubMessage{
  237. {Data: []byte("d1")},
  238. {Data: []byte("d2")},
  239. {Data: []byte("d3")},
  240. })
  241. msgs := pullN(t, 3, sclient, sub)
  242. var ackIDs []string
  243. for _, m := range msgs {
  244. ackIDs = append(ackIDs, m.AckId)
  245. }
  246. if _, err := sclient.Acknowledge(ctx, &pb.AcknowledgeRequest{
  247. Subscription: sub.Name,
  248. AckIds: ackIDs,
  249. }); err != nil {
  250. t.Fatal(err)
  251. }
  252. smsgs := srv.Messages()
  253. if got, want := len(smsgs), 3; got != want {
  254. t.Fatalf("got %d messages, want %d", got, want)
  255. }
  256. for _, sm := range smsgs {
  257. if sm.Acks != 1 {
  258. t.Errorf("message %s: got %d acks, want 1", sm.ID, sm.Acks)
  259. }
  260. }
  261. }
  262. func TestModAck(t *testing.T) {
  263. ctx := context.Background()
  264. pclient, sclient, _ := newFake(t)
  265. top := mustCreateTopic(t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  266. sub := mustCreateSubscription(t, sclient, &pb.Subscription{
  267. Name: "projects/P/subscriptions/S",
  268. Topic: top.Name,
  269. AckDeadlineSeconds: 10,
  270. })
  271. publish(t, pclient, top, []*pb.PubsubMessage{
  272. {Data: []byte("d1")},
  273. {Data: []byte("d2")},
  274. {Data: []byte("d3")},
  275. })
  276. msgs := pullN(t, 3, sclient, sub)
  277. var ackIDs []string
  278. for _, m := range msgs {
  279. ackIDs = append(ackIDs, m.AckId)
  280. }
  281. if _, err := sclient.ModifyAckDeadline(ctx, &pb.ModifyAckDeadlineRequest{
  282. Subscription: sub.Name,
  283. AckIds: ackIDs,
  284. AckDeadlineSeconds: 0,
  285. }); err != nil {
  286. t.Fatal(err)
  287. }
  288. // Having nacked all three messages, we should see them again.
  289. msgs = pullN(t, 3, sclient, sub)
  290. if got, want := len(msgs), 3; got != want {
  291. t.Errorf("got %d messages, want %d", got, want)
  292. }
  293. }
  294. func TestAckDeadline(t *testing.T) {
  295. // Messages should be resent after they expire.
  296. pclient, sclient, _ := newFake(t)
  297. minAckDeadlineSecs = 2
  298. top := mustCreateTopic(t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  299. sub := mustCreateSubscription(t, sclient, &pb.Subscription{
  300. Name: "projects/P/subscriptions/S",
  301. Topic: top.Name,
  302. AckDeadlineSeconds: minAckDeadlineSecs,
  303. })
  304. _ = publish(t, pclient, top, []*pb.PubsubMessage{
  305. {Data: []byte("d1")},
  306. {Data: []byte("d2")},
  307. {Data: []byte("d3")},
  308. })
  309. got := map[string]int{}
  310. spc := mustStartPull(t, sclient, sub)
  311. // In 5 seconds the ack deadline will expire twice, so we should see each message
  312. // exactly three times.
  313. time.AfterFunc(5*time.Second, func() {
  314. if err := spc.CloseSend(); err != nil {
  315. t.Errorf("CloseSend: %v", err)
  316. }
  317. })
  318. for {
  319. res, err := spc.Recv()
  320. if err == io.EOF {
  321. break
  322. }
  323. if err != nil {
  324. t.Fatal(err)
  325. }
  326. for _, m := range res.ReceivedMessages {
  327. got[m.Message.MessageId]++
  328. }
  329. }
  330. for id, n := range got {
  331. if n != 3 {
  332. t.Errorf("message %s: saw %d times, want 3", id, n)
  333. }
  334. }
  335. }
  336. func TestMultiSubs(t *testing.T) {
  337. // Each subscription gets every message.
  338. pclient, sclient, _ := newFake(t)
  339. top := mustCreateTopic(t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  340. sub1 := mustCreateSubscription(t, sclient, &pb.Subscription{
  341. Name: "projects/P/subscriptions/S1",
  342. Topic: top.Name,
  343. AckDeadlineSeconds: 10,
  344. })
  345. sub2 := mustCreateSubscription(t, sclient, &pb.Subscription{
  346. Name: "projects/P/subscriptions/S2",
  347. Topic: top.Name,
  348. AckDeadlineSeconds: 10,
  349. })
  350. want := publish(t, pclient, top, []*pb.PubsubMessage{
  351. {Data: []byte("d1")},
  352. {Data: []byte("d2")},
  353. {Data: []byte("d3")},
  354. })
  355. got1 := pubsubMessages(pullN(t, len(want), sclient, sub1))
  356. got2 := pubsubMessages(pullN(t, len(want), sclient, sub2))
  357. if diff := testutil.Diff(got1, want); diff != "" {
  358. t.Error(diff)
  359. }
  360. if diff := testutil.Diff(got2, want); diff != "" {
  361. t.Error(diff)
  362. }
  363. }
  364. func TestMultiStreams(t *testing.T) {
  365. // Messages are handed out to the streams of a subscription in round-robin order.
  366. pclient, sclient, _ := newFake(t)
  367. top := mustCreateTopic(t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  368. sub := mustCreateSubscription(t, sclient, &pb.Subscription{
  369. Name: "projects/P/subscriptions/S",
  370. Topic: top.Name,
  371. AckDeadlineSeconds: 10,
  372. })
  373. want := publish(t, pclient, top, []*pb.PubsubMessage{
  374. {Data: []byte("d1")},
  375. {Data: []byte("d2")},
  376. {Data: []byte("d3")},
  377. {Data: []byte("d4")},
  378. })
  379. streams := []pb.Subscriber_StreamingPullClient{
  380. mustStartPull(t, sclient, sub),
  381. mustStartPull(t, sclient, sub),
  382. }
  383. got := map[string]*pb.PubsubMessage{}
  384. for i := 0; i < 2; i++ {
  385. for _, st := range streams {
  386. res, err := st.Recv()
  387. if err != nil {
  388. t.Fatal(err)
  389. }
  390. m := res.ReceivedMessages[0]
  391. got[m.Message.MessageId] = m.Message
  392. }
  393. }
  394. if diff := testutil.Diff(got, want); diff != "" {
  395. t.Error(diff)
  396. }
  397. }
  398. func TestStreamingPullTimeout(t *testing.T) {
  399. pclient, sclient, srv := newFake(t)
  400. timeout := 200 * time.Millisecond
  401. srv.SetStreamTimeout(timeout)
  402. top := mustCreateTopic(t, pclient, &pb.Topic{Name: "projects/P/topics/T"})
  403. sub := mustCreateSubscription(t, sclient, &pb.Subscription{
  404. Name: "projects/P/subscriptions/S",
  405. Topic: top.Name,
  406. AckDeadlineSeconds: 10,
  407. })
  408. stream := mustStartPull(t, sclient, sub)
  409. time.Sleep(2 * timeout)
  410. _, err := stream.Recv()
  411. if err != io.EOF {
  412. t.Errorf("got %v, want io.EOF", err)
  413. }
  414. }
  415. func mustStartPull(t *testing.T, sc pb.SubscriberClient, sub *pb.Subscription) pb.Subscriber_StreamingPullClient {
  416. spc, err := sc.StreamingPull(context.Background())
  417. if err != nil {
  418. t.Fatal(err)
  419. }
  420. if err := spc.Send(&pb.StreamingPullRequest{Subscription: sub.Name}); err != nil {
  421. t.Fatal(err)
  422. }
  423. return spc
  424. }
  425. func pullN(t *testing.T, n int, sc pb.SubscriberClient, sub *pb.Subscription) map[string]*pb.ReceivedMessage {
  426. spc := mustStartPull(t, sc, sub)
  427. got := map[string]*pb.ReceivedMessage{}
  428. for i := 0; i < n; i++ {
  429. res, err := spc.Recv()
  430. if err != nil {
  431. t.Fatal(err)
  432. }
  433. for _, m := range res.ReceivedMessages {
  434. got[m.Message.MessageId] = m
  435. }
  436. }
  437. if err := spc.CloseSend(); err != nil {
  438. t.Fatal(err)
  439. }
  440. res, err := spc.Recv()
  441. if err != io.EOF {
  442. t.Fatalf("Recv returned <%v> instead of EOF; res = %v", err, res)
  443. }
  444. return got
  445. }
  446. func pubsubMessages(rms map[string]*pb.ReceivedMessage) map[string]*pb.PubsubMessage {
  447. ms := map[string]*pb.PubsubMessage{}
  448. for k, rm := range rms {
  449. ms[k] = rm.Message
  450. }
  451. return ms
  452. }
  453. func mustCreateTopic(t *testing.T, pc pb.PublisherClient, topic *pb.Topic) *pb.Topic {
  454. top, err := pc.CreateTopic(context.Background(), topic)
  455. if err != nil {
  456. t.Fatal(err)
  457. }
  458. return top
  459. }
  460. func mustCreateSubscription(t *testing.T, sc pb.SubscriberClient, sub *pb.Subscription) *pb.Subscription {
  461. sub, err := sc.CreateSubscription(context.Background(), sub)
  462. if err != nil {
  463. t.Fatal(err)
  464. }
  465. return sub
  466. }
  467. func newFake(t *testing.T) (pb.PublisherClient, pb.SubscriberClient, *Server) {
  468. srv := NewServer()
  469. conn, err := grpc.Dial(srv.Addr, grpc.WithInsecure())
  470. if err != nil {
  471. t.Fatal(err)
  472. }
  473. return pb.NewPublisherClient(conn), pb.NewSubscriberClient(conn), srv
  474. }