github.com/klaytn/klaytn@v1.10.2/reward/staking_manager_test.go (about)

     1  // Copyright 2019 The klaytn Authors
     2  // This file is part of the klaytn library.
     3  //
     4  // The klaytn library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser 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  // The klaytn library 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 Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package reward
    18  
    19  import (
    20  	"encoding/json"
    21  	"testing"
    22  
    23  	"github.com/klaytn/klaytn/log"
    24  	"github.com/klaytn/klaytn/params"
    25  	"github.com/klaytn/klaytn/storage/database"
    26  	"github.com/stretchr/testify/assert"
    27  )
    28  
    29  type testGovernance struct {
    30  	p *params.GovParamSet
    31  }
    32  
    33  func newTestGovernance(intMap map[int]interface{}) *testGovernance {
    34  	p, _ := params.NewGovParamSetIntMap(intMap)
    35  	return &testGovernance{p}
    36  }
    37  
    38  func newDefaultTestGovernance() *testGovernance {
    39  	return newTestGovernance(map[int]interface{}{
    40  		params.Epoch:               604800,
    41  		params.Policy:              params.WeightedRandom,
    42  		params.UnitPrice:           25000000000,
    43  		params.MintingAmount:       "9600000000000000000",
    44  		params.Ratio:               "34/54/12",
    45  		params.UseGiniCoeff:        true,
    46  		params.DeferredTxFee:       true,
    47  		params.MinimumStake:        "5000000",
    48  		params.StakeUpdateInterval: 86400,
    49  	})
    50  }
    51  
    52  type stakingManagerTestCase struct {
    53  	blockNum    uint64       // Requested num in GetStakingInfo(num)
    54  	stakingNum  uint64       // Corresponding staking info block number
    55  	stakingInfo *StakingInfo // Expected GetStakingInfo() output
    56  }
    57  
    58  // Note that Golang will correctly initialize these globals according to dependency.
    59  // https://go.dev/ref/spec#Order_of_evaluation
    60  
    61  // Note the testdata must not exceed maxStakingCache because otherwise cache test will fail.
    62  var stakingManagerTestData = []*StakingInfo{
    63  	stakingInfoTestCases[0].stakingInfo,
    64  	stakingInfoTestCases[1].stakingInfo,
    65  	stakingInfoTestCases[2].stakingInfo,
    66  	stakingInfoTestCases[3].stakingInfo,
    67  }
    68  var stakingManagerTestCases = generateStakingManagerTestCases()
    69  
    70  func generateStakingManagerTestCases() []stakingManagerTestCase {
    71  	s := stakingManagerTestData
    72  
    73  	return []stakingManagerTestCase{
    74  		{1, 0, s[0]},
    75  		{100, 0, s[0]},
    76  		{86400, 0, s[0]},
    77  		{86401, 0, s[0]},
    78  		{172800, 0, s[0]},
    79  		{172801, 86400, s[1]},
    80  		{200000, 86400, s[1]},
    81  		{259200, 86400, s[1]},
    82  		{259201, 172800, s[2]},
    83  		{300000, 172800, s[2]},
    84  		{345600, 172800, s[2]},
    85  		{345601, 259200, s[3]},
    86  		{400000, 259200, s[3]},
    87  	}
    88  }
    89  
    90  func newStakingManagerForTest(t *testing.T) {
    91  	// test if nil
    92  	assert.Nil(t, GetStakingManager())
    93  	assert.Nil(t, GetStakingInfo(123))
    94  
    95  	st, err := updateStakingInfo(456)
    96  	assert.Nil(t, st)
    97  	assert.EqualError(t, err, ErrStakingManagerNotSet.Error())
    98  
    99  	assert.EqualError(t, CheckStakingInfoStored(789), ErrStakingManagerNotSet.Error())
   100  
   101  	// test if get same
   102  	stNew := NewStakingManager(newTestBlockChain(), newDefaultTestGovernance(), nil)
   103  	stGet := GetStakingManager()
   104  	assert.NotNil(t, stNew)
   105  	assert.Equal(t, stGet, stNew)
   106  }
   107  
   108  func resetStakingManagerForTest(t *testing.T) {
   109  	sm := GetStakingManager()
   110  	if sm == nil {
   111  		newStakingManagerForTest(t)
   112  		sm = GetStakingManager()
   113  	}
   114  
   115  	sm.stakingInfoCache = newStakingInfoCache()
   116  	sm.stakingInfoDB = database.NewMemoryDBManager()
   117  }
   118  
   119  func TestStakingManager_NewStakingManager(t *testing.T) {
   120  	newStakingManagerForTest(t)
   121  }
   122  
   123  // Check that appropriate StakingInfo is returned given various blockNum argument.
   124  func checkGetStakingInfo(t *testing.T) {
   125  	for _, testcase := range stakingManagerTestCases {
   126  		expcectedInfo := testcase.stakingInfo
   127  		actualInfo := GetStakingInfo(testcase.blockNum)
   128  
   129  		assert.Equal(t, testcase.stakingNum, actualInfo.BlockNum)
   130  		assert.Equal(t, expcectedInfo, actualInfo)
   131  	}
   132  }
   133  
   134  // Check that StakinInfo are loaded from cache
   135  func TestStakingManager_GetFromCache(t *testing.T) {
   136  	log.EnableLogForTest(log.LvlCrit, log.LvlDebug)
   137  	resetStakingManagerForTest(t)
   138  
   139  	for _, testdata := range stakingManagerTestData {
   140  		GetStakingManager().stakingInfoCache.add(testdata)
   141  	}
   142  
   143  	checkGetStakingInfo(t)
   144  }
   145  
   146  // Check that StakinInfo are loaded from database
   147  func TestStakingManager_GetFromDB(t *testing.T) {
   148  	log.EnableLogForTest(log.LvlCrit, log.LvlDebug)
   149  	resetStakingManagerForTest(t)
   150  
   151  	for _, testdata := range stakingManagerTestData {
   152  		AddStakingInfoToDB(testdata)
   153  	}
   154  
   155  	checkGetStakingInfo(t)
   156  }
   157  
   158  // Even if Gini was -1 in the cache, GetStakingInfo returns valid Gini
   159  func TestStakingManager_FillGiniFromCache(t *testing.T) {
   160  	log.EnableLogForTest(log.LvlCrit, log.LvlDebug)
   161  	resetStakingManagerForTest(t)
   162  
   163  	for _, testdata := range stakingManagerTestData {
   164  		// Insert a modified copy of testdata to cache
   165  		copydata := &StakingInfo{}
   166  		json.Unmarshal([]byte(testdata.String()), copydata)
   167  		copydata.Gini = -1 // Suppose Gini was -1 in the cache
   168  		GetStakingManager().stakingInfoCache.add(copydata)
   169  	}
   170  
   171  	checkGetStakingInfo(t)
   172  }
   173  
   174  // Even if Gini was -1 in the DB, GetStakingInfo returns valid Gini
   175  func TestStakingManager_FillGiniFromDB(t *testing.T) {
   176  	log.EnableLogForTest(log.LvlCrit, log.LvlDebug)
   177  	resetStakingManagerForTest(t)
   178  
   179  	for _, testdata := range stakingManagerTestData {
   180  		// Insert a modified copy of testdata to cache
   181  		copydata := &StakingInfo{}
   182  		json.Unmarshal([]byte(testdata.String()), copydata)
   183  		copydata.Gini = -1 // Suppose Gini was -1 in the cache
   184  		AddStakingInfoToDB(copydata)
   185  	}
   186  
   187  	checkGetStakingInfo(t)
   188  }