github.com/nakagami/firebirdsql@v0.9.10/event_test.go (about) 1 /******************************************************************************* 2 The MIT License (MIT) 3 4 Copyright (c) 2019 Arteev Aleksey 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy of 7 this software and associated documentation files (the "Software"), to deal in 8 the Software without restriction, including without limitation the rights to 9 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 the Software, and to permit persons to whom the Software is furnished to do so, 11 subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in all 14 copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 *******************************************************************************/ 23 24 package firebirdsql 25 26 import ( 27 "database/sql" 28 "math/rand" 29 "net" 30 "sync" 31 "testing" 32 "time" 33 ) 34 35 func TestEventsCallback(t *testing.T) { 36 dsn := GetTestDSN("test_events_") 37 conn, err := sql.Open("firebirdsql_createdb", dsn) 38 if err != nil { 39 t.Fatalf("Error connecting: %v", err) 40 } 41 conn.Ping() 42 conn.Close() 43 44 fbevent, err := NewFBEvent(dsn) 45 if err != nil { 46 t.Fatalf("Error connecting: %v", err) 47 } 48 defer fbevent.Close() 49 50 doEvent := func(wg *sync.WaitGroup, wantEvents map[string]int) { 51 eventsSlice := make([]string, 0, len(wantEvents)) 52 events := make(map[string]int, len(wantEvents)) 53 for event, count := range wantEvents { 54 if count > 0 { 55 eventsSlice = append(eventsSlice, event) 56 events[event] = count 57 } 58 } 59 waitDone := len(events) 60 for len(events) > 0 { 61 idx := rand.Intn(len(events)) 62 name := eventsSlice[idx] 63 64 if err := fbevent.PostEvent(name); err != nil { 65 for i := 0; i < waitDone; i++ { 66 wg.Done() 67 } 68 t.Error(err) 69 return 70 } 71 events[name]-- 72 if events[name] <= 0 { 73 delete(events, name) 74 eventsSlice = append(eventsSlice[:idx], eventsSlice[idx+1:]...) 75 wg.Done() 76 waitDone-- 77 } 78 } 79 80 } 81 82 t.Run("callback", func(t *testing.T) { 83 wg := &sync.WaitGroup{} 84 85 wantEvents := map[string]int{ 86 "event_1": 12, 87 "event_2": 15, 88 "event_3": 23, 89 } 90 events := make([]string, 0, len(wantEvents)) 91 for event := range wantEvents { 92 events = append(events, event) 93 } 94 wg.Add(3) 95 96 muEvents := &sync.Mutex{} 97 gotEvents := map[string]int{} 98 99 subscribe, err := fbevent.Subscribe(events, func(e Event) { 100 muEvents.Lock() 101 gotEvents[e.Name] += e.Count 102 muEvents.Unlock() 103 time.Sleep(time.Millisecond * time.Duration(rand.Intn(10))) 104 }) 105 if err != nil { 106 t.Fatal(err) 107 } 108 defer subscribe.Unsubscribe() 109 110 go doEvent(wg, wantEvents) 111 wg.Wait() 112 time.Sleep(time.Second * 1) 113 114 muEvents.Lock() 115 for wantEvent, wantCount := range wantEvents { 116 if wantCount <= 0 { 117 continue 118 } 119 gotCount, ok := gotEvents[wantEvent] 120 if !ok { 121 t.Errorf("Expected %s count %d", wantEvent, wantCount) 122 } else if gotCount != wantCount { 123 t.Errorf("Expected %s count %d, got %d", wantEvent, wantCount, gotCount) 124 } 125 } 126 muEvents.Unlock() 127 }) 128 129 t.Run("channel", func(t *testing.T) { 130 wg := &sync.WaitGroup{} 131 132 wantEvents := map[string]int{ 133 "event_ch_1": 31, 134 "event_ch_2": 21, 135 "event_ch_3": 15, 136 } 137 events := make([]string, 0, len(wantEvents)) 138 for event := range wantEvents { 139 events = append(events, event) 140 } 141 wg.Add(3) 142 143 muEvents := &sync.Mutex{} 144 gotEvents := map[string]int{} 145 chEvent := make(chan Event) 146 subscribe, err := fbevent.SubscribeChan(events, chEvent) 147 if err != nil { 148 t.Fatal(err) 149 } 150 chClose := make(chan error) 151 subscribe.NotifyClose(chClose) 152 go func() { 153 for { 154 select { 155 case e := <-chEvent: 156 muEvents.Lock() 157 gotEvents[e.Name] += e.Count 158 muEvents.Unlock() 159 time.Sleep(time.Millisecond * time.Duration(rand.Intn(10))) 160 case err := <-chClose: 161 if err != nil { 162 if _, ok := err.(*net.OpError); !ok { 163 t.Error(err) 164 } 165 } 166 return 167 } 168 } 169 }() 170 defer subscribe.Unsubscribe() 171 172 go doEvent(wg, wantEvents) 173 wg.Wait() 174 time.Sleep(time.Second * 1) 175 176 muEvents.Lock() 177 for wantEvent, wantCount := range wantEvents { 178 if wantCount <= 0 { 179 continue 180 } 181 gotCount, ok := gotEvents[wantEvent] 182 if !ok { 183 t.Errorf("Expected %s count %d", wantEvent, wantCount) 184 } else if gotCount != wantCount { 185 t.Errorf("Expected %s count %d, got %d", wantEvent, wantCount, gotCount) 186 } 187 188 } 189 muEvents.Unlock() 190 }) 191 } 192 193 func TestSubscribe(t *testing.T) { 194 dsn := GetTestDSN("test_subscribe_") 195 conn, err := sql.Open("firebirdsql_createdb", dsn) 196 if err != nil { 197 t.Fatalf("Error connecting: %v", err) 198 } 199 conn.Ping() 200 conn.Close() 201 202 fbevent, err := NewFBEvent(dsn) 203 if err != nil { 204 t.Fatalf("Error connecting: %v", err) 205 } 206 defer fbevent.Close() 207 events := []string{"event1", "event2"} 208 subscriber1, err := fbevent.Subscribe(events, func(Event) { 209 }) 210 if err != nil { 211 t.Fatal(err) 212 } 213 subscriber2, err := fbevent.Subscribe(events, func(Event) { 214 }) 215 if err != nil { 216 t.Fatal(err) 217 } 218 219 if l := len(fbevent.Subscribers()); l != 2 { 220 t.Errorf("expected len subscribers %d, got %d", 2, l) 221 } 222 223 if l := len(fbevent.Subscribers()); l != fbevent.Count() { 224 t.Errorf("expected len subscribers %d, got %d", fbevent.Count(), l) 225 } 226 227 subscriber2.Unsubscribe() 228 time.Sleep(time.Millisecond * 50) 229 230 if l := len(fbevent.Subscribers()); l != 1 { 231 t.Errorf("expected len subscribers %d, got %d", 1, l) 232 } 233 if fbevent.Subscribers()[0] != subscriber1 { 234 t.Errorf("expected subscriber1") 235 } 236 237 if subscriber1.IsClose() { 238 t.Errorf("unexpected closed subscriber") 239 } 240 241 fbevent.Close() 242 if l := len(fbevent.Subscribers()); l != 0 { 243 t.Errorf("unexpected subscribers %d", l) 244 } 245 246 if !subscriber1.IsClose() { 247 t.Errorf("expected closed subscriber") 248 } 249 }