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 }