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  }