// Tests an n-node system func TestPropagate(t *testing.T) { for _, nbrNodes := range []int{3, 10, 14} { local := sda.NewLocalTest() _, el, _ := local.GenTree(nbrNodes, false, true, true) o := local.Overlays[el.List[0].ID] i := 0 msg := &PropagateMsg{[]byte("propagate")} tree := el.GenerateNaryTreeWithRoot(8, o.ServerIdentity()) log.Lvl2("Starting to propagate", reflect.TypeOf(msg)) pi, err := o.CreateProtocolSDA(tree, "Propagate") log.ErrFatal(err) nodes, err := propagateStartAndWait(pi, msg, 1000, func(m network.Body) { if bytes.Equal(msg.Data, m.(*PropagateMsg).Data) { i++ } else { t.Error("Didn't receive correct data") } }) log.ErrFatal(err) if i != 1 { t.Fatal("Didn't get data-request") } if nodes != nbrNodes { t.Fatal("Not all nodes replied") } local.CloseAll() } }
func (s *simpleService) ProcessClientRequest(e *network.ServerIdentity, r *sda.ClientRequest) { msgT, pm, err := network.UnmarshalRegisteredType(r.Data, network.DefaultConstructors(network.Suite)) log.ErrFatal(err) if msgT != simpleRequestType { return } req := pm.(simpleRequest) tree := req.ServerIdentities.GenerateBinaryTree() tni := s.ctx.NewTreeNodeInstance(tree, tree.Root, "BackForth") proto, err := newBackForthProtocolRoot(tni, req.Val, func(n int) { if err := s.ctx.SendRaw(e, &simpleResponse{ Val: n, }); err != nil { log.Error(err) } }) if err != nil { log.Error(err) return } if err := s.ctx.RegisterProtocolInstance(proto); err != nil { log.Error(err) } go proto.Start() }
func TestClient_Send(t *testing.T) { local := sda.NewLocalTest() defer local.CloseAll() // register service sda.RegisterNewService("BackForth", func(c *sda.Context, path string) sda.Service { return &simpleService{ ctx: c, } }) // create hosts hosts, el, _ := local.GenTree(4, true, true, false) client := sda.NewClient("BackForth") r := &simpleRequest{ ServerIdentities: el, Val: 10, } nm, err := client.Send(hosts[0].ServerIdentity, r) log.ErrFatal(err) assert.Equal(t, nm.MsgType, simpleResponseType) resp := nm.Msg.(simpleResponse) assert.Equal(t, resp.Val, 10) }
func TestProcessor_GetReply(t *testing.T) { defer log.AfterTest(t) p := NewServiceProcessor(nil) log.ErrFatal(p.RegisterMessage(procMsg)) pair := config.NewKeyPair(network.Suite) e := network.NewServerIdentity(pair.Public, "") rep := p.GetReply(e, mkClientRequest(&testMsg{11})) val, ok := rep.(*testMsg) if !ok { t.Fatalf("Couldn't cast reply to testMsg: %+v", rep) } if val.I != 11 { t.Fatal("Value got lost - should be 11") } rep = p.GetReply(e, mkClientRequest(&testMsg{42})) errMsg, ok := rep.(*StatusRet) if !ok { t.Fatal("42 should return an error") } if errMsg.Status == "" { t.Fatal("The error should be non-empty") } }
func TestProcessor_AddMessage(t *testing.T) { defer log.AfterTest(t) p := NewServiceProcessor(nil) log.ErrFatal(p.RegisterMessage(procMsg)) if len(p.functions) != 1 { t.Fatal("Should have registered one function") } mt := network.TypeFromData(&testMsg{}) if mt == network.ErrorType { t.Fatal("Didn't register message-type correctly") } var wrongFunctions = []interface{}{ procMsgWrong1, procMsgWrong2, procMsgWrong3, procMsgWrong4, procMsgWrong5, procMsgWrong6, } for _, f := range wrongFunctions { log.Lvl2("Checking function", reflect.TypeOf(f).String()) err := p.RegisterMessage(f) if err == nil { t.Fatalf("Shouldn't accept function %+s", reflect.TypeOf(f).String()) } } }
func TestServiceProtocolProcessMessage(t *testing.T) { ds := &DummyService{ link: make(chan bool), } var count int sda.RegisterNewService("DummyService", func(c *sda.Context, path string) sda.Service { if count == 0 { count++ // the client does not need a Service return &DummyService{link: make(chan bool)} } ds.c = c ds.path = path ds.Config = DummyConfig{ Send: true, } return ds }) // fake a client h2 := sda.NewLocalHost(2010) defer h2.Close() host := sda.NewLocalHost(2000) host.ListenAndBind() host.StartProcessMessages() log.Lvl1("Host created and listening") defer host.Close() // create the entityList and tree el := sda.NewRoster([]*network.ServerIdentity{host.ServerIdentity}) tree := el.GenerateBinaryTree() // give it to the service ds.fakeTree = tree // Send a request to the service b, err := network.MarshalRegisteredType(&DummyMsg{10}) log.ErrFatal(err) re := &sda.ClientRequest{ Service: sda.ServiceFactory.ServiceID("DummyService"), Data: b, } log.Lvl1("Client connecting to host") if _, err := h2.Connect(host.ServerIdentity); err != nil { t.Fatal(err) } log.Lvl1("Sending request to service...") if err := h2.SendRaw(host.ServerIdentity, re); err != nil { t.Fatal(err) } // wait for the link from the protocol waitOrFatalValue(ds.link, true, t) // now wait for the same link as the protocol should have sent a message to // himself ! waitOrFatalValue(ds.link, true, t) }
func TestReconnection(t *testing.T) { defer log.AfterTest(t) h1 := sda.NewLocalHost(2000) h2 := sda.NewLocalHost(2001) defer h1.Close() defer h2.Close() h1.ListenAndBind() h2.ListenAndBind() log.Lvl1("Sending h1->h2") log.ErrFatal(sendrcv(h1, h2)) log.Lvl1("Sending h2->h1") log.ErrFatal(sendrcv(h2, h1)) log.Lvl1("Closing h1") h1.CloseConnections() log.Lvl1("Listening again on h1") h1.ListenAndBind() log.Lvl1("Sending h2->h1") log.ErrFatal(sendrcv(h2, h1)) log.Lvl1("Sending h1->h2") log.ErrFatal(sendrcv(h1, h2)) log.Lvl1("Shutting down listener of h2") // closing h2, but simulate *hard* failure, without sending a FIN packet c2 := h1.Connection(h2.ServerIdentity) // making h2 fails h2.AbortConnections() log.Lvl1("asking h2 to listen again") // making h2 backup again h2.ListenAndBind() // and re-registering the connection to h2 from h1 h1.RegisterConnection(h2.ServerIdentity, c2) log.Lvl1("Sending h1->h2") log.ErrFatal(sendrcv(h1, h2)) }
func TestReadGroupDescToml(t *testing.T) { group, err := ReadGroupDescToml(strings.NewReader(serverGroup)) log.ErrFatal(err) if len(group.Roster.List) != 2 { t.Fatal("Should have 2 ServerIdentities") } if len(group.description) != 2 { t.Fatal("Should have 2 descriptions") } if group.description[group.Roster.List[1]] != "Ismail's server" { t.Fatal("This should be Ismail's server") } }
// Test if a request that makes the service create a new protocol works func TestServiceRequestNewProtocol(t *testing.T) { ds := &DummyService{ link: make(chan bool), } sda.RegisterNewService("DummyService", func(c *sda.Context, path string) sda.Service { ds.c = c ds.path = path return ds }) host := sda.NewLocalHost(2000) host.Listen() host.StartProcessMessages() log.Lvl1("Host created and listening") defer host.Close() // create the entityList and tree el := sda.NewRoster([]*network.ServerIdentity{host.ServerIdentity}) tree := el.GenerateBinaryTree() // give it to the service ds.fakeTree = tree // Send a request to the service b, err := network.MarshalRegisteredType(&DummyMsg{10}) log.ErrFatal(err) re := &sda.ClientRequest{ Service: sda.ServiceFactory.ServiceID("DummyService"), Data: b, } // fake a client h2 := sda.NewLocalHost(2010) defer h2.Close() log.Lvl1("Client connecting to host") if _, err := h2.Connect(host.ServerIdentity); err != nil { t.Fatal(err) } log.Lvl1("Sending request to service...") if err := h2.SendRaw(host.ServerIdentity, re); err != nil { t.Fatal(err) } // wait for the link from the waitOrFatalValue(ds.link, true, t) // Now RESEND the value so we instantiate using the SAME TREENODE log.Lvl1("Sending request AGAIN to service...") if err := h2.SendRaw(host.ServerIdentity, re); err != nil { t.Fatal(err) } // wait for the link from the // NOW expect false waitOrFatalValue(ds.link, false, t) }
func TestLoadSave(t *testing.T) { defer log.AfterTest(t) log.TestOutput(testing.Verbose(), 4) sc, _, err := createBFTree(7, 2) if err != nil { t.Fatal(err) } dir, err := ioutil.TempDir("", "example") log.ErrFatal(err) defer os.RemoveAll(dir) sc.Save(dir) sc2, err := sda.LoadSimulationConfig(dir, "local1:2000") if err != nil { t.Fatal(err) } if sc2[0].Tree.ID != sc.Tree.ID { t.Fatal("Tree-id is not correct") } }
func TestMultipleInstances(t *testing.T) { defer log.AfterTest(t) log.TestOutput(testing.Verbose(), 4) sc, _, err := createBFTree(7, 2) if err != nil { t.Fatal(err) } dir, err := ioutil.TempDir("", "example") log.ErrFatal(err) defer os.RemoveAll(dir) sc.Save(dir) sc2, err := sda.LoadSimulationConfig(dir, "local1") if err != nil { t.Fatal(err) } if len(sc2) != 4 { t.Fatal("We should have 4 local1-hosts but have", len(sc2)) } if sc2[0].Host.ServerIdentity.ID == sc2[1].Host.ServerIdentity.ID { t.Fatal("Hosts are not copies") } }
func TestClient_Parallel(t *testing.T) { nbrNodes := 2 nbrParallel := 2 local := sda.NewLocalTest() defer local.CloseAll() // register service sda.RegisterNewService("BackForth", func(c *sda.Context, path string) sda.Service { return &simpleService{ ctx: c, } }) // create hosts hosts, el, _ := local.GenTree(nbrNodes, true, true, false) wg := sync.WaitGroup{} wg.Add(nbrParallel) for i := 0; i < nbrParallel; i++ { go func(i int) { log.Lvl1("Starting message", i) r := &simpleRequest{ ServerIdentities: el, Val: 10 * i, } client := sda.NewClient("BackForth") nm, err := client.Send(hosts[0].ServerIdentity, r) log.ErrFatal(err) assert.Equal(t, nm.MsgType, simpleResponseType) resp := nm.Msg.(simpleResponse) assert.Equal(t, resp.Val, 10*i) log.Lvl1("Done with message", i) wg.Done() }(i) } wg.Wait() }
// test for calling the NewProtocol method on a remote Service func TestServiceNewProtocol(t *testing.T) { ds1 := &DummyService{ link: make(chan bool), Config: DummyConfig{ Send: true, }, } ds2 := &DummyService{ link: make(chan bool), } var count int sda.RegisterNewService("DummyService", func(c *sda.Context, path string) sda.Service { var localDs *DummyService switch count { case 2: // the client does not need a Service return &DummyService{link: make(chan bool)} case 1: // children localDs = ds2 case 0: // root localDs = ds1 } localDs.c = c localDs.path = path count++ return localDs }) host := sda.NewLocalHost(2000) host.ListenAndBind() host.StartProcessMessages() log.Lvl1("Host created and listening") defer host.Close() host2 := sda.NewLocalHost(2002) host2.ListenAndBind() host2.StartProcessMessages() defer host2.Close() // create the entityList and tree el := sda.NewRoster([]*network.ServerIdentity{host.ServerIdentity, host2.ServerIdentity}) tree := el.GenerateBinaryTree() // give it to the service ds1.fakeTree = tree // Send a request to the service b, err := network.MarshalRegisteredType(&DummyMsg{10}) log.ErrFatal(err) re := &sda.ClientRequest{ Service: sda.ServiceFactory.ServiceID("DummyService"), Data: b, } // fake a client client := sda.NewLocalHost(2010) defer client.Close() log.Lvl1("Client connecting to host") if _, err := client.Connect(host.ServerIdentity); err != nil { t.Fatal(err) } log.Lvl1("Sending request to service...") if err := client.SendRaw(host.ServerIdentity, re); err != nil { t.Fatal(err) } // wait for the link from the protocol that Starts waitOrFatalValue(ds1.link, true, t) // now wait for the same link as the protocol should have sent a message to // himself ! waitOrFatalValue(ds1.link, true, t) // now wait for the SECOND LINK on the SECOND HOST that the SECOND SERVICE // should have started (ds2) in ProcessRequest waitOrFatalValue(ds2.link, true, t) }
func mkClientRequest(msg network.Body) []byte { b, err := network.MarshalRegisteredType(msg) log.ErrFatal(err) return b }