2023-06-04 10:31:26 -07:00
|
|
|
package elect_test
|
|
|
|
|
|
|
|
|
|
import (
|
2023-06-17 14:58:49 -07:00
|
|
|
"context"
|
2023-06-04 10:31:26 -07:00
|
|
|
"net"
|
|
|
|
|
"net/http"
|
|
|
|
|
"testing"
|
|
|
|
|
"time"
|
|
|
|
|
|
2023-06-04 10:43:32 -07:00
|
|
|
"github.com/dchest/uniuri"
|
2023-06-04 10:31:26 -07:00
|
|
|
"github.com/gopatchy/elect"
|
2023-06-17 14:58:49 -07:00
|
|
|
"github.com/gopatchy/event"
|
2023-06-04 10:43:32 -07:00
|
|
|
"github.com/gopatchy/proxy"
|
2023-06-04 10:31:26 -07:00
|
|
|
"github.com/samber/lo"
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type TestServer struct {
|
|
|
|
|
Candidate *elect.Candidate
|
|
|
|
|
|
|
|
|
|
listener *net.TCPListener
|
|
|
|
|
srv *http.Server
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-04 10:43:32 -07:00
|
|
|
type TestSystem struct {
|
|
|
|
|
signingKey string
|
|
|
|
|
servers []*TestServer
|
|
|
|
|
voters []*elect.Voter
|
2023-06-07 21:52:38 -07:00
|
|
|
proxies []*proxy.Proxy
|
2023-06-04 10:43:32 -07:00
|
|
|
}
|
|
|
|
|
|
2023-06-07 23:22:53 -07:00
|
|
|
type Waiter struct {
|
|
|
|
|
chans []<-chan bool
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-17 15:05:42 -07:00
|
|
|
func NewTestServer(ctx context.Context, t *testing.T, ec *event.Client, numVoters int, signingKey string) *TestServer {
|
2023-06-04 10:31:26 -07:00
|
|
|
ts := &TestServer{
|
2023-06-17 15:05:42 -07:00
|
|
|
Candidate: elect.NewCandidate(ctx, ec, numVoters, signingKey),
|
2023-06-04 10:31:26 -07:00
|
|
|
listener: lo.Must(net.ListenTCP("tcp", nil)),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ts.srv = &http.Server{
|
|
|
|
|
Handler: ts.Candidate,
|
|
|
|
|
ReadHeaderTimeout: 30 * time.Second,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
err := ts.srv.Serve(ts.listener)
|
|
|
|
|
require.ErrorIs(t, err, http.ErrServerClosed)
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
return ts
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ts *TestServer) Stop() {
|
|
|
|
|
ts.srv.Close()
|
|
|
|
|
ts.Candidate.Stop()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ts *TestServer) Addr() *net.TCPAddr {
|
|
|
|
|
return ts.listener.Addr().(*net.TCPAddr)
|
|
|
|
|
}
|
2023-06-04 10:43:32 -07:00
|
|
|
|
2023-06-07 23:22:53 -07:00
|
|
|
func NewTestSystem(t *testing.T, numCandidates, numVoters int) *TestSystem {
|
2023-06-17 14:58:49 -07:00
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
ec := event.New()
|
|
|
|
|
defer ec.Close()
|
|
|
|
|
|
2023-06-04 10:43:32 -07:00
|
|
|
ts := &TestSystem{
|
|
|
|
|
signingKey: uniuri.New(),
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-07 23:22:53 -07:00
|
|
|
for i := 0; i < numCandidates; i++ {
|
2023-06-17 15:05:42 -07:00
|
|
|
ts.servers = append(ts.servers, NewTestServer(ctx, t, ec, numVoters, ts.signingKey))
|
2023-06-07 23:22:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i := 0; i < numVoters; i++ {
|
2023-06-07 21:52:38 -07:00
|
|
|
ts.proxies = append(ts.proxies, proxy.NewProxy(t, ts.Server(0).Addr()))
|
2023-06-17 14:58:49 -07:00
|
|
|
ts.voters = append(ts.voters, elect.NewVoter(ctx, ec, ts.Proxy(i).HTTP(), ts.signingKey))
|
2023-06-04 10:43:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ts
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ts *TestSystem) Stop() {
|
|
|
|
|
for _, s := range ts.servers {
|
|
|
|
|
s.Stop()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, v := range ts.voters {
|
|
|
|
|
v.Stop()
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-07 21:52:38 -07:00
|
|
|
for _, p := range ts.proxies {
|
|
|
|
|
p.Close()
|
|
|
|
|
}
|
2023-06-04 10:43:32 -07:00
|
|
|
}
|
|
|
|
|
|
2023-06-07 23:22:53 -07:00
|
|
|
func (ts *TestSystem) SetServer(server int) {
|
2023-06-07 21:52:38 -07:00
|
|
|
for _, p := range ts.proxies {
|
2023-06-07 23:22:53 -07:00
|
|
|
p.SetBackend(ts.Server(server).Addr())
|
2023-06-07 21:52:38 -07:00
|
|
|
}
|
2023-06-04 10:43:32 -07:00
|
|
|
}
|
|
|
|
|
|
2023-06-07 23:22:53 -07:00
|
|
|
func (ts *TestSystem) SetServerForVoter(server, voter int) {
|
|
|
|
|
ts.Proxy(voter).SetBackend(ts.Server(server).Addr())
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-04 10:43:32 -07:00
|
|
|
func (ts *TestSystem) Candidate(i int) *elect.Candidate {
|
|
|
|
|
return ts.servers[i].Candidate
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-07 21:52:38 -07:00
|
|
|
func (ts *TestSystem) Proxy(i int) *proxy.Proxy {
|
|
|
|
|
return ts.proxies[i]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (ts *TestSystem) Server(i int) *TestServer {
|
|
|
|
|
return ts.servers[i]
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-04 10:43:32 -07:00
|
|
|
func (ts *TestSystem) Voter(i int) *elect.Voter {
|
|
|
|
|
return ts.voters[i]
|
|
|
|
|
}
|
2023-06-07 23:22:53 -07:00
|
|
|
|
|
|
|
|
func NewWaiter() *Waiter {
|
|
|
|
|
return &Waiter{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *Waiter) Wait() {
|
|
|
|
|
for _, ch := range w.chans {
|
|
|
|
|
<-ch
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (w *Waiter) Async(cb func()) {
|
|
|
|
|
ch := make(chan bool)
|
|
|
|
|
w.chans = append(w.chans, ch)
|
|
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
|
defer close(ch)
|
|
|
|
|
cb()
|
|
|
|
|
}()
|
|
|
|
|
}
|