github.com/ethereum/go-ethereum@v1.16.1/cmd/utils/export_test.go (about) 1 // Copyright 2021 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package utils 18 19 import ( 20 "fmt" 21 "os" 22 "strings" 23 "testing" 24 "time" 25 26 "github.com/ethereum/go-ethereum/core/rawdb" 27 "github.com/ethereum/go-ethereum/rlp" 28 ) 29 30 // TestExport does basic sanity checks on the export/import functionality 31 func TestExport(t *testing.T) { 32 f := fmt.Sprintf("%v/tempdump", t.TempDir()) 33 testExport(t, f) 34 } 35 36 func TestExportGzip(t *testing.T) { 37 f := fmt.Sprintf("%v/tempdump.gz", t.TempDir()) 38 testExport(t, f) 39 } 40 41 type testIterator struct { 42 index int 43 } 44 45 func newTestIterator() *testIterator { 46 return &testIterator{index: -1} 47 } 48 49 func (iter *testIterator) Next() (byte, []byte, []byte, bool) { 50 if iter.index >= 999 { 51 return 0, nil, nil, false 52 } 53 iter.index += 1 54 if iter.index == 42 { 55 iter.index += 1 56 } 57 return OpBatchAdd, fmt.Appendf(nil, "key-%04d", iter.index), 58 fmt.Appendf(nil, "value %d", iter.index), true 59 } 60 61 func (iter *testIterator) Release() {} 62 63 func testExport(t *testing.T, f string) { 64 err := ExportChaindata(f, "testdata", newTestIterator(), make(chan struct{})) 65 if err != nil { 66 t.Fatal(err) 67 } 68 db := rawdb.NewMemoryDatabase() 69 err = ImportLDBData(db, f, 5, make(chan struct{})) 70 if err != nil { 71 t.Fatal(err) 72 } 73 // verify 74 for i := 0; i < 1000; i++ { 75 v, err := db.Get(fmt.Appendf(nil, "key-%04d", i)) 76 if (i < 5 || i == 42) && err == nil { 77 t.Fatalf("expected no element at idx %d, got '%v'", i, string(v)) 78 } 79 if !(i < 5 || i == 42) { 80 if err != nil { 81 t.Fatalf("expected element idx %d: %v", i, err) 82 } 83 if have, want := string(v), fmt.Sprintf("value %d", i); have != want { 84 t.Fatalf("have %v, want %v", have, want) 85 } 86 } 87 } 88 v, err := db.Get(fmt.Appendf(nil, "key-%04d", 1000)) 89 if err == nil { 90 t.Fatalf("expected no element at idx %d, got '%v'", 1000, string(v)) 91 } 92 } 93 94 // TestDeletionExport tests if the deletion markers can be exported/imported correctly 95 func TestDeletionExport(t *testing.T) { 96 f := fmt.Sprintf("%v/tempdump", t.TempDir()) 97 testDeletion(t, f) 98 } 99 100 // TestDeletionExportGzip tests if the deletion markers can be exported/imported 101 // correctly with gz compression. 102 func TestDeletionExportGzip(t *testing.T) { 103 f := fmt.Sprintf("%v/tempdump.gz", t.TempDir()) 104 testDeletion(t, f) 105 } 106 107 type deletionIterator struct { 108 index int 109 } 110 111 func newDeletionIterator() *deletionIterator { 112 return &deletionIterator{index: -1} 113 } 114 115 func (iter *deletionIterator) Next() (byte, []byte, []byte, bool) { 116 if iter.index >= 999 { 117 return 0, nil, nil, false 118 } 119 iter.index += 1 120 if iter.index == 42 { 121 iter.index += 1 122 } 123 return OpBatchDel, fmt.Appendf(nil, "key-%04d", iter.index), nil, true 124 } 125 126 func (iter *deletionIterator) Release() {} 127 128 func testDeletion(t *testing.T, f string) { 129 err := ExportChaindata(f, "testdata", newDeletionIterator(), make(chan struct{})) 130 if err != nil { 131 t.Fatal(err) 132 } 133 db := rawdb.NewMemoryDatabase() 134 for i := 0; i < 1000; i++ { 135 db.Put(fmt.Appendf(nil, "key-%04d", i), fmt.Appendf(nil, "value %d", i)) 136 } 137 err = ImportLDBData(db, f, 5, make(chan struct{})) 138 if err != nil { 139 t.Fatal(err) 140 } 141 for i := 0; i < 1000; i++ { 142 v, err := db.Get(fmt.Appendf(nil, "key-%04d", i)) 143 if i < 5 || i == 42 { 144 if err != nil { 145 t.Fatalf("expected element at idx %d, got '%v'", i, err) 146 } 147 if have, want := string(v), fmt.Sprintf("value %d", i); have != want { 148 t.Fatalf("have %v, want %v", have, want) 149 } 150 } 151 if !(i < 5 || i == 42) { 152 if err == nil { 153 t.Fatalf("expected no element idx %d: %v", i, string(v)) 154 } 155 } 156 } 157 } 158 159 // TestImportFutureFormat tests that we reject unsupported future versions. 160 func TestImportFutureFormat(t *testing.T) { 161 t.Parallel() 162 f := fmt.Sprintf("%v/tempdump-future", t.TempDir()) 163 fh, err := os.OpenFile(f, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm) 164 if err != nil { 165 t.Fatal(err) 166 } 167 defer fh.Close() 168 if err := rlp.Encode(fh, &exportHeader{ 169 Magic: exportMagic, 170 Version: 500, 171 Kind: "testdata", 172 UnixTime: uint64(time.Now().Unix()), 173 }); err != nil { 174 t.Fatal(err) 175 } 176 db2 := rawdb.NewMemoryDatabase() 177 err = ImportLDBData(db2, f, 0, make(chan struct{})) 178 if err == nil { 179 t.Fatal("Expected error, got none") 180 } 181 if !strings.HasPrefix(err.Error(), "incompatible version") { 182 t.Fatalf("wrong error: %v", err) 183 } 184 }