github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/internal/pubsub/pubsub_test.go (about) 1 // Copyright (c) 2015-2021 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package pubsub 19 20 import ( 21 "fmt" 22 "testing" 23 "time" 24 ) 25 26 func TestSubscribe(t *testing.T) { 27 ps := New[Maskable, Mask](2) 28 ch1 := make(chan Maskable, 1) 29 ch2 := make(chan Maskable, 1) 30 doneCh := make(chan struct{}) 31 defer close(doneCh) 32 if err := ps.Subscribe(MaskAll, ch1, doneCh, nil); err != nil { 33 t.Fatalf("unexpected error: %v", err) 34 } 35 if err := ps.Subscribe(MaskAll, ch2, doneCh, nil); err != nil { 36 t.Fatalf("unexpected error: %v", err) 37 } 38 ps.Lock() 39 defer ps.Unlock() 40 41 if len(ps.subs) != 2 || ps.NumSubscribers(MaskAll) != 2 || ps.Subscribers() != 2 { 42 t.Fatalf("expected 2 subscribers") 43 } 44 } 45 46 func TestNumSubscribersMask(t *testing.T) { 47 ps := New[Maskable, Mask](2) 48 ch1 := make(chan Maskable, 1) 49 ch2 := make(chan Maskable, 1) 50 doneCh := make(chan struct{}) 51 defer close(doneCh) 52 if err := ps.Subscribe(Mask(1), ch1, doneCh, nil); err != nil { 53 t.Fatalf("unexpected error: %v", err) 54 } 55 if err := ps.Subscribe(Mask(2), ch2, doneCh, nil); err != nil { 56 t.Fatalf("unexpected error: %v", err) 57 } 58 ps.Lock() 59 defer ps.Unlock() 60 61 if len(ps.subs) != 2 { 62 t.Fatalf("expected 2 subscribers") 63 } 64 if want, got := int32(2), ps.NumSubscribers(Mask(1)); got != want { 65 t.Fatalf("want %d subscribers, got %d", want, got) 66 } 67 if want, got := int32(2), ps.NumSubscribers(Mask(2)); got != want { 68 t.Fatalf("want %d subscribers, got %d", want, got) 69 } 70 if want, got := int32(2), ps.NumSubscribers(Mask(1|2)); got != want { 71 t.Fatalf("want %d subscribers, got %d", want, got) 72 } 73 if want, got := int32(2), ps.NumSubscribers(MaskAll); got != want { 74 t.Fatalf("want %d subscribers, got %d", want, got) 75 } 76 if want, got := int32(0), ps.NumSubscribers(Mask(4)); got != want { 77 t.Fatalf("want %d subscribers, got %d", want, got) 78 } 79 } 80 81 func TestSubscribeExceedingLimit(t *testing.T) { 82 ps := New[Maskable, Maskable](2) 83 ch1 := make(chan Maskable, 1) 84 ch2 := make(chan Maskable, 1) 85 ch3 := make(chan Maskable, 1) 86 doneCh := make(chan struct{}) 87 defer close(doneCh) 88 if err := ps.Subscribe(MaskAll, ch1, doneCh, nil); err != nil { 89 t.Fatalf("unexpected error: %v", err) 90 } 91 if err := ps.Subscribe(MaskAll, ch2, doneCh, nil); err != nil { 92 t.Fatalf("unexpected error: %v", err) 93 } 94 if err := ps.Subscribe(MaskAll, ch3, doneCh, nil); err == nil { 95 t.Fatalf("unexpected nil err") 96 } 97 } 98 99 func TestUnsubscribe(t *testing.T) { 100 ps := New[Maskable, Maskable](2) 101 ch1 := make(chan Maskable, 1) 102 ch2 := make(chan Maskable, 1) 103 doneCh1 := make(chan struct{}) 104 doneCh2 := make(chan struct{}) 105 if err := ps.Subscribe(MaskAll, ch1, doneCh1, nil); err != nil { 106 t.Fatalf("unexpected error: %v", err) 107 } 108 if err := ps.Subscribe(MaskAll, ch2, doneCh2, nil); err != nil { 109 t.Fatalf("unexpected error: %v", err) 110 } 111 112 close(doneCh1) 113 // Allow for the above statement to take effect. 114 time.Sleep(100 * time.Millisecond) 115 ps.Lock() 116 if len(ps.subs) != 1 { 117 t.Fatal("expected 1 subscriber") 118 } 119 ps.Unlock() 120 close(doneCh2) 121 } 122 123 type maskString string 124 125 func (m maskString) Mask() uint64 { 126 return 1 127 } 128 129 func TestPubSub(t *testing.T) { 130 ps := New[Maskable, Maskable](1) 131 ch1 := make(chan Maskable, 1) 132 doneCh1 := make(chan struct{}) 133 defer close(doneCh1) 134 if err := ps.Subscribe(MaskAll, ch1, doneCh1, func(entry Maskable) bool { return true }); err != nil { 135 t.Fatalf("unexpected error: %v", err) 136 } 137 val := maskString("hello") 138 ps.Publish(val) 139 msg := <-ch1 140 if msg != val { 141 t.Fatalf(fmt.Sprintf("expected %s , found %s", val, msg)) 142 } 143 } 144 145 func TestMultiPubSub(t *testing.T) { 146 ps := New[Maskable, Maskable](2) 147 ch1 := make(chan Maskable, 1) 148 ch2 := make(chan Maskable, 1) 149 doneCh := make(chan struct{}) 150 defer close(doneCh) 151 if err := ps.Subscribe(MaskAll, ch1, doneCh, func(entry Maskable) bool { return true }); err != nil { 152 t.Fatalf("unexpected error: %v", err) 153 } 154 if err := ps.Subscribe(MaskAll, ch2, doneCh, func(entry Maskable) bool { return true }); err != nil { 155 t.Fatalf("unexpected error: %v", err) 156 } 157 val := maskString("hello") 158 ps.Publish(val) 159 160 msg1 := <-ch1 161 msg2 := <-ch2 162 if msg1 != val && msg2 != val { 163 t.Fatalf(fmt.Sprintf("expected both subscribers to have%s , found %s and %s", val, msg1, msg2)) 164 } 165 } 166 167 func TestMultiPubSubMask(t *testing.T) { 168 ps := New[Maskable, Maskable](3) 169 ch1 := make(chan Maskable, 1) 170 ch2 := make(chan Maskable, 1) 171 ch3 := make(chan Maskable, 1) 172 doneCh := make(chan struct{}) 173 defer close(doneCh) 174 // Mask matches maskString, should get result 175 if err := ps.Subscribe(Mask(1), ch1, doneCh, func(entry Maskable) bool { return true }); err != nil { 176 t.Fatalf("unexpected error: %v", err) 177 } 178 // Mask matches maskString, should get result 179 if err := ps.Subscribe(Mask(1|2), ch2, doneCh, func(entry Maskable) bool { return true }); err != nil { 180 t.Fatalf("unexpected error: %v", err) 181 } 182 // Does NOT overlap maskString 183 if err := ps.Subscribe(Mask(2), ch3, doneCh, func(entry Maskable) bool { return true }); err != nil { 184 t.Fatalf("unexpected error: %v", err) 185 } 186 val := maskString("hello") 187 ps.Publish(val) 188 189 msg1 := <-ch1 190 msg2 := <-ch2 191 if msg1 != val && msg2 != val { 192 t.Fatalf(fmt.Sprintf("expected both subscribers to have%s , found %s and %s", val, msg1, msg2)) 193 } 194 195 select { 196 case msg := <-ch3: 197 t.Fatalf(fmt.Sprintf("unexpected msg, f got %s", msg)) 198 default: 199 } 200 }