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  }