google.golang.org/grpc@v1.62.1/internal/grpcsync/pubsub_test.go (about) 1 /* 2 * 3 * Copyright 2023 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package grpcsync 20 21 import ( 22 "context" 23 "sync" 24 "testing" 25 "time" 26 ) 27 28 type testSubscriber struct { 29 onMsgCh chan int 30 } 31 32 func newTestSubscriber(chSize int) *testSubscriber { 33 return &testSubscriber{onMsgCh: make(chan int, chSize)} 34 } 35 36 func (ts *testSubscriber) OnMessage(msg any) { 37 select { 38 case ts.onMsgCh <- msg.(int): 39 default: 40 } 41 } 42 43 func (s) TestPubSub_PublishNoMsg(t *testing.T) { 44 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 45 defer cancel() 46 pubsub := NewPubSub(ctx) 47 48 ts := newTestSubscriber(1) 49 pubsub.Subscribe(ts) 50 51 select { 52 case <-ts.onMsgCh: 53 t.Fatal("Subscriber callback invoked when no message was published") 54 case <-time.After(defaultTestShortTimeout): 55 } 56 } 57 58 func (s) TestPubSub_PublishMsgs_RegisterSubs_And_Stop(t *testing.T) { 59 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 60 defer cancel() 61 pubsub := NewPubSub(ctx) 62 63 const numPublished = 10 64 65 ts1 := newTestSubscriber(numPublished) 66 pubsub.Subscribe(ts1) 67 68 var wg sync.WaitGroup 69 wg.Add(2) 70 // Publish ten messages on the pubsub and ensure that they are received in order by the subscriber. 71 go func() { 72 for i := 0; i < numPublished; i++ { 73 pubsub.Publish(i) 74 } 75 wg.Done() 76 }() 77 78 go func() { 79 defer wg.Done() 80 for i := 0; i < numPublished; i++ { 81 select { 82 case m := <-ts1.onMsgCh: 83 if m != i { 84 t.Errorf("Received unexpected message: %q; want: %q", m, i) 85 return 86 } 87 case <-time.After(defaultTestTimeout): 88 t.Error("Timeout when expecting the onMessage() callback to be invoked") 89 return 90 } 91 } 92 }() 93 wg.Wait() 94 if t.Failed() { 95 t.FailNow() 96 } 97 98 // Register another subscriber and ensure that it receives the last published message. 99 ts2 := newTestSubscriber(numPublished) 100 pubsub.Subscribe(ts2) 101 102 select { 103 case m := <-ts2.onMsgCh: 104 if m != numPublished-1 { 105 t.Fatalf("Received unexpected message: %q; want: %q", m, numPublished-1) 106 } 107 case <-time.After(defaultTestShortTimeout): 108 t.Fatal("Timeout when expecting the onMessage() callback to be invoked") 109 } 110 111 wg.Add(3) 112 // Publish ten messages on the pubsub and ensure that they are received in order by the subscribers. 113 go func() { 114 for i := 0; i < numPublished; i++ { 115 pubsub.Publish(i) 116 } 117 wg.Done() 118 }() 119 go func() { 120 defer wg.Done() 121 for i := 0; i < numPublished; i++ { 122 select { 123 case m := <-ts1.onMsgCh: 124 if m != i { 125 t.Errorf("Received unexpected message: %q; want: %q", m, i) 126 return 127 } 128 case <-time.After(defaultTestTimeout): 129 t.Error("Timeout when expecting the onMessage() callback to be invoked") 130 return 131 } 132 } 133 134 }() 135 go func() { 136 defer wg.Done() 137 for i := 0; i < numPublished; i++ { 138 select { 139 case m := <-ts2.onMsgCh: 140 if m != i { 141 t.Errorf("Received unexpected message: %q; want: %q", m, i) 142 return 143 } 144 case <-time.After(defaultTestTimeout): 145 t.Error("Timeout when expecting the onMessage() callback to be invoked") 146 return 147 } 148 } 149 }() 150 wg.Wait() 151 if t.Failed() { 152 t.FailNow() 153 } 154 155 cancel() 156 <-pubsub.Done() 157 158 go func() { 159 pubsub.Publish(99) 160 }() 161 // Ensure that the subscriber callback is not invoked as instantiated 162 // pubsub has already closed. 163 select { 164 case <-ts1.onMsgCh: 165 t.Fatal("The callback was invoked after pubsub being stopped") 166 case <-ts2.onMsgCh: 167 t.Fatal("The callback was invoked after pubsub being stopped") 168 case <-time.After(defaultTestShortTimeout): 169 } 170 } 171 172 func (s) TestPubSub_PublishMsgs_BeforeRegisterSub(t *testing.T) { 173 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 174 defer cancel() 175 pubsub := NewPubSub(ctx) 176 177 const numPublished = 3 178 for i := 0; i < numPublished; i++ { 179 pubsub.Publish(i) 180 } 181 182 ts := newTestSubscriber(numPublished) 183 pubsub.Subscribe(ts) 184 185 // Ensure that the subscriber callback is invoked with a previously 186 // published message. 187 select { 188 case d := <-ts.onMsgCh: 189 if d != numPublished-1 { 190 t.Fatalf("Unexpected message received: %q; %q", d, numPublished-1) 191 } 192 193 case <-time.After(defaultTestShortTimeout): 194 t.Fatal("Timeout when expecting the onMessage() callback to be invoked") 195 } 196 }