github.com/shyftnetwork/go-empyrean@v1.8.3-0.20191127201940-fbfca9338f04/swarm/network/stream/common_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 stream
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"flag"
    23  	"fmt"
    24  	"io"
    25  	"io/ioutil"
    26  	"math/rand"
    27  	"os"
    28  	"strings"
    29  	"sync/atomic"
    30  	"testing"
    31  	"time"
    32  
    33  	"github.com/ShyftNetwork/go-empyrean/log"
    34  	"github.com/ShyftNetwork/go-empyrean/p2p/enode"
    35  	p2ptest "github.com/ShyftNetwork/go-empyrean/p2p/testing"
    36  	"github.com/ShyftNetwork/go-empyrean/swarm/network"
    37  	"github.com/ShyftNetwork/go-empyrean/swarm/network/simulation"
    38  	"github.com/ShyftNetwork/go-empyrean/swarm/state"
    39  	"github.com/ShyftNetwork/go-empyrean/swarm/storage"
    40  	"github.com/ShyftNetwork/go-empyrean/swarm/testutil"
    41  	colorable "github.com/mattn/go-colorable"
    42  )
    43  
    44  var (
    45  	loglevel     = flag.Int("loglevel", 2, "verbosity of logs")
    46  	nodes        = flag.Int("nodes", 0, "number of nodes")
    47  	chunks       = flag.Int("chunks", 0, "number of chunks")
    48  	useMockStore = flag.Bool("mockstore", false, "disabled mock store (default: enabled)")
    49  	longrunning  = flag.Bool("longrunning", false, "do run long-running tests")
    50  
    51  	bucketKeyDB        = simulation.BucketKey("db")
    52  	bucketKeyStore     = simulation.BucketKey("store")
    53  	bucketKeyFileStore = simulation.BucketKey("filestore")
    54  	bucketKeyNetStore  = simulation.BucketKey("netstore")
    55  	bucketKeyDelivery  = simulation.BucketKey("delivery")
    56  	bucketKeyRegistry  = simulation.BucketKey("registry")
    57  
    58  	chunkSize = 4096
    59  	pof       = network.Pof
    60  )
    61  
    62  func init() {
    63  	flag.Parse()
    64  	rand.Seed(time.Now().UnixNano())
    65  
    66  	log.PrintOrigins(true)
    67  	log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))))
    68  }
    69  
    70  func newStreamerTester(t *testing.T, registryOptions *RegistryOptions) (*p2ptest.ProtocolTester, *Registry, *storage.LocalStore, func(), error) {
    71  	// setup
    72  	addr := network.RandomAddr() // tested peers peer address
    73  	to := network.NewKademlia(addr.OAddr, network.NewKadParams())
    74  
    75  	// temp datadir
    76  	datadir, err := ioutil.TempDir("", "streamer")
    77  	if err != nil {
    78  		return nil, nil, nil, func() {}, err
    79  	}
    80  	removeDataDir := func() {
    81  		os.RemoveAll(datadir)
    82  	}
    83  
    84  	params := storage.NewDefaultLocalStoreParams()
    85  	params.Init(datadir)
    86  	params.BaseKey = addr.Over()
    87  
    88  	localStore, err := storage.NewTestLocalStoreForAddr(params)
    89  	if err != nil {
    90  		return nil, nil, nil, removeDataDir, err
    91  	}
    92  
    93  	netStore, err := storage.NewNetStore(localStore, nil)
    94  	if err != nil {
    95  		return nil, nil, nil, removeDataDir, err
    96  	}
    97  
    98  	delivery := NewDelivery(to, netStore)
    99  	netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New
   100  	streamer := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), registryOptions, nil)
   101  	teardown := func() {
   102  		streamer.Close()
   103  		removeDataDir()
   104  	}
   105  	protocolTester := p2ptest.NewProtocolTester(t, addr.ID(), 1, streamer.runProtocol)
   106  
   107  	err = waitForPeers(streamer, 1*time.Second, 1)
   108  	if err != nil {
   109  		return nil, nil, nil, nil, errors.New("timeout: peer is not created")
   110  	}
   111  
   112  	return protocolTester, streamer, localStore, teardown, nil
   113  }
   114  
   115  func waitForPeers(streamer *Registry, timeout time.Duration, expectedPeers int) error {
   116  	ticker := time.NewTicker(10 * time.Millisecond)
   117  	timeoutTimer := time.NewTimer(timeout)
   118  	for {
   119  		select {
   120  		case <-ticker.C:
   121  			if streamer.peersCount() >= expectedPeers {
   122  				return nil
   123  			}
   124  		case <-timeoutTimer.C:
   125  			return errors.New("timeout")
   126  		}
   127  	}
   128  }
   129  
   130  type roundRobinStore struct {
   131  	index  uint32
   132  	stores []storage.ChunkStore
   133  }
   134  
   135  func newRoundRobinStore(stores ...storage.ChunkStore) *roundRobinStore {
   136  	return &roundRobinStore{
   137  		stores: stores,
   138  	}
   139  }
   140  
   141  func (rrs *roundRobinStore) Get(ctx context.Context, addr storage.Address) (storage.Chunk, error) {
   142  	return nil, errors.New("get not well defined on round robin store")
   143  }
   144  
   145  func (rrs *roundRobinStore) Put(ctx context.Context, chunk storage.Chunk) error {
   146  	i := atomic.AddUint32(&rrs.index, 1)
   147  	idx := int(i) % len(rrs.stores)
   148  	return rrs.stores[idx].Put(ctx, chunk)
   149  }
   150  
   151  func (rrs *roundRobinStore) Close() {
   152  	for _, store := range rrs.stores {
   153  		store.Close()
   154  	}
   155  }
   156  
   157  func readAll(fileStore *storage.FileStore, hash []byte) (int64, error) {
   158  	r, _ := fileStore.Retrieve(context.TODO(), hash)
   159  	buf := make([]byte, 1024)
   160  	var n int
   161  	var total int64
   162  	var err error
   163  	for (total == 0 || n > 0) && err == nil {
   164  		n, err = r.ReadAt(buf, total)
   165  		total += int64(n)
   166  	}
   167  	if err != nil && err != io.EOF {
   168  		return total, err
   169  	}
   170  	return total, nil
   171  }
   172  
   173  func uploadFilesToNodes(sim *simulation.Simulation) ([]storage.Address, []string, error) {
   174  	nodes := sim.UpNodeIDs()
   175  	nodeCnt := len(nodes)
   176  	log.Debug(fmt.Sprintf("Uploading %d files to nodes", nodeCnt))
   177  	//array holding generated files
   178  	rfiles := make([]string, nodeCnt)
   179  	//array holding the root hashes of the files
   180  	rootAddrs := make([]storage.Address, nodeCnt)
   181  
   182  	var err error
   183  	//for every node, generate a file and upload
   184  	for i, id := range nodes {
   185  		item, ok := sim.NodeItem(id, bucketKeyFileStore)
   186  		if !ok {
   187  			return nil, nil, fmt.Errorf("Error accessing localstore")
   188  		}
   189  		fileStore := item.(*storage.FileStore)
   190  		//generate a file
   191  		rfiles[i], err = generateRandomFile()
   192  		if err != nil {
   193  			return nil, nil, err
   194  		}
   195  		//store it (upload it) on the FileStore
   196  		ctx := context.TODO()
   197  		rk, wait, err := fileStore.Store(ctx, strings.NewReader(rfiles[i]), int64(len(rfiles[i])), false)
   198  		log.Debug("Uploaded random string file to node")
   199  		if err != nil {
   200  			return nil, nil, err
   201  		}
   202  		err = wait(ctx)
   203  		if err != nil {
   204  			return nil, nil, err
   205  		}
   206  		rootAddrs[i] = rk
   207  	}
   208  	return rootAddrs, rfiles, nil
   209  }
   210  
   211  //generate a random file (string)
   212  func generateRandomFile() (string, error) {
   213  	//generate a random file size between minFileSize and maxFileSize
   214  	fileSize := rand.Intn(maxFileSize-minFileSize) + minFileSize
   215  	log.Debug(fmt.Sprintf("Generated file with filesize %d kB", fileSize))
   216  	b := testutil.RandomBytes(1, fileSize*1024)
   217  	return string(b), nil
   218  }
   219  
   220  //create a local store for the given node
   221  func createTestLocalStorageForID(id enode.ID, addr *network.BzzAddr) (storage.ChunkStore, string, error) {
   222  	var datadir string
   223  	var err error
   224  	datadir, err = ioutil.TempDir("", fmt.Sprintf("syncer-test-%s", id.TerminalString()))
   225  	if err != nil {
   226  		return nil, "", err
   227  	}
   228  	var store storage.ChunkStore
   229  	params := storage.NewDefaultLocalStoreParams()
   230  	params.ChunkDbPath = datadir
   231  	params.BaseKey = addr.Over()
   232  	store, err = storage.NewTestLocalStoreForAddr(params)
   233  	if err != nil {
   234  		os.RemoveAll(datadir)
   235  		return nil, "", err
   236  	}
   237  	return store, datadir, nil
   238  }