github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/session/pingpong/hermes_status_checker_test.go (about)

     1  /*
     2   * Copyright (C) 2021 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package pingpong
    19  
    20  import (
    21  	"sync"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/common"
    26  	"github.com/stretchr/testify/assert"
    27  )
    28  
    29  var hid = common.HexToAddress("0x8129243802538e426A023FedB0Da20689aee797A")
    30  var rid = common.HexToAddress("0x7129243802538e426A023FedB0Da20689aee797A")
    31  var chainID int64 = 5
    32  
    33  func Test_HermesActivityChecker(t *testing.T) {
    34  	t.Run("uses cached value if present and valid", func(t *testing.T) {
    35  		mbc := &mockBc{}
    36  		checker := NewHermesStatusChecker(mbc, nil, time.Minute)
    37  		checker.cachedValues[checker.formKey(chainID, hid)] = HermesStatus{
    38  			IsActive:   true,
    39  			ValidUntil: time.Now().Add(time.Minute),
    40  		}
    41  		status, err := checker.GetHermesStatus(chainID, rid, hid)
    42  		assert.NoError(t, err)
    43  		assert.True(t, status.IsActive)
    44  
    45  		assert.Equal(t, 0, mbc.getTimesCalled())
    46  	})
    47  
    48  	t.Run("updates value if present and not valid", func(t *testing.T) {
    49  		startTime := time.Now()
    50  
    51  		mbc := &mockBc{
    52  			isActiveResult:     true,
    53  			isRegisteredResult: true,
    54  			feeResult:          1,
    55  		}
    56  		checker := NewHermesStatusChecker(mbc, nil, time.Minute)
    57  		checker.cachedValues[checker.formKey(chainID, hid)] = HermesStatus{
    58  			IsActive:   false,
    59  			ValidUntil: time.Now().Add(-time.Minute),
    60  		}
    61  		status, err := checker.GetHermesStatus(chainID, rid, hid)
    62  		assert.NoError(t, err)
    63  		assert.True(t, status.IsActive)
    64  
    65  		assert.Equal(t, uint16(1), status.Fee)
    66  
    67  		assert.Equal(t, 3, mbc.getTimesCalled())
    68  
    69  		v, _ := checker.cachedValues[checker.formKey(chainID, hid)]
    70  		assert.True(t, v.isValid())
    71  
    72  		// check if extended by somewhere around a minute
    73  		assert.True(t, v.ValidUntil.After(startTime.Add(time.Minute)))
    74  		assert.False(t, v.ValidUntil.After(startTime.Add(time.Minute).Add(time.Second*2)))
    75  	})
    76  
    77  	t.Run("updates and sets cache if not present initially", func(t *testing.T) {
    78  		startTime := time.Now()
    79  
    80  		mbc := &mockBc{
    81  			isActiveResult:     true,
    82  			isRegisteredResult: true,
    83  			feeResult:          1,
    84  		}
    85  
    86  		checker := NewHermesStatusChecker(mbc, nil, time.Minute)
    87  		status, err := checker.GetHermesStatus(chainID, rid, hid)
    88  		assert.NoError(t, err)
    89  		assert.True(t, status.IsActive)
    90  
    91  		assert.Equal(t, uint16(1), status.Fee)
    92  
    93  		assert.Equal(t, 3, mbc.getTimesCalled())
    94  
    95  		v, _ := checker.cachedValues[checker.formKey(chainID, hid)]
    96  		assert.True(t, v.isValid())
    97  
    98  		// check if extended by somewhere around a minute
    99  		assert.True(t, v.ValidUntil.After(startTime.Add(time.Minute)))
   100  		assert.False(t, v.ValidUntil.After(startTime.Add(time.Minute).Add(time.Second*2)))
   101  	})
   102  
   103  	t.Run("successive runs do not fetch from source if already cached and valid", func(t *testing.T) {
   104  		mbc := &mockBc{
   105  			isActiveResult:     true,
   106  			isRegisteredResult: true,
   107  			feeResult:          1,
   108  		}
   109  
   110  		checker := NewHermesStatusChecker(mbc, nil, time.Minute)
   111  		status, err := checker.GetHermesStatus(chainID, rid, hid)
   112  		assert.NoError(t, err)
   113  		assert.True(t, status.IsActive)
   114  
   115  		assert.Equal(t, 3, mbc.getTimesCalled())
   116  
   117  		status, err = checker.GetHermesStatus(chainID, rid, hid)
   118  		assert.NoError(t, err)
   119  		assert.True(t, status.IsActive)
   120  		assert.Equal(t, 3, mbc.getTimesCalled())
   121  	})
   122  
   123  	t.Run("successive fetch from source if cache invalid", func(t *testing.T) {
   124  		mbc := &mockBc{
   125  			isActiveResult:     true,
   126  			isRegisteredResult: true,
   127  			feeResult:          1,
   128  		}
   129  
   130  		checker := NewHermesStatusChecker(mbc, nil, time.Minute)
   131  		status, err := checker.GetHermesStatus(chainID, rid, hid)
   132  		assert.NoError(t, err)
   133  		assert.True(t, status.IsActive)
   134  		assert.Equal(t, 3, mbc.getTimesCalled())
   135  
   136  		checker.cachedValues[checker.formKey(chainID, hid)] = HermesStatus{
   137  			IsActive:   true,
   138  			ValidUntil: time.Now().Add(-time.Minute),
   139  		}
   140  
   141  		status, err = checker.GetHermesStatus(chainID, rid, hid)
   142  		assert.NoError(t, err)
   143  		assert.True(t, status.IsActive)
   144  		assert.Equal(t, 6, mbc.getTimesCalled())
   145  	})
   146  }
   147  
   148  type mockBc struct {
   149  	isActiveResult bool
   150  	isActiveErr    error
   151  
   152  	isRegisteredResult bool
   153  	isRegisteredErr    error
   154  
   155  	feeResult uint16
   156  	feeErr    error
   157  
   158  	timesCalled int
   159  	lock        sync.Mutex
   160  }
   161  
   162  func (mbc *mockBc) incTimesCalled() {
   163  	mbc.lock.Lock()
   164  	defer mbc.lock.Unlock()
   165  	mbc.timesCalled++
   166  }
   167  
   168  func (mbc *mockBc) getTimesCalled() int {
   169  	mbc.lock.Lock()
   170  	defer mbc.lock.Unlock()
   171  	return mbc.timesCalled
   172  }
   173  
   174  func (mbc *mockBc) IsHermesActive(chainID int64, hermesID common.Address) (bool, error) {
   175  	defer mbc.incTimesCalled()
   176  	return mbc.isActiveResult, mbc.isActiveErr
   177  }
   178  
   179  func (mbc *mockBc) IsHermesRegistered(chainID int64, registryAddress, hermesID common.Address) (bool, error) {
   180  	defer mbc.incTimesCalled()
   181  	return mbc.isRegisteredResult, mbc.isRegisteredErr
   182  }
   183  
   184  func (mbc *mockBc) GetHermesFee(chainID int64, hermesID common.Address) (uint16, error) {
   185  	defer mbc.incTimesCalled()
   186  	return mbc.feeResult, mbc.feeErr
   187  }