github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/go-ethereum-master/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 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  	crand "crypto/rand"
    22  	"encoding/binary"
    23  	"fmt"
    24  	"io"
    25  	"sync"
    26  	"testing"
    27  	"time"
    28  
    29  	"github.com/ethereum/go-ethereum/node"
    30  	"github.com/ethereum/go-ethereum/p2p/discover"
    31  	"github.com/ethereum/go-ethereum/p2p/simulations"
    32  	"github.com/ethereum/go-ethereum/p2p/simulations/adapters"
    33  	"github.com/ethereum/go-ethereum/rpc"
    34  	"github.com/ethereum/go-ethereum/swarm/network"
    35  	streamTesting "github.com/ethereum/go-ethereum/swarm/network/stream/testing"
    36  	"github.com/ethereum/go-ethereum/swarm/state"
    37  	"github.com/ethereum/go-ethereum/swarm/storage"
    38  )
    39  
    40  var (
    41  	externalStreamName             = "externalStream"
    42  	externalStreamSessionAt uint64 = 50
    43  	externalStreamMaxKeys   uint64 = 100
    44  )
    45  
    46  func newIntervalsStreamerService(ctx *adapters.ServiceContext) (node.Service, error) {
    47  	id := ctx.Config.ID
    48  	addr := toAddr(id)
    49  	kad := network.NewKademlia(addr.Over(), network.NewKadParams())
    50  	store := stores[id].(*storage.LocalStore)
    51  	db := storage.NewDBAPI(store)
    52  	delivery := NewDelivery(kad, db)
    53  	deliveries[id] = delivery
    54  	r := NewRegistry(addr, delivery, db, state.NewInmemoryStore(), &RegistryOptions{
    55  		SkipCheck: defaultSkipCheck,
    56  	})
    57  
    58  	r.RegisterClientFunc(externalStreamName, func(p *Peer, t string, live bool) (Client, error) {
    59  		return newTestExternalClient(db), nil
    60  	})
    61  	r.RegisterServerFunc(externalStreamName, func(p *Peer, t string, live bool) (Server, error) {
    62  		return newTestExternalServer(t, externalStreamSessionAt, externalStreamMaxKeys, nil), nil
    63  	})
    64  
    65  	go func() {
    66  		waitPeerErrC <- waitForPeers(r, 1*time.Second, peerCount(id))
    67  	}()
    68  	return &TestExternalRegistry{r}, nil
    69  }
    70  
    71  func TestIntervals(t *testing.T) {
    72  	testIntervals(t, true, nil, false)
    73  	testIntervals(t, false, NewRange(9, 26), false)
    74  	testIntervals(t, true, NewRange(9, 26), false)
    75  
    76  	testIntervals(t, true, nil, true)
    77  	testIntervals(t, false, NewRange(9, 26), true)
    78  	testIntervals(t, true, NewRange(9, 26), true)
    79  }
    80  
    81  func testIntervals(t *testing.T, live bool, history *Range, skipCheck bool) {
    82  	nodes := 2
    83  	chunkCount := dataChunkCount
    84  
    85  	defer setDefaultSkipCheck(defaultSkipCheck)
    86  	defaultSkipCheck = skipCheck
    87  
    88  	toAddr = network.NewAddrFromNodeID
    89  	conf := &streamTesting.RunConfig{
    90  		Adapter:        *adapter,
    91  		NodeCount:      nodes,
    92  		ConnLevel:      1,
    93  		ToAddr:         toAddr,
    94  		Services:       services,
    95  		DefaultService: "intervalsStreamer",
    96  	}
    97  
    98  	sim, teardown, err := streamTesting.NewSimulation(conf)
    99  	var rpcSubscriptionsWg sync.WaitGroup
   100  	defer func() {
   101  		rpcSubscriptionsWg.Wait()
   102  		teardown()
   103  	}()
   104  	if err != nil {
   105  		t.Fatal(err)
   106  	}
   107  
   108  	stores = make(map[discover.NodeID]storage.ChunkStore)
   109  	deliveries = make(map[discover.NodeID]*Delivery)
   110  	for i, id := range sim.IDs {
   111  		stores[id] = sim.Stores[i]
   112  	}
   113  
   114  	peerCount = func(id discover.NodeID) int {
   115  		return 1
   116  	}
   117  
   118  	fileStore := storage.NewFileStore(sim.Stores[0], storage.NewFileStoreParams())
   119  	size := chunkCount * chunkSize
   120  	ctx := context.TODO()
   121  	_, wait, err := fileStore.Store(ctx, io.LimitReader(crand.Reader, int64(size)), int64(size), false)
   122  	if err != nil {
   123  		t.Fatal(err)
   124  	}
   125  	err = wait(ctx)
   126  	if err != nil {
   127  		t.Fatal(err)
   128  	}
   129  
   130  	errc := make(chan error, 1)
   131  	waitPeerErrC = make(chan error)
   132  	quitC := make(chan struct{})
   133  	defer close(quitC)
   134  
   135  	action := func(ctx context.Context) error {
   136  		i := 0
   137  		for err := range waitPeerErrC {
   138  			if err != nil {
   139  				return fmt.Errorf("error waiting for peers: %s", err)
   140  			}
   141  			i++
   142  			if i == nodes {
   143  				break
   144  			}
   145  		}
   146  
   147  		id := sim.IDs[1]
   148  
   149  		err := sim.CallClient(id, func(client *rpc.Client) error {
   150  
   151  			sid := sim.IDs[0]
   152  
   153  			doneC, err := streamTesting.WatchDisconnections(id, client, errc, quitC)
   154  			if err != nil {
   155  				return err
   156  			}
   157  			rpcSubscriptionsWg.Add(1)
   158  			go func() {
   159  				<-doneC
   160  				rpcSubscriptionsWg.Done()
   161  			}()
   162  			ctx, cancel := context.WithTimeout(ctx, 100*time.Second)
   163  			defer cancel()
   164  
   165  			err = client.CallContext(ctx, nil, "stream_subscribeStream", sid, NewStream(externalStreamName, "", live), history, Top)
   166  			if err != nil {
   167  				return err
   168  			}
   169  
   170  			liveErrC := make(chan error)
   171  			historyErrC := make(chan error)
   172  
   173  			go func() {
   174  				if !live {
   175  					close(liveErrC)
   176  					return
   177  				}
   178  
   179  				var err error
   180  				defer func() {
   181  					liveErrC <- err
   182  				}()
   183  
   184  				// live stream
   185  				liveHashesChan := make(chan []byte)
   186  				liveSubscription, err := client.Subscribe(ctx, "stream", liveHashesChan, "getHashes", sid, NewStream(externalStreamName, "", true))
   187  				if err != nil {
   188  					return
   189  				}
   190  				defer liveSubscription.Unsubscribe()
   191  
   192  				i := externalStreamSessionAt
   193  
   194  				// we have subscribed, enable notifications
   195  				err = client.CallContext(ctx, nil, "stream_enableNotifications", sid, NewStream(externalStreamName, "", true))
   196  				if err != nil {
   197  					return
   198  				}
   199  
   200  				for {
   201  					select {
   202  					case hash := <-liveHashesChan:
   203  						h := binary.BigEndian.Uint64(hash)
   204  						if h != i {
   205  							err = fmt.Errorf("expected live hash %d, got %d", i, h)
   206  							return
   207  						}
   208  						i++
   209  						if i > externalStreamMaxKeys {
   210  							return
   211  						}
   212  					case err = <-liveSubscription.Err():
   213  						return
   214  					case <-ctx.Done():
   215  						return
   216  					}
   217  				}
   218  			}()
   219  
   220  			go func() {
   221  				if live && history == nil {
   222  					close(historyErrC)
   223  					return
   224  				}
   225  
   226  				var err error
   227  				defer func() {
   228  					historyErrC <- err
   229  				}()
   230  
   231  				// history stream
   232  				historyHashesChan := make(chan []byte)
   233  				historySubscription, err := client.Subscribe(ctx, "stream", historyHashesChan, "getHashes", sid, NewStream(externalStreamName, "", false))
   234  				if err != nil {
   235  					return
   236  				}
   237  				defer historySubscription.Unsubscribe()
   238  
   239  				var i uint64
   240  				historyTo := externalStreamMaxKeys
   241  				if history != nil {
   242  					i = history.From
   243  					if history.To != 0 {
   244  						historyTo = history.To
   245  					}
   246  				}
   247  
   248  				// we have subscribed, enable notifications
   249  				err = client.CallContext(ctx, nil, "stream_enableNotifications", sid, NewStream(externalStreamName, "", false))
   250  				if err != nil {
   251  					return
   252  				}
   253  
   254  				for {
   255  					select {
   256  					case hash := <-historyHashesChan:
   257  						h := binary.BigEndian.Uint64(hash)
   258  						if h != i {
   259  							err = fmt.Errorf("expected history hash %d, got %d", i, h)
   260  							return
   261  						}
   262  						i++
   263  						if i > historyTo {
   264  							return
   265  						}
   266  					case err = <-historySubscription.Err():
   267  						return
   268  					case <-ctx.Done():
   269  						return
   270  					}
   271  				}
   272  			}()
   273  
   274  			if err := <-liveErrC; err != nil {
   275  				return err
   276  			}
   277  			if err := <-historyErrC; err != nil {
   278  				return err
   279  			}
   280  
   281  			return nil
   282  		})
   283  		return err
   284  	}
   285  	check := func(ctx context.Context, id discover.NodeID) (bool, error) {
   286  		select {
   287  		case err := <-errc:
   288  			return false, err
   289  		case <-ctx.Done():
   290  			return false, ctx.Err()
   291  		default:
   292  		}
   293  		return true, nil
   294  	}
   295  
   296  	conf.Step = &simulations.Step{
   297  		Action:  action,
   298  		Trigger: streamTesting.Trigger(10*time.Millisecond, quitC, sim.IDs[0]),
   299  		Expect: &simulations.Expectation{
   300  			Nodes: sim.IDs[1:1],
   301  			Check: check,
   302  		},
   303  	}
   304  	startedAt := time.Now()
   305  	timeout := 300 * time.Second
   306  	ctx, cancel := context.WithTimeout(context.Background(), timeout)
   307  	defer cancel()
   308  	result, err := sim.Run(ctx, conf)
   309  	finishedAt := time.Now()
   310  	if err != nil {
   311  		t.Fatalf("Setting up simulation failed: %v", err)
   312  	}
   313  	if result.Error != nil {
   314  		t.Fatalf("Simulation failed: %s", result.Error)
   315  	}
   316  	streamTesting.CheckResult(t, result, startedAt, finishedAt)
   317  }