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 TestRunBroadcastFive(t *testing.T) { c := make(chan Packet, 100) var r run r.seqn = 1 r.out = c r.addr = []*net.UDPAddr{ &net.UDPAddr{net.IP{1, 2, 3, 4}, 5}, &net.UDPAddr{net.IP{2, 3, 4, 5}, 6}, &net.UDPAddr{net.IP{3, 4, 5, 6}, 7}, &net.UDPAddr{net.IP{4, 5, 6, 7}, 8}, &net.UDPAddr{net.IP{5, 6, 7, 8}, 9}, } r.broadcast(newInvite(1)) c <- Packet{} exp := msg{ Seqn: proto.Int64(1), Cmd: invite, Crnd: proto.Int64(1), } addr := make([]*net.UDPAddr, len(r.addr)) for i := 0; i < len(r.addr); i++ { p := <-c addr[i] = p.Addr var got msg err := proto.Unmarshal(p.Data, &got) assert.Equal(t, nil, err) assert.Equal(t, exp, got) } assert.Equal(t, Packet{}, <-c) assert.Equal(t, r.addr, addr) }
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 TestRecvInvalidPacket(t *testing.T) { q := new(packets) x := &net.UDPAddr{net.IP{1, 2, 3, 4}, 5} p := recvPacket(q, Packet{x, invalidProtobuf}) assert.Equal(t, (*packet)(nil), p) assert.Equal(t, 0, q.Len()) }
func TestCoordQuorum(t *testing.T) { co := coordinator{ size: 10, quor: 6, crnd: 1, } co.update(&packet{msg: *newPropose("foo")}, -1) got, tick := co.update(newRsvpFrom(1, 1, 0, "")) assert.Equal(t, (*msg)(nil), got) assert.Equal(t, false, tick) got, tick = co.update(newRsvpFrom(2, 1, 0, "")) assert.Equal(t, (*msg)(nil), got) assert.Equal(t, false, tick) got, tick = co.update(newRsvpFrom(3, 1, 0, "")) assert.Equal(t, (*msg)(nil), got) assert.Equal(t, false, tick) got, tick = co.update(newRsvpFrom(4, 1, 0, "")) assert.Equal(t, (*msg)(nil), got) assert.Equal(t, false, tick) got, tick = co.update(newRsvpFrom(5, 1, 0, "")) assert.Equal(t, (*msg)(nil), got) assert.Equal(t, false, tick) }
func TestCoordStart(t *testing.T) { co := coordinator{crnd: 1} got, tick := co.update(&packet{msg: *newPropose("foo")}, -1) assert.Equal(t, newInvite(1), got) assert.Equal(t, true, tick) }
func TestEventIsSet(t *testing.T) { p, v := "/x", "a" m := MustEncodeSet(p, v, Clobber) ev := Event{1, p, v, 1, m, nil, nil} assert.Equal(t, true, ev.IsSet()) assert.Equal(t, false, ev.IsDel()) assert.Equal(t, false, ev.IsNop()) }
func TestRecvEmptyPacket(t *testing.T) { q := new(packets) x := &net.UDPAddr{net.IP{1, 2, 3, 4}, 5} p := recvPacket(q, Packet{x, []byte{}}) assert.Equal(t, (*packet)(nil), p) assert.Equal(t, 0, q.Len()) }
func TestEventIsDel(t *testing.T) { p := "/x" m := MustEncodeDel(p, Clobber) ev := Event{1, p, "", Missing, m, nil, nil} assert.Equal(t, true, ev.IsDel()) assert.Equal(t, false, ev.IsSet()) assert.Equal(t, false, ev.IsNop()) }
func TestLivenessNoCheck(t *testing.T) { a := &net.UDPAddr{net.IP{1, 2, 3, 4}, 5} lv := liveness{ prev: 5, ival: 3, times: []liverec{{a, 5}}, } lv.check(7) assert.Equal(t, int64(5), lv.prev) assert.Equal(t, []liverec{{a, 5}}, lv.times) }
func TestSchedTrigger(t *testing.T) { var q triggers d := int64(15e8) t0 := time.Now().UnixNano() ts := t0 + d schedTrigger(&q, 1, t0, d) assert.Equal(t, 1, q.Len()) f := q[0] assert.Equal(t, int64(1), f.n) assert.T(t, f.t == ts) }
func TestGcPulse(t *testing.T) { seqns := make(chan int64) defer close(seqns) fs := make(FakeProposer) go Pulse("test", seqns, fs, 1) seqns <- 0 assert.Equal(t, "-1:/ctl/node/test/applied=0", <-fs) seqns <- 1 assert.Equal(t, "-1:/ctl/node/test/applied=1", <-fs) }
func TestLivenessStaysAlive(t *testing.T) { shun := make(chan string, 1) a := &net.UDPAddr{net.IP{1, 2, 3, 4}, 5} lv := liveness{ prev: 0, ival: 1, timeout: 3, times: []liverec{{a, 5}}, shun: shun, } lv.check(7) assert.Equal(t, int64(7), lv.prev) assert.Equal(t, 0, len(shun)) assert.Equal(t, []liverec{{a, 5}}, lv.times) }
func TestCoordTargetNomination(t *testing.T) { co := coordinator{crnd: 1, quor: 6, size: 10} co.update(&packet{msg: *newPropose("foo")}, -1) co.update(newRsvpFrom(1, 1, 0, "")) co.update(newRsvpFrom(2, 1, 0, "")) co.update(newRsvpFrom(3, 1, 0, "")) co.update(newRsvpFrom(4, 1, 0, "")) co.update(newRsvpFrom(5, 1, 0, "")) got, tick := co.update(newRsvpFrom(6, 1, 0, "")) assert.Equal(t, newNominate(1, "foo"), got) assert.Equal(t, false, tick) }
func TestCoordStartRsvp(t *testing.T) { co := coordinator{ quor: 1, crnd: 1, } got, tick := co.update(newRsvpFrom(0, 1, 0, "")) assert.Equal(t, (*msg)(nil), got) assert.Equal(t, false, tick) got, tick = co.update(&packet{msg: *newPropose("foo")}, -1) // If the RSVPs were ignored, this will be an invite. // Otherwise, it'll be a nominate. assert.Equal(t, newInvite(1), got) assert.Equal(t, true, tick) }
func TestLivenessTimesOut(t *testing.T) { shun := make(chan string, 1) a := &net.UDPAddr{net.IP{1, 2, 3, 4}, 5} lv := liveness{ prev: 0, ival: 1, timeout: 3, times: []liverec{{a, 5}}, shun: shun, self: &net.UDPAddr{net.IP{2, 3, 4, 5}, 6}, } lv.check(9) assert.Equal(t, int64(9), lv.prev) assert.Equal(t, 1, len(shun)) assert.Equal(t, "1.2.3.4:5", <-shun) assert.Equal(t, []liverec{}, lv.times) }
func TestRunProposeDelivered(t *testing.T) { var r run r.out = make(chan Packet, 100) r.ops = make(chan store.Op, 100) r.update(&packet{msg: msg{Cmd: propose}}, -1, new(triggers)) assert.Equal(t, true, r.c.begun) }
func TestQuorum(t *testing.T) { assert.Equal(t, 1, (&run{cals: []string{"a"}}).quorum()) assert.Equal(t, 2, (&run{cals: []string{"a", "b"}}).quorum()) assert.Equal(t, 2, (&run{cals: []string{"a", "b", "c"}}).quorum()) assert.Equal(t, 3, (&run{cals: []string{"a", "b", "c", "d"}}).quorum()) assert.Equal(t, 3, (&run{cals: []string{"a", "b", "c", "d", "e"}}).quorum()) assert.Equal(t, 4, (&run{cals: []string{"a", "b", "c", "d", "e", "f"}}).quorum()) assert.Equal(t, 4, (&run{cals: []string{"a", "b", "c", "d", "e", "f", "g"}}).quorum()) assert.Equal(t, 5, (&run{cals: []string{"a", "b", "c", "d", "e", "f", "g", "h"}}).quorum()) }
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 TestRunInviteDelivered(t *testing.T) { var r run r.out = make(chan Packet, 100) r.ops = make(chan store.Op, 100) r.update(&packet{msg: *newInviteSeqn1(1)}, 0, new(triggers)) assert.Equal(t, int64(1), r.a.rnd) }
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 TestRunSchedulesTick(t *testing.T) { var r run r.seqn = 1 r.bound = 10 r.out = make(chan Packet, 100) ticks := new(triggers) r.update(&packet{msg: *newPropose("foo")}, -1, ticks) assert.Equal(t, 1, ticks.Len()) }
func TestRunAppliesOp(t *testing.T) { c := make(chan store.Op, 100) var r run r.seqn = 1 r.out = make(chan Packet, 100) r.ops = c r.l.init(1, 1) r.update(&packet{msg: *newVote(1, "foo")}, 0, new(triggers)) assert.Equal(t, store.Op{1, "foo"}, <-c) }
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 TestRunVoteDelivered(t *testing.T) { r := run{} r.out = make(chan Packet, 100) r.ops = make(chan store.Op, 100) r.l.init(1, 1) p := packet{ msg: msg{ Seqn: proto.Int64(1), Cmd: vote, Vrnd: proto.Int64(1), Value: []byte("foo"), }, Addr: &net.UDPAddr{net.IP{1, 2, 3, 4}, 5}, } r.update(&p, 0, new(triggers)) assert.Equal(t, true, r.l.done) assert.Equal(t, "foo", r.l.v) }
func TestLivenessMark(t *testing.T) { a1, err := net.ResolveUDPAddr("udp", "127.0.0.1:8046") if err != nil { panic(err) } a2, err := net.ResolveUDPAddr("udp", "127.0.0.2:8046") if err != nil { panic(err) } lv := liveness{ timeout: 10, ival: 5, self: a1, shun: make(chan string, 100), } lv.mark(a1, 1) assert.Equal(t, []liverec{{a1, 1}}, lv.times) lv.mark(a2, 2) assert.Equal(t, []liverec{{a1, 1}, {a2, 2}}, lv.times) }
func TestRunSendsLearnerPacket(t *testing.T) { c := make(chan Packet, 100) var r run r.out = c r.ops = make(chan store.Op, 100) r.addr = []*net.UDPAddr{nil, nil} r.l.init(1, 1) var got msg exp := msg{ Seqn: proto.Int64(0), Cmd: learn, Value: []byte("foo"), } r.update(&packet{msg: *newVote(1, "foo")}, 0, new(triggers)) assert.Equal(t, 2, len(c)) err := proto.Unmarshal((<-c).Data, &got) assert.Equal(t, nil, err) assert.Equal(t, exp, got) }
func TestRecvPacket(t *testing.T) { q := new(packets) x := &net.UDPAddr{net.IP{1, 2, 3, 4}, 5} p := recvPacket(q, Packet{x, mustMarshal(&msg{ Seqn: proto.Int64(1), Cmd: invite, })}) assert.Equal(t, &packet{x, msg{Seqn: proto.Int64(1), Cmd: invite}}, p) p = recvPacket(q, Packet{x, mustMarshal(&msg{ Seqn: proto.Int64(2), Cmd: invite, })}) assert.Equal(t, &packet{x, msg{Seqn: proto.Int64(2), Cmd: invite}}, p) p = recvPacket(q, Packet{x, mustMarshal(&msg{ Seqn: proto.Int64(3), Cmd: invite, })}) assert.Equal(t, &packet{x, msg{Seqn: proto.Int64(3), Cmd: invite}}, p) assert.Equal(t, 3, q.Len()) }
func TestGlobNonMatches(t *testing.T) { for _, parts := range nonMatches { pat, paths := parts[0], parts[1:] glob, err := CompileGlob(pat) assert.Equal(t, nil, err) for _, path := range paths { if glob.Match(path) { t.Errorf("pat %q should not match %q", pat, path) } } } }
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) }