github.com/jincm/wesharechain@v0.0.0-20210122032815-1537409ce26a/chain/swarm/storage/mock/test/test.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser 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  // The go-ethereum library 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 Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package test provides functions that are used for testing
    18  // GlobalStorer implementations.
    19  package test
    20  
    21  import (
    22  	"bytes"
    23  	"encoding/binary"
    24  	"fmt"
    25  	"io"
    26  	"strconv"
    27  	"testing"
    28  
    29  	"github.com/ethereum/go-ethereum/common"
    30  	"github.com/ethereum/go-ethereum/swarm/storage"
    31  	"github.com/ethereum/go-ethereum/swarm/storage/mock"
    32  )
    33  
    34  // MockStore creates NodeStore instances from provided GlobalStorer,
    35  // each one with a unique address, stores different chunks on them
    36  // and checks if they are retrievable or not on all nodes.
    37  // Attribute n defines the number of NodeStores that will be created.
    38  func MockStore(t *testing.T, globalStore mock.GlobalStorer, n int) {
    39  	t.Run("GlobalStore", func(t *testing.T) {
    40  		addrs := make([]common.Address, n)
    41  		for i := 0; i < n; i++ {
    42  			addrs[i] = common.HexToAddress(strconv.FormatInt(int64(i)+1, 16))
    43  		}
    44  
    45  		for i, addr := range addrs {
    46  			chunkAddr := storage.Address(append(addr[:], []byte(strconv.FormatInt(int64(i)+1, 16))...))
    47  			data := []byte(strconv.FormatInt(int64(i)+1, 16))
    48  			data = append(data, make([]byte, 4096-len(data))...)
    49  			globalStore.Put(addr, chunkAddr, data)
    50  
    51  			for _, cAddr := range addrs {
    52  				cData, err := globalStore.Get(cAddr, chunkAddr)
    53  				if cAddr == addr {
    54  					if err != nil {
    55  						t.Fatalf("get data from store %s key %s: %v", cAddr.Hex(), chunkAddr.Hex(), err)
    56  					}
    57  					if !bytes.Equal(data, cData) {
    58  						t.Fatalf("data on store %s: expected %x, got %x", cAddr.Hex(), data, cData)
    59  					}
    60  					if !globalStore.HasKey(cAddr, chunkAddr) {
    61  						t.Fatalf("expected key %s on global store for node %s, but it was not found", chunkAddr.Hex(), cAddr.Hex())
    62  					}
    63  				} else {
    64  					if err != mock.ErrNotFound {
    65  						t.Fatalf("expected error from store %s: %v, got %v", cAddr.Hex(), mock.ErrNotFound, err)
    66  					}
    67  					if len(cData) > 0 {
    68  						t.Fatalf("data on store %s: expected nil, got %x", cAddr.Hex(), cData)
    69  					}
    70  					if globalStore.HasKey(cAddr, chunkAddr) {
    71  						t.Fatalf("not expected key %s on global store for node %s, but it was found", chunkAddr.Hex(), cAddr.Hex())
    72  					}
    73  				}
    74  			}
    75  		}
    76  		t.Run("delete", func(t *testing.T) {
    77  			chunkAddr := storage.Address([]byte("1234567890abcd"))
    78  			for _, addr := range addrs {
    79  				err := globalStore.Put(addr, chunkAddr, []byte("data"))
    80  				if err != nil {
    81  					t.Fatalf("put data to store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err)
    82  				}
    83  			}
    84  			firstNodeAddr := addrs[0]
    85  			if err := globalStore.Delete(firstNodeAddr, chunkAddr); err != nil {
    86  				t.Fatalf("delete from store %s key %s: %v", firstNodeAddr.Hex(), chunkAddr.Hex(), err)
    87  			}
    88  			for i, addr := range addrs {
    89  				_, err := globalStore.Get(addr, chunkAddr)
    90  				if i == 0 {
    91  					if err != mock.ErrNotFound {
    92  						t.Errorf("get data from store %s key %s: expected mock.ErrNotFound error, got %v", addr.Hex(), chunkAddr.Hex(), err)
    93  					}
    94  				} else {
    95  					if err != nil {
    96  						t.Errorf("get data from store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err)
    97  					}
    98  				}
    99  			}
   100  		})
   101  	})
   102  
   103  	t.Run("NodeStore", func(t *testing.T) {
   104  		nodes := make(map[common.Address]*mock.NodeStore)
   105  		for i := 0; i < n; i++ {
   106  			addr := common.HexToAddress(strconv.FormatInt(int64(i)+1, 16))
   107  			nodes[addr] = globalStore.NewNodeStore(addr)
   108  		}
   109  
   110  		i := 0
   111  		for addr, store := range nodes {
   112  			i++
   113  			chunkAddr := storage.Address(append(addr[:], []byte(fmt.Sprintf("%x", i))...))
   114  			data := []byte(strconv.FormatInt(int64(i)+1, 16))
   115  			data = append(data, make([]byte, 4096-len(data))...)
   116  			store.Put(chunkAddr, data)
   117  
   118  			for cAddr, cStore := range nodes {
   119  				cData, err := cStore.Get(chunkAddr)
   120  				if cAddr == addr {
   121  					if err != nil {
   122  						t.Fatalf("get data from store %s key %s: %v", cAddr.Hex(), chunkAddr.Hex(), err)
   123  					}
   124  					if !bytes.Equal(data, cData) {
   125  						t.Fatalf("data on store %s: expected %x, got %x", cAddr.Hex(), data, cData)
   126  					}
   127  					if !globalStore.HasKey(cAddr, chunkAddr) {
   128  						t.Fatalf("expected key %s on global store for node %s, but it was not found", chunkAddr.Hex(), cAddr.Hex())
   129  					}
   130  				} else {
   131  					if err != mock.ErrNotFound {
   132  						t.Fatalf("expected error from store %s: %v, got %v", cAddr.Hex(), mock.ErrNotFound, err)
   133  					}
   134  					if len(cData) > 0 {
   135  						t.Fatalf("data on store %s: expected nil, got %x", cAddr.Hex(), cData)
   136  					}
   137  					if globalStore.HasKey(cAddr, chunkAddr) {
   138  						t.Fatalf("not expected key %s on global store for node %s, but it was found", chunkAddr.Hex(), cAddr.Hex())
   139  					}
   140  				}
   141  			}
   142  		}
   143  		t.Run("delete", func(t *testing.T) {
   144  			chunkAddr := storage.Address([]byte("1234567890abcd"))
   145  			var chosenStore *mock.NodeStore
   146  			for addr, store := range nodes {
   147  				if chosenStore == nil {
   148  					chosenStore = store
   149  				}
   150  				err := store.Put(chunkAddr, []byte("data"))
   151  				if err != nil {
   152  					t.Fatalf("put data to store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err)
   153  				}
   154  			}
   155  			if err := chosenStore.Delete(chunkAddr); err != nil {
   156  				t.Fatalf("delete key %s: %v", chunkAddr.Hex(), err)
   157  			}
   158  			for addr, store := range nodes {
   159  				_, err := store.Get(chunkAddr)
   160  				if store == chosenStore {
   161  					if err != mock.ErrNotFound {
   162  						t.Errorf("get data from store %s key %s: expected mock.ErrNotFound error, got %v", addr.Hex(), chunkAddr.Hex(), err)
   163  					}
   164  				} else {
   165  					if err != nil {
   166  						t.Errorf("get data from store %s key %s: %v", addr.Hex(), chunkAddr.Hex(), err)
   167  					}
   168  				}
   169  			}
   170  		})
   171  	})
   172  }
   173  
   174  // MockStoreListings tests global store methods Keys, Nodes, NodeKeys and KeyNodes.
   175  // It uses a provided globalstore to put chunks for n number of node addresses
   176  // and to validate that methods are returning the right responses.
   177  func MockStoreListings(t *testing.T, globalStore mock.GlobalStorer, n int) {
   178  	addrs := make([]common.Address, n)
   179  	for i := 0; i < n; i++ {
   180  		addrs[i] = common.HexToAddress(strconv.FormatInt(int64(i)+1, 16))
   181  	}
   182  	type chunk struct {
   183  		key  []byte
   184  		data []byte
   185  	}
   186  	const chunksPerNode = 5
   187  	keys := make([][]byte, n*chunksPerNode)
   188  	for i := 0; i < n*chunksPerNode; i++ {
   189  		b := make([]byte, 8)
   190  		binary.BigEndian.PutUint64(b, uint64(i))
   191  		keys[i] = b
   192  	}
   193  
   194  	// keep track of keys on every node
   195  	nodeKeys := make(map[common.Address][][]byte)
   196  	// keep track of nodes that store particular key
   197  	keyNodes := make(map[string][]common.Address)
   198  	for i := 0; i < chunksPerNode; i++ {
   199  		// put chunks for every address
   200  		for j := 0; j < n; j++ {
   201  			addr := addrs[j]
   202  			key := keys[(i*n)+j]
   203  			err := globalStore.Put(addr, key, []byte("data"))
   204  			if err != nil {
   205  				t.Fatal(err)
   206  			}
   207  			nodeKeys[addr] = append(nodeKeys[addr], key)
   208  			keyNodes[string(key)] = append(keyNodes[string(key)], addr)
   209  		}
   210  
   211  		// test Keys method
   212  		var startKey []byte
   213  		var gotKeys [][]byte
   214  		for {
   215  			keys, err := globalStore.Keys(startKey, 0)
   216  			if err != nil {
   217  				t.Fatal(err)
   218  			}
   219  			gotKeys = append(gotKeys, keys.Keys...)
   220  			if keys.Next == nil {
   221  				break
   222  			}
   223  			startKey = keys.Next
   224  		}
   225  		wantKeys := keys[:(i+1)*n]
   226  		if fmt.Sprint(gotKeys) != fmt.Sprint(wantKeys) {
   227  			t.Fatalf("got #%v keys %v, want %v", i+1, gotKeys, wantKeys)
   228  		}
   229  
   230  		// test Nodes method
   231  		var startNode *common.Address
   232  		var gotNodes []common.Address
   233  		for {
   234  			nodes, err := globalStore.Nodes(startNode, 0)
   235  			if err != nil {
   236  				t.Fatal(err)
   237  			}
   238  			gotNodes = append(gotNodes, nodes.Addrs...)
   239  			if nodes.Next == nil {
   240  				break
   241  			}
   242  			startNode = nodes.Next
   243  		}
   244  		wantNodes := addrs
   245  		if fmt.Sprint(gotNodes) != fmt.Sprint(wantNodes) {
   246  			t.Fatalf("got #%v nodes %v, want %v", i+1, gotNodes, wantNodes)
   247  		}
   248  
   249  		// test NodeKeys method
   250  		for addr, wantKeys := range nodeKeys {
   251  			var startKey []byte
   252  			var gotKeys [][]byte
   253  			for {
   254  				keys, err := globalStore.NodeKeys(addr, startKey, 0)
   255  				if err != nil {
   256  					t.Fatal(err)
   257  				}
   258  				gotKeys = append(gotKeys, keys.Keys...)
   259  				if keys.Next == nil {
   260  					break
   261  				}
   262  				startKey = keys.Next
   263  			}
   264  			if fmt.Sprint(gotKeys) != fmt.Sprint(wantKeys) {
   265  				t.Fatalf("got #%v %s node keys %v, want %v", i+1, addr.Hex(), gotKeys, wantKeys)
   266  			}
   267  		}
   268  
   269  		// test KeyNodes method
   270  		for key, wantNodes := range keyNodes {
   271  			var startNode *common.Address
   272  			var gotNodes []common.Address
   273  			for {
   274  				nodes, err := globalStore.KeyNodes([]byte(key), startNode, 0)
   275  				if err != nil {
   276  					t.Fatal(err)
   277  				}
   278  				gotNodes = append(gotNodes, nodes.Addrs...)
   279  				if nodes.Next == nil {
   280  					break
   281  				}
   282  				startNode = nodes.Next
   283  			}
   284  			if fmt.Sprint(gotNodes) != fmt.Sprint(wantNodes) {
   285  				t.Fatalf("got #%v %x key nodes %v, want %v", i+1, []byte(key), gotNodes, wantNodes)
   286  			}
   287  		}
   288  	}
   289  }
   290  
   291  // ImportExport saves chunks to the outStore, exports them to the tar archive,
   292  // imports tar archive to the inStore and checks if all chunks are imported correctly.
   293  func ImportExport(t *testing.T, outStore, inStore mock.GlobalStorer, n int) {
   294  	exporter, ok := outStore.(mock.Exporter)
   295  	if !ok {
   296  		t.Fatal("outStore does not implement mock.Exporter")
   297  	}
   298  	importer, ok := inStore.(mock.Importer)
   299  	if !ok {
   300  		t.Fatal("inStore does not implement mock.Importer")
   301  	}
   302  	addrs := make([]common.Address, n)
   303  	for i := 0; i < n; i++ {
   304  		addrs[i] = common.HexToAddress(strconv.FormatInt(int64(i)+1, 16))
   305  	}
   306  
   307  	for i, addr := range addrs {
   308  		chunkAddr := storage.Address(append(addr[:], []byte(strconv.FormatInt(int64(i)+1, 16))...))
   309  		data := []byte(strconv.FormatInt(int64(i)+1, 16))
   310  		data = append(data, make([]byte, 4096-len(data))...)
   311  		outStore.Put(addr, chunkAddr, data)
   312  	}
   313  
   314  	r, w := io.Pipe()
   315  	defer r.Close()
   316  
   317  	exportErrChan := make(chan error)
   318  	go func() {
   319  		defer w.Close()
   320  
   321  		_, err := exporter.Export(w)
   322  		exportErrChan <- err
   323  	}()
   324  
   325  	if _, err := importer.Import(r); err != nil {
   326  		t.Fatalf("import: %v", err)
   327  	}
   328  
   329  	if err := <-exportErrChan; err != nil {
   330  		t.Fatalf("export: %v", err)
   331  	}
   332  
   333  	for i, addr := range addrs {
   334  		chunkAddr := storage.Address(append(addr[:], []byte(strconv.FormatInt(int64(i)+1, 16))...))
   335  		data := []byte(strconv.FormatInt(int64(i)+1, 16))
   336  		data = append(data, make([]byte, 4096-len(data))...)
   337  		for _, cAddr := range addrs {
   338  			cData, err := inStore.Get(cAddr, chunkAddr)
   339  			if cAddr == addr {
   340  				if err != nil {
   341  					t.Fatalf("get data from store %s key %s: %v", cAddr.Hex(), chunkAddr.Hex(), err)
   342  				}
   343  				if !bytes.Equal(data, cData) {
   344  					t.Fatalf("data on store %s: expected %x, got %x", cAddr.Hex(), data, cData)
   345  				}
   346  				if !inStore.HasKey(cAddr, chunkAddr) {
   347  					t.Fatalf("expected key %s on global store for node %s, but it was not found", chunkAddr.Hex(), cAddr.Hex())
   348  				}
   349  			} else {
   350  				if err != mock.ErrNotFound {
   351  					t.Fatalf("expected error from store %s: %v, got %v", cAddr.Hex(), mock.ErrNotFound, err)
   352  				}
   353  				if len(cData) > 0 {
   354  					t.Fatalf("data on store %s: expected nil, got %x", cAddr.Hex(), cData)
   355  				}
   356  				if inStore.HasKey(cAddr, chunkAddr) {
   357  					t.Fatalf("not expected key %s on global store for node %s, but it was found", chunkAddr.Hex(), cAddr.Hex())
   358  				}
   359  			}
   360  		}
   361  	}
   362  }