github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/swarm/network/stream/intervals_test.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:44</date>
    10  //</624450115469316096>
    11  
    12  
    13  package stream
    14  
    15  import (
    16  	"context"
    17  	"encoding/binary"
    18  	"errors"
    19  	"fmt"
    20  	"os"
    21  	"sync"
    22  	"sync/atomic"
    23  	"testing"
    24  	"time"
    25  
    26  	"github.com/ethereum/go-ethereum/log"
    27  	"github.com/ethereum/go-ethereum/node"
    28  	"github.com/ethereum/go-ethereum/p2p/enode"
    29  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    30  	"github.com/ethereum/go-ethereum/swarm/network"
    31  	"github.com/ethereum/go-ethereum/swarm/network/simulation"
    32  	"github.com/ethereum/go-ethereum/swarm/state"
    33  	"github.com/ethereum/go-ethereum/swarm/storage"
    34  	"github.com/ethereum/go-ethereum/swarm/testutil"
    35  )
    36  
    37  func TestIntervalsLive(t *testing.T) {
    38  	testIntervals(t, true, nil, false)
    39  	testIntervals(t, true, nil, true)
    40  }
    41  
    42  func TestIntervalsHistory(t *testing.T) {
    43  	testIntervals(t, false, NewRange(9, 26), false)
    44  	testIntervals(t, false, NewRange(9, 26), true)
    45  }
    46  
    47  func TestIntervalsLiveAndHistory(t *testing.T) {
    48  	testIntervals(t, true, NewRange(9, 26), false)
    49  	testIntervals(t, true, NewRange(9, 26), true)
    50  }
    51  
    52  func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) {
    53  
    54  	nodes := 2
    55  	chunkCount := dataChunkCount
    56  	externalStreamName := "externalStream"
    57  	externalStreamSessionAt := uint64(50)
    58  	externalStreamMaxKeys := uint64(100)
    59  
    60  	sim := simulation.New(map[string]simulation.ServiceFunc{
    61  		"intervalsStreamer": func(ctx *adapters.ServiceContext, bucket *sync.Map) (s node.Service, cleanup func(), err error) {
    62  			n := ctx.Config.Node()
    63  			addr := network.NewAddr(n)
    64  			store, datadir, err := createTestLocalStorageForID(n.ID(), addr)
    65  			if err != nil {
    66  				return nil, nil, err
    67  			}
    68  			bucket.Store(bucketKeyStore, store)
    69  			cleanup = func() {
    70  				store.Close()
    71  				os.RemoveAll(datadir)
    72  			}
    73  			localStore := store.(*storage.LocalStore)
    74  			netStore, err := storage.NewNetStore(localStore, nil)
    75  			if err != nil {
    76  				return nil, nil, err
    77  			}
    78  			kad := network.NewKademlia(addr.Over(), network.NewKadParams())
    79  			delivery := NewDelivery(kad, netStore)
    80  			netStore.NewNetFetcherFunc = network.NewFetcherFactory(delivery.RequestFromPeers, true).New
    81  
    82  			r := NewRegistry(addr.ID(), delivery, netStore, state.NewInmemoryStore(), &RegistryOptions{
    83  				Retrieval: RetrievalDisabled,
    84  				Syncing:   SyncingRegisterOnly,
    85  				SkipCheck: skipCheck,
    86  			}, nil)
    87  			bucket.Store(bucketKeyRegistry, r)
    88  
    89  			r.RegisterClientFunc(externalStreamName, func(p *Peer, t string, live bool) (Client, error) {
    90  				return newTestExternalClient(netStore), nil
    91  			})
    92  			r.RegisterServerFunc(externalStreamName, func(p *Peer, t string, live bool) (Server, error) {
    93  				return newTestExternalServer(t, externalStreamSessionAt, externalStreamMaxKeys, nil), nil
    94  			})
    95  
    96  			fileStore := storage.NewFileStore(localStore, storage.NewFileStoreParams())
    97  			bucket.Store(bucketKeyFileStore, fileStore)
    98  
    99  			return r, cleanup, nil
   100  
   101  		},
   102  	})
   103  	defer sim.Close()
   104  
   105  	log.Info("Adding nodes to simulation")
   106  	_, err := sim.AddNodesAndConnectChain(nodes)
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  
   111  	ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
   112  	defer cancel()
   113  
   114  	if _, err := sim.WaitTillHealthy(ctx); err != nil {
   115  		t.Fatal(err)
   116  	}
   117  
   118  	result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) (err error) {
   119  		nodeIDs := sim.UpNodeIDs()
   120  		storer := nodeIDs[0]
   121  		checker := nodeIDs[1]
   122  
   123  		item, ok := sim.NodeItem(storer, bucketKeyFileStore)
   124  		if !ok {
   125  			return fmt.Errorf("No filestore")
   126  		}
   127  		fileStore := item.(*storage.FileStore)
   128  
   129  		size := chunkCount * chunkSize
   130  
   131  		_, wait, err := fileStore.Store(ctx, testutil.RandomReader(1, size), int64(size), false)
   132  		if err != nil {
   133  			log.Error("Store error: %v", "err", err)
   134  			t.Fatal(err)
   135  		}
   136  		err = wait(ctx)
   137  		if err != nil {
   138  			log.Error("Wait error: %v", "err", err)
   139  			t.Fatal(err)
   140  		}
   141  
   142  		item, ok = sim.NodeItem(checker, bucketKeyRegistry)
   143  		if !ok {
   144  			return fmt.Errorf("No registry")
   145  		}
   146  		registry := item.(*Registry)
   147  
   148  		liveErrC := make(chan error)
   149  		historyErrC := make(chan error)
   150  
   151  		log.Debug("Watching for disconnections")
   152  		disconnections := sim.PeerEvents(
   153  			context.Background(),
   154  			sim.NodeIDs(),
   155  			simulation.NewPeerEventsFilter().Drop(),
   156  		)
   157  
   158  		err = registry.Subscribe(storer, NewStream(externalStreamName, "", live), history, Top)
   159  		if err != nil {
   160  			return err
   161  		}
   162  
   163  		var disconnected atomic.Value
   164  		go func() {
   165  			for d := range disconnections {
   166  				if d.Error != nil {
   167  					log.Error("peer drop", "node", d.NodeID, "peer", d.PeerID)
   168  					disconnected.Store(true)
   169  				}
   170  			}
   171  		}()
   172  		defer func() {
   173  			if err != nil {
   174  				if yes, ok := disconnected.Load().(bool); ok && yes {
   175  					err = errors.New("disconnect events received")
   176  				}
   177  			}
   178  		}()
   179  
   180  		go func() {
   181  			if !live {
   182  				close(liveErrC)
   183  				return
   184  			}
   185  
   186  			var err error
   187  			defer func() {
   188  				liveErrC <- err
   189  			}()
   190  
   191  //活流
   192  			var liveHashesChan chan []byte
   193  			liveHashesChan, err = getHashes(ctx, registry, storer, NewStream(externalStreamName, "", true))
   194  			if err != nil {
   195  				log.Error("get hashes", "err", err)
   196  				return
   197  			}
   198  			i := externalStreamSessionAt
   199  
   200  //我们已订阅,启用通知
   201  			err = enableNotifications(registry, storer, NewStream(externalStreamName, "", true))
   202  			if err != nil {
   203  				return
   204  			}
   205  
   206  			for {
   207  				select {
   208  				case hash := <-liveHashesChan:
   209  					h := binary.BigEndian.Uint64(hash)
   210  					if h != i {
   211  						err = fmt.Errorf("expected live hash %d, got %d", i, h)
   212  						return
   213  					}
   214  					i++
   215  					if i > externalStreamMaxKeys {
   216  						return
   217  					}
   218  				case <-ctx.Done():
   219  					return
   220  				}
   221  			}
   222  		}()
   223  
   224  		go func() {
   225  			if live && history == nil {
   226  				close(historyErrC)
   227  				return
   228  			}
   229  
   230  			var err error
   231  			defer func() {
   232  				historyErrC <- err
   233  			}()
   234  
   235  //历史流
   236  			var historyHashesChan chan []byte
   237  			historyHashesChan, err = getHashes(ctx, registry, storer, NewStream(externalStreamName, "", false))
   238  			if err != nil {
   239  				log.Error("get hashes", "err", err)
   240  				return
   241  			}
   242  
   243  			var i uint64
   244  			historyTo := externalStreamMaxKeys
   245  			if history != nil {
   246  				i = history.From
   247  				if history.To != 0 {
   248  					historyTo = history.To
   249  				}
   250  			}
   251  
   252  //我们已订阅,启用通知
   253  			err = enableNotifications(registry, storer, NewStream(externalStreamName, "", false))
   254  			if err != nil {
   255  				return
   256  			}
   257  
   258  			for {
   259  				select {
   260  				case hash := <-historyHashesChan:
   261  					h := binary.BigEndian.Uint64(hash)
   262  					if h != i {
   263  						err = fmt.Errorf("expected history hash %d, got %d", i, h)
   264  						return
   265  					}
   266  					i++
   267  					if i > historyTo {
   268  						return
   269  					}
   270  				case <-ctx.Done():
   271  					return
   272  				}
   273  			}
   274  		}()
   275  
   276  		if err := <-liveErrC; err != nil {
   277  			return err
   278  		}
   279  		if err := <-historyErrC; err != nil {
   280  			return err
   281  		}
   282  
   283  		return nil
   284  	})
   285  
   286  	if result.Error != nil {
   287  		t.Fatal(result.Error)
   288  	}
   289  }
   290  
   291  func getHashes(ctx context.Context, r *Registry, peerID enode.ID, s Stream) (chan []byte, error) {
   292  	peer := r.getPeer(peerID)
   293  
   294  	client, err := peer.getClient(ctx, s)
   295  	if err != nil {
   296  		return nil, err
   297  	}
   298  
   299  	c := client.Client.(*testExternalClient)
   300  
   301  	return c.hashes, nil
   302  }
   303  
   304  func enableNotifications(r *Registry, peerID enode.ID, s Stream) error {
   305  	peer := r.getPeer(peerID)
   306  
   307  	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
   308  	defer cancel()
   309  
   310  	client, err := peer.getClient(ctx, s)
   311  	if err != nil {
   312  		return err
   313  	}
   314  
   315  	close(client.Client.(*testExternalClient).enableNotificationsC)
   316  
   317  	return nil
   318  }
   319  
   320  type testExternalClient struct {
   321  	hashes               chan []byte
   322  	store                storage.SyncChunkStore
   323  	enableNotificationsC chan struct{}
   324  }
   325  
   326  func newTestExternalClient(store storage.SyncChunkStore) *testExternalClient {
   327  	return &testExternalClient{
   328  		hashes:               make(chan []byte),
   329  		store:                store,
   330  		enableNotificationsC: make(chan struct{}),
   331  	}
   332  }
   333  
   334  func (c *testExternalClient) NeedData(ctx context.Context, hash []byte) func(context.Context) error {
   335  	wait := c.store.FetchFunc(ctx, storage.Address(hash))
   336  	if wait == nil {
   337  		return nil
   338  	}
   339  	select {
   340  	case c.hashes <- hash:
   341  	case <-ctx.Done():
   342  		log.Warn("testExternalClient NeedData context", "err", ctx.Err())
   343  		return func(_ context.Context) error {
   344  			return ctx.Err()
   345  		}
   346  	}
   347  	return wait
   348  }
   349  
   350  func (c *testExternalClient) BatchDone(Stream, uint64, []byte, []byte) func() (*TakeoverProof, error) {
   351  	return nil
   352  }
   353  
   354  func (c *testExternalClient) Close() {}
   355  
   356  type testExternalServer struct {
   357  	t         string
   358  	keyFunc   func(key []byte, index uint64)
   359  	sessionAt uint64
   360  	maxKeys   uint64
   361  }
   362  
   363  func newTestExternalServer(t string, sessionAt, maxKeys uint64, keyFunc func(key []byte, index uint64)) *testExternalServer {
   364  	if keyFunc == nil {
   365  		keyFunc = binary.BigEndian.PutUint64
   366  	}
   367  	return &testExternalServer{
   368  		t:         t,
   369  		keyFunc:   keyFunc,
   370  		sessionAt: sessionAt,
   371  		maxKeys:   maxKeys,
   372  	}
   373  }
   374  
   375  func (s *testExternalServer) SessionIndex() (uint64, error) {
   376  	return s.sessionAt, nil
   377  }
   378  
   379  func (s *testExternalServer) SetNextBatch(from uint64, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) {
   380  	if to > s.maxKeys {
   381  		to = s.maxKeys
   382  	}
   383  	b := make([]byte, HashSize*(to-from+1))
   384  	for i := from; i <= to; i++ {
   385  		s.keyFunc(b[(i-from)*HashSize:(i-from+1)*HashSize], i)
   386  	}
   387  	return b, from, to, nil, nil
   388  }
   389  
   390  func (s *testExternalServer) GetData(context.Context, []byte) ([]byte, error) {
   391  	return make([]byte, 4096), nil
   392  }
   393  
   394  func (s *testExternalServer) Close() {}
   395