gitlab.com/SkynetLabs/skyd@v1.6.9/skymodules/accounting/persist_test.go (about)

     1  package accounting
     2  
     3  import (
     4  	"bytes"
     5  	"reflect"
     6  	"testing"
     7  	"time"
     8  
     9  	"gitlab.com/SkynetLabs/skyd/siatest/dependencies"
    10  	"gitlab.com/SkynetLabs/skyd/skymodules"
    11  )
    12  
    13  // TestPersist tests the persistence of the accounting package
    14  func TestPersist(t *testing.T) {
    15  	t.Parallel()
    16  
    17  	// Short tests
    18  	t.Run("Marshal", testMarshal)
    19  
    20  	// Long tests
    21  	if testing.Short() {
    22  		t.SkipNow()
    23  	}
    24  
    25  	// Basic functionality test
    26  	t.Run("Basic", testBasic)
    27  
    28  	// Specific method tests
    29  	t.Run("callThreadedPersistAccounting", testCallThreadedPersistAccounting)
    30  	t.Run("managedUpdateAndPersistAccounting", testManagedUpdateAndPersistAccounting)
    31  }
    32  
    33  // testBasic tests the basic functionality of the Accounting module
    34  func testBasic(t *testing.T) {
    35  	// Create new accounting
    36  	testDir := accountingTestDir(t.Name())
    37  	h, m, r, w, _ := testingParams()
    38  	a, err := NewCustomAccounting(h, m, r, w, testDir, &dependencies.AccountingDisablePersistLoop{})
    39  	if err != nil {
    40  		t.Fatal(err)
    41  	}
    42  
    43  	// Check initial persistence
    44  	a.mu.Lock()
    45  	lenHistory := len(a.history)
    46  	a.mu.Unlock()
    47  	if lenHistory != 0 {
    48  		t.Error("history should be empty")
    49  	}
    50  
    51  	// Update, close, open, and verify several times
    52  	var expectedHistoryLen int
    53  	for i := 0; i < 5; i++ {
    54  		// Update the persistence
    55  		a.managedUpdateAndPersistAccounting()
    56  
    57  		// Grab the current persistence
    58  		a.mu.Lock()
    59  		initHistory := a.history
    60  		a.mu.Unlock()
    61  		expectedHistoryLen++
    62  
    63  		// Close accounting
    64  		err = a.Close()
    65  		if err != nil {
    66  			t.Fatal(err)
    67  		}
    68  
    69  		// Load Accounting
    70  		a, err = NewCustomAccounting(h, m, r, w, testDir, &dependencies.AccountingDisablePersistLoop{})
    71  		if err != nil {
    72  			t.Fatal(err)
    73  		}
    74  
    75  		// Check persistence
    76  		a.mu.Lock()
    77  		history := a.history
    78  		a.mu.Unlock()
    79  		if !reflect.DeepEqual(initHistory, history) {
    80  			t.Log("Expected:", initHistory)
    81  			t.Log("Actual:", history)
    82  			t.Error("history mismatch")
    83  		}
    84  		if len(history) != expectedHistoryLen {
    85  			t.Error("history length unexpected", len(history), expectedHistoryLen)
    86  		}
    87  	}
    88  	// Close accounting
    89  	err = a.Close()
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  }
    94  
    95  // testCallThreadedPersistAccounting probes the callThreadedPersistAccounting method
    96  func testCallThreadedPersistAccounting(t *testing.T) {
    97  	// Initialize Accounting
    98  	a, err := newTestAccounting(accountingTestDir(t.Name()))
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  	defer func() {
   103  		err = a.Close()
   104  		if err != nil {
   105  			t.Fatal(err)
   106  		}
   107  	}()
   108  
   109  	// Check that the background thread timer is working and the persistence is
   110  	// updating
   111  	for i := 0; i < 2; i++ {
   112  		// Grab the current persistence
   113  		a.mu.Lock()
   114  		initLen := len(a.history)
   115  		a.mu.Unlock()
   116  
   117  		// Sleep
   118  		time.Sleep(persistInterval * 2)
   119  
   120  		// Validate the persistence was updated
   121  		a.mu.Lock()
   122  		lenHistory := len(a.history)
   123  		a.mu.Unlock()
   124  		if initLen >= lenHistory {
   125  			t.Error("History not updated")
   126  		}
   127  	}
   128  }
   129  
   130  // testManagedUpdateAndPersistAccounting probes the
   131  // managedUpdateAndPersistAccounting method
   132  func testManagedUpdateAndPersistAccounting(t *testing.T) {
   133  	// Initialize Accounting
   134  	testDir := accountingTestDir(t.Name())
   135  	h, m, r, w, _ := testingParams()
   136  	a, err := NewCustomAccounting(h, m, r, w, testDir, &dependencies.AccountingDisablePersistLoop{})
   137  	if err != nil {
   138  		t.Fatal(err)
   139  	}
   140  	defer func() {
   141  		err = a.Close()
   142  		if err != nil {
   143  			t.Fatal(err)
   144  		}
   145  	}()
   146  
   147  	// Grab the persistence beforehand
   148  	a.mu.Lock()
   149  	initLen := len(a.history)
   150  	a.mu.Unlock()
   151  
   152  	// Call managedUpdateAndPersistAccounting
   153  	a.managedUpdateAndPersistAccounting()
   154  
   155  	// Validate expectations
   156  	a.mu.Lock()
   157  	lenHistory := len(a.history)
   158  	a.mu.Unlock()
   159  	if initLen == lenHistory {
   160  		t.Error("History should have been updated")
   161  	}
   162  }
   163  
   164  // testMarshal probes the marshalling and unmarshalling of the persistence
   165  func testMarshal(t *testing.T) {
   166  	// Create AccountingInfo
   167  	ai := skymodules.AccountingInfo{
   168  		Renter: skymodules.RenterAccounting{
   169  			WithheldFunds:      randomCurrency(),
   170  			UnspentUnallocated: randomCurrency(),
   171  		},
   172  		Wallet: skymodules.WalletAccounting{
   173  			ConfirmedSiacoinBalance: randomCurrency(),
   174  			ConfirmedSiafundBalance: randomCurrency(),
   175  		},
   176  		Timestamp: time.Now().Unix(),
   177  	}
   178  
   179  	// Marshal persistence
   180  	data, err := marshalPersistence(ai)
   181  	if err != nil {
   182  		t.Fatal(err)
   183  	}
   184  
   185  	// Unmarshal persistence
   186  	unmarshalledInfo, err := unmarshalPersistence(bytes.NewReader(data))
   187  	if err != nil {
   188  		t.Fatal(err)
   189  	}
   190  	if len(unmarshalledInfo) != 1 {
   191  		t.Fatal("unexpected")
   192  	}
   193  
   194  	// Compare
   195  	if !reflect.DeepEqual(ai, unmarshalledInfo[0]) {
   196  		t.Log("ai", ai)
   197  		t.Log("unmarshalledInfo", unmarshalledInfo[0])
   198  		t.Fatal("info mismatch")
   199  	}
   200  
   201  	// Append several persist elements together
   202  	var datas []byte
   203  	for i := 0; i < 5; i++ {
   204  		datas = append(datas, data...)
   205  	}
   206  
   207  	// Unmarshal
   208  	unmarshalledInfo, err = unmarshalPersistence(bytes.NewReader(datas))
   209  	if err != nil {
   210  		t.Fatal(err)
   211  	}
   212  	if len(unmarshalledInfo) != 5 {
   213  		t.Fatal("unexpected")
   214  	}
   215  	// Compare each element to the original persistence
   216  	for _, uai := range unmarshalledInfo {
   217  		if !reflect.DeepEqual(ai, uai) {
   218  			t.Log("ai", ai)
   219  			t.Log("uai", uai)
   220  			t.Fatal("accounting info mismatch")
   221  		}
   222  	}
   223  }