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  }