78 lines
2.4 KiB
Go
78 lines
2.4 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestGuessLotteryDrawSelectsExactQuota(t *testing.T) {
|
|
l := newGuessLottery(nil)
|
|
const total = 40
|
|
const quota = 9
|
|
b := &lotteryBucket{max: quota, end: time.Now().Add(time.Second), keys: make(map[string]struct{})}
|
|
for i := 0; i < total; i++ {
|
|
ticket := &lotteryTicket{key: fmt.Sprintf("c-%d|0", i), ctx: context.Background(), result: make(chan lotteryDelivery, 1)}
|
|
b.tickets = append(b.tickets, ticket)
|
|
b.keys[ticket.key] = struct{}{}
|
|
}
|
|
l.buckets["test"] = b
|
|
l.draw("test", "task-test")
|
|
selected := 0
|
|
for _, ticket := range b.tickets {
|
|
if (<-ticket.result).result.Selected {
|
|
selected++
|
|
}
|
|
}
|
|
if selected != quota {
|
|
t.Fatalf("selected %d tickets, want %d", selected, quota)
|
|
}
|
|
}
|
|
|
|
func TestGuessLotteryCanceledTicketDoesNotConsumeQuota(t *testing.T) {
|
|
l := newGuessLottery(nil)
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
cancel()
|
|
canceled := &lotteryTicket{key: "canceled", ctx: ctx, result: make(chan lotteryDelivery, 1)}
|
|
alive := &lotteryTicket{key: "alive", ctx: context.Background(), result: make(chan lotteryDelivery, 1)}
|
|
l.buckets["test"] = &lotteryBucket{max: 1, tickets: []*lotteryTicket{canceled, alive}, keys: map[string]struct{}{"canceled": {}, "alive": {}}}
|
|
l.draw("test", "task-test")
|
|
if got := (<-alive.result).result.Selected; !got {
|
|
t.Fatal("live ticket should receive the available slot")
|
|
}
|
|
}
|
|
|
|
func TestWeightedBeaconDrawIsDeterministicAndRewardsBoostedPath(t *testing.T) {
|
|
tickets := []*lotteryTicket{
|
|
{key: "a", path: "PULSE"}, {key: "b", path: "FLUX"}, {key: "c", path: "PULSE"},
|
|
{key: "d", path: "ORBIT"}, {key: "e", path: "PULSE"}, {key: "f", path: "FLUX"},
|
|
}
|
|
a := weightedBeaconDraw(tickets, 3, "PULSE", 2, "deadbeef", "bucket")
|
|
b := weightedBeaconDraw(tickets, 3, "PULSE", 2, "deadbeef", "bucket")
|
|
if len(a) != len(b) {
|
|
t.Fatal("draw length mismatch")
|
|
}
|
|
count := 0
|
|
for i := range a {
|
|
if a[i] != b[i] {
|
|
t.Fatalf("draw is not deterministic at %d", i)
|
|
}
|
|
if a[i] {
|
|
count++
|
|
}
|
|
}
|
|
if count != 3 {
|
|
t.Fatalf("selected %d, want 3", count)
|
|
}
|
|
}
|
|
|
|
func TestBeaconTargetRoundIsStrictlyAfterWindow(t *testing.T) {
|
|
info := drandInfo{Period: 3, GenesisTime: 1000}
|
|
end := time.Unix(1006, 0).UTC() // exact round boundary
|
|
r := targetRound(info, end)
|
|
if !roundTime(info, r).After(end) {
|
|
t.Fatalf("round %d at %s must be after %s", r, roundTime(info, r), end)
|
|
}
|
|
}
|