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  }