github.com/decred/dcrlnd@v0.7.6/channeldb/forwarding_log_test.go (about) 1 package channeldb 2 3 import ( 4 "math/rand" 5 "reflect" 6 "testing" 7 "time" 8 9 "github.com/davecgh/go-spew/spew" 10 "github.com/decred/dcrlnd/lnwire" 11 "github.com/stretchr/testify/assert" 12 ) 13 14 // TestForwardingLogBasicStorageAndQuery tests that we're able to store and 15 // then query for items that have previously been added to the event log. 16 func TestForwardingLogBasicStorageAndQuery(t *testing.T) { 17 t.Parallel() 18 19 // First, we'll set up a test database, and use that to instantiate the 20 // forwarding event log that we'll be using for the duration of the 21 // test. 22 db, cleanUp, err := MakeTestDB() 23 if err != nil { 24 t.Fatalf("unable to make test db: %v", err) 25 } 26 defer cleanUp() 27 28 log := ForwardingLog{ 29 db: db, 30 } 31 32 initialTime := time.Unix(1234, 0) 33 timestamp := time.Unix(1234, 0) 34 35 // We'll create 100 random events, which each event being spaced 10 36 // minutes after the prior event. 37 numEvents := 100 38 events := make([]ForwardingEvent, numEvents) 39 for i := 0; i < numEvents; i++ { 40 events[i] = ForwardingEvent{ 41 Timestamp: timestamp, 42 IncomingChanID: lnwire.NewShortChanIDFromInt(uint64(rand.Int63())), 43 OutgoingChanID: lnwire.NewShortChanIDFromInt(uint64(rand.Int63())), 44 AmtIn: lnwire.MilliAtom(rand.Int63()), 45 AmtOut: lnwire.MilliAtom(rand.Int63()), 46 } 47 48 timestamp = timestamp.Add(time.Minute * 10) 49 } 50 51 // Now that all of our set of events constructed, we'll add them to the 52 // database in a batch manner. 53 if err := log.AddForwardingEvents(events); err != nil { 54 t.Fatalf("unable to add events: %v", err) 55 } 56 57 // With our events added we'll now construct a basic query to retrieve 58 // all of the events. 59 eventQuery := ForwardingEventQuery{ 60 StartTime: initialTime, 61 EndTime: timestamp, 62 IndexOffset: 0, 63 NumMaxEvents: 1000, 64 } 65 timeSlice, err := log.Query(eventQuery) 66 if err != nil { 67 t.Fatalf("unable to query for events: %v", err) 68 } 69 70 // The set of returned events should match identically, as they should 71 // be returned in sorted order. 72 if !reflect.DeepEqual(events, timeSlice.ForwardingEvents) { 73 t.Fatalf("event mismatch: expected %v vs %v", 74 spew.Sdump(events), spew.Sdump(timeSlice.ForwardingEvents)) 75 } 76 77 // The offset index of the final entry should be numEvents, so the 78 // number of total events we've written. 79 if timeSlice.LastIndexOffset != uint32(numEvents) { 80 t.Fatalf("wrong final offset: expected %v, got %v", 81 timeSlice.LastIndexOffset, numEvents) 82 } 83 } 84 85 // TestForwardingLogQueryOptions tests that the query offset works properly. So 86 // if we add a series of events, then we should be able to seek within the 87 // timeslice accordingly. This exercises the index offset and num max event 88 // field in the query, and also the last index offset field int he response. 89 func TestForwardingLogQueryOptions(t *testing.T) { 90 t.Parallel() 91 92 // First, we'll set up a test database, and use that to instantiate the 93 // forwarding event log that we'll be using for the duration of the 94 // test. 95 db, cleanUp, err := MakeTestDB() 96 if err != nil { 97 t.Fatalf("unable to make test db: %v", err) 98 } 99 defer cleanUp() 100 101 log := ForwardingLog{ 102 db: db, 103 } 104 105 initialTime := time.Unix(1234, 0) 106 endTime := time.Unix(1234, 0) 107 108 // We'll create 20 random events, which each event being spaced 10 109 // minutes after the prior event. 110 numEvents := 20 111 events := make([]ForwardingEvent, numEvents) 112 for i := 0; i < numEvents; i++ { 113 events[i] = ForwardingEvent{ 114 Timestamp: endTime, 115 IncomingChanID: lnwire.NewShortChanIDFromInt(uint64(rand.Int63())), 116 OutgoingChanID: lnwire.NewShortChanIDFromInt(uint64(rand.Int63())), 117 AmtIn: lnwire.MilliAtom(rand.Int63()), 118 AmtOut: lnwire.MilliAtom(rand.Int63()), 119 } 120 121 endTime = endTime.Add(time.Minute * 10) 122 } 123 124 // Now that all of our set of events constructed, we'll add them to the 125 // database in a batch manner. 126 if err := log.AddForwardingEvents(events); err != nil { 127 t.Fatalf("unable to add events: %v", err) 128 } 129 130 // With all of our events added, we should be able to query for the 131 // first 10 events using the max event query field. 132 eventQuery := ForwardingEventQuery{ 133 StartTime: initialTime, 134 EndTime: endTime, 135 IndexOffset: 0, 136 NumMaxEvents: 10, 137 } 138 timeSlice, err := log.Query(eventQuery) 139 if err != nil { 140 t.Fatalf("unable to query for events: %v", err) 141 } 142 143 // We should get exactly 10 events back. 144 if len(timeSlice.ForwardingEvents) != 10 { 145 t.Fatalf("wrong number of events: expected %v, got %v", 10, 146 len(timeSlice.ForwardingEvents)) 147 } 148 149 // The set of events returned should be the first 10 events that we 150 // added. 151 if !reflect.DeepEqual(events[:10], timeSlice.ForwardingEvents) { 152 t.Fatalf("wrong response: expected %v, got %v", 153 spew.Sdump(events[:10]), 154 spew.Sdump(timeSlice.ForwardingEvents)) 155 } 156 157 // The final offset should be the exact number of events returned. 158 if timeSlice.LastIndexOffset != 10 { 159 t.Fatalf("wrong index offset: expected %v, got %v", 10, 160 timeSlice.LastIndexOffset) 161 } 162 163 // If we use the final offset to query again, then we should get 10 164 // more events, that are the last 10 events we wrote. 165 eventQuery.IndexOffset = 10 166 timeSlice, err = log.Query(eventQuery) 167 if err != nil { 168 t.Fatalf("unable to query for events: %v", err) 169 } 170 171 // We should get exactly 10 events back once again. 172 if len(timeSlice.ForwardingEvents) != 10 { 173 t.Fatalf("wrong number of events: expected %v, got %v", 10, 174 len(timeSlice.ForwardingEvents)) 175 } 176 177 // The events that we got back should be the last 10 events that we 178 // wrote out. 179 if !reflect.DeepEqual(events[10:], timeSlice.ForwardingEvents) { 180 t.Fatalf("wrong response: expected %v, got %v", 181 spew.Sdump(events[10:]), 182 spew.Sdump(timeSlice.ForwardingEvents)) 183 } 184 185 // Finally, the last index offset should be 20, or the number of 186 // records we've written out. 187 if timeSlice.LastIndexOffset != 20 { 188 t.Fatalf("wrong index offset: expected %v, got %v", 20, 189 timeSlice.LastIndexOffset) 190 } 191 } 192 193 // TestForwardingLogQueryLimit tests that we're able to properly limit the 194 // number of events that are returned as part of a query. 195 func TestForwardingLogQueryLimit(t *testing.T) { 196 t.Parallel() 197 198 // First, we'll set up a test database, and use that to instantiate the 199 // forwarding event log that we'll be using for the duration of the 200 // test. 201 db, cleanUp, err := MakeTestDB() 202 if err != nil { 203 t.Fatalf("unable to make test db: %v", err) 204 } 205 defer cleanUp() 206 207 log := ForwardingLog{ 208 db: db, 209 } 210 211 initialTime := time.Unix(1234, 0) 212 endTime := time.Unix(1234, 0) 213 214 // We'll create 200 random events, which each event being spaced 10 215 // minutes after the prior event. 216 numEvents := 200 217 events := make([]ForwardingEvent, numEvents) 218 for i := 0; i < numEvents; i++ { 219 events[i] = ForwardingEvent{ 220 Timestamp: endTime, 221 IncomingChanID: lnwire.NewShortChanIDFromInt(uint64(rand.Int63())), 222 OutgoingChanID: lnwire.NewShortChanIDFromInt(uint64(rand.Int63())), 223 AmtIn: lnwire.MilliAtom(rand.Int63()), 224 AmtOut: lnwire.MilliAtom(rand.Int63()), 225 } 226 227 endTime = endTime.Add(time.Minute * 10) 228 } 229 230 // Now that all of our set of events constructed, we'll add them to the 231 // database in a batch manner. 232 if err := log.AddForwardingEvents(events); err != nil { 233 t.Fatalf("unable to add events: %v", err) 234 } 235 236 // Once the events have been written out, we'll issue a query over the 237 // entire range, but restrict the number of events to the first 100. 238 eventQuery := ForwardingEventQuery{ 239 StartTime: initialTime, 240 EndTime: endTime, 241 IndexOffset: 0, 242 NumMaxEvents: 100, 243 } 244 timeSlice, err := log.Query(eventQuery) 245 if err != nil { 246 t.Fatalf("unable to query for events: %v", err) 247 } 248 249 // We should get exactly 100 events back. 250 if len(timeSlice.ForwardingEvents) != 100 { 251 t.Fatalf("wrong number of events: expected %v, got %v", 10, 252 len(timeSlice.ForwardingEvents)) 253 } 254 255 // The set of events returned should be the first 100 events that we 256 // added. 257 if !reflect.DeepEqual(events[:100], timeSlice.ForwardingEvents) { 258 t.Fatalf("wrong response: expected %v, got %v", 259 spew.Sdump(events[:100]), 260 spew.Sdump(timeSlice.ForwardingEvents)) 261 } 262 263 // The final offset should be the exact number of events returned. 264 if timeSlice.LastIndexOffset != 100 { 265 t.Fatalf("wrong index offset: expected %v, got %v", 100, 266 timeSlice.LastIndexOffset) 267 } 268 } 269 270 // TestForwardingLogMakeUniqueTimestamps makes sure the function that creates 271 // unique timestamps does it job correctly. 272 func TestForwardingLogMakeUniqueTimestamps(t *testing.T) { 273 t.Parallel() 274 275 // Create a list of events where some of the timestamps collide. We 276 // expect no existing timestamp to be overwritten, instead the "gaps" 277 // between them should be filled. 278 inputSlice := []ForwardingEvent{ 279 {Timestamp: time.Unix(0, 1001)}, 280 {Timestamp: time.Unix(0, 2001)}, 281 {Timestamp: time.Unix(0, 1001)}, 282 {Timestamp: time.Unix(0, 1002)}, 283 {Timestamp: time.Unix(0, 1004)}, 284 {Timestamp: time.Unix(0, 1004)}, 285 {Timestamp: time.Unix(0, 1007)}, 286 {Timestamp: time.Unix(0, 1001)}, 287 } 288 expectedSlice := []ForwardingEvent{ 289 {Timestamp: time.Unix(0, 1001)}, 290 {Timestamp: time.Unix(0, 1002)}, 291 {Timestamp: time.Unix(0, 1003)}, 292 {Timestamp: time.Unix(0, 1004)}, 293 {Timestamp: time.Unix(0, 1005)}, 294 {Timestamp: time.Unix(0, 1006)}, 295 {Timestamp: time.Unix(0, 1007)}, 296 {Timestamp: time.Unix(0, 2001)}, 297 } 298 299 makeUniqueTimestamps(inputSlice) 300 301 for idx, in := range inputSlice { 302 expect := expectedSlice[idx] 303 assert.Equal( 304 t, expect.Timestamp.UnixNano(), in.Timestamp.UnixNano(), 305 ) 306 } 307 } 308 309 // TestForwardingLogStoreEvent makes sure forwarding events are stored without 310 // colliding on duplicate timestamps. 311 func TestForwardingLogStoreEvent(t *testing.T) { 312 t.Parallel() 313 314 // First, we'll set up a test database, and use that to instantiate the 315 // forwarding event log that we'll be using for the duration of the 316 // test. 317 db, cleanUp, err := MakeTestDB() 318 if err != nil { 319 t.Fatalf("unable to make test db: %v", err) 320 } 321 defer cleanUp() 322 323 log := ForwardingLog{ 324 db: db, 325 } 326 327 // We'll create 20 random events, with each event having a timestamp 328 // with just one nanosecond apart. 329 numEvents := 20 330 events := make([]ForwardingEvent, numEvents) 331 ts := time.Now().UnixNano() 332 for i := 0; i < numEvents; i++ { 333 events[i] = ForwardingEvent{ 334 Timestamp: time.Unix(0, ts+int64(i)), 335 IncomingChanID: lnwire.NewShortChanIDFromInt(uint64(rand.Int63())), 336 OutgoingChanID: lnwire.NewShortChanIDFromInt(uint64(rand.Int63())), 337 AmtIn: lnwire.MilliAtom(rand.Int63()), 338 AmtOut: lnwire.MilliAtom(rand.Int63()), 339 } 340 } 341 342 // Now that all of our events are constructed, we'll add them to the 343 // database in a batched manner. 344 if err := log.AddForwardingEvents(events); err != nil { 345 t.Fatalf("unable to add events: %v", err) 346 } 347 348 // Because timestamps are de-duplicated when adding them in a single 349 // batch before they even hit the DB, we add the same events again but 350 // in a new batch. They now have to be de-duplicated on the DB level. 351 if err := log.AddForwardingEvents(events); err != nil { 352 t.Fatalf("unable to add second batch of events: %v", err) 353 } 354 355 // With all of our events added, we should be able to query for all 356 // events with a range of just 40 nanoseconds (2 times 20 events, all 357 // spaced one nanosecond apart). 358 eventQuery := ForwardingEventQuery{ 359 StartTime: time.Unix(0, ts), 360 EndTime: time.Unix(0, ts+int64(numEvents*2)), 361 IndexOffset: 0, 362 NumMaxEvents: uint32(numEvents * 3), 363 } 364 timeSlice, err := log.Query(eventQuery) 365 if err != nil { 366 t.Fatalf("unable to query for events: %v", err) 367 } 368 369 // We should get exactly 40 events back. 370 if len(timeSlice.ForwardingEvents) != numEvents*2 { 371 t.Fatalf("wrong number of events: expected %v, got %v", 372 numEvents*2, len(timeSlice.ForwardingEvents)) 373 } 374 375 // The timestamps should be spaced out evenly and in order. 376 for i := 0; i < numEvents*2; i++ { 377 eventTs := timeSlice.ForwardingEvents[i].Timestamp.UnixNano() 378 if eventTs != ts+int64(i) { 379 t.Fatalf("unexpected timestamp of event %d: expected "+ 380 "%d, got %d", i, ts+int64(i), eventTs) 381 } 382 } 383 }