github.com/searKing/golang/go@v1.2.117/sync/subject_test.go (about)

     1  // Copyright 2022 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  package sync_test
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"sync"
    10  	"testing"
    11  	"time"
    12  
    13  	sync_ "github.com/searKing/golang/go/sync"
    14  )
    15  
    16  func TestSubject_PublishSignal(t *testing.T) {
    17  	var s sync_.Subject
    18  	n := 2
    19  	awake := make(chan bool, n)
    20  	var wg sync.WaitGroup
    21  	eventC, _ := s.Subscribe()
    22  	for i := 0; i < n; i++ {
    23  		wg.Add(1)
    24  		go func() {
    25  			wg.Done()
    26  			<-eventC
    27  			awake <- true
    28  		}()
    29  	}
    30  	// Wait for everyone to run.
    31  	wg.Wait()
    32  
    33  	for n > 0 {
    34  		select {
    35  		case <-awake:
    36  			t.Fatal("goroutine not asleep")
    37  		default:
    38  		}
    39  		go func() {
    40  			ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    41  			defer cancel()
    42  			err := s.PublishSignal(ctx, nil)
    43  			if err != nil {
    44  				t.Fatalf("PublishSignal: %s", err)
    45  				return
    46  			}
    47  		}()
    48  		<-awake // Will deadlock if no goroutine wakes up
    49  		select {
    50  		case <-awake:
    51  			t.Fatal("too many goroutines awake")
    52  		default:
    53  		}
    54  		n--
    55  	}
    56  	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    57  	defer cancel()
    58  	err := s.PublishSignal(ctx, nil)
    59  	if !errors.Is(err, context.DeadlineExceeded) {
    60  		t.Fatalf("PublishSignal: %s", err)
    61  		return
    62  	}
    63  }
    64  
    65  func TestSubject_PublishBroadcast(t *testing.T) {
    66  	s := sync_.Subject{}
    67  	n := 2
    68  	awake := make(chan bool, n)
    69  	var wg sync.WaitGroup
    70  	for i := 0; i < n; i++ {
    71  		eventC, _ := s.Subscribe()
    72  		wg.Add(1)
    73  		go func() {
    74  			wg.Done()
    75  			<-eventC
    76  			awake <- true
    77  		}()
    78  	}
    79  	// Wait for everyone to run.
    80  	wg.Wait()
    81  	{
    82  		select {
    83  		case <-awake:
    84  			t.Fatal("goroutine not asleep")
    85  		default:
    86  		}
    87  		go func() {
    88  			ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    89  			defer cancel()
    90  			err := s.PublishBroadcast(ctx, nil)
    91  			if err != nil {
    92  				t.Fatalf("PublishBroadcast: %s", err)
    93  				return
    94  			}
    95  		}()
    96  		for n > 0 {
    97  			<-awake // Will deadlock if no goroutine wakes up
    98  			n--
    99  		}
   100  		select {
   101  		case <-awake:
   102  			t.Fatal("too many goroutines awake")
   103  		default:
   104  		}
   105  	}
   106  	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
   107  	defer cancel()
   108  	err := s.PublishBroadcast(ctx, nil)
   109  	if !errors.Is(err, context.DeadlineExceeded) {
   110  		t.Fatalf("PublishBroadcast: %s", err)
   111  		return
   112  	}
   113  }
   114  
   115  func TestSubject_PublishBroadcastDeadLock(t *testing.T) {
   116  	s := sync_.Subject{}
   117  	func() {
   118  		eventC, cancel := s.Subscribe()
   119  		go func() {
   120  			defer cancel()
   121  			<-eventC
   122  		}()
   123  	}()
   124  	err := s.PublishBroadcast(context.Background(), struct{}{})
   125  	if err != nil {
   126  		t.Errorf("PublishBroadcast: %s", err)
   127  		return
   128  	}
   129  }