From 1eb99dc0b6d04d85b9736ab5a050e08d410abb4a Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sun, 21 May 2023 23:57:53 +0300 Subject: refactor vote into its own package --- internal/quorum.go | 11 ++++++----- internal/quorum_test.go | 37 +++++++++++++++++++------------------ internal/server.go | 5 +++-- internal/tcpserver.go | 9 ++++++--- internal/vote.go | 36 ------------------------------------ internal/vote/vote.go | 36 ++++++++++++++++++++++++++++++++++++ internal/vote/vote_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ internal/vote_test.go | 46 ---------------------------------------------- 8 files changed, 116 insertions(+), 110 deletions(-) delete mode 100644 internal/vote.go create mode 100644 internal/vote/vote.go create mode 100644 internal/vote/vote_test.go delete mode 100644 internal/vote_test.go (limited to 'internal') diff --git a/internal/quorum.go b/internal/quorum.go index b680378..a64b07b 100644 --- a/internal/quorum.go +++ b/internal/quorum.go @@ -6,18 +6,19 @@ import ( "sort" "codeberg.org/snonux/gorum/internal/config" + "codeberg.org/snonux/gorum/internal/vote" ) -type quorumMap map[string]vote +type quorumMap map[string]vote.Vote type score struct { id string score int } -func (q quorumMap) vote(v vote) { +func (q quorumMap) vote(v vote.Vote) { log.Printf("Adding vote %v", v) - q[v.from] = v + q[v.From] = v } func (q quorumMap) winner(conf config.Config) (string, error) { @@ -32,7 +33,7 @@ func (q quorumMap) score(conf config.Config) (scores []score) { scoreMap := make(map[string]int) for _, vote := range q { - for _, id := range vote.ids { + for _, id := range vote.IDs { score, _ := scoreMap[id] scoreMap[id] = score + 1 } @@ -60,7 +61,7 @@ func (q quorumMap) cleanExpired() { var expired []string for from, vote := range q { - if vote.expired() { + if vote.Expired() { expired = append(expired, from) } } diff --git a/internal/quorum_test.go b/internal/quorum_test.go index 6da4956..2001937 100644 --- a/internal/quorum_test.go +++ b/internal/quorum_test.go @@ -5,26 +5,27 @@ import ( "time" "codeberg.org/snonux/gorum/internal/config" + "codeberg.org/snonux/gorum/internal/vote" ) func TestScore(t *testing.T) { quorum := make(quorumMap) conf := config.Config{Participants: []string{"foo:1234", "bar:4321", "baz:3444"}} - vote1 := newVote(conf, "foo:334234", "foo bar\n") - vote1.expiresAt = time.Now().Add(1 * time.Hour) + vote1 := vote.New(conf, "foo:334234", "foo bar\n") + vote1.ExpiresAt = time.Now().Add(1 * time.Hour) quorum.vote(vote1) - vote2 := newVote(conf, "bar:334234", "bar baz\n") - vote2.expiresAt = time.Now().Add(1 * time.Hour) + vote2 := vote.New(conf, "bar:334234", "bar baz\n") + vote2.ExpiresAt = time.Now().Add(1 * time.Hour) quorum.vote(vote2) - vote3_dup := newVote(conf, "bar:33234", "bar baz\n") - vote3_dup.expiresAt = time.Now().Add(1 * time.Hour) + vote3_dup := vote.New(conf, "bar:33234", "bar baz\n") + vote3_dup.ExpiresAt = time.Now().Add(1 * time.Hour) quorum.vote(vote3_dup) - vote4 := newVote(conf, "baz:334234", "foo bar baz\n") - vote4.expiresAt = time.Now().Add(1 * time.Hour) + vote4 := vote.New(conf, "baz:334234", "foo bar baz\n") + vote4.ExpiresAt = time.Now().Add(1 * time.Hour) quorum.vote(vote4) scores := quorum.score(conf) @@ -39,16 +40,16 @@ func TestScore(t *testing.T) { func TestTieScore(t *testing.T) { addVotes := func(conf config.Config, quorum quorumMap) { - vote1 := newVote(conf, "foo:334234", "foo bar baz\n") - vote1.expiresAt = time.Now().Add(1 * time.Hour) + vote1 := vote.New(conf, "foo:334234", "foo bar baz\n") + vote1.ExpiresAt = time.Now().Add(1 * time.Hour) quorum.vote(vote1) - vote2 := newVote(conf, "bar:334234", "foo bar baz\n") - vote2.expiresAt = time.Now().Add(1 * time.Hour) + vote2 := vote.New(conf, "bar:334234", "foo bar baz\n") + vote2.ExpiresAt = time.Now().Add(1 * time.Hour) quorum.vote(vote2) - vote3 := newVote(conf, "baz:334234", "foo bar baz\n") - vote3.expiresAt = time.Now().Add(1 * time.Hour) + vote3 := vote.New(conf, "baz:334234", "foo bar baz\n") + vote3.ExpiresAt = time.Now().Add(1 * time.Hour) quorum.vote(vote3) } @@ -99,12 +100,12 @@ func TestCleanExpired(t *testing.T) { quorum := make(quorumMap) conf := config.Config{Participants: []string{"foo:1234", "bay:4321"}} - vote1 := newVote(conf, "foo:334234", " foo bar baz bay\n") - vote1.expiresAt = time.Now().Add(1 * time.Hour) + vote1 := vote.New(conf, "foo:334234", " foo bar baz bay\n") + vote1.ExpiresAt = time.Now().Add(1 * time.Hour) quorum.vote(vote1) - vote2 := newVote(conf, "bar:334234", " foo bar baz bay\n") - vote2.expiresAt = time.Now() + vote2 := vote.New(conf, "bar:334234", " foo bar baz bay\n") + vote2.ExpiresAt = time.Now() quorum.vote(vote2) if len(quorum) != 2 { diff --git a/internal/server.go b/internal/server.go index e5e55d1..05babc0 100644 --- a/internal/server.go +++ b/internal/server.go @@ -6,10 +6,11 @@ import ( "time" "codeberg.org/snonux/gorum/internal/config" + "codeberg.org/snonux/gorum/internal/vote" ) func runServer(ctx context.Context, conf config.Config) { - ch := make(chan vote) + ch := make(chan vote.Vote) quorum := make(quorumMap) go func() { @@ -23,7 +24,7 @@ func runServer(ctx context.Context, conf config.Config) { continue } log.Printf("The current leader node is %s", winner) - case <-time.After(voteExpiry): + case <-time.After(vote.Expiry): quorum.cleanExpired() case <-ctx.Done(): return diff --git a/internal/tcpserver.go b/internal/tcpserver.go index 0f9c006..b1fd11e 100644 --- a/internal/tcpserver.go +++ b/internal/tcpserver.go @@ -8,9 +8,12 @@ import ( "net" "codeberg.org/snonux/gorum/internal/config" + "codeberg.org/snonux/gorum/internal/vote" ) -func startTcpServer(ctx context.Context, conf config.Config, ch chan<- vote) error { +func startTcpServer(ctx context.Context, conf config.Config, + ch chan<- vote.Vote) error { + listener, err := net.Listen("tcp", conf.Address) if err != nil { return fmt.Errorf("Error starting TCP server: %s", err.Error()) @@ -38,7 +41,7 @@ func startTcpServer(ctx context.Context, conf config.Config, ch chan<- vote) err } func handleConnection(ctx context.Context, conf config.Config, - conn net.Conn, ch chan<- vote) { + conn net.Conn, ch chan<- vote.Vote) { defer conn.Close() remoteAddr := conn.RemoteAddr().String() @@ -57,7 +60,7 @@ func handleConnection(ctx context.Context, conf config.Config, } log.Printf("Received message from %s: %s", remoteAddr, message) - ch <- newVote(conf, remoteAddr, message) + ch <- vote.New(conf, remoteAddr, message) conn.Write([]byte(message)) } diff --git a/internal/vote.go b/internal/vote.go deleted file mode 100644 index a9c93f0..0000000 --- a/internal/vote.go +++ /dev/null @@ -1,36 +0,0 @@ -package internal - -import ( - "log" - "strings" - "time" - - "codeberg.org/snonux/gorum/internal/config" - "codeberg.org/snonux/gorum/internal/utils" -) - -const voteExpiry = 20 * time.Second - -type vote struct { - from string - ids []string - expiresAt time.Time -} - -func newVote(conf config.Config, from, message string) vote { - var ids []string - for _, id := range strings.Split(strings.TrimSpace(message), " ") { - if !conf.IsParticipant(id) { - log.Printf("%s is not a participant, excluding from the vote", id) - continue - } - ids = append(ids, id) - } - - return vote{utils.StripPort(from), ids, time.Now().Add(voteExpiry)} -} - -func (v vote) expired() bool { - now := time.Now() - return now.After(v.expiresAt) || now.Equal(v.expiresAt) -} diff --git a/internal/vote/vote.go b/internal/vote/vote.go new file mode 100644 index 0000000..079e021 --- /dev/null +++ b/internal/vote/vote.go @@ -0,0 +1,36 @@ +package vote + +import ( + "log" + "strings" + "time" + + "codeberg.org/snonux/gorum/internal/config" + "codeberg.org/snonux/gorum/internal/utils" +) + +const Expiry = 20 * time.Second + +type Vote struct { + From string + IDs []string + ExpiresAt time.Time +} + +func New(conf config.Config, from, message string) Vote { + var ids []string + for _, id := range strings.Split(strings.TrimSpace(message), " ") { + if !conf.IsParticipant(id) { + log.Printf("%s is not a participant, excluding from the vote", id) + continue + } + ids = append(ids, id) + } + + return Vote{utils.StripPort(from), ids, time.Now().Add(Expiry)} +} + +func (v Vote) Expired() bool { + now := time.Now() + return now.After(v.ExpiresAt) || now.Equal(v.ExpiresAt) +} diff --git a/internal/vote/vote_test.go b/internal/vote/vote_test.go new file mode 100644 index 0000000..0986e00 --- /dev/null +++ b/internal/vote/vote_test.go @@ -0,0 +1,46 @@ +package vote + +import ( + "testing" + "time" + + "codeberg.org/snonux/gorum/internal/config" +) + +func TestVote(t *testing.T) { + conf := config.Config{Participants: []string{"foo:1234", "bay:4321"}} + v := New(conf, "earth:334234", " foo bar baz bay\n") + + if v.From != "earth" { + t.Errorf("Expected vote to come from earth but came from %s", v.From) + } + + if len(v.IDs) != 2 { + t.Errorf("Expected vote length to be 2 but is %d", len(v.IDs)) + } + + if v.IDs[0] != "foo" { + t.Errorf("Expected vote 1 to be foo but is %s", v.IDs[0]) + } + + if v.IDs[1] != "bay" { + t.Errorf("Expected vote 2 to be bay but is %s", v.IDs[1]) + } +} + +func TestVoteExpiry(t *testing.T) { + conf := config.Config{Participants: []string{"foo:1234", "bay:4321"}} + v := New(conf, "earth:334234", " foo bar baz bay\n") + + // Set expiry 1h into the future + v.ExpiresAt = time.Now().Add(1 * time.Hour) + if v.Expired() { + t.Errorf("Didn't expect vote to be expired") + } + + // Set expiry to now + v.ExpiresAt = time.Now() + if !v.Expired() { + t.Errorf("Expected vote to be expired") + } +} diff --git a/internal/vote_test.go b/internal/vote_test.go deleted file mode 100644 index 77e54c8..0000000 --- a/internal/vote_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package internal - -import ( - "testing" - "time" - - "codeberg.org/snonux/gorum/internal/config" -) - -func TestVote(t *testing.T) { - conf := config.Config{Participants: []string{"foo:1234", "bay:4321"}} - v := newVote(conf, "earth:334234", " foo bar baz bay\n") - - if v.from != "earth" { - t.Errorf("Expected vote to come from earth but came from %s", v.from) - } - - if len(v.ids) != 2 { - t.Errorf("Expected vote length to be 2 but is %d", len(v.ids)) - } - - if v.ids[0] != "foo" { - t.Errorf("Expected vote 1 to be foo but is %s", v.ids[0]) - } - - if v.ids[1] != "bay" { - t.Errorf("Expected vote 2 to be bay but is %s", v.ids[1]) - } -} - -func TestVoteExpiry(t *testing.T) { - conf := config.Config{Participants: []string{"foo:1234", "bay:4321"}} - v := newVote(conf, "earth:334234", " foo bar baz bay\n") - - // Set expiry 1h into the future - v.expiresAt = time.Now().Add(1 * time.Hour) - if v.expired() { - t.Errorf("Didn't expect vote to be expired") - } - - // Set expiry to now - v.expiresAt = time.Now() - if !v.expired() { - t.Errorf("Expected vote to be expired") - } -} -- cgit v1.2.3