code.vegaprotocol.io/vega@v0.79.0/datanode/utils/observer_test.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package utils_test 17 18 import ( 19 "context" 20 "testing" 21 "time" 22 23 "code.vegaprotocol.io/vega/datanode/utils" 24 "code.vegaprotocol.io/vega/logging" 25 26 "github.com/stretchr/testify/assert" 27 "go.uber.org/zap" 28 logObserver "go.uber.org/zap/zaptest/observer" 29 ) 30 31 func newRecordedLogger() (*logging.Logger, *logObserver.ObservedLogs) { 32 zapCore, logs := logObserver.New(zap.DebugLevel) 33 zapLogger := zap.New(zapCore) 34 logger := &logging.Logger{Logger: zapLogger} 35 return logger, logs 36 } 37 38 func TestNotifyDoesNotBlock(t *testing.T) { 39 logger, logs := newRecordedLogger() 40 41 // An observer with no input buffer 42 o := utils.NewObserver[int]("test", logger, 0, 0) 43 ch, _ := o.Observe(context.Background(), 3, func(x int) bool { return true }) 44 45 // We have an observer that isn't reading from it's channel - when we notify it should 46 // output a debug message saying "channel could not be updated". There's an effective buffer 47 // of 1 message in the Observe() select loop, which may or may not have started by the time 48 // we Notify(), so notify twice just in case. 49 o.Notify([]int{1, 2, 3}) 50 o.Notify([]int{1, 2, 3}) 51 52 flogs := logs.FilterMessageSnippet("channel could not be updated") 53 assert.NotZero(t, flogs.Len()) 54 55 // The channel should be closed eventually, but it might take a few cycles to get there. 56 for { 57 select { 58 case _, ok := <-ch: 59 if !ok { 60 return 61 } 62 t.Fail() 63 default: 64 time.Sleep(10 * time.Millisecond) 65 } 66 } 67 } 68 69 func TestFilter(t *testing.T) { 70 logger := logging.NewTestLogger() 71 ctx := context.Background() 72 73 o := utils.NewObserver[int]("test", logger, 10, 10) 74 ch1, _ := o.Observe(ctx, 3, func(x int) bool { return x > 1 }) 75 ch2, _ := o.Observe(ctx, 3, func(x int) bool { return true }) 76 77 o.Notify([]int{1, 2, 3}) 78 out1 := <-ch1 79 out2 := <-ch2 80 81 assert.Equal(t, []int{2, 3}, out1) 82 assert.Equal(t, []int{1, 2, 3}, out2) 83 } 84 85 func TestCannotSend(t *testing.T) { 86 logger, logs := newRecordedLogger() 87 ctx := context.Background() 88 89 // To represent the case where the observer accepts a value on its input channel but 90 // cannot output it, create an observer with a small input buffer, but no output buffer 91 o := utils.NewObserver[int]("test", logger, 1, 0) 92 ch, _ := o.Observe(ctx, 3, func(x int) bool { return true }) 93 o.Notify([]int{1, 2, 3}) 94 95 // The observer goroutine should try 3 times with a short delay between and eventually give up. 96 time.Sleep(100 * time.Millisecond) 97 assert.Equal(t, 2, logs.FilterMessageSnippet("retrying").Len()) 98 assert.Equal(t, 1, logs.FilterMessageSnippet("retry limit").Len()) 99 100 // There should be nothing on the channel, and it should be closed 101 select { 102 case _, ok := <-ch: 103 if ok { 104 t.Fail() 105 } 106 default: 107 } 108 }