Skip to content
Snippets Groups Projects
Commit 70852e00 authored by Josh Brooks's avatar Josh Brooks
Browse files

Refactor dummy package

parent 0b664bff
No related branches found
No related tags found
2 merge requests!510Release,!331Hotfix/dummy message clean up
......@@ -21,20 +21,25 @@ import (
"time"
)
// Manager related thread handling constants.
const (
// The name of the Manager's stoppable.Stoppable
dummyTrafficStoppableName = "DummyTraffic"
statusChanLen = 100
// The amount of statuses in queue that can be placed
// by Manager.SetStatus.
statusChanLen = 100
)
// Thread status.
// The thread status values.
const (
notStarted uint32 = iota
running
paused
stopped
notStarted uint32 = iota // Sending thread has not been started
running // Sending thread is currently operating
paused // Sending thread is temporarily halted.
stopped // Sending thread is halted.
)
// Error messages.
// Error messages for Manager.
const (
setStatusErr = "Failed to change status of dummy traffic send thread to %t: channel full"
)
......@@ -56,15 +61,17 @@ type Manager struct {
// Pauses/Resumes the dummy send thread when triggered
statusChan chan bool
// Cmix interfaces
// Interfaces
net cmix.Client
store storage.Session
rng *fastRNG.StreamGenerator
// Generates
rng *fastRNG.StreamGenerator
}
// NewManager creates a Manager object and initialises the
// dummy traffic sending thread. Note that the Manager does not start sending dummy
// traffic until True is passed into Manager.SetStatus. The time duration
// traffic until `True` is passed into Manager.SetStatus. The time duration
// between each sending operation and the amount of messages sent each interval
// are randomly generated values with bounds defined by the
// given parameters below.
......@@ -74,9 +81,9 @@ type Manager struct {
// each sending cycle.
// - avgSendDeltaMS - the average duration, in milliseconds, to wait
// between sends.
// - randomRangeMS - the upper bound of the interval between sending cycles.
// Sends occur every avgSendDeltaMS +/- a random duration with an
// upper bound of randomRangeMS
// - randomRangeMS - the upper bound of the interval between sending cycles,
// in milliseconds. Sends occur every avgSendDeltaMS +/- a random duration
// with an upper bound of randomRangeMS.
func NewManager(maxNumMessages int,
avgSendDelta, randomRange time.Duration,
net *xxdk.Cmix) *Manager {
......@@ -86,7 +93,7 @@ func NewManager(maxNumMessages int,
}
// newManager builds a new dummy Manager from fields explicitly passed in. This
// function is a helper function for NewManager to make it easier to test.
// function is a helper function for NewManager.
func newManager(maxNumMessages int, avgSendDelta, randomRange time.Duration,
net cmix.Client, store storage.Session, rng *fastRNG.StreamGenerator) *Manager {
return &Manager{
......@@ -102,7 +109,7 @@ func newManager(maxNumMessages int, avgSendDelta, randomRange time.Duration,
}
// StartDummyTraffic starts the process of sending dummy traffic. This function
// matches the xxdk.Service type.
// adheres to xxdk.Service.
func (m *Manager) StartDummyTraffic() (stoppable.Stoppable, error) {
stop := stoppable.NewSingle(dummyTrafficStoppableName)
go m.sendThread(stop)
......@@ -118,10 +125,10 @@ func (m *Manager) StartDummyTraffic() (stoppable.Stoppable, error) {
// operation has completed.
//
// Params:
// - boolean - True: Sending thread is sending dummy messages.
// False: Sending thread is paused/stopped and is not sending dummy messages
// - boolean - Input should be true if you want to send dummy messages.
// Input should be false if you want to pause dummy messages.
// Returns:
// - error - if the DummyTraffic.SetStatus is called too frequently, causing the
// - error - if the Manager.SetStatus is called too frequently, causing the
// internal status channel to fill.
func (m *Manager) SetStatus(status bool) error {
select {
......@@ -132,15 +139,16 @@ func (m *Manager) SetStatus(status bool) error {
}
}
// GetStatus returns the current state of the dummy traffic sending thread.
// GetStatus returns the current state of the Manager's sending thread.
// Note that this function does not return the status set by the most recent call to
// SetStatus directly. Instead, this call returns the current status of the sending thread.
// SetStatus. Instead, this call returns the current status of the sending thread.
// This is due to the small delay that may occur between calling SetStatus and the
// sending thread taking into effect that status change.
//
// Returns:
// - boolean - True: Sending thread is sending dummy messages.
// - False: Sending thread is paused/stopped and is not sending dummy messages.
// - boolean - Returns true if sending thread is sending dummy messages.
// Returns false if sending thread is paused/stopped and is
// not sending dummy messages.
func (m *Manager) GetStatus() bool {
switch atomic.LoadUint32(&m.status) {
case running:
......
......@@ -45,7 +45,7 @@ func Test_newManager(t *testing.T) {
// Tests that Manager.StartDummyTraffic sends dummy messages and that it stops
// when the stoppable is closed.
func TestManager_StartDummyTraffic(t *testing.T) {
m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t)
m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t)
err := m.SetStatus(true)
if err != nil {
......@@ -104,7 +104,7 @@ func TestManager_StartDummyTraffic(t *testing.T) {
// can be called multiple times with the same status without it affecting
// anything. Also tests that the thread quits even when paused.
func TestManager_SetStatus(t *testing.T) {
m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t)
m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t)
err := m.SetStatus(false)
if err != nil {
......@@ -213,7 +213,7 @@ func TestManager_SetStatus(t *testing.T) {
// Error path: tests that Manager.SetStatus returns an error if the status
// cannot be set.
func TestManager_SetStatus_ChannelError(t *testing.T) {
m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t)
m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t)
// Send the max number of status changes on the channel
for i := 0; i < statusChanLen; i++ {
......@@ -236,7 +236,7 @@ func TestManager_SetStatus_ChannelError(t *testing.T) {
// Tests that Manager.GetStatus gets the correct status before the send thread
// starts, while sending, while paused, and after it is stopped.
func TestManager_GetStatus(t *testing.T) {
m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t)
m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t)
err := m.SetStatus(false)
if err != nil {
......
......@@ -25,21 +25,23 @@ import (
// mockCmix is a testing structure that adheres to cmix.Client.
type mockCmix struct {
messages map[id.ID][]byte
messages map[id.ID]format.Message
sync.RWMutex
payloadSize int
}
func newMockCmix() cmix.Client {
func newMockCmix(payloadSize int) cmix.Client {
return &mockCmix{
messages: make(map[id.ID][]byte),
messages: make(map[id.ID]format.Message),
payloadSize: payloadSize,
}
}
func (m *mockCmix) Send(recipient *id.ID, fingerprint format.Fingerprint, service message.Service, payload, mac []byte, cmixParams cmix.CMIXParams) (id.Round, ephemeral.Id, error) {
m.Lock()
defer m.Unlock()
m.messages[*recipient] = fingerprint.Bytes()
m.messages[*recipient] = generateMessage(m.payloadSize, fingerprint, service, payload, mac)
return 0, ephemeral.Id{}, nil
}
......@@ -50,7 +52,7 @@ func (m *mockCmix) GetMsgListLen() int {
return len(m.messages)
}
func (m *mockCmix) GetMsgList() map[id.ID][]byte {
func (m *mockCmix) GetMsgList() map[id.ID]format.Message {
m.RLock()
defer m.RUnlock()
return m.messages
......
......@@ -10,42 +10,78 @@ package dummy
import (
"encoding/binary"
"github.com/pkg/errors"
"gitlab.com/elixxir/client/cmix/message"
"gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/crypto/csprng"
"gitlab.com/xx_network/primitives/id"
"time"
) // Error messages.
// Error constants for Manager.newRandomCmixMessage and it's helper functions..
const (
payloadSizeRngErr = "failed to generate random payload size: %+v"
payloadRngErr = "failed to generate random payload: %+v"
fingerprintRngErr = "failed to generate random fingerprint: %+v"
macRngErr = "failed to generate random MAC: %+v"
recipientRngErr = "failed to generate random recipient: %+v"
)
// intRng returns, as an int, a non-negative, non-zero random number in [1, n)
// from the csprng.Source.
func intRng(n int, rng csprng.Source) (int, error) {
v, err := csprng.Generate(8, rng)
// newRandomCmixMessage returns random format.Message data.
//
// Returns in order a:
// - Recipient (id.ID)
// - Message fingerprint (format.Fingerprint)
// - Message service (message.Service)
// - Payload ([]byte)
// - MAC ([]byte)
// - Error if there was an issue randomly generating any of the above data.
// The error will specify which of the above failed to be randomly generated.
func (m *Manager) newRandomCmixMessage(rng csprng.Source) (
recipient *id.ID, fingerprint format.Fingerprint,
service message.Service,
payload, mac []byte, err error) {
// Generate random recipient
recipient, err = id.NewRandomID(rng, id.User)
if err != nil {
return 0, err
return nil, format.Fingerprint{}, message.Service{}, nil, nil,
errors.Errorf(recipientRngErr, err)
}
return int(binary.LittleEndian.Uint64(v)%uint64(n-1)) + 1, nil
}
// todo: use error constants above?
// Generate random message payload
payloadSize := m.store.GetCmixGroup().GetP().ByteLen()
payload, err = newRandomPayload(payloadSize, rng)
if err != nil {
return nil, format.Fingerprint{}, message.Service{}, nil, nil,
errors.Errorf(payloadRngErr, err)
}
// durationRng returns a duration that is the base duration plus or minus a
// random duration of max randomRange.
func durationRng(base, randomRange time.Duration, rng csprng.Source) (
time.Duration, error) {
delta, err := intRng(int(2*randomRange), rng)
// Generate random fingerprint
fingerprint, err = newRandomFingerprint(rng)
if err != nil {
return 0, err
return nil, format.Fingerprint{}, message.Service{}, nil, nil,
errors.Errorf(fingerprintRngErr, err)
}
return base + randomRange - time.Duration(delta), nil
// Generate random MAC
mac, err = newRandomMAC(rng)
if err != nil {
return nil, format.Fingerprint{}, message.Service{}, nil, nil,
errors.Errorf(macRngErr, err)
}
// Generate random service
service = message.GetRandomService(rng)
return
}
// newRandomPayload generates a random payload of a random length.
// newRandomPayload generates a random payload of a random length
// within the maxPayloadSize.
func newRandomPayload(maxPayloadSize int, rng csprng.Source) ([]byte, error) {
// Generate random payload size
randomPayloadSize, err := intRng(maxPayloadSize, rng)
randomPayloadSize, err := randomInt(maxPayloadSize, rng)
if err != nil {
return nil, errors.Errorf(payloadSizeRngErr, err)
}
......@@ -86,3 +122,36 @@ func newRandomMAC(rng csprng.Source) ([]byte, error) {
return mac, nil
}
//////////////////////////////////////////////////////////////////////////////////
// Random Duration functions
//////////////////////////////////////////////////////////////////////////////////
// randomDuration returns a duration that is the base duration plus or minus a
// random duration of max randomRange.
func randomDuration(base, randomRange time.Duration, rng csprng.Source) (
time.Duration, error) {
// Generate a random duration
delta, err := randomInt(int(2*randomRange), rng)
if err != nil {
return 0, err
}
return base + randomRange - time.Duration(delta), nil
}
//////////////////////////////////////////////////////////////////////////////////
// Miscellaneous
//////////////////////////////////////////////////////////////////////////////////
// randomInt returns, as an int, a non-negative, non-zero random number in [1, n)
// from the csprng.Source.
func randomInt(n int, rng csprng.Source) (int, error) {
v, err := csprng.Generate(8, rng)
if err != nil {
return 0, err
}
return int(binary.LittleEndian.Uint64(v)%uint64(n-1)) + 1, nil
}
......@@ -13,7 +13,7 @@ import (
"time"
)
// Consistency test: tests that intRng returns the expected int when using a
// Consistency test: tests that randomInt returns the expected int when using a
// PRNG and that the result is not larger than the max.
func Test_intRng_Consistency(t *testing.T) {
expectedInts := []int{15, 1, 35, 13, 42, 52, 57, 3, 48}
......@@ -22,9 +22,9 @@ func Test_intRng_Consistency(t *testing.T) {
max := 64
for i, expected := range expectedInts {
v, err := intRng(max, prng)
v, err := randomInt(max, prng)
if err != nil {
t.Errorf("intRng returned an error (%d): %+v", i, err)
t.Errorf("randomInt returned an error (%d): %+v", i, err)
}
if v != expected {
......@@ -40,7 +40,7 @@ func Test_intRng_Consistency(t *testing.T) {
}
}
// Consistency test: tests that durationRng returns the expected int when using
// Consistency test: tests that randomDuration returns the expected int when using
// a PRNG and that the result is within the allowed range.
func Test_durationRng_Consistency(t *testing.T) {
expectedDurations := []time.Duration{
......@@ -52,9 +52,9 @@ func Test_durationRng_Consistency(t *testing.T) {
base, randomRange := time.Minute, 15*time.Second
for i, expected := range expectedDurations {
v, err := durationRng(base, randomRange, prng)
v, err := randomDuration(base, randomRange, prng)
if err != nil {
t.Errorf("durationRng returned an error (%d): %+v", i, err)
t.Errorf("randomDuration returned an error (%d): %+v", i, err)
}
if v != expected {
......
......@@ -8,27 +8,20 @@
package dummy
import (
"gitlab.com/elixxir/client/cmix/message"
"gitlab.com/elixxir/client/cmix"
"gitlab.com/xx_network/crypto/csprng"
"sync"
"sync/atomic"
"time"
"github.com/pkg/errors"
jww "github.com/spf13/jwalterweatherman"
"gitlab.com/elixxir/client/cmix"
"gitlab.com/elixxir/client/stoppable"
"gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/crypto/csprng"
"gitlab.com/xx_network/primitives/id"
)
// Error messages.
// Error messages for the Manager.sendThread and its helper functions.
const (
numMsgsRngErr = "failed to generate random number of messages to send: %+v"
payloadRngErr = "failed to generate random payload: %+v"
recipientRngErr = "failed to generate random recipient: %+v"
fingerprintRngErr = "failed to generate random fingerprint: %+v"
macRngErr = "failed to generate random MAC: %+v"
numMsgsRngErr = "failed to generate random number of messages to send: %+v"
)
// sendThread is a thread that sends the dummy messages at random intervals.
......@@ -40,152 +33,113 @@ func (m *Manager) sendThread(stop *stoppable.Single) {
for {
select {
case <-stop.Quit():
m.stopSendThread(stop)
return
case status := <-m.statusChan:
if status {
atomic.StoreUint32(&m.status, running)
nextSendChanPtr = &(m.randomTimer().C)
// Generate random duration
rng := m.rng.GetStream()
duration, err := randomDuration(m.avgSendDelta, m.randomRange, rng)
if err != nil {
rng.Close()
jww.FATAL.Panicf("Failed to generate random sending interval: %+v", err)
}
rng.Close()
// Create timer
nextSendChanPtr = &(time.NewTimer(duration).C)
} else {
atomic.StoreUint32(&m.status, paused)
nextSendChan = make(<-chan time.Time)
nextSendChanPtr = &nextSendChan
}
case <-*nextSendChanPtr:
nextSendChanPtr = &(m.randomTimer().C)
// Generate random duration
rng := m.rng.GetStream()
duration, err := randomDuration(m.avgSendDelta, m.randomRange, rng)
if err != nil {
rng.Close()
jww.FATAL.Panicf("Failed to generate random sending interval: %+v", err)
}
rng.Close()
go func() {
// get list of random messages and recipients
rng := m.rng.GetStream()
defer rng.Close()
msgs, err := m.newRandomMessages(rng)
if err != nil {
jww.ERROR.Printf("Failed to generate dummy messages: %+v", err)
return
}
// Create timer
nextSendChanPtr = &(time.NewTimer(duration).C)
err = m.sendMessages(msgs, rng)
// Send messages
go func() {
err := m.sendMessages()
if err != nil {
jww.ERROR.Printf("Failed to send dummy messages: %+v", err)
}
}()
case <-stop.Quit():
m.stopSendThread(stop)
return
}
}
}
// stopSendThread is triggered when the stoppable is triggered. It prints a
// debug message, sets the thread status to stopped, and sets the status of the
// stoppable to stopped.
func (m *Manager) stopSendThread(stop *stoppable.Single) {
jww.DEBUG.Print(
"Stopping dummy traffic sending thread: stoppable triggered")
atomic.StoreUint32(&m.status, stopped)
stop.ToStopped()
}
// sendMessages generates and sends random messages.
func (m *Manager) sendMessages(msgs map[id.ID]format.Message, rng csprng.Source) error {
var sent, i int64
func (m *Manager) sendMessages() error {
var sent int64
var wg sync.WaitGroup
for recipient, msg := range msgs {
wg.Add(1)
// Randomly generate amount of messages to send
rng := m.rng.GetStream()
defer rng.Close()
numMessages, err := randomInt(m.maxNumMessages+1, rng)
if err != nil {
return errors.Errorf(numMsgsRngErr, err)
}
go func(i int64, recipient id.ID, msg format.Message) {
for i := 0; i < numMessages; i++ {
wg.Add(1)
go func(localIndex, totalMessages int) {
defer wg.Done()
// Fill the preimage with random data to ensure it is not repeatable
p := cmix.GetDefaultCMIXParams()
_, _, err := m.net.Send(&recipient, msg.GetKeyFP(),
message.GetRandomService(rng), msg.GetContents(), msg.GetMac(), p)
err = m.sendMessage(localIndex, totalMessages, rng)
if err != nil {
jww.WARN.Printf("Failed to send dummy message %d/%d via "+
"Send: %+v", i, len(msgs), err)
} else {
atomic.AddInt64(&sent, 1)
jww.ERROR.Printf(err.Error())
}
}(i, recipient, msg)
i++
// Add to counter of successful sends
atomic.AddInt64(&sent, 1)
}(i, numMessages)
}
wg.Wait()
jww.INFO.Printf("Sent %d/%d dummy messages.", sent, len(msgs))
jww.INFO.Printf("Sent %d/%d dummy messages.", sent, numMessages)
return nil
}
// newRandomMessages returns a map of a random recipients and random messages of
// a randomly generated length in [1, Manager.maxNumMessages].
func (m *Manager) newRandomMessages(rng csprng.Source) (
map[id.ID]format.Message, error) {
numMessages, err := intRng(m.maxNumMessages+1, rng)
if err != nil {
return nil, errors.Errorf(numMsgsRngErr, err)
}
msgs := make(map[id.ID]format.Message, numMessages)
for i := 0; i < numMessages; i++ {
// Generate random recipient
recipient, err := id.NewRandomID(rng, id.User)
if err != nil {
return nil, errors.Errorf(recipientRngErr, err)
}
msgs[*recipient], err = m.newRandomCmixMessage(rng)
if err != nil {
return nil, err
}
}
return msgs, nil
}
// newRandomCmixMessage returns a new cMix message filled with a randomly
// generated payload, fingerprint, and MAC.
func (m *Manager) newRandomCmixMessage(rng csprng.Source) (format.Message, error) {
// Create new empty cMix message
cMixMsg := format.NewMessage(m.store.GetCmixGroup().GetP().ByteLen())
// Generate random message
randomMsg, err := newRandomPayload(cMixMsg.ContentsSize(), rng)
// sendMessage is a helper function which generates a sends a single random format.Message
// to a random recipient.
func (m *Manager) sendMessage(index, totalMessages int, rng csprng.Source) error {
// Generate message data
recipient, fp, service, payload, mac, err := m.newRandomCmixMessage(rng)
if err != nil {
return format.Message{}, errors.Errorf(payloadRngErr, err)
return errors.Errorf("Failed to create dummy message %d/%d: %+v",
index, totalMessages, err)
}
// Generate random fingerprint
fingerprint, err := newRandomFingerprint(rng)
// Send message
p := cmix.GetDefaultCMIXParams()
_, _, err = m.net.Send(recipient, fp, service, payload, mac, p)
if err != nil {
return format.Message{}, errors.Errorf(fingerprintRngErr, err)
return errors.Errorf("Failed to send dummy message %d/%d: %+v",
index, totalMessages, err)
}
// Generate random MAC
mac, err := newRandomMAC(rng)
if err != nil {
return format.Message{}, errors.Errorf(macRngErr, err)
}
// Set contents, fingerprint, and MAC, of the cMix message
cMixMsg.SetContents(randomMsg)
cMixMsg.SetKeyFP(fingerprint)
cMixMsg.SetMac(mac)
return cMixMsg, nil
return nil
}
// randomTimer generates a timer that will trigger after a random duration.
func (m *Manager) randomTimer() *time.Timer {
rng := m.rng.GetStream()
duration, err := durationRng(m.avgSendDelta, m.randomRange, rng)
if err != nil {
jww.FATAL.Panicf("Failed to generate random duration to wait to send "+
"dummy messages: %+v", err)
}
return time.NewTimer(duration)
// stopSendThread is triggered when the stoppable is triggered. It prints a
// debug message, sets the thread status to stopped, and sets the status of the
// stoppable to stopped.
func (m *Manager) stopSendThread(stop *stoppable.Single) {
jww.DEBUG.Print(
"Stopping dummy traffic sending thread: stoppable triggered")
atomic.StoreUint32(&m.status, stopped)
stop.ToStopped()
}
......@@ -9,7 +9,6 @@ package dummy
import (
"bytes"
"encoding/base64"
"gitlab.com/elixxir/client/stoppable"
"gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/primitives/id"
......@@ -21,7 +20,7 @@ import (
// Tests that Manager.sendThread sends multiple sets of messages.
func TestManager_sendThread(t *testing.T) {
m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, false, t)
m := newTestManager(10, 50*time.Millisecond, 10*time.Millisecond, t)
stop := stoppable.NewSingle("sendThreadTest")
go m.sendThread(stop)
......@@ -86,32 +85,33 @@ func TestManager_sendThread(t *testing.T) {
}
// Tests that Manager.sendMessages sends all the messages with the correct
// recipient.
func TestManager_sendMessages(t *testing.T) {
m := newTestManager(100, 0, 0, false, t)
prng := NewPrng(42)
// Tests that sendMessage generates random message data using pseudo-RNGs.
func TestManager_sendMessage(t *testing.T) {
m := newTestManager(100, 0, 0, t)
// Generate two identical RNGs, one for generating expected data (newRandomCmixMessage)
// and one for received data (sendMessage)
prngOne := NewPrng(42)
prngTwo := NewPrng(42)
// Generate map of recipients and messages
msgs := make(map[id.ID]format.Message, m.maxNumMessages)
for i := 0; i < m.maxNumMessages; i++ {
recipient, err := id.NewRandomID(prng, id.User)
// Generate random data
recipient, fp, service, payload, mac, err := m.newRandomCmixMessage(prngOne)
if err != nil {
t.Errorf("Failed to generate random recipient ID (%d): %+v", i, err)
t.Fatalf("Failed to generate random cMix message (%d): %+v", i, err)
}
msg, err := m.newRandomCmixMessage(prng)
payloadSize := m.store.GetCmixGroup().GetP().ByteLen()
msgs[*recipient] = generateMessage(payloadSize, fp, service, payload, mac)
// Send the messages
err = m.sendMessage(i, m.maxNumMessages, prngTwo)
if err != nil {
t.Errorf("Failed to generate random cMix message (%d): %+v", i, err)
t.Errorf("sendMessages returned an error: %+v", err)
}
msgs[*recipient] = msg
}
// Send the messages
err := m.sendMessages(msgs, prng)
if err != nil {
t.Errorf("sendMessages returned an error: %+v", err)
}
// get sent messages
......@@ -127,61 +127,46 @@ func TestManager_sendMessages(t *testing.T) {
for recipient, msg := range msgs {
receivedMsg, exists := receivedMsgs[recipient]
if !exists {
t.Errorf("Failed to receive message from %s: %+v", &recipient, msg)
} else if !reflect.DeepEqual(msg.GetKeyFP().Bytes(), receivedMsg) {
t.Errorf("Failed to receive message from %s: %+v", &recipient, msg.Marshal())
} else if !reflect.DeepEqual(msg.Marshal(), receivedMsg.Marshal()) {
// In mockCmix.Send, we map recipientId to the passed fingerprint.
t.Errorf("Received unexpected message for recipient %s."+
"\nexpected: %+v\nreceived: %+v", &recipient, msg.GetKeyFP(), receivedMsg)
"\nexpected: %+v\nreceived: %+v", &recipient, msg, receivedMsg)
}
}
}
// Tests that Manager.newRandomMessages creates a non-empty map of messages and
// that each message is unique.
func TestManager_newRandomMessages(t *testing.T) {
m := newTestManager(10, 0, 0, false, t)
// Tests that newRandomCmixMessage generates cMix message data with
// populated recipient, payload, fingerprint, and MAC.
func TestManager_newRandomCmixMessage(t *testing.T) {
m := newTestManager(0, 0, 0, t)
prng := NewPrng(42)
msgMap, err := m.newRandomMessages(prng)
// Generate data
recipient, fp, _, payload, mac, err := m.newRandomCmixMessage(prng)
if err != nil {
t.Errorf("newRandomMessages returned an error: %+v", err)
}
if len(msgMap) == 0 {
t.Error("Message map is empty.")
t.Fatalf("newRandomCmixMessage returned an error: %+v", err)
}
marshalledMsgs := make(map[string]format.Message, len(msgMap))
for _, msg := range msgMap {
msgString := base64.StdEncoding.EncodeToString(msg.Marshal())
if _, exists := marshalledMsgs[msgString]; exists {
t.Errorf("Message not unique.")
} else {
marshalledMsgs[msgString] = msg
}
// Check that recipient is not empty data
if bytes.Equal(recipient.Bytes(), make([]byte, id.ArrIDLen)) {
t.Errorf("Recipient ID not set")
}
}
// Tests that Manager.newRandomCmixMessage generates a cMix message with
// populated contents, fingerprint, and MAC.
func TestManager_newRandomCmixMessage(t *testing.T) {
m := newTestManager(0, 0, 0, false, t)
prng := NewPrng(42)
cMixMsg, err := m.newRandomCmixMessage(prng)
if err != nil {
t.Errorf("newRandomCmixMessage returned an error: %+v", err)
}
if bytes.Equal(cMixMsg.GetContents(), make([]byte, len(cMixMsg.GetContents()))) {
// Check that payload is not empty data
payloadSize := m.store.GetCmixGroup().GetP().ByteLen()
if bytes.Equal(payload, make([]byte, payloadSize)) {
t.Error("cMix message contents not set.")
}
if cMixMsg.GetKeyFP() == (format.Fingerprint{}) {
// Check that fingerprint is not empty data
if fp == (format.Fingerprint{}) {
t.Error("cMix message fingerprint not set.")
}
if bytes.Equal(cMixMsg.GetMac(), make([]byte, format.MacLen)) {
// Check that mac is not empty data
if bytes.Equal(mac, make([]byte, format.MacLen)) {
t.Error("cMix message MAC not set.")
}
}
......@@ -8,10 +8,11 @@
package dummy
import (
"gitlab.com/elixxir/client/cmix/message"
"gitlab.com/elixxir/client/storage"
"gitlab.com/elixxir/crypto/fastRNG"
"gitlab.com/elixxir/primitives/format"
"gitlab.com/xx_network/crypto/csprng"
"gitlab.com/xx_network/primitives/ndf"
"io"
"math/rand"
"testing"
......@@ -36,59 +37,35 @@ func (s *Prng) SetSeed([]byte) error { return nil }
// newTestManager creates a new Manager that has groups stored for testing. One
// of the groups in the list is also returned.
func newTestManager(maxNumMessages int, avgSendDelta, randomRange time.Duration,
sendErr bool, t *testing.T) *Manager {
t *testing.T) *Manager {
store := storage.InitTestingSession(t)
payloadSize := store.GetCmixGroup().GetP().ByteLen()
m := &Manager{
maxNumMessages: maxNumMessages,
avgSendDelta: avgSendDelta,
randomRange: randomRange,
statusChan: make(chan bool, statusChanLen),
store: store,
net: newMockCmix(),
net: newMockCmix(payloadSize),
rng: fastRNG.NewStreamGenerator(1000, 10, csprng.NewSystemRNG),
}
return m
}
func getNDF() *ndf.NetworkDefinition {
return &ndf.NetworkDefinition{
E2E: ndf.Group{
Prime: "E2EE983D031DC1DB6F1A7A67DF0E9A8E5561DB8E8D49413394C049B7A" +
"8ACCEDC298708F121951D9CF920EC5D146727AA4AE535B0922C688B55B3D" +
"D2AEDF6C01C94764DAB937935AA83BE36E67760713AB44A6337C20E78615" +
"75E745D31F8B9E9AD8412118C62A3E2E29DF46B0864D0C951C394A5CBBDC" +
"6ADC718DD2A3E041023DBB5AB23EBB4742DE9C1687B5B34FA48C3521632C" +
"4A530E8FFB1BC51DADDF453B0B2717C2BC6669ED76B4BDD5C9FF558E88F2" +
"6E5785302BEDBCA23EAC5ACE92096EE8A60642FB61E8F3D24990B8CB12EE" +
"448EEF78E184C7242DD161C7738F32BF29A841698978825B4111B4BC3E1E" +
"198455095958333D776D8B2BEEED3A1A1A221A6E37E664A64B83981C46FF" +
"DDC1A45E3D5211AAF8BFBC072768C4F50D7D7803D2D4F278DE8014A47323" +
"631D7E064DE81C0C6BFA43EF0E6998860F1390B5D3FEACAF1696015CB79C" +
"3F9C2D93D961120CD0E5F12CBB687EAB045241F96789C38E89D796138E63" +
"19BE62E35D87B1048CA28BE389B575E994DCA755471584A09EC723742DC3" +
"5873847AEF49F66E43873",
Generator: "2",
},
CMIX: ndf.Group{
Prime: "9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642" +
"F0B5C48C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757" +
"264E5A1A44FFE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F" +
"9716BFE6117C6B5B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091E" +
"B51743BF33050C38DE235567E1B34C3D6A5C0CEAA1A0F368213C3D19843D" +
"0B4B09DCB9FC72D39C8DE41F1BF14D4BB4563CA28371621CAD3324B6A2D3" +
"92145BEBFAC748805236F5CA2FE92B871CD8F9C36D3292B5509CA8CAA77A" +
"2ADFC7BFD77DDA6F71125A7456FEA153E433256A2261C6A06ED3693797E7" +
"995FAD5AABBCFBE3EDA2741E375404AE25B",
Generator: "5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E2480" +
"9670716C613D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D" +
"1AA58C4328A06C46A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A33" +
"8661D10461C0D135472085057F3494309FFA73C611F78B32ADBB5740C361" +
"C9F35BE90997DB2014E2EF5AA61782F52ABEB8BD6432C4DD097BC5423B28" +
"5DAFB60DC364E8161F4A2A35ACA3A10B1C4D203CC76A470A33AFDCBDD929" +
"59859ABD8B56E1725252D78EAC66E71BA9AE3F1DD2487199874393CD4D83" +
"2186800654760E1E34C09E4D155179F9EC0DC4473F996BDCE6EED1CABED8" +
"B6F116F7AD9CF505DF0F998E34AB27514B0FFE7",
},
}
// generateMessage is a utility function which generates a format.Message
// given message data.
func generateMessage(payloadSize int,
fingerprint format.Fingerprint,
service message.Service,
payload, mac []byte) format.Message {
// Build message. Will panic if inputs are not correct.
msg := format.NewMessage(payloadSize)
msg.SetContents(payload)
msg.SetKeyFP(fingerprint)
msg.SetSIH(service.Hash(msg.GetContents()))
msg.SetMac(mac)
return msg
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment