github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/internal/xsync/once_test.go (about)

     1  package xsync
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"sync"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest"
    12  )
    13  
    14  func TestOnceFunc(t *testing.T) {
    15  	var (
    16  		ctx = xtest.Context(t)
    17  		cnt = 0
    18  	)
    19  	f := OnceFunc(func(ctx context.Context) error {
    20  		cnt++
    21  
    22  		return nil
    23  	})
    24  	require.Equal(t, 0, cnt)
    25  	require.NoError(t, f(ctx))
    26  	require.Equal(t, 1, cnt)
    27  	require.NoError(t, f(ctx))
    28  	require.Equal(t, 1, cnt)
    29  }
    30  
    31  type testCloser struct {
    32  	value    int
    33  	inited   bool
    34  	closed   bool
    35  	closeErr error
    36  }
    37  
    38  func (c *testCloser) Close(ctx context.Context) error {
    39  	c.closed = true
    40  
    41  	return c.closeErr
    42  }
    43  
    44  func TestOnceValue(t *testing.T) {
    45  	ctx := xtest.Context(t)
    46  	t.Run("Race", func(t *testing.T) {
    47  		counter := 0
    48  		once := OnceValue(func() (*testCloser, error) {
    49  			counter++
    50  
    51  			return &testCloser{value: counter}, nil
    52  		})
    53  		var wg sync.WaitGroup
    54  		wg.Add(1000)
    55  		for range make([]struct{}, 1000) {
    56  			go func() {
    57  				defer wg.Done()
    58  				v, err := once.Get()
    59  				require.NoError(t, err)
    60  				require.Equal(t, 1, v.value)
    61  			}()
    62  		}
    63  		wg.Wait()
    64  	})
    65  	t.Run("GetBeforeClose", func(t *testing.T) {
    66  		constCloseErr := errors.New("")
    67  		once := OnceValue(func() (*testCloser, error) {
    68  			return &testCloser{
    69  				inited:   true,
    70  				closeErr: constCloseErr,
    71  			}, nil
    72  		})
    73  		require.NotPanics(t, func() {
    74  			v := once.Must()
    75  			require.True(t, v.inited)
    76  			require.False(t, v.closed)
    77  			err := once.Close(ctx)
    78  			require.ErrorIs(t, err, constCloseErr)
    79  			require.True(t, v.inited)
    80  			require.True(t, v.closed)
    81  		})
    82  	})
    83  	t.Run("CloseBeforeGet", func(t *testing.T) {
    84  		constCloseErr := errors.New("")
    85  		once := OnceValue(func() (*testCloser, error) {
    86  			return &testCloser{
    87  				inited:   true,
    88  				closeErr: constCloseErr,
    89  			}, nil
    90  		})
    91  		err := once.Close(ctx)
    92  		require.NoError(t, err)
    93  		v, err := once.Get()
    94  		require.NoError(t, err)
    95  		require.Nil(t, v)
    96  	})
    97  }