Skip to content

Commit

Permalink
add tests for rumortate, rumorstate answer, rumor answer
Browse files Browse the repository at this point in the history
  • Loading branch information
emonnin-epfl committed Jun 26, 2024
1 parent 2ba8475 commit b737c4e
Show file tree
Hide file tree
Showing 9 changed files with 274 additions and 6 deletions.
4 changes: 2 additions & 2 deletions be1-go/internal/handler/answer/hanswer/answer.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (h *Handler) Handle(socket socket.Socket, msg []byte) error {
}

if h.queries.IsRumor(*answerMsg.ID) {
return h.handleRumorAnswer(answerMsg)
return h.handleRumorAnswer(continueMongering, answerMsg)
}

if h.queries.IsRumorState(*answerMsg.ID) {
Expand Down Expand Up @@ -168,7 +168,7 @@ func (h *Handler) getSortedChannels(msgsByChannel map[string]map[string]mmessage
return sortedChannelIDs
}

func (h *Handler) handleRumorAnswer(msg manswer.Answer) error {
func (h *Handler) handleRumorAnswer(continueMongering float64, msg manswer.Answer) error {
defer h.queries.Remove(*msg.ID)

h.log.Debug().Msgf("received an answer to rumor query %d", *msg.ID)
Expand Down
76 changes: 76 additions & 0 deletions be1-go/internal/handler/answer/hanswer/answer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@ import (
"io"
"popstellar/internal/crypto"
"popstellar/internal/errors"
"popstellar/internal/handler/answer/hanswer/mocks"
"popstellar/internal/handler/answer/manswer"
"popstellar/internal/handler/channel"
"popstellar/internal/handler/channel/root/mroot"
"popstellar/internal/handler/message/mmessage"
"popstellar/internal/handler/method/rumor/mrumor"
"popstellar/internal/logger"
"popstellar/internal/network/socket"
mocks2 "popstellar/internal/network/socket/mocks"
"popstellar/internal/state"
"popstellar/internal/test/generator"
"testing"
Expand Down Expand Up @@ -146,3 +150,75 @@ func Test_handleMessagesByChannel(t *testing.T) {
}

}

func Test_handleRumorStateAnswer(t *testing.T) {
log := logger.Logger.With().Str("test", "handleRumorState").Logger()
queries := mocks.NewQueries(t)
rumorHandler := mocks.NewRumorHandler(t)
messageHandler := mocks.NewMessageHandler(t)
fakeSocket := mocks2.NewFakeSocket("0")

answerHandler := New(queries, Handlers{MessageHandler: messageHandler, RumorHandler: rumorHandler}, log)

sender1 := "sender1"
sender2 := "sender2"

timestamp1 := make(mrumor.RumorTimestamp)
timestamp1[sender1] = 0
timestamp2 := make(mrumor.RumorTimestamp)
timestamp2[sender2] = 0
timestamp3 := make(mrumor.RumorTimestamp)
timestamp3[sender1] = 1

rumor1, _ := generator.NewRumorQuery(t, 1, sender1, 0, timestamp1, make(map[string][]mmessage.Message))
rumor2, _ := generator.NewRumorQuery(t, 2, sender2, 0, timestamp2, make(map[string][]mmessage.Message))
rumor3, _ := generator.NewRumorQuery(t, 3, sender1, 1, timestamp3, make(map[string][]mmessage.Message))

rumors := []mrumor.Rumor{rumor3, rumor1, rumor2}
answer1, _ := generator.NewRumorStateAnswer(t, 4, rumors)

queries.On("Remove", 4).Return(nil).Once()
rumorHandler.On("HandleRumorStateAnswer", fakeSocket, rumor1.Params).Return(nil).Once()
rumorHandler.On("HandleRumorStateAnswer", fakeSocket, rumor3.Params).Return(nil).Once()
rumorHandler.On("HandleRumorStateAnswer", fakeSocket, rumor2.Params).Return(nil).Once()

err := answerHandler.handleRumorStateAnswer(fakeSocket, answer1)
require.NoError(t, err)
}

func Test_handleRumorAnswer(t *testing.T) {
log := logger.Logger.With().Str("test", "handleRumorState").Logger()
queries := mocks.NewQueries(t)
rumorHandler := mocks.NewRumorHandler(t)
messageHandler := mocks.NewMessageHandler(t)

answerHandler := New(queries, Handlers{MessageHandler: messageHandler, RumorHandler: rumorHandler}, log)

continueMongeringTest := float64(0)

answer1, _ := generator.NewRumorAnswer(t, 1, nil)

queries.On("Remove", 1).Return(nil).Once()
queries.On("GetRumor", 1).Return(mrumor.Rumor{}, true).Once()
rumorHandler.On("SendRumor", nil, mrumor.Rumor{}).Return().Once()

err := answerHandler.handleRumorAnswer(continueMongeringTest, answer1)
require.NoError(t, err)

answer2, _ := generator.NewRumorAnswer(t, 1, &manswer.Error{Code: errors.DuplicateResourceErrorCode})

queries.On("Remove", 1).Return(nil).Once()
queries.On("GetRumor", 1).Return(mrumor.Rumor{}, true).Once()
rumorHandler.On("SendRumor", nil, mrumor.Rumor{}).Return().Once()

err = answerHandler.handleRumorAnswer(continueMongeringTest, answer2)
require.NoError(t, err)

continueMongeringTest = float64(1)

queries.On("Remove", 1).Return(nil).Once()

err = answerHandler.handleRumorAnswer(continueMongeringTest, answer2)
require.NoError(t, err)

}
6 changes: 3 additions & 3 deletions be1-go/internal/handler/answer/manswer/answer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type Answer struct {
// Result can be either a 0 int, a slice of messages or a map of messages associated to a channel ID
type Result struct {
isEmpty bool
data []json.RawMessage
Data []json.RawMessage
MessagesByChannel map[string][]json.RawMessage
}

Expand All @@ -32,7 +32,7 @@ func (r *Result) UnmarshalJSON(buf []byte) error {
return nil
}

errData := json.Unmarshal(buf, &r.data)
errData := json.Unmarshal(buf, &r.Data)
if errData == nil {
return nil
}
Expand All @@ -56,7 +56,7 @@ func (r Result) IsEmpty() bool {

// GetData returns the answer data. It can be nil in case the return is empty.
func (r *Result) GetData() []json.RawMessage {
return r.data
return r.Data
}

// GetMessagesByChannel returns the array of objects mapping a channel with its messages.
Expand Down
18 changes: 18 additions & 0 deletions be1-go/internal/handler/method/rumor/mrumor/rumor.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,24 @@ func (r RumorTimestamp) IsBefore(other RumorTimestamp) bool {
return true
}

func (r RumorTimestamp) IsEqual(other RumorTimestamp) bool {
for senderID, rumorID := range other {
myRumorID, ok := r[senderID]
if !ok || myRumorID != rumorID {
return false
}
}

for senderID, rumorID := range r {
otherRumorID, ok := other[senderID]
if !ok || otherRumorID != rumorID {
return false
}
}

return true
}

func (r RumorTimestamp) IsValid(other RumorTimestamp) bool {
for senderID, rumorID := range other {
myRumorID, ok := r[senderID]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (h *Handler) Handle(socket socket.Socket, msg []byte) (*int, error) {
rumors := make([]mrumor.Rumor, 0)

for _, rumor := range myRumors {
if rumor.Params.Timestamp.IsBefore(rumorState.Params.State) {
if rumor.Params.Timestamp.IsBefore(rumorState.Params.State) || rumor.Params.Timestamp.IsEqual(rumorState.Params.State) {
continue
}
rumors = append(rumors, rumor)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package hrumorstate

import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"popstellar/internal/handler/message/mmessage"
"popstellar/internal/handler/method/rumor/mrumor"
"popstellar/internal/handler/method/rumorstate/hrumorstate/mocks"
"popstellar/internal/logger"
mocks2 "popstellar/internal/network/socket/mocks"
"popstellar/internal/test/generator"
"testing"
)

func Test_Handle(t *testing.T) {

log := logger.Logger.With().Str("test", "Handle").Logger()

queries := mocks.NewQueries(t)
db := mocks.NewRepository(t)
sockets := mocks.NewSockets(t)
fakeSocket := mocks2.NewFakeSocket("0")

rumorStateHandler := New(queries, sockets, db, log)

sender1 := "sender1"
sender2 := "sender2"

timestamp1 := make(mrumor.RumorTimestamp)
timestamp1[sender1] = 0
timestamp2 := make(mrumor.RumorTimestamp)
timestamp2[sender2] = 0
timestamp3 := make(mrumor.RumorTimestamp)
timestamp3[sender1] = 1

rumor1, _ := generator.NewRumorQuery(t, 1, sender1, 0, timestamp1, make(map[string][]mmessage.Message))
rumor2, _ := generator.NewRumorQuery(t, 2, sender2, 0, timestamp2, make(map[string][]mmessage.Message))
rumor3, _ := generator.NewRumorQuery(t, 3, sender1, 1, timestamp3, make(map[string][]mmessage.Message))

rumors := []mrumor.Rumor{rumor3, rumor1, rumor2}

db.On("GetAllRumors").Return(rumors, nil).Once()

_, rumorStateBuf1 := generator.NewRumorStateQuery(t, 4, timestamp1)

id, err := rumorStateHandler.Handle(fakeSocket, rumorStateBuf1)
require.NoError(t, err)
require.Nil(t, id)

expected := []mrumor.Rumor{rumor3, rumor2}

require.Equal(t, fakeSocket.ResultID, 4)
require.Equal(t, expected, fakeSocket.Rumors)

db.On("GetAllRumors").Return(rumors, nil).Once()

_, rumorStateBuf2 := generator.NewRumorStateQuery(t, 4, timestamp2)
id, err = rumorStateHandler.Handle(fakeSocket, rumorStateBuf2)
require.NoError(t, err)
require.Nil(t, id)

expected = []mrumor.Rumor{rumor1, rumor3}

require.Equal(t, fakeSocket.ResultID, 4)
require.Equal(t, expected, fakeSocket.Rumors)

db.On("GetAllRumors").Return(rumors, nil).Once()

_, rumorStateBuf3 := generator.NewRumorStateQuery(t, 4, timestamp3)
id, err = rumorStateHandler.Handle(fakeSocket, rumorStateBuf3)
require.NoError(t, err)
require.Nil(t, id)

expected = []mrumor.Rumor{rumor2}

require.Equal(t, fakeSocket.ResultID, 4)
require.Equal(t, expected, fakeSocket.Rumors)

}

func Test_SendRumorState(t *testing.T) {
log := logger.Logger.With().Str("test", "SendRumorState").Logger()

queries := mocks.NewQueries(t)
db := mocks.NewRepository(t)
sockets := mocks.NewSockets(t)

rumorStateHandler := New(queries, sockets, db, log)

timestamp := make(mrumor.RumorTimestamp)
timestamp["sender"] = 0

db.On("GetRumorTimestamp").Return(timestamp, nil).Once()
queries.On("GetNextID").Return(1).Once()
queries.On("AddRumorState", 1).Return(nil).Once()
sockets.On("SendToRandom", mock.AnythingOfType("[]uint8")).Once()

err := rumorStateHandler.SendRumorState()
require.NoError(t, err)
}
13 changes: 13 additions & 0 deletions be1-go/internal/network/socket/mocks/socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package mocks

import (
"popstellar/internal/handler/message/mmessage"
"popstellar/internal/handler/method/rumor/mrumor"
"popstellar/internal/network/socket"
)

Expand All @@ -20,6 +21,9 @@ type FakeSocket struct {

// the Socket ID
Id string

// the rumors present in a rumor state answer
Rumors []mrumor.Rumor
}

func NewFakeSocket(ID string) *FakeSocket {
Expand Down Expand Up @@ -48,6 +52,15 @@ func (f *FakeSocket) SendPopError(_ *int, err error) {
f.Err = err
}

func (f *FakeSocket) SendToRandom(buf []byte) {
f.Msg = buf
}

func (f *FakeSocket) SendRumorStateAnswer(id int, rumors []mrumor.Rumor) {
f.Rumors = rumors
f.ResultID = id
}

func (f *FakeSocket) ID() string {
return f.Id
}
Expand Down
40 changes: 40 additions & 0 deletions be1-go/internal/test/generator/answer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package generator

import (
"encoding/json"
"github.com/stretchr/testify/require"
"popstellar/internal/handler/answer/manswer"
"popstellar/internal/handler/method/rumor/mrumor"
"testing"
)

func NewRumorStateAnswer(t *testing.T, id int, rumors []mrumor.Rumor) (manswer.Answer, []byte) {
data := make([]json.RawMessage, 0)
for _, rumor := range rumors {
paramBuf, err := json.Marshal(rumor.Params)
require.NoError(t, err)
data = append(data, paramBuf)
}

answer := manswer.Answer{
ID: &id,
Result: &manswer.Result{Data: data},
}

answerBuf, err := json.Marshal(&answer)
require.NoError(t, err)

return answer, answerBuf
}

func NewRumorAnswer(t *testing.T, id int, err *manswer.Error) (manswer.Answer, []byte) {
answer := manswer.Answer{
ID: &id,
Error: err,
}

answerBuf, err2 := json.Marshal(&answer)
require.NoError(t, err2)

return answer, answerBuf
}
21 changes: 21 additions & 0 deletions be1-go/internal/test/generator/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"popstellar/internal/handler/method/heartbeat/mheartbeat"
"popstellar/internal/handler/method/publish/mpublish"
"popstellar/internal/handler/method/rumor/mrumor"
"popstellar/internal/handler/method/rumorstate/mrumorstate"
"popstellar/internal/handler/method/subscribe/msubscribe"
"popstellar/internal/handler/method/unsubscribe/munsubscribe"
"popstellar/internal/handler/query/mquery"
Expand Down Expand Up @@ -179,3 +180,23 @@ func NewRumorQuery(t *testing.T, queryID int, senderID string, rumorID int, time

return rumor, rumorBuf
}

func NewRumorStateQuery(t *testing.T, queryID int, timestamp mrumor.RumorTimestamp) (mrumorstate.RumorState, []byte) {
rumorState := mrumorstate.RumorState{
Base: mquery.Base{
JSONRPCBase: mjsonrpc.JSONRPCBase{
JSONRPC: "2.0",
},
Method: mquery.MethodRumorState,
},
ID: queryID,
Params: mrumorstate.RumorStateParams{
State: timestamp,
},
}

rumorStateBuf, err := json.Marshal(&rumorState)
require.NoError(t, err)

return rumorState, rumorStateBuf
}

0 comments on commit b737c4e

Please sign in to comment.