func TestManagerEvent(t *testing.T) { const alpha = 2 runs := make(map[int64]*run) st := store.New() defer close(st.Ops) st.Ops <- store.Op{ Seqn: 1, Mut: store.MustEncodeSet(node+"/a/addr", "1.2.3.4:5", 0), } st.Ops <- store.Op{ Seqn: 2, Mut: store.MustEncodeSet(cal+"/1", "a", 0), } ch, err := st.Wait(store.Any, 2) if err != nil { panic(err) } x, _ := net.ResolveUDPAddr("udp", "1.2.3.4:5") pseqn := make(chan int64, 1) m := &Manager{ Alpha: alpha, Self: "a", PSeqn: pseqn, Ops: st.Ops, Out: make(chan Packet), run: runs, } m.event(<-ch) exp := &run{ self: "a", seqn: 2 + alpha, cals: []string{"a"}, addr: []*net.UDPAddr{x}, ops: st.Ops, out: m.Out, bound: initialWaitBound, } exp.c = coordinator{ crnd: 1, size: 1, quor: exp.quorum(), } exp.l = learner{ round: 1, size: 1, quorum: int64(exp.quorum()), votes: map[string]int64{}, voted: []bool{false}, } assert.Equal(t, 1, len(runs)) assert.Equal(t, exp, runs[exp.seqn]) assert.Equal(t, exp.seqn, <-pseqn) assert.Equal(t, exp.seqn+1, m.next) }
func TestManagerPacketProcessing(t *testing.T) { st := store.New() defer close(st.Ops) in := make(chan Packet) out := make(chan Packet, 100) var m Manager m.run = make(map[int64]*run) m.Alpha = 1 m.Store = st m.In = in m.Out = out m.Ops = st.Ops st.Ops <- store.Op{1, store.MustEncodeSet(node+"/a/addr", "1.2.3.4:5", 0)} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/cal/0", "a", 0)} m.event(<-mustWait(st, 2)) addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:9999") recvPacket(&m.packet, Packet{ Data: mustMarshal(&msg{Seqn: proto.Int64(2), Cmd: learn, Value: []byte("foo")}), Addr: addr, }) m.pump() assert.Equal(t, 0, m.packet.Len()) }
func TestManagerFilterPropSeqn(t *testing.T) { ps := make(chan int64, 100) st := store.New() defer close(st.Ops) m := &Manager{ DefRev: 2, Alpha: 1, Self: "b", PSeqn: ps, Store: st, } go m.Run() st.Ops <- store.Op{1, store.MustEncodeSet("/ctl/cal/0", "a", 0)} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/cal/1", "b", 0)} st.Ops <- store.Op{3, store.Nop} st.Ops <- store.Op{4, store.Nop} assert.Equal(t, int64(3), <-ps) assert.Equal(t, int64(5), <-ps) st.Ops <- store.Op{5, store.Nop} st.Ops <- store.Op{6, store.Nop} assert.Equal(t, int64(7), <-ps) }
func TestConsensusOne(t *testing.T) { self := "test" const alpha = 1 st := store.New() st.Ops <- store.Op{1, store.MustEncodeSet("/ctl/node/"+self+"/addr", "1.2.3.4:5", 0)} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/cal/1", self, 0)} <-st.Seqns in := make(chan Packet) out := make(chan Packet) seqns := make(chan int64, alpha) props := make(chan *Prop) m := &Manager{ Self: self, DefRev: 2, Alpha: alpha, In: in, Out: out, Ops: st.Ops, PSeqn: seqns, Props: props, TFill: 10e9, Store: st, Ticker: time.Tick(10e6), } go m.Run() go func() { for o := range out { in <- o } }() n := <-seqns w, err := st.Wait(store.Any, n) if err != nil { panic(err) } props <- &Prop{n, []byte("foo")} e := <-w exp := store.Event{ Seqn: 3, Path: "/ctl/err", Body: "bad mutation", Rev: 3, Mut: "foo", Err: errors.New("bad mutation"), } e.Getter = nil assert.Equal(t, exp, e) }
func TestGetCalsPartial(t *testing.T) { st := store.New() defer close(st.Ops) st.Ops <- store.Op{Seqn: 1, Mut: store.MustEncodeSet(cal+"/1", "a", 0)} st.Ops <- store.Op{Seqn: 2, Mut: store.MustEncodeSet(cal+"/2", "", 0)} st.Ops <- store.Op{Seqn: 3, Mut: store.MustEncodeSet(cal+"/3", "", 0)} <-st.Seqns assert.Equal(t, []string{"a"}, getCals(st)) }
func TestGetAddrs(t *testing.T) { st := store.New() defer close(st.Ops) st.Ops <- store.Op{1, store.MustEncodeSet(node+"/1/addr", "1.2.3.4:5", 0)} st.Ops <- store.Op{2, store.MustEncodeSet(node+"/2/addr", "2.3.4.5:6", 0)} st.Ops <- store.Op{3, store.MustEncodeSet(node+"/3/addr", "3.4.5.6:7", 0)} <-st.Seqns x, _ := net.ResolveUDPAddr("udp", "1.2.3.4:5") y, _ := net.ResolveUDPAddr("udp", "2.3.4.5:6") z, _ := net.ResolveUDPAddr("udp", "3.4.5.6:7") addrs := getAddrs(st, []string{"1", "2", "3"}) assert.Equal(t, []*net.UDPAddr{x, y, z}, addrs) }
func TestManagerPumpDropsOldPackets(t *testing.T) { st := store.New() defer close(st.Ops) x := &net.UDPAddr{net.IP{1, 2, 3, 4}, 5} st.Ops <- store.Op{1, store.MustEncodeSet(node+"/a/addr", "1.2.3.4:5", 0)} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/cal/0", "a", 0)} var m Manager m.run = make(map[int64]*run) m.event(<-mustWait(st, 2)) m.pump() recvPacket(&m.packet, Packet{x, mustMarshal(&msg{Seqn: proto.Int64(1)})}) m.pump() assert.Equal(t, 0, m.Stats.WaitPackets) }
func TestMemberSimple(t *testing.T) { st := store.New() defer close(st.Ops) fp := &test.FakeProposer{Store: st} c := make(chan string) go Clean(c, fp.Store, fp) fp.Propose([]byte(store.MustEncodeSet("/ctl/node/a/x", "a", store.Missing))) fp.Propose([]byte(store.MustEncodeSet("/ctl/node/a/y", "b", store.Missing))) fp.Propose([]byte(store.MustEncodeSet("/ctl/node/a/addr", "1.2.3.4", store.Missing))) fp.Propose([]byte(store.MustEncodeSet("/ctl/cal/0", "a", store.Missing))) calCh, err := fp.Wait(store.MustCompileGlob("/ctl/cal/0"), 1+<-fp.Seqns) if err != nil { panic(err) } nodeCh, err := fp.Wait(store.MustCompileGlob("/ctl/node/a/?"), 1+<-fp.Seqns) if err != nil { panic(err) } // indicate that this peer is inactive go func() { c <- "1.2.3.4" }() ev := <-calCh assert.T(t, ev.IsSet()) assert.Equal(t, "", ev.Body) cs := []int{} ev = <-nodeCh assert.T(t, ev.IsDel()) cs = append(cs, int(ev.Path[len(ev.Path)-1])) nodeCh, err = fp.Wait(store.MustCompileGlob("/ctl/node/a/?"), ev.Seqn+1) if err != nil { panic(err) } ev = <-nodeCh assert.T(t, ev.IsDel()) cs = append(cs, int(ev.Path[len(ev.Path)-1])) sort.Ints(cs) assert.Equal(t, []int{'x', 'y'}, cs) }
func (c cloner) VisitFile(path string, f *doozer.FileInfo) { // store.Clobber is okay here because the event // has already passed through another store body, _, err := c.cl.Get(path, &c.storeRev) if err != nil { panic(err) } mut := store.MustEncodeSet(path, string(body), store.Clobber) c.ch <- store.Op{f.Rev, mut} }
func TestDelRun(t *testing.T) { const alpha = 2 runs := make(map[int64]*run) st := store.New() defer close(st.Ops) st.Ops <- store.Op{1, store.MustEncodeSet(node+"/a/addr", "x", 0)} st.Ops <- store.Op{2, store.MustEncodeSet(cal+"/1", "a", 0)} st.Ops <- store.Op{3, store.Nop} st.Ops <- store.Op{4, store.Nop} c2, err := st.Wait(store.Any, 2) if err != nil { panic(err) } c3, err := st.Wait(store.Any, 3) if err != nil { panic(err) } c4, err := st.Wait(store.Any, 4) if err != nil { panic(err) } pseqn := make(chan int64, 100) m := &Manager{ Alpha: alpha, Self: "a", PSeqn: pseqn, Ops: st.Ops, Out: make(chan Packet), run: runs, } m.event(<-c2) assert.Equal(t, 1, len(m.run)) m.event(<-c3) assert.Equal(t, 2, len(m.run)) m.event(<-c4) assert.Equal(t, 2, len(m.run)) }
func TestManagerTickQueue(t *testing.T) { st := store.New() defer close(st.Ops) st.Ops <- store.Op{1, store.MustEncodeSet(node+"/a/addr", "1.2.3.4:5", 0)} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/cal/0", "a", 0)} var m Manager m.run = make(map[int64]*run) m.Alpha = 1 m.Store = st m.Out = make(chan Packet, 100) m.event(<-mustWait(st, 2)) // get it to tick for seqn 3 recvPacket(&m.packet, Packet{Data: mustMarshal(&msg{Seqn: proto.Int64(3), Cmd: propose})}) m.pump() assert.Equal(t, 1, m.tick.Len()) m.doTick(time.Now().UnixNano() + initialWaitBound*2) assert.Equal(t, int64(1), m.Stats.TotalTicks) }
func follow(st *store.Store, cl *doozer.Conn, rev int64, stop chan bool) { for { ev, err := cl.Wait("/**", rev) if err != nil { panic(err) } // store.Clobber is okay here because the event // has already passed through another store mut := store.MustEncodeSet(ev.Path, string(ev.Body), store.Clobber) st.Ops <- store.Op{ev.Rev, mut} rev = ev.Rev + 1 select { case <-stop: return default: } } }
func TestConsensusTwo(t *testing.T) { a := "a" b := "b" x, _ := net.ResolveUDPAddr("udp", "1.2.3.4:5") xs := "1.2.3.4:5" y, _ := net.ResolveUDPAddr("udp", "2.3.4.5:6") ys := "2.3.4.5:6" const alpha = 1 st := store.New() st.Ops <- store.Op{1, store.Nop} st.Ops <- store.Op{2, store.MustEncodeSet("/ctl/node/a/addr", xs, 0)} st.Ops <- store.Op{3, store.MustEncodeSet("/ctl/cal/1", a, 0)} st.Ops <- store.Op{4, store.MustEncodeSet("/ctl/node/b/addr", ys, 0)} st.Ops <- store.Op{5, store.MustEncodeSet("/ctl/cal/2", b, 0)} ain := make(chan Packet) aout := make(chan Packet) aseqns := make(chan int64, alpha) aprops := make(chan *Prop) am := &Manager{ Self: a, DefRev: 5, Alpha: alpha, In: ain, Out: aout, Ops: st.Ops, PSeqn: aseqns, Props: aprops, TFill: 10e9, Store: st, Ticker: time.Tick(10e6), } go am.Run() bin := make(chan Packet) bout := make(chan Packet) bseqns := make(chan int64, alpha) bprops := make(chan *Prop) bm := &Manager{ Self: b, DefRev: 5, Alpha: alpha, In: bin, Out: bout, Ops: st.Ops, PSeqn: bseqns, Props: bprops, TFill: 10e9, Store: st, Ticker: time.Tick(10e6), } go bm.Run() go func() { for o := range aout { if o.Addr.Port == x.Port && o.Addr.IP.Equal(x.IP) { go func(o Packet) { ain <- o }(o) } else { o.Addr = x go func(o Packet) { bin <- o }(o) } } }() go func() { for o := range bout { if o.Addr.Port == y.Port && o.Addr.IP.Equal(y.IP) { go func(o Packet) { bin <- o }(o) } else { o.Addr = y go func(o Packet) { ain <- o }(o) } } }() n := <-aseqns assert.Equal(t, int64(6), n) w, err := st.Wait(store.Any, n) if err != nil { panic(err) } aprops <- &Prop{n, []byte("foo")} e := <-w exp := store.Event{ Seqn: 6, Path: "/ctl/err", Body: "bad mutation", Rev: 6, Mut: "foo", Err: errors.New("bad mutation"), } e.Getter = nil assert.Equal(t, exp, e) }
func set(st *store.Store, path, body string, rev int64) { mut := store.MustEncodeSet(path, body, rev) st.Ops <- store.Op{1 + <-st.Seqns, mut} }