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