github.com/insight-chain/inb-go@v1.1.3-0.20191221022159-da049980ae38/swarm/network/stream/visualized_snapshot_sync_sim_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  // +build withserver
    18  
    19  package stream
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/insight-chain/inb-go/p2p"
    28  	"github.com/insight-chain/inb-go/p2p/discover"
    29  	"github.com/insight-chain/inb-go/p2p/simulations"
    30  	"github.com/insight-chain/inb-go/swarm/log"
    31  	"github.com/insight-chain/inb-go/swarm/network/simulation"
    32  	"github.com/insight-chain/inb-go/swarm/storage"
    33  )
    34  
    35  /*
    36  The tests in this file need to be executed with
    37  
    38  			-tags=withserver
    39  
    40  Also, they will stall if executed stand-alone, because they wait
    41  for the visualization frontend to send a POST /runsim message.
    42  */
    43  
    44  //setup the sim, evaluate nodeCount and chunkCount and create the sim
    45  func setupSim(serviceMap map[string]simulation.ServiceFunc) (int, int, *simulation.Simulation) {
    46  	nodeCount := *nodes
    47  	chunkCount := *chunks
    48  
    49  	if nodeCount == 0 || chunkCount == 0 {
    50  		nodeCount = 32
    51  		chunkCount = 1
    52  	}
    53  
    54  	//setup the simulation with server, which means the sim won't run
    55  	//until it receives a POST /runsim from the frontend
    56  	sim := simulation.New(serviceMap).WithServer(":8888")
    57  	return nodeCount, chunkCount, sim
    58  }
    59  
    60  //watch for disconnections and wait for healthy
    61  func watchSim(sim *simulation.Simulation) (context.Context, context.CancelFunc) {
    62  	ctx, cancelSimRun := context.WithTimeout(context.Background(), 1*time.Minute)
    63  
    64  	if _, err := sim.WaitTillHealthy(ctx, 2); err != nil {
    65  		panic(err)
    66  	}
    67  
    68  	disconnections := sim.PeerEvents(
    69  		context.Background(),
    70  		sim.NodeIDs(),
    71  		simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeDrop),
    72  	)
    73  
    74  	go func() {
    75  		for d := range disconnections {
    76  			log.Error("peer drop", "node", d.NodeID, "peer", d.Event.Peer)
    77  			panic("unexpected disconnect")
    78  			cancelSimRun()
    79  		}
    80  	}()
    81  
    82  	return ctx, cancelSimRun
    83  }
    84  
    85  //This test requests bogus hashes into the network
    86  func TestNonExistingHashesWithServer(t *testing.T) {
    87  
    88  	t.Skip("temporarily disabled as simulations.WaitTillHealthy cannot be trusted")
    89  	nodeCount, _, sim := setupSim(retrievalSimServiceMap)
    90  	defer sim.Close()
    91  
    92  	err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount))
    93  	if err != nil {
    94  		panic(err)
    95  	}
    96  
    97  	ctx, cancelSimRun := watchSim(sim)
    98  	defer cancelSimRun()
    99  
   100  	//in order to get some meaningful visualization, it is beneficial
   101  	//to define a minimum duration of this test
   102  	testDuration := 20 * time.Second
   103  
   104  	result := sim.Run(ctx, func(ctx context.Context, sim *simulation.Simulation) error {
   105  		//check on the node's FileStore (netstore)
   106  		id := sim.RandomUpNode().ID
   107  		item, ok := sim.NodeItem(id, bucketKeyFileStore)
   108  		if !ok {
   109  			t.Fatalf("No filestore")
   110  		}
   111  		fileStore := item.(*storage.FileStore)
   112  		//create a bogus hash
   113  		fakeHash := storage.GenerateRandomChunk(1000).Address()
   114  		//try to retrieve it - will propagate RetrieveRequestMsg into the network
   115  		reader, _ := fileStore.Retrieve(context.TODO(), fakeHash)
   116  		if _, err := reader.Size(ctx, nil); err != nil {
   117  			log.Debug("expected error for non-existing chunk")
   118  		}
   119  		//sleep so that the frontend can have something to display
   120  		time.Sleep(testDuration)
   121  
   122  		return nil
   123  	})
   124  	if result.Error != nil {
   125  		sendSimTerminatedEvent(sim)
   126  		t.Fatal(result.Error)
   127  	}
   128  
   129  	sendSimTerminatedEvent(sim)
   130  
   131  }
   132  
   133  //send a termination event to the frontend
   134  func sendSimTerminatedEvent(sim *simulation.Simulation) {
   135  	evt := &simulations.Event{
   136  		Type:    EventTypeSimTerminated,
   137  		Control: false,
   138  	}
   139  	sim.Net.Events().Send(evt)
   140  }
   141  
   142  //This test is the same as the snapshot sync test,
   143  //but with a HTTP server
   144  //It also sends some custom events so that the frontend
   145  //can visualize messages like SendOfferedMsg, WantedHashesMsg, DeliveryMsg
   146  func TestSnapshotSyncWithServer(t *testing.T) {
   147  
   148  	t.Skip("temporarily disabled as simulations.WaitTillHealthy cannot be trusted")
   149  	nodeCount, chunkCount, sim := setupSim(simServiceMap)
   150  	defer sim.Close()
   151  
   152  	log.Info("Initializing test config")
   153  
   154  	conf := &synctestConfig{}
   155  	//map of discover ID to indexes of chunks expected at that ID
   156  	conf.idToChunksMap = make(map[discover.NodeID][]int)
   157  	//map of overlay address to discover ID
   158  	conf.addrToIDMap = make(map[string]discover.NodeID)
   159  	//array where the generated chunk hashes will be stored
   160  	conf.hashes = make([]storage.Address, 0)
   161  
   162  	err := sim.UploadSnapshot(fmt.Sprintf("testing/snapshot_%d.json", nodeCount))
   163  	if err != nil {
   164  		panic(err)
   165  	}
   166  
   167  	ctx, cancelSimRun := watchSim(sim)
   168  	defer cancelSimRun()
   169  
   170  	//setup filters in the event feed
   171  	offeredHashesFilter := simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("stream").MsgCode(1)
   172  	wantedFilter := simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("stream").MsgCode(2)
   173  	deliveryFilter := simulation.NewPeerEventsFilter().Type(p2p.PeerEventTypeMsgRecv).Protocol("stream").MsgCode(6)
   174  	eventC := sim.PeerEvents(ctx, sim.UpNodeIDs(), offeredHashesFilter, wantedFilter, deliveryFilter)
   175  
   176  	quit := make(chan struct{})
   177  
   178  	go func() {
   179  		for e := range eventC {
   180  			select {
   181  			case <-quit:
   182  				fmt.Println("quitting event loop")
   183  				return
   184  			default:
   185  			}
   186  			if e.Error != nil {
   187  				t.Fatal(e.Error)
   188  			}
   189  			if *e.Event.MsgCode == uint64(1) {
   190  				evt := &simulations.Event{
   191  					Type:    EventTypeChunkOffered,
   192  					Node:    sim.Net.GetNode(e.NodeID),
   193  					Control: false,
   194  				}
   195  				sim.Net.Events().Send(evt)
   196  			} else if *e.Event.MsgCode == uint64(2) {
   197  				evt := &simulations.Event{
   198  					Type:    EventTypeChunkWanted,
   199  					Node:    sim.Net.GetNode(e.NodeID),
   200  					Control: false,
   201  				}
   202  				sim.Net.Events().Send(evt)
   203  			} else if *e.Event.MsgCode == uint64(6) {
   204  				evt := &simulations.Event{
   205  					Type:    EventTypeChunkDelivered,
   206  					Node:    sim.Net.GetNode(e.NodeID),
   207  					Control: false,
   208  				}
   209  				sim.Net.Events().Send(evt)
   210  			}
   211  		}
   212  	}()
   213  	//run the sim
   214  	result := runSim(conf, ctx, sim, chunkCount)
   215  
   216  	//send terminated event
   217  	evt := &simulations.Event{
   218  		Type:    EventTypeSimTerminated,
   219  		Control: false,
   220  	}
   221  	sim.Net.Events().Send(evt)
   222  
   223  	if result.Error != nil {
   224  		panic(result.Error)
   225  	}
   226  	close(quit)
   227  	log.Info("Simulation ended")
   228  }