github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/watch/watch_test.go (about)

     1  // Copyright (c) 2016 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package watch
    22  
    23  import (
    24  	"fmt"
    25  	"math/rand"
    26  	"sync"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/stretchr/testify/assert"
    31  )
    32  
    33  func TestWatchable(t *testing.T) {
    34  	p := NewWatchable()
    35  	assert.Nil(t, p.Get())
    36  	assert.Equal(t, 0, p.NumWatches())
    37  	assert.NoError(t, p.Update(nil))
    38  	assert.False(t, p.IsClosed())
    39  	get := 100
    40  	p = NewWatchable()
    41  	p.Update(get)
    42  	assert.Equal(t, get, p.Get())
    43  	v, s, err := p.Watch()
    44  	assert.NotNil(t, s)
    45  	assert.Equal(t, get, v)
    46  	assert.NoError(t, err)
    47  	assert.NoError(t, p.Update(get))
    48  	assert.Equal(t, 1, p.NumWatches())
    49  
    50  	p.Close()
    51  	assert.True(t, p.IsClosed())
    52  	assert.Equal(t, 0, p.NumWatches())
    53  	assert.Equal(t, get, p.Get())
    54  	_, s, err = p.Watch()
    55  	assert.Nil(t, s)
    56  	assert.Equal(t, errClosed, err)
    57  	assert.Equal(t, errClosed, p.Update(get))
    58  	assert.NotPanics(t, p.Close)
    59  }
    60  
    61  func TestWatch(t *testing.T) {
    62  	p := NewWatchable()
    63  	_, s, err := p.Watch()
    64  	assert.NoError(t, err)
    65  
    66  	err = p.Update(nil)
    67  	assert.NoError(t, err)
    68  
    69  	_, ok := <-s.C()
    70  	assert.True(t, ok)
    71  	assert.Nil(t, s.Get())
    72  
    73  	assert.Equal(t, 1, p.NumWatches())
    74  	s.Close()
    75  	_, ok = <-s.C()
    76  	assert.False(t, ok)
    77  	assert.Equal(t, 0, p.NumWatches())
    78  	assert.NotPanics(t, s.Close)
    79  
    80  	get := 100
    81  	p = NewWatchable()
    82  	_, s, err = p.Watch()
    83  	assert.NoError(t, err)
    84  
    85  	err = p.Update(get)
    86  	assert.Equal(t, get, p.Get())
    87  	assert.NoError(t, err)
    88  	_, ok = <-s.C()
    89  	assert.True(t, ok)
    90  	assert.Equal(t, get, s.Get())
    91  
    92  	// sub.Close() after p.Close()
    93  	assert.Equal(t, 1, p.NumWatches())
    94  	p.Close()
    95  	assert.Equal(t, 0, p.NumWatches())
    96  	s.Close()
    97  	_, ok = <-s.C()
    98  	assert.False(t, ok)
    99  	assert.Equal(t, 0, p.NumWatches())
   100  
   101  	// second watch has initial update
   102  	p = NewWatchable()
   103  	_, first, err := p.Watch()
   104  	assert.NoError(t, err)
   105  	assert.Equal(t, 0, len(first.C()))
   106  
   107  	p.Update(get)
   108  	<-first.C()
   109  	assert.Equal(t, get, first.Get())
   110  	assert.Equal(t, 0, len(first.C()))
   111  
   112  	_, second, err := p.Watch()
   113  	assert.NoError(t, err)
   114  	assert.Equal(t, 0, len(first.C()))
   115  	<-second.C()
   116  	assert.Equal(t, get, second.Get())
   117  	assert.Equal(t, 0, len(second.C()))
   118  }
   119  
   120  func TestMultiWatch(t *testing.T) {
   121  	p := NewWatchable()
   122  	subLen := 20
   123  	subMap := make(map[int]Watch, subLen)
   124  	valueMap := make(map[int]int, subLen)
   125  	for i := 0; i < subLen; i++ {
   126  		_, s, err := p.Watch()
   127  		assert.NoError(t, err)
   128  		subMap[i] = s
   129  		valueMap[i] = -1
   130  	}
   131  
   132  	for i := 0; i < subLen; i++ {
   133  		testWatchAndClose(t, p, subMap, valueMap, i)
   134  	}
   135  
   136  	assert.Equal(t, 0, p.NumWatches())
   137  	p.Close()
   138  }
   139  
   140  func testWatchAndClose(t *testing.T, p Watchable, subMap map[int]Watch, valueMap map[int]int, value interface{}) {
   141  	err := p.Update(value)
   142  	assert.NoError(t, err)
   143  
   144  	for i, s := range subMap {
   145  		_, ok := <-s.C()
   146  		assert.True(t, ok)
   147  		v := s.Get().(int)
   148  		assert.True(t, v > valueMap[i], fmt.Sprintf("Get() value should be > than before: %v, %v", v, valueMap[i]))
   149  		valueMap[i] = v
   150  	}
   151  
   152  	l := p.NumWatches()
   153  	assert.Equal(t, len(subMap), l)
   154  
   155  	// randomly close 1 subscriber
   156  	for i, s := range subMap {
   157  		s.Close()
   158  		_, ok := <-s.C()
   159  		assert.False(t, ok)
   160  		p.Get()
   161  		delete(subMap, i)
   162  		delete(valueMap, i)
   163  		break
   164  	}
   165  	assert.Equal(t, l-1, p.NumWatches())
   166  }
   167  
   168  func TestAsyncWatch(t *testing.T) {
   169  	p := NewWatchable()
   170  
   171  	subLen := 10
   172  	var wg sync.WaitGroup
   173  
   174  	for i := 0; i < subLen; i++ {
   175  		_, s, err := p.Watch()
   176  		assert.NoError(t, err)
   177  
   178  		wg.Add(1)
   179  		go func() {
   180  			for range s.C() {
   181  				r := rand.Int63n(100)
   182  				time.Sleep(time.Millisecond * time.Duration(r))
   183  			}
   184  			_, ok := <-s.C()
   185  			// chan got closed
   186  			assert.False(t, ok)
   187  			// got the latest value
   188  			assert.Equal(t, subLen-1, s.Get())
   189  			wg.Done()
   190  		}()
   191  	}
   192  
   193  	for i := 0; i < subLen; i++ {
   194  		err := p.Update(i)
   195  		assert.NoError(t, err)
   196  	}
   197  	p.Close()
   198  	assert.Equal(t, 0, p.NumWatches())
   199  	wg.Wait()
   200  }