github.com/ethw3/go-ethereuma@v0.0.0-20221013053120-c14602a4c23c/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/ethw3/go-ethereuma/core/rawdb"
    27  	"github.com/ethw3/go-ethereuma/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", os.TempDir())
    33  	defer func() {
    34  		os.Remove(f)
    35  	}()
    36  	testExport(t, f)
    37  }
    38  
    39  func TestExportGzip(t *testing.T) {
    40  	f := fmt.Sprintf("%v/tempdump.gz", os.TempDir())
    41  	defer func() {
    42  		os.Remove(f)
    43  	}()
    44  	testExport(t, f)
    45  }
    46  
    47  type testIterator struct {
    48  	index int
    49  }
    50  
    51  func newTestIterator() *testIterator {
    52  	return &testIterator{index: -1}
    53  }
    54  
    55  func (iter *testIterator) Next() (byte, []byte, []byte, bool) {
    56  	if iter.index >= 999 {
    57  		return 0, nil, nil, false
    58  	}
    59  	iter.index += 1
    60  	if iter.index == 42 {
    61  		iter.index += 1
    62  	}
    63  	return OpBatchAdd, []byte(fmt.Sprintf("key-%04d", iter.index)),
    64  		[]byte(fmt.Sprintf("value %d", iter.index)), true
    65  }
    66  
    67  func (iter *testIterator) Release() {}
    68  
    69  func testExport(t *testing.T, f string) {
    70  	err := ExportChaindata(f, "testdata", newTestIterator(), make(chan struct{}))
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	db := rawdb.NewMemoryDatabase()
    75  	err = ImportLDBData(db, f, 5, make(chan struct{}))
    76  	if err != nil {
    77  		t.Fatal(err)
    78  	}
    79  	// verify
    80  	for i := 0; i < 1000; i++ {
    81  		v, err := db.Get([]byte(fmt.Sprintf("key-%04d", i)))
    82  		if (i < 5 || i == 42) && err == nil {
    83  			t.Fatalf("expected no element at idx %d, got '%v'", i, string(v))
    84  		}
    85  		if !(i < 5 || i == 42) {
    86  			if err != nil {
    87  				t.Fatalf("expected element idx %d: %v", i, err)
    88  			}
    89  			if have, want := string(v), fmt.Sprintf("value %d", i); have != want {
    90  				t.Fatalf("have %v, want %v", have, want)
    91  			}
    92  		}
    93  	}
    94  	v, err := db.Get([]byte(fmt.Sprintf("key-%04d", 1000)))
    95  	if err == nil {
    96  		t.Fatalf("expected no element at idx %d, got '%v'", 1000, string(v))
    97  	}
    98  }
    99  
   100  // testDeletion tests if the deletion markers can be exported/imported correctly
   101  func TestDeletionExport(t *testing.T) {
   102  	f := fmt.Sprintf("%v/tempdump", os.TempDir())
   103  	defer func() {
   104  		os.Remove(f)
   105  	}()
   106  	testDeletion(t, f)
   107  }
   108  
   109  // TestDeletionExportGzip tests if the deletion markers can be exported/imported
   110  // correctly with gz compression.
   111  func TestDeletionExportGzip(t *testing.T) {
   112  	f := fmt.Sprintf("%v/tempdump.gz", os.TempDir())
   113  	defer func() {
   114  		os.Remove(f)
   115  	}()
   116  	testDeletion(t, f)
   117  }
   118  
   119  type deletionIterator struct {
   120  	index int
   121  }
   122  
   123  func newDeletionIterator() *deletionIterator {
   124  	return &deletionIterator{index: -1}
   125  }
   126  
   127  func (iter *deletionIterator) Next() (byte, []byte, []byte, bool) {
   128  	if iter.index >= 999 {
   129  		return 0, nil, nil, false
   130  	}
   131  	iter.index += 1
   132  	if iter.index == 42 {
   133  		iter.index += 1
   134  	}
   135  	return OpBatchDel, []byte(fmt.Sprintf("key-%04d", iter.index)), nil, true
   136  }
   137  
   138  func (iter *deletionIterator) Release() {}
   139  
   140  func testDeletion(t *testing.T, f string) {
   141  	err := ExportChaindata(f, "testdata", newDeletionIterator(), make(chan struct{}))
   142  	if err != nil {
   143  		t.Fatal(err)
   144  	}
   145  	db := rawdb.NewMemoryDatabase()
   146  	for i := 0; i < 1000; i++ {
   147  		db.Put([]byte(fmt.Sprintf("key-%04d", i)), []byte(fmt.Sprintf("value %d", i)))
   148  	}
   149  	err = ImportLDBData(db, f, 5, make(chan struct{}))
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  	for i := 0; i < 1000; i++ {
   154  		v, err := db.Get([]byte(fmt.Sprintf("key-%04d", i)))
   155  		if i < 5 || i == 42 {
   156  			if err != nil {
   157  				t.Fatalf("expected element at idx %d, got '%v'", i, err)
   158  			}
   159  			if have, want := string(v), fmt.Sprintf("value %d", i); have != want {
   160  				t.Fatalf("have %v, want %v", have, want)
   161  			}
   162  		}
   163  		if !(i < 5 || i == 42) {
   164  			if err == nil {
   165  				t.Fatalf("expected no element idx %d: %v", i, string(v))
   166  			}
   167  		}
   168  	}
   169  }
   170  
   171  // TestImportFutureFormat tests that we reject unsupported future versions.
   172  func TestImportFutureFormat(t *testing.T) {
   173  	f := fmt.Sprintf("%v/tempdump-future", os.TempDir())
   174  	defer func() {
   175  		os.Remove(f)
   176  	}()
   177  	fh, err := os.OpenFile(f, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
   178  	if err != nil {
   179  		t.Fatal(err)
   180  	}
   181  	defer fh.Close()
   182  	if err := rlp.Encode(fh, &exportHeader{
   183  		Magic:    exportMagic,
   184  		Version:  500,
   185  		Kind:     "testdata",
   186  		UnixTime: uint64(time.Now().Unix()),
   187  	}); err != nil {
   188  		t.Fatal(err)
   189  	}
   190  	db2 := rawdb.NewMemoryDatabase()
   191  	err = ImportLDBData(db2, f, 0, make(chan struct{}))
   192  	if err == nil {
   193  		t.Fatal("Expected error, got none")
   194  	}
   195  	if !strings.HasPrefix(err.Error(), "incompatible version") {
   196  		t.Fatalf("wrong error: %v", err)
   197  	}
   198  }