github.com/nitinawathare/ethereumassignment3@v0.0.0-20211021213010-f07344c2b868/go-ethereum/swarm/storage/feed/lookup/lookup_test.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum 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 go-ethereum 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 go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package lookup_test
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"math/rand"
    23  	"testing"
    24  
    25  	"github.com/ethereum/go-ethereum/swarm/log"
    26  	"github.com/ethereum/go-ethereum/swarm/storage/feed/lookup"
    27  )
    28  
    29  type Data struct {
    30  	Payload uint64
    31  	Time    uint64
    32  }
    33  
    34  type Store map[lookup.EpochID]*Data
    35  
    36  func write(store Store, epoch lookup.Epoch, value *Data) {
    37  	log.Debug("Write: %d-%d, value='%d'\n", epoch.Base(), epoch.Level, value.Payload)
    38  	store[epoch.ID()] = value
    39  }
    40  
    41  func update(store Store, last lookup.Epoch, now uint64, value *Data) lookup.Epoch {
    42  	epoch := lookup.GetNextEpoch(last, now)
    43  
    44  	write(store, epoch, value)
    45  
    46  	return epoch
    47  }
    48  
    49  const Day = 60 * 60 * 24
    50  const Year = Day * 365
    51  const Month = Day * 30
    52  
    53  func makeReadFunc(store Store, counter *int) lookup.ReadFunc {
    54  	return func(ctx context.Context, epoch lookup.Epoch, now uint64) (interface{}, error) {
    55  		*counter++
    56  		data := store[epoch.ID()]
    57  		var valueStr string
    58  		if data != nil {
    59  			valueStr = fmt.Sprintf("%d", data.Payload)
    60  		}
    61  		log.Debug("Read: %d-%d, value='%s'\n", epoch.Base(), epoch.Level, valueStr)
    62  		if data != nil && data.Time <= now {
    63  			return data, nil
    64  		}
    65  		return nil, nil
    66  	}
    67  }
    68  
    69  func TestLookup(t *testing.T) {
    70  
    71  	store := make(Store)
    72  	readCount := 0
    73  	readFunc := makeReadFunc(store, &readCount)
    74  
    75  	// write an update every month for 12 months 3 years ago and then silence for two years
    76  	now := uint64(1533799046)
    77  	var epoch lookup.Epoch
    78  
    79  	var lastData *Data
    80  	for i := uint64(0); i < 12; i++ {
    81  		t := uint64(now - Year*3 + i*Month)
    82  		data := Data{
    83  			Payload: t, //our "payload" will be the timestamp itself.
    84  			Time:    t,
    85  		}
    86  		epoch = update(store, epoch, t, &data)
    87  		lastData = &data
    88  	}
    89  
    90  	// try to get the last value
    91  
    92  	value, err := lookup.Lookup(context.Background(), now, lookup.NoClue, readFunc)
    93  	if err != nil {
    94  		t.Fatal(err)
    95  	}
    96  
    97  	readCountWithoutHint := readCount
    98  
    99  	if value != lastData {
   100  		t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value)
   101  	}
   102  
   103  	// reset the read count for the next test
   104  	readCount = 0
   105  	// Provide a hint to get a faster lookup. In particular, we give the exact location of the last update
   106  	value, err = lookup.Lookup(context.Background(), now, epoch, readFunc)
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  
   111  	if value != lastData {
   112  		t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value)
   113  	}
   114  
   115  	if readCount > readCountWithoutHint {
   116  		t.Fatalf("Expected lookup to complete with fewer or same reads than %d since we provided a hint. Did %d reads.", readCountWithoutHint, readCount)
   117  	}
   118  
   119  	// try to get an intermediate value
   120  	// if we look for a value in now - Year*3 + 6*Month, we should get that value
   121  	// Since the "payload" is the timestamp itself, we can check this.
   122  
   123  	expectedTime := now - Year*3 + 6*Month
   124  
   125  	value, err = lookup.Lookup(context.Background(), expectedTime, lookup.NoClue, readFunc)
   126  	if err != nil {
   127  		t.Fatal(err)
   128  	}
   129  
   130  	data, ok := value.(*Data)
   131  
   132  	if !ok {
   133  		t.Fatal("Expected value to contain data")
   134  	}
   135  
   136  	if data.Time != expectedTime {
   137  		t.Fatalf("Expected value timestamp to be %d, got %d", data.Time, expectedTime)
   138  	}
   139  
   140  }
   141  
   142  func TestOneUpdateAt0(t *testing.T) {
   143  
   144  	store := make(Store)
   145  	readCount := 0
   146  
   147  	readFunc := makeReadFunc(store, &readCount)
   148  	now := uint64(1533903729)
   149  
   150  	var epoch lookup.Epoch
   151  	data := Data{
   152  		Payload: 79,
   153  		Time:    0,
   154  	}
   155  	update(store, epoch, 0, &data)
   156  
   157  	value, err := lookup.Lookup(context.Background(), now, lookup.NoClue, readFunc)
   158  	if err != nil {
   159  		t.Fatal(err)
   160  	}
   161  	if value != &data {
   162  		t.Fatalf("Expected lookup to return the last written value: %v. Got %v", data, value)
   163  	}
   164  }
   165  
   166  // Tests the update is found even when a bad hint is given
   167  func TestBadHint(t *testing.T) {
   168  
   169  	store := make(Store)
   170  	readCount := 0
   171  
   172  	readFunc := makeReadFunc(store, &readCount)
   173  	now := uint64(1533903729)
   174  
   175  	var epoch lookup.Epoch
   176  	data := Data{
   177  		Payload: 79,
   178  		Time:    0,
   179  	}
   180  
   181  	// place an update for t=1200
   182  	update(store, epoch, 1200, &data)
   183  
   184  	// come up with some evil hint
   185  	badHint := lookup.Epoch{
   186  		Level: 18,
   187  		Time:  1200000000,
   188  	}
   189  
   190  	value, err := lookup.Lookup(context.Background(), now, badHint, readFunc)
   191  	if err != nil {
   192  		t.Fatal(err)
   193  	}
   194  	if value != &data {
   195  		t.Fatalf("Expected lookup to return the last written value: %v. Got %v", data, value)
   196  	}
   197  }
   198  
   199  // Tests whether the update is found when the bad hint is exactly below the last update
   200  func TestBadHintNextToUpdate(t *testing.T) {
   201  	store := make(Store)
   202  	readCount := 0
   203  
   204  	readFunc := makeReadFunc(store, &readCount)
   205  	now := uint64(1533903729)
   206  	var last *Data
   207  
   208  	/*  the following loop places updates in the following epochs:
   209  	Update# Time       Base       Level
   210  	0       1200000000 1174405120 25
   211  	1       1200000001 1191182336 24
   212  	2       1200000002 1199570944 23
   213  	3       1200000003 1199570944 22
   214  	4       1200000004 1199570944 21
   215  
   216  	The situation we want to trigger is to give a bad hint exactly
   217  	in T=1200000005, B=1199570944 and L=20, which is where the next
   218  	update would have logically been.
   219  	This affects only when the bad hint's base == previous update's base,
   220  	in this case 1199570944
   221  
   222  	*/
   223  	var epoch lookup.Epoch
   224  	for i := uint64(0); i < 5; i++ {
   225  		data := Data{
   226  			Payload: i,
   227  			Time:    0,
   228  		}
   229  		last = &data
   230  		epoch = update(store, epoch, 1200000000+i, &data)
   231  	}
   232  
   233  	// come up with some evil hint:
   234  	// put it where the next update would have been
   235  	badHint := lookup.Epoch{
   236  		Level: 20,
   237  		Time:  1200000005,
   238  	}
   239  
   240  	value, err := lookup.Lookup(context.Background(), now, badHint, readFunc)
   241  	if err != nil {
   242  		t.Fatal(err)
   243  	}
   244  	if value != last {
   245  		t.Fatalf("Expected lookup to return the last written value: %v. Got %v", last, value)
   246  	}
   247  }
   248  
   249  func TestContextCancellation(t *testing.T) {
   250  
   251  	readFunc := func(ctx context.Context, epoch lookup.Epoch, now uint64) (interface{}, error) {
   252  		<-ctx.Done()
   253  		return nil, ctx.Err()
   254  	}
   255  
   256  	ctx, cancel := context.WithCancel(context.Background())
   257  
   258  	errc := make(chan error)
   259  
   260  	go func() {
   261  		_, err := lookup.Lookup(ctx, 1200000000, lookup.NoClue, readFunc)
   262  		errc <- err
   263  	}()
   264  
   265  	cancel()
   266  
   267  	if err := <-errc; err != context.Canceled {
   268  		t.Fatalf("Expected lookup to return a context Cancelled error, got %v", err)
   269  	}
   270  
   271  	// text context cancellation during hint lookup:
   272  	ctx, cancel = context.WithCancel(context.Background())
   273  	errc = make(chan error)
   274  	someHint := lookup.Epoch{
   275  		Level: 25,
   276  		Time:  300,
   277  	}
   278  
   279  	readFunc = func(ctx context.Context, epoch lookup.Epoch, now uint64) (interface{}, error) {
   280  		if epoch == someHint {
   281  			go cancel()
   282  			<-ctx.Done()
   283  			return nil, ctx.Err()
   284  		}
   285  		return nil, nil
   286  	}
   287  
   288  	go func() {
   289  		_, err := lookup.Lookup(ctx, 301, someHint, readFunc)
   290  		errc <- err
   291  	}()
   292  
   293  	if err := <-errc; err != context.Canceled {
   294  		t.Fatalf("Expected lookup to return a context Cancelled error, got %v", err)
   295  	}
   296  
   297  }
   298  
   299  func TestLookupFail(t *testing.T) {
   300  
   301  	store := make(Store)
   302  	readCount := 0
   303  
   304  	readFunc := makeReadFunc(store, &readCount)
   305  	now := uint64(1533903729)
   306  
   307  	// don't write anything and try to look up.
   308  	// we're testing we don't get stuck in a loop
   309  
   310  	value, err := lookup.Lookup(context.Background(), now, lookup.NoClue, readFunc)
   311  	if err != nil {
   312  		t.Fatal(err)
   313  	}
   314  	if value != nil {
   315  		t.Fatal("Expected value to be nil, since the update should've failed")
   316  	}
   317  
   318  	expectedReads := now/(1<<lookup.HighestLevel) + 1
   319  	if uint64(readCount) != expectedReads {
   320  		t.Fatalf("Expected lookup to fail after %d reads. Did %d reads.", expectedReads, readCount)
   321  	}
   322  }
   323  
   324  func TestHighFreqUpdates(t *testing.T) {
   325  
   326  	store := make(Store)
   327  	readCount := 0
   328  
   329  	readFunc := makeReadFunc(store, &readCount)
   330  	now := uint64(1533903729)
   331  
   332  	// write an update every second for the last 1000 seconds
   333  	var epoch lookup.Epoch
   334  
   335  	var lastData *Data
   336  	for i := uint64(0); i <= 994; i++ {
   337  		T := uint64(now - 1000 + i)
   338  		data := Data{
   339  			Payload: T, //our "payload" will be the timestamp itself.
   340  			Time:    T,
   341  		}
   342  		epoch = update(store, epoch, T, &data)
   343  		lastData = &data
   344  	}
   345  
   346  	value, err := lookup.Lookup(context.Background(), lastData.Time, lookup.NoClue, readFunc)
   347  	if err != nil {
   348  		t.Fatal(err)
   349  	}
   350  
   351  	if value != lastData {
   352  		t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value)
   353  	}
   354  
   355  	readCountWithoutHint := readCount
   356  	// reset the read count for the next test
   357  	readCount = 0
   358  	// Provide a hint to get a faster lookup. In particular, we give the exact location of the last update
   359  	value, err = lookup.Lookup(context.Background(), now, epoch, readFunc)
   360  	if err != nil {
   361  		t.Fatal(err)
   362  	}
   363  
   364  	if value != lastData {
   365  		t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value)
   366  	}
   367  
   368  	if readCount > readCountWithoutHint {
   369  		t.Fatalf("Expected lookup to complete with fewer or equal reads than %d since we provided a hint. Did %d reads.", readCountWithoutHint, readCount)
   370  	}
   371  
   372  	for i := uint64(0); i <= 994; i++ {
   373  		T := uint64(now - 1000 + i) // update every second for the last 1000 seconds
   374  		value, err := lookup.Lookup(context.Background(), T, lookup.NoClue, readFunc)
   375  		if err != nil {
   376  			t.Fatal(err)
   377  		}
   378  		data, _ := value.(*Data)
   379  		if data == nil {
   380  			t.Fatalf("Expected lookup to return %d, got nil", T)
   381  		}
   382  		if data.Payload != T {
   383  			t.Fatalf("Expected lookup to return %d, got %d", T, data.Time)
   384  		}
   385  	}
   386  }
   387  
   388  func TestSparseUpdates(t *testing.T) {
   389  
   390  	store := make(Store)
   391  	readCount := 0
   392  	readFunc := makeReadFunc(store, &readCount)
   393  
   394  	// write an update every 5 years 3 times starting in Jan 1st 1970 and then silence
   395  
   396  	now := uint64(1533799046)
   397  	var epoch lookup.Epoch
   398  
   399  	var lastData *Data
   400  	for i := uint64(0); i < 5; i++ {
   401  		T := uint64(Year * 5 * i) // write an update every 5 years 3 times starting in Jan 1st 1970 and then silence
   402  		data := Data{
   403  			Payload: T, //our "payload" will be the timestamp itself.
   404  			Time:    T,
   405  		}
   406  		epoch = update(store, epoch, T, &data)
   407  		lastData = &data
   408  	}
   409  
   410  	// try to get the last value
   411  
   412  	value, err := lookup.Lookup(context.Background(), now, lookup.NoClue, readFunc)
   413  	if err != nil {
   414  		t.Fatal(err)
   415  	}
   416  
   417  	readCountWithoutHint := readCount
   418  
   419  	if value != lastData {
   420  		t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value)
   421  	}
   422  
   423  	// reset the read count for the next test
   424  	readCount = 0
   425  	// Provide a hint to get a faster lookup. In particular, we give the exact location of the last update
   426  	value, err = lookup.Lookup(context.Background(), now, epoch, readFunc)
   427  	if err != nil {
   428  		t.Fatal(err)
   429  	}
   430  
   431  	if value != lastData {
   432  		t.Fatalf("Expected lookup to return the last written value: %v. Got %v", lastData, value)
   433  	}
   434  
   435  	if readCount > readCountWithoutHint {
   436  		t.Fatalf("Expected lookup to complete with fewer reads than %d since we provided a hint. Did %d reads.", readCountWithoutHint, readCount)
   437  	}
   438  
   439  }
   440  
   441  // testG will hold precooked test results
   442  // fields are abbreviated to reduce the size of the literal below
   443  type testG struct {
   444  	e lookup.Epoch // last
   445  	n uint64       // next level
   446  	x uint8        // expected result
   447  }
   448  
   449  // test cases
   450  var testGetNextLevelCases = []testG{{e: lookup.Epoch{Time: 989875233, Level: 12}, n: 989875233, x: 11}, {e: lookup.Epoch{Time: 995807650, Level: 18}, n: 995598156, x: 19}, {e: lookup.Epoch{Time: 969167082, Level: 0}, n: 968990357, x: 18}, {e: lookup.Epoch{Time: 993087628, Level: 14}, n: 992987044, x: 20}, {e: lookup.Epoch{Time: 963364631, Level: 20}, n: 963364630, x: 19}, {e: lookup.Epoch{Time: 963497510, Level: 16}, n: 963370732, x: 18}, {e: lookup.Epoch{Time: 955421349, Level: 22}, n: 955421348, x: 21}, {e: lookup.Epoch{Time: 968220379, Level: 15}, n: 968220378, x: 14}, {e: lookup.Epoch{Time: 939129014, Level: 6}, n: 939128771, x: 11}, {e: lookup.Epoch{Time: 907847903, Level: 6}, n: 907791833, x: 18}, {e: lookup.Epoch{Time: 910835564, Level: 15}, n: 910835564, x: 14}, {e: lookup.Epoch{Time: 913578333, Level: 22}, n: 881808431, x: 25}, {e: lookup.Epoch{Time: 895818460, Level: 3}, n: 895818132, x: 9}, {e: lookup.Epoch{Time: 903843025, Level: 24}, n: 895609561, x: 23}, {e: lookup.Epoch{Time: 877889433, Level: 13}, n: 877877093, x: 15}, {e: lookup.Epoch{Time: 901450396, Level: 10}, n: 901450058, x: 9}, {e: lookup.Epoch{Time: 925179910, Level: 3}, n: 925168393, x: 16}, {e: lookup.Epoch{Time: 913485477, Level: 21}, n: 913485476, x: 20}, {e: lookup.Epoch{Time: 924462991, Level: 18}, n: 924462990, x: 17}, {e: lookup.Epoch{Time: 941175128, Level: 13}, n: 941175127, x: 12}, {e: lookup.Epoch{Time: 920126583, Level: 3}, n: 920100782, x: 19}, {e: lookup.Epoch{Time: 932403200, Level: 9}, n: 932279891, x: 17}, {e: lookup.Epoch{Time: 948284931, Level: 2}, n: 948284921, x: 9}, {e: lookup.Epoch{Time: 953540997, Level: 7}, n: 950547986, x: 22}, {e: lookup.Epoch{Time: 926639837, Level: 18}, n: 918608882, x: 24}, {e: lookup.Epoch{Time: 954637598, Level: 1}, n: 954578761, x: 17}, {e: lookup.Epoch{Time: 943482981, Level: 10}, n: 942924151, x: 19}, {e: lookup.Epoch{Time: 963580771, Level: 7}, n: 963580771, x: 6}, {e: lookup.Epoch{Time: 993744930, Level: 7}, n: 993690858, x: 16}, {e: lookup.Epoch{Time: 1018890213, Level: 12}, n: 1018890212, x: 11}, {e: lookup.Epoch{Time: 1030309411, Level: 2}, n: 1030309227, x: 9}, {e: lookup.Epoch{Time: 1063204997, Level: 20}, n: 1063204996, x: 19}, {e: lookup.Epoch{Time: 1094340832, Level: 6}, n: 1094340633, x: 7}, {e: lookup.Epoch{Time: 1077880597, Level: 10}, n: 1075914292, x: 20}, {e: lookup.Epoch{Time: 1051114957, Level: 18}, n: 1051114957, x: 17}, {e: lookup.Epoch{Time: 1045649701, Level: 22}, n: 1045649700, x: 21}, {e: lookup.Epoch{Time: 1066198885, Level: 14}, n: 1066198884, x: 13}, {e: lookup.Epoch{Time: 1053231952, Level: 1}, n: 1053210845, x: 16}, {e: lookup.Epoch{Time: 1068763404, Level: 14}, n: 1068675428, x: 18}, {e: lookup.Epoch{Time: 1039042173, Level: 15}, n: 1038973110, x: 17}, {e: lookup.Epoch{Time: 1050747636, Level: 6}, n: 1050747364, x: 9}, {e: lookup.Epoch{Time: 1030034434, Level: 23}, n: 1030034433, x: 22}, {e: lookup.Epoch{Time: 1003783425, Level: 18}, n: 1003783424, x: 17}, {e: lookup.Epoch{Time: 988163976, Level: 15}, n: 988084064, x: 17}, {e: lookup.Epoch{Time: 1007222377, Level: 15}, n: 1007222377, x: 14}, {e: lookup.Epoch{Time: 1001211375, Level: 13}, n: 1001208178, x: 14}, {e: lookup.Epoch{Time: 997623199, Level: 8}, n: 997623198, x: 7}, {e: lookup.Epoch{Time: 1026283830, Level: 10}, n: 1006681704, x: 24}, {e: lookup.Epoch{Time: 1019421907, Level: 20}, n: 1019421906, x: 19}, {e: lookup.Epoch{Time: 1043154306, Level: 16}, n: 1043108343, x: 16}, {e: lookup.Epoch{Time: 1075643767, Level: 17}, n: 1075325898, x: 18}, {e: lookup.Epoch{Time: 1043726309, Level: 20}, n: 1043726308, x: 19}, {e: lookup.Epoch{Time: 1056415324, Level: 17}, n: 1056415324, x: 16}, {e: lookup.Epoch{Time: 1088650219, Level: 13}, n: 1088650218, x: 12}, {e: lookup.Epoch{Time: 1088551662, Level: 7}, n: 1088543355, x: 13}, {e: lookup.Epoch{Time: 1069667265, Level: 6}, n: 1069667075, x: 7}, {e: lookup.Epoch{Time: 1079145970, Level: 18}, n: 1079145969, x: 17}, {e: lookup.Epoch{Time: 1083338876, Level: 7}, n: 1083338875, x: 6}, {e: lookup.Epoch{Time: 1051581086, Level: 4}, n: 1051568869, x: 14}, {e: lookup.Epoch{Time: 1028430882, Level: 4}, n: 1028430864, x: 5}, {e: lookup.Epoch{Time: 1057356462, Level: 1}, n: 1057356417, x: 5}, {e: lookup.Epoch{Time: 1033104266, Level: 0}, n: 1033097479, x: 13}, {e: lookup.Epoch{Time: 1031391367, Level: 11}, n: 1031387304, x: 14}, {e: lookup.Epoch{Time: 1049781164, Level: 15}, n: 1049781163, x: 14}, {e: lookup.Epoch{Time: 1027271628, Level: 12}, n: 1027271627, x: 11}, {e: lookup.Epoch{Time: 1057270560, Level: 23}, n: 1057270560, x: 22}, {e: lookup.Epoch{Time: 1047501317, Level: 15}, n: 1047501317, x: 14}, {e: lookup.Epoch{Time: 1058349035, Level: 11}, n: 1045175573, x: 24}, {e: lookup.Epoch{Time: 1057396147, Level: 20}, n: 1057396147, x: 19}, {e: lookup.Epoch{Time: 1048906375, Level: 18}, n: 1039616919, x: 25}, {e: lookup.Epoch{Time: 1074294831, Level: 20}, n: 1074294831, x: 19}, {e: lookup.Epoch{Time: 1088946052, Level: 1}, n: 1088917364, x: 14}, {e: lookup.Epoch{Time: 1112337595, Level: 17}, n: 1111008110, x: 22}, {e: lookup.Epoch{Time: 1099990284, Level: 5}, n: 1099968370, x: 15}, {e: lookup.Epoch{Time: 1087036441, Level: 16}, n: 1053967855, x: 25}, {e: lookup.Epoch{Time: 1069225185, Level: 8}, n: 1069224660, x: 10}, {e: lookup.Epoch{Time: 1057505479, Level: 9}, n: 1057505170, x: 14}, {e: lookup.Epoch{Time: 1072381377, Level: 12}, n: 1065950959, x: 22}, {e: lookup.Epoch{Time: 1093887139, Level: 8}, n: 1093863305, x: 14}, {e: lookup.Epoch{Time: 1082366510, Level: 24}, n: 1082366510, x: 23}, {e: lookup.Epoch{Time: 1103231132, Level: 14}, n: 1102292201, x: 22}, {e: lookup.Epoch{Time: 1094502355, Level: 3}, n: 1094324652, x: 18}, {e: lookup.Epoch{Time: 1068488344, Level: 12}, n: 1067577330, x: 19}, {e: lookup.Epoch{Time: 1050278233, Level: 12}, n: 1050278232, x: 11}, {e: lookup.Epoch{Time: 1047660768, Level: 5}, n: 1047652137, x: 17}, {e: lookup.Epoch{Time: 1060116167, Level: 11}, n: 1060114091, x: 12}, {e: lookup.Epoch{Time: 1068149392, Level: 21}, n: 1052074801, x: 24}, {e: lookup.Epoch{Time: 1081934120, Level: 6}, n: 1081933847, x: 8}, {e: lookup.Epoch{Time: 1107943693, Level: 16}, n: 1107096139, x: 25}, {e: lookup.Epoch{Time: 1131571649, Level: 9}, n: 1131570428, x: 11}, {e: lookup.Epoch{Time: 1123139367, Level: 0}, n: 1122912198, x: 20}, {e: lookup.Epoch{Time: 1121144423, Level: 6}, n: 1120568289, x: 20}, {e: lookup.Epoch{Time: 1089932411, Level: 17}, n: 1089932410, x: 16}, {e: lookup.Epoch{Time: 1104899012, Level: 22}, n: 1098978789, x: 22}, {e: lookup.Epoch{Time: 1094588059, Level: 21}, n: 1094588059, x: 20}, {e: lookup.Epoch{Time: 1114987438, Level: 24}, n: 1114987437, x: 23}, {e: lookup.Epoch{Time: 1084186305, Level: 7}, n: 1084186241, x: 6}, {e: lookup.Epoch{Time: 1058827111, Level: 8}, n: 1058826504, x: 9}, {e: lookup.Epoch{Time: 1090679810, Level: 12}, n: 1090616539, x: 17}, {e: lookup.Epoch{Time: 1084299475, Level: 23}, n: 1084299475, x: 22}}
   451  
   452  func TestGetNextLevel(t *testing.T) {
   453  
   454  	// First, test well-known cases
   455  	last := lookup.Epoch{
   456  		Time:  1533799046,
   457  		Level: 5,
   458  	}
   459  
   460  	level := lookup.GetNextLevel(last, last.Time)
   461  	expected := uint8(4)
   462  	if level != expected {
   463  		t.Fatalf("Expected GetNextLevel to return %d for same-time updates at a nonzero level, got %d", expected, level)
   464  	}
   465  
   466  	level = lookup.GetNextLevel(last, last.Time+(1<<lookup.HighestLevel)+3000)
   467  	expected = lookup.HighestLevel
   468  	if level != expected {
   469  		t.Fatalf("Expected GetNextLevel to return %d for updates set 2^lookup.HighestLevel seconds away, got %d", expected, level)
   470  	}
   471  
   472  	level = lookup.GetNextLevel(last, last.Time+(1<<last.Level))
   473  	expected = last.Level
   474  	if level != expected {
   475  		t.Fatalf("Expected GetNextLevel to return %d for updates set 2^last.Level seconds away, got %d", expected, level)
   476  	}
   477  
   478  	last.Level = 0
   479  	level = lookup.GetNextLevel(last, last.Time)
   480  	expected = 0
   481  	if level != expected {
   482  		t.Fatalf("Expected GetNextLevel to return %d for same-time updates at a zero level, got %d", expected, level)
   483  	}
   484  
   485  	// run a batch of 100 cooked tests
   486  	for _, s := range testGetNextLevelCases {
   487  		level := lookup.GetNextLevel(s.e, s.n)
   488  		if level != s.x {
   489  			t.Fatalf("Expected GetNextLevel to return %d for last=%s when now=%d, got %d", s.x, s.e.String(), s.n, level)
   490  		}
   491  	}
   492  
   493  }
   494  
   495  // cookGetNextLevelTests is used to generate a deterministic
   496  // set of cases for TestGetNextLevel and thus "freeze" its current behavior
   497  func CookGetNextLevelTests(t *testing.T) {
   498  	st := ""
   499  	var last lookup.Epoch
   500  	last.Time = 1000000000
   501  	var now uint64
   502  	var expected uint8
   503  	for i := 0; i < 100; i++ {
   504  		last.Time += uint64(rand.Intn(1<<26)) - (1 << 25)
   505  		last.Level = uint8(rand.Intn(25))
   506  		v := last.Level + uint8(rand.Intn(lookup.HighestLevel))
   507  		if v > lookup.HighestLevel {
   508  			v = 0
   509  		}
   510  		now = last.Time + uint64(rand.Intn(1<<v+1)) - (1 << v)
   511  		expected = lookup.GetNextLevel(last, now)
   512  		st = fmt.Sprintf("%s,testG{e:lookup.Epoch{Time:%d, Level:%d}, n:%d, x:%d}", st, last.Time, last.Level, now, expected)
   513  	}
   514  	fmt.Println(st)
   515  }