github.com/MetalBlockchain/metalgo@v1.11.9/utils/dynamicip/updater_test.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package dynamicip 5 6 import ( 7 "context" 8 "net/netip" 9 "testing" 10 "time" 11 12 "github.com/stretchr/testify/require" 13 14 "github.com/MetalBlockchain/metalgo/utils" 15 "github.com/MetalBlockchain/metalgo/utils/logging" 16 ) 17 18 var _ Resolver = (*mockResolver)(nil) 19 20 type mockResolver struct { 21 onResolve func(context.Context) (netip.Addr, error) 22 } 23 24 func (r *mockResolver) Resolve(ctx context.Context) (netip.Addr, error) { 25 return r.onResolve(ctx) 26 } 27 28 func TestNewUpdater(t *testing.T) { 29 require := require.New(t) 30 31 const ( 32 port = 9651 33 updateFrequency = time.Millisecond 34 stopTimeout = 5 * time.Second 35 ) 36 37 var ( 38 originalAddr = netip.IPv4Unspecified() 39 originalAddrPort = netip.AddrPortFrom(originalAddr, port) 40 newAddr = netip.AddrFrom4([4]byte{1, 2, 3, 4}) 41 expectedNewAddrPort = netip.AddrPortFrom(newAddr, port) 42 dynamicIP = utils.NewAtomic(originalAddrPort) 43 ) 44 resolver := &mockResolver{ 45 onResolve: func(context.Context) (netip.Addr, error) { 46 return newAddr, nil 47 }, 48 } 49 updaterIntf := NewUpdater( 50 dynamicIP, 51 resolver, 52 updateFrequency, 53 ) 54 55 // Assert NewUpdater returns expected type 56 require.IsType(&updater{}, updaterIntf) 57 updater := updaterIntf.(*updater) 58 59 // Assert fields set 60 require.Equal(dynamicIP, updater.dynamicIP) 61 require.Equal(resolver, updater.resolver) 62 require.NotNil(updater.rootCtx) 63 require.NotNil(updater.rootCtxCancel) 64 require.NotNil(updater.doneChan) 65 require.Equal(updateFrequency, updater.updateFreq) 66 67 // Start updating the IP address 68 go updater.Dispatch(logging.NoLog{}) 69 70 // Assert that the IP is updated within 5s. 71 require.Eventually( 72 func() bool { 73 return dynamicIP.Get() == expectedNewAddrPort 74 }, 75 5*time.Second, 76 updateFrequency, 77 ) 78 79 // Make sure stopChan and doneChan are closed when stop is called 80 updater.Stop() 81 82 ctx, cancel := context.WithTimeout(context.Background(), stopTimeout) 83 defer cancel() 84 select { 85 case <-updater.rootCtx.Done(): 86 case <-ctx.Done(): 87 require.FailNow("timeout waiting for root context cancellation") 88 } 89 select { 90 case _, open := <-updater.doneChan: 91 require.False(open) 92 case <-ctx.Done(): 93 require.FailNow("timeout waiting for doneChan to close") 94 } 95 }