2022-01-11 00:59:15 +00:00
|
|
|
package snapshot
|
|
|
|
|
|
|
|
import (
|
2022-02-18 11:12:53 +00:00
|
|
|
"errors"
|
2022-05-13 08:30:40 +00:00
|
|
|
"math/big"
|
2022-02-18 11:12:53 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2022-01-11 00:59:15 +00:00
|
|
|
"testing"
|
2022-07-13 06:09:36 +00:00
|
|
|
"time"
|
2022-01-11 00:59:15 +00:00
|
|
|
|
2022-01-11 23:49:04 +00:00
|
|
|
"github.com/golang/mock/gomock"
|
|
|
|
|
2022-03-30 23:57:30 +00:00
|
|
|
fixt "github.com/vulcanize/ipld-eth-state-snapshot/fixture"
|
|
|
|
mock "github.com/vulcanize/ipld-eth-state-snapshot/mocks/snapshot"
|
|
|
|
snapt "github.com/vulcanize/ipld-eth-state-snapshot/pkg/types"
|
|
|
|
"github.com/vulcanize/ipld-eth-state-snapshot/test"
|
2022-01-11 00:59:15 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func testConfig(leveldbpath, ancientdbpath string) *Config {
|
|
|
|
return &Config{
|
2022-01-11 00:59:26 +00:00
|
|
|
Eth: &EthConfig{
|
|
|
|
LevelDBPath: leveldbpath,
|
|
|
|
AncientDBPath: ancientdbpath,
|
2022-02-09 15:19:10 +00:00
|
|
|
NodeInfo: test.DefaultNodeInfo,
|
|
|
|
},
|
|
|
|
DB: &DBConfig{
|
|
|
|
URI: test.DefaultPgConfig.DbConnectionString(),
|
|
|
|
ConnConfig: test.DefaultPgConfig,
|
2022-01-11 00:59:26 +00:00
|
|
|
},
|
2022-01-11 00:59:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-18 11:12:53 +00:00
|
|
|
func makeMocks(t *testing.T) (*mock.MockPublisher, *mock.MockTx) {
|
|
|
|
ctl := gomock.NewController(t)
|
|
|
|
pub := mock.NewMockPublisher(ctl)
|
|
|
|
tx := mock.NewMockTx(ctl)
|
|
|
|
return pub, tx
|
|
|
|
}
|
|
|
|
|
2022-01-11 00:59:15 +00:00
|
|
|
func TestCreateSnapshot(t *testing.T) {
|
2022-02-18 11:12:53 +00:00
|
|
|
runCase := func(t *testing.T, workers int) {
|
|
|
|
pub, tx := makeMocks(t)
|
|
|
|
pub.EXPECT().PublishHeader(gomock.Eq(&fixt.Block1_Header))
|
|
|
|
pub.EXPECT().BeginTx().Return(tx, nil).
|
|
|
|
Times(workers)
|
|
|
|
pub.EXPECT().PrepareTxForBatch(gomock.Any(), gomock.Any()).Return(tx, nil).
|
|
|
|
AnyTimes()
|
2022-04-19 10:19:49 +00:00
|
|
|
pub.EXPECT().PublishStateNode(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
2022-05-31 15:34:02 +00:00
|
|
|
// Use MinTimes as duplicate nodes are expected at boundaries
|
|
|
|
MinTimes(len(fixt.Block1_StateNodePaths))
|
2022-02-18 11:12:53 +00:00
|
|
|
|
|
|
|
// TODO: fixtures for storage node
|
|
|
|
// pub.EXPECT().PublishStorageNode(gomock.Eq(fixt.StorageNode), gomock.Eq(int64(0)), gomock.Any())
|
2022-01-11 23:49:04 +00:00
|
|
|
|
2022-02-18 11:12:53 +00:00
|
|
|
tx.EXPECT().Commit().
|
|
|
|
Times(workers)
|
|
|
|
|
|
|
|
config := testConfig(fixt.ChaindataPath, fixt.AncientdataPath)
|
|
|
|
edb, err := NewLevelDB(config.Eth)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer edb.Close()
|
|
|
|
|
|
|
|
recovery := filepath.Join(t.TempDir(), "recover.csv")
|
|
|
|
service, err := NewSnapshotService(edb, pub, recovery)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
params := SnapshotParams{Height: 1, Workers: uint(workers)}
|
|
|
|
err = service.CreateSnapshot(params)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2022-01-11 23:49:04 +00:00
|
|
|
}
|
2022-02-09 15:19:10 +00:00
|
|
|
|
2022-02-18 11:12:53 +00:00
|
|
|
testCases := []int{1, 4, 16, 32}
|
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run("case", func(t *testing.T) { runCase(t, tc) })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-13 08:30:40 +00:00
|
|
|
func failingPublishStateNode(_ *snapt.Node, _ string, _ *big.Int, _ snapt.Tx) error {
|
2022-02-18 11:12:53 +00:00
|
|
|
return errors.New("failingPublishStateNode")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestRecovery(t *testing.T) {
|
|
|
|
runCase := func(t *testing.T, workers int) {
|
|
|
|
pub, tx := makeMocks(t)
|
|
|
|
pub.EXPECT().PublishHeader(gomock.Any()).AnyTimes()
|
|
|
|
pub.EXPECT().BeginTx().Return(tx, nil).AnyTimes()
|
|
|
|
pub.EXPECT().PrepareTxForBatch(gomock.Any(), gomock.Any()).Return(tx, nil).AnyTimes()
|
2022-04-19 10:19:49 +00:00
|
|
|
pub.EXPECT().PublishStateNode(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
|
2022-02-18 11:12:53 +00:00
|
|
|
Times(workers).
|
|
|
|
DoAndReturn(failingPublishStateNode)
|
|
|
|
tx.EXPECT().Commit().AnyTimes()
|
|
|
|
|
|
|
|
config := testConfig(fixt.ChaindataPath, fixt.AncientdataPath)
|
|
|
|
edb, err := NewLevelDB(config.Eth)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
defer edb.Close()
|
|
|
|
|
|
|
|
recovery := filepath.Join(t.TempDir(), "recover.csv")
|
|
|
|
service, err := NewSnapshotService(edb, pub, recovery)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
params := SnapshotParams{Height: 1, Workers: uint(workers)}
|
|
|
|
err = service.CreateSnapshot(params)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("expected an error")
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err = os.Stat(recovery); err != nil {
|
|
|
|
t.Fatal("cannot stat recovery file:", err)
|
|
|
|
}
|
|
|
|
|
2022-07-13 06:09:36 +00:00
|
|
|
// Wait for earlier snapshot process to complete
|
|
|
|
time.Sleep(5 * time.Second)
|
|
|
|
|
2022-04-19 10:19:49 +00:00
|
|
|
pub.EXPECT().PublishStateNode(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
2022-02-18 11:12:53 +00:00
|
|
|
err = service.CreateSnapshot(params)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2022-01-11 23:49:04 +00:00
|
|
|
|
2022-02-18 11:12:53 +00:00
|
|
|
_, err = os.Stat(recovery)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("recovery file still present")
|
|
|
|
} else {
|
|
|
|
if !os.IsNotExist(err) {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
2022-01-11 00:59:15 +00:00
|
|
|
}
|
|
|
|
|
2022-02-18 11:12:53 +00:00
|
|
|
testCases := []int{1, 4, 32}
|
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run("case", func(t *testing.T) { runCase(t, tc) })
|
2022-01-11 00:59:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|