Add TestSystem
This commit is contained in:
@@ -1,32 +1,17 @@
|
|||||||
package elect_test
|
package elect_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/dchest/uniuri"
|
|
||||||
"github.com/gopatchy/elect"
|
|
||||||
"github.com/gopatchy/proxy"
|
|
||||||
"github.com/samber/lo"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSimple(t *testing.T) {
|
func TestOne(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
signingKey := uniuri.New()
|
ts := NewTestSystem(t, 1)
|
||||||
|
|
||||||
ts := NewTestServer(t, signingKey)
|
|
||||||
defer ts.Stop()
|
defer ts.Stop()
|
||||||
|
|
||||||
p := lo.Must(proxy.NewProxy(t, ts.Addr()))
|
require.Eventually(t, ts.Candidate(0).IsLeader, 15*time.Second, 100*time.Millisecond)
|
||||||
defer p.Close()
|
|
||||||
|
|
||||||
url := fmt.Sprintf("http://%s/", p.Addr())
|
|
||||||
|
|
||||||
v := elect.NewVoter(url, signingKey)
|
|
||||||
defer v.Stop()
|
|
||||||
|
|
||||||
require.Eventually(t, ts.Candidate.IsLeader, 15*time.Second, 100*time.Millisecond)
|
|
||||||
}
|
}
|
||||||
|
|||||||
54
lib_test.go
54
lib_test.go
@@ -1,12 +1,15 @@
|
|||||||
package elect_test
|
package elect_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/dchest/uniuri"
|
||||||
"github.com/gopatchy/elect"
|
"github.com/gopatchy/elect"
|
||||||
|
"github.com/gopatchy/proxy"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
@@ -18,6 +21,13 @@ type TestServer struct {
|
|||||||
srv *http.Server
|
srv *http.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TestSystem struct {
|
||||||
|
signingKey string
|
||||||
|
servers []*TestServer
|
||||||
|
voters []*elect.Voter
|
||||||
|
proxy *proxy.Proxy
|
||||||
|
}
|
||||||
|
|
||||||
func NewTestServer(t *testing.T, signingKey string) *TestServer {
|
func NewTestServer(t *testing.T, signingKey string) *TestServer {
|
||||||
ts := &TestServer{
|
ts := &TestServer{
|
||||||
Candidate: elect.NewCandidate(1, signingKey),
|
Candidate: elect.NewCandidate(1, signingKey),
|
||||||
@@ -45,3 +55,47 @@ func (ts *TestServer) Stop() {
|
|||||||
func (ts *TestServer) Addr() *net.TCPAddr {
|
func (ts *TestServer) Addr() *net.TCPAddr {
|
||||||
return ts.listener.Addr().(*net.TCPAddr)
|
return ts.listener.Addr().(*net.TCPAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewTestSystem(t *testing.T, num int) *TestSystem {
|
||||||
|
ts := &TestSystem{
|
||||||
|
signingKey: uniuri.New(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
ts.servers = append(ts.servers, NewTestServer(t, ts.signingKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.proxy = lo.Must(proxy.NewProxy(t, ts.Server(0).Addr()))
|
||||||
|
|
||||||
|
url := fmt.Sprintf("http://%s/", ts.proxy.Addr())
|
||||||
|
|
||||||
|
for i := 0; i < num; i++ {
|
||||||
|
ts.voters = append(ts.voters, elect.NewVoter(url, ts.signingKey, ts.Candidate(i)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestSystem) Stop() {
|
||||||
|
for _, s := range ts.servers {
|
||||||
|
s.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range ts.voters {
|
||||||
|
v.Stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
ts.proxy.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestSystem) Server(i int) *TestServer {
|
||||||
|
return ts.servers[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestSystem) Candidate(i int) *elect.Candidate {
|
||||||
|
return ts.servers[i].Candidate
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *TestSystem) Voter(i int) *elect.Voter {
|
||||||
|
return ts.voters[i]
|
||||||
|
}
|
||||||
|
|||||||
13
voter.go
13
voter.go
@@ -20,8 +20,8 @@ type Voter struct {
|
|||||||
// used by loop() goroutine only
|
// used by loop() goroutine only
|
||||||
client *resty.Client
|
client *resty.Client
|
||||||
signingKey []byte
|
signingKey []byte
|
||||||
|
candidate *Candidate
|
||||||
vote vote
|
vote vote
|
||||||
candidates []*Candidate
|
|
||||||
period time.Duration
|
period time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,12 +40,13 @@ type voteResponse struct {
|
|||||||
ResponseSent time.Time `json:"responseSent"`
|
ResponseSent time.Time `json:"responseSent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVoter(url string, signingKey string) *Voter {
|
func NewVoter(url string, signingKey string, candidate *Candidate) *Voter {
|
||||||
v := &Voter{
|
v := &Voter{
|
||||||
client: resty.New().
|
client: resty.New().
|
||||||
SetCloseConnection(true).
|
SetCloseConnection(true).
|
||||||
SetBaseURL(url),
|
SetBaseURL(url),
|
||||||
signingKey: []byte(signingKey),
|
signingKey: []byte(signingKey),
|
||||||
|
candidate: candidate,
|
||||||
update: make(chan time.Duration),
|
update: make(chan time.Duration),
|
||||||
done: make(chan bool),
|
done: make(chan bool),
|
||||||
vote: vote{
|
vote: vote{
|
||||||
@@ -64,10 +65,6 @@ func (v *Voter) Stop() {
|
|||||||
<-v.done
|
<-v.done
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Voter) AddCandidate(c *Candidate) {
|
|
||||||
v.candidates = append(v.candidates, c)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *Voter) loop() {
|
func (v *Voter) loop() {
|
||||||
defer close(v.done)
|
defer close(v.done)
|
||||||
|
|
||||||
@@ -111,9 +108,7 @@ func (v *Voter) poll() bool {
|
|||||||
func (v *Voter) sendVote() {
|
func (v *Voter) sendVote() {
|
||||||
v.vote.VoteSent = time.Now().UTC()
|
v.vote.VoteSent = time.Now().UTC()
|
||||||
|
|
||||||
for _, c := range v.candidates {
|
v.candidate.voteIfNo(&v.vote)
|
||||||
c.voteIfNo(&v.vote)
|
|
||||||
}
|
|
||||||
|
|
||||||
js := lo.Must(json.Marshal(v.vote))
|
js := lo.Must(json.Marshal(v.vote))
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user