github.com/gobitfly/go-ethereum@v1.8.12/swarm/storage/common_test.go (about)

     1  // Copyright 2016 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 storage
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/rand"
    22  	"flag"
    23  	"fmt"
    24  	"io"
    25  	"sync"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/ethereum/go-ethereum/log"
    30  	colorable "github.com/mattn/go-colorable"
    31  )
    32  
    33  var (
    34  	loglevel = flag.Int("loglevel", 3, "verbosity of logs")
    35  )
    36  
    37  func init() {
    38  	flag.Parse()
    39  	log.PrintOrigins(true)
    40  	log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(*loglevel), log.StreamHandler(colorable.NewColorableStderr(), log.TerminalFormat(true))))
    41  }
    42  
    43  type brokenLimitedReader struct {
    44  	lr    io.Reader
    45  	errAt int
    46  	off   int
    47  	size  int
    48  }
    49  
    50  func brokenLimitReader(data io.Reader, size int, errAt int) *brokenLimitedReader {
    51  	return &brokenLimitedReader{
    52  		lr:    data,
    53  		errAt: errAt,
    54  		size:  size,
    55  	}
    56  }
    57  
    58  func mputRandomChunks(store ChunkStore, processors int, n int, chunksize int64) (hs []Address) {
    59  	return mput(store, processors, n, GenerateRandomChunk)
    60  }
    61  
    62  func mput(store ChunkStore, processors int, n int, f func(i int64) *Chunk) (hs []Address) {
    63  	wg := sync.WaitGroup{}
    64  	wg.Add(processors)
    65  	c := make(chan *Chunk)
    66  	for i := 0; i < processors; i++ {
    67  		go func() {
    68  			defer wg.Done()
    69  			for chunk := range c {
    70  				wg.Add(1)
    71  				chunk := chunk
    72  				store.Put(chunk)
    73  				go func() {
    74  					defer wg.Done()
    75  					<-chunk.dbStoredC
    76  				}()
    77  			}
    78  		}()
    79  	}
    80  	fa := f
    81  	if _, ok := store.(*MemStore); ok {
    82  		fa = func(i int64) *Chunk {
    83  			chunk := f(i)
    84  			chunk.markAsStored()
    85  			return chunk
    86  		}
    87  	}
    88  	for i := 0; i < n; i++ {
    89  		chunk := fa(int64(i))
    90  		hs = append(hs, chunk.Addr)
    91  		c <- chunk
    92  	}
    93  	close(c)
    94  	wg.Wait()
    95  	return hs
    96  }
    97  
    98  func mget(store ChunkStore, hs []Address, f func(h Address, chunk *Chunk) error) error {
    99  	wg := sync.WaitGroup{}
   100  	wg.Add(len(hs))
   101  	errc := make(chan error)
   102  
   103  	for _, k := range hs {
   104  		go func(h Address) {
   105  			defer wg.Done()
   106  			chunk, err := store.Get(h)
   107  			if err != nil {
   108  				errc <- err
   109  				return
   110  			}
   111  			if f != nil {
   112  				err = f(h, chunk)
   113  				if err != nil {
   114  					errc <- err
   115  					return
   116  				}
   117  			}
   118  		}(k)
   119  	}
   120  	go func() {
   121  		wg.Wait()
   122  		close(errc)
   123  	}()
   124  	var err error
   125  	select {
   126  	case err = <-errc:
   127  	case <-time.NewTimer(5 * time.Second).C:
   128  		err = fmt.Errorf("timed out after 5 seconds")
   129  	}
   130  	return err
   131  }
   132  
   133  func testDataReader(l int) (r io.Reader) {
   134  	return io.LimitReader(rand.Reader, int64(l))
   135  }
   136  
   137  func (r *brokenLimitedReader) Read(buf []byte) (int, error) {
   138  	if r.off+len(buf) > r.errAt {
   139  		return 0, fmt.Errorf("Broken reader")
   140  	}
   141  	r.off += len(buf)
   142  	return r.lr.Read(buf)
   143  }
   144  
   145  func generateRandomData(l int) (r io.Reader, slice []byte) {
   146  	slice = make([]byte, l)
   147  	if _, err := rand.Read(slice); err != nil {
   148  		panic("rand error")
   149  	}
   150  	r = io.LimitReader(bytes.NewReader(slice), int64(l))
   151  	return
   152  }
   153  
   154  func testStoreRandom(m ChunkStore, processors int, n int, chunksize int64, t *testing.T) {
   155  	hs := mputRandomChunks(m, processors, n, chunksize)
   156  	err := mget(m, hs, nil)
   157  	if err != nil {
   158  		t.Fatalf("testStore failed: %v", err)
   159  	}
   160  }
   161  
   162  func testStoreCorrect(m ChunkStore, processors int, n int, chunksize int64, t *testing.T) {
   163  	hs := mputRandomChunks(m, processors, n, chunksize)
   164  	f := func(h Address, chunk *Chunk) error {
   165  		if !bytes.Equal(h, chunk.Addr) {
   166  			return fmt.Errorf("key does not match retrieved chunk Key")
   167  		}
   168  		hasher := MakeHashFunc(DefaultHash)()
   169  		hasher.ResetWithLength(chunk.SData[:8])
   170  		hasher.Write(chunk.SData[8:])
   171  		exp := hasher.Sum(nil)
   172  		if !bytes.Equal(h, exp) {
   173  			return fmt.Errorf("key is not hash of chunk data")
   174  		}
   175  		return nil
   176  	}
   177  	err := mget(m, hs, f)
   178  	if err != nil {
   179  		t.Fatalf("testStore failed: %v", err)
   180  	}
   181  }
   182  
   183  func benchmarkStorePut(store ChunkStore, processors int, n int, chunksize int64, b *testing.B) {
   184  	chunks := make([]*Chunk, n)
   185  	i := 0
   186  	f := func(dataSize int64) *Chunk {
   187  		chunk := GenerateRandomChunk(dataSize)
   188  		chunks[i] = chunk
   189  		i++
   190  		return chunk
   191  	}
   192  
   193  	mput(store, processors, n, f)
   194  
   195  	f = func(dataSize int64) *Chunk {
   196  		chunk := chunks[i]
   197  		i++
   198  		return chunk
   199  	}
   200  
   201  	b.ReportAllocs()
   202  	b.ResetTimer()
   203  
   204  	for j := 0; j < b.N; j++ {
   205  		i = 0
   206  		mput(store, processors, n, f)
   207  	}
   208  }
   209  
   210  func benchmarkStoreGet(store ChunkStore, processors int, n int, chunksize int64, b *testing.B) {
   211  	hs := mputRandomChunks(store, processors, n, chunksize)
   212  	b.ReportAllocs()
   213  	b.ResetTimer()
   214  	for i := 0; i < b.N; i++ {
   215  		err := mget(store, hs, nil)
   216  		if err != nil {
   217  			b.Fatalf("mget failed: %v", err)
   218  		}
   219  	}
   220  }