github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/scripts/scmigrate/migrate_test.go (about)

     1  package scmigrate
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"math/rand"
     7  	"testing"
     8  
     9  	"github.com/gogo/protobuf/proto"
    10  	dbm "github.com/tendermint/tm-db"
    11  
    12  	"github.com/ari-anchor/sei-tendermint/types"
    13  )
    14  
    15  func appendRandomMigrations(in []toMigrate, num int) []toMigrate {
    16  	if in == nil {
    17  		in = []toMigrate{}
    18  	}
    19  
    20  	for i := 0; i < num; i++ {
    21  		height := rand.Int63()
    22  		if height <= 0 {
    23  			continue
    24  		}
    25  		in = append(in, toMigrate{commit: &types.Commit{Height: height}})
    26  	}
    27  	return in
    28  }
    29  
    30  func assertWellOrderedMigrations(t *testing.T, testData []toMigrate) {
    31  	t.Run("ValuesDescend", func(t *testing.T) {
    32  		for idx := range testData {
    33  			height := testData[idx].commit.Height
    34  			if idx == 0 {
    35  				continue
    36  			}
    37  			prev := testData[idx-1].commit.Height
    38  			if prev < height {
    39  				t.Fatal("height decreased in sort order")
    40  			}
    41  		}
    42  	})
    43  	t.Run("EarliestIsZero", func(t *testing.T) {
    44  		earliestHeight := testData[len(testData)-1].commit.Height
    45  		if earliestHeight != 0 {
    46  			t.Fatalf("the earliest height is not 0: %d", earliestHeight)
    47  		}
    48  	})
    49  }
    50  
    51  func getLatestHeight(data []toMigrate) int64 {
    52  	var out int64
    53  
    54  	for _, d := range data {
    55  		if d.commit.Height >= out {
    56  			out = d.commit.Height
    57  		}
    58  	}
    59  
    60  	return out
    61  }
    62  
    63  func insertTestData(t *testing.T, db dbm.DB, data []toMigrate) {
    64  	t.Helper()
    65  
    66  	batch := db.NewBatch()
    67  
    68  	for idx, val := range data {
    69  		payload, err := proto.Marshal(val.commit.ToProto())
    70  		if err != nil {
    71  			t.Fatal(err)
    72  		}
    73  
    74  		if err := batch.Set(makeKeyFromPrefix(prefixSeenCommit, int64(idx)), payload); err != nil {
    75  			t.Fatal(err)
    76  		}
    77  	}
    78  	if err := batch.WriteSync(); err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	if err := batch.Close(); err != nil {
    82  		t.Fatal(err)
    83  	}
    84  }
    85  
    86  func TestMigrations(t *testing.T) {
    87  	t.Run("Sort", func(t *testing.T) {
    88  		t.Run("HandCraftedData", func(t *testing.T) {
    89  			testData := []toMigrate{
    90  				{commit: &types.Commit{Height: 100}},
    91  				{commit: &types.Commit{Height: 0}},
    92  				{commit: &types.Commit{Height: 8}},
    93  				{commit: &types.Commit{Height: 1}},
    94  			}
    95  
    96  			sortMigrations(testData)
    97  			assertWellOrderedMigrations(t, testData)
    98  		})
    99  		t.Run("RandomGeneratedData", func(t *testing.T) {
   100  			testData := []toMigrate{{commit: &types.Commit{Height: 0}}}
   101  
   102  			testData = appendRandomMigrations(testData, 10000)
   103  
   104  			sortMigrations(testData)
   105  			assertWellOrderedMigrations(t, testData)
   106  		})
   107  	})
   108  	t.Run("InvalidMigrations", func(t *testing.T) {
   109  		if _, err := makeToMigrate(nil); err == nil {
   110  			t.Fatal("should error for nil migrations")
   111  		}
   112  		if _, err := makeToMigrate([]byte{}); err == nil {
   113  			t.Fatal("should error for empty migrations")
   114  		}
   115  		if _, err := makeToMigrate([]byte("invalid")); err == nil {
   116  			t.Fatal("should error for empty migrations")
   117  		}
   118  	})
   119  
   120  	t.Run("GetSeenCommits", func(t *testing.T) {
   121  		ctx, cancel := context.WithCancel(context.Background())
   122  		defer cancel()
   123  
   124  		db := dbm.NewMemDB()
   125  		data := appendRandomMigrations([]toMigrate{}, 100)
   126  		insertTestData(t, db, data)
   127  		commits, err := getAllSeenCommits(ctx, db)
   128  		if err != nil {
   129  			t.Fatal(err)
   130  		}
   131  		if len(commits) != len(data) {
   132  			t.Log("inputs", len(data))
   133  			t.Log("commits", len(commits))
   134  			t.Fatal("migrations not found in database")
   135  		}
   136  	})
   137  	t.Run("Integration", func(t *testing.T) {
   138  		ctx, cancel := context.WithCancel(context.Background())
   139  		defer cancel()
   140  
   141  		db := dbm.NewMemDB()
   142  		data := appendRandomMigrations([]toMigrate{}, 1000)
   143  		insertTestData(t, db, data)
   144  
   145  		latestHeight := getLatestHeight(data)
   146  		for _, test := range []string{"Migration", "Idempotency"} {
   147  			// run the test twice to make sure that it's
   148  			// safe to rerun
   149  			t.Run(test, func(t *testing.T) {
   150  				if err := Migrate(ctx, db); err != nil {
   151  					t.Fatalf("Migration failed: %v", err)
   152  				}
   153  
   154  				post, err := getAllSeenCommits(ctx, db)
   155  				if err != nil {
   156  					t.Fatalf("Fetching seen commits: %v", err)
   157  				}
   158  
   159  				if len(post) != 1 {
   160  					t.Fatalf("Wrong number of commits: got %d, wanted 1", len(post))
   161  				}
   162  
   163  				wantKey := makeKeyFromPrefix(prefixSeenCommit)
   164  				if !bytes.Equal(post[0].key, wantKey) {
   165  					t.Errorf("Seen commit key: got %x, want %x", post[0].key, wantKey)
   166  				}
   167  				if got := post[0].commit.Height; got != latestHeight {
   168  					t.Fatalf("Wrong commit height after migration: got %d, wanted %d", got, latestHeight)
   169  				}
   170  			})
   171  		}
   172  	})
   173  
   174  }