Skip to content
Snippets Groups Projects
Commit 50f0fd02 authored by Jono Wenger's avatar Jono Wenger
Browse files

Rename CheckedRounds to knownRounds, fix tests, and add the the Session object

parent 8da33ffd
No related branches found
No related tags found
No related merge requests found
......@@ -3,4 +3,5 @@ package storage
const (
criticalMessagesKey = "CriticalMessages"
garbledMessagesKey = "GarbledMessages"
checkedRoundsKey = "CheckedRounds"
)
......@@ -26,6 +26,9 @@ import (
"testing"
)
// Number of rounds to store in the CheckedRound buffer
const checkRoundsMaxSize = 1000000 / 64
// Session object, backed by encrypted filestore
type Session struct {
kv *versioned.KV
......@@ -41,6 +44,7 @@ type Session struct {
partition *partition.Store
criticalMessages *utility.E2eMessageBuffer
garbledMessages *utility.CmixMessageBuffer
checkedRounds *utility.KnownRounds
}
// Initialize a new Session object
......@@ -100,6 +104,11 @@ func New(baseDir, password string, uid *id.ID, salt []byte, rsaKey *rsa.PrivateK
return nil, errors.WithMessage(err, "Failed to create session")
}
s.checkedRounds, err = utility.NewKnownRounds(s.kv, checkedRoundsKey, checkRoundsMaxSize)
if err != nil {
return nil, errors.WithMessage(err, "Failed to create session")
}
s.conversations = conversation.NewStore(s.kv)
s.partition = partition.New(s.kv)
......@@ -143,6 +152,11 @@ func Load(baseDir, password string) (*Session, error) {
return nil, errors.WithMessage(err, "Failed to load session")
}
s.checkedRounds, err = utility.LoadKnownRounds(s.kv, checkedRoundsKey, checkRoundsMaxSize)
if err != nil {
return nil, errors.WithMessage(err, "Failed to load session")
}
s.conversations = conversation.NewStore(s.kv)
s.partition = partition.New(s.kv)
......@@ -179,6 +193,12 @@ func (s *Session) GetGarbledMessages() *utility.CmixMessageBuffer {
return s.garbledMessages
}
func (s *Session) GetCheckedRounds() *utility.KnownRounds {
s.mux.RLock()
defer s.mux.RUnlock()
return s.checkedRounds
}
func (s *Session) Conversations() *conversation.Store {
s.mux.RLock()
defer s.mux.RUnlock()
......
......@@ -9,87 +9,90 @@ import (
"time"
)
// Sub key used in building keys for saving the message to the key value store
const knownRoundsSubKey = "knownRound"
// Version of the file saved to the key value store
const currentCheckedRoundsVersion = 0
const currentKnownRoundsVersion = 0
// CheckedRounds stores a buffer of which rounds have been checked and those
// KnownRounds stores a buffer of which rounds have been checked and those
// that have yet to be checked. The buffer is saved in a key value store so that
// the values can be recovered if something happens to the buffer in memory.
type CheckedRounds struct {
type KnownRounds struct {
rounds *knownRounds.KnownRounds
kv *versioned.KV
key string
mux sync.RWMutex
}
// NewCheckedRounds creates a new empty CheckedRounds and saves it to the passed
// NewKnownRounds creates a new empty KnownRounds and saves it to the passed
// in key value store at the specified key. An error is returned on an
// unsuccessful save.
func NewCheckedRounds(kv *versioned.KV, key string, size int) (*CheckedRounds, error) {
func NewKnownRounds(kv *versioned.KV, key string, size int) (*KnownRounds, error) {
// Create new empty struct
cr := &CheckedRounds{
kr := &KnownRounds{
rounds: knownRounds.NewKnownRound(size),
kv: kv,
key: key,
}
// Save the struct
err := cr.save()
err := kr.save()
// Return the new CheckedRounds or an error if the saving failed
return cr, err
// Return the new KnownRounds or an error if the saving failed
return kr, err
}
// LoadCheckedRounds loads and existing CheckedRounds from the key value store
// LoadKnownRounds loads and existing KnownRounds from the key value store
// into memory at the given key. Returns an error if it cannot be loaded.
func LoadCheckedRounds(kv *versioned.KV, key string, size int) (*CheckedRounds, error) {
func LoadKnownRounds(kv *versioned.KV, key string, size int) (*KnownRounds, error) {
// Create new empty struct
cr := &CheckedRounds{
kr := &KnownRounds{
rounds: knownRounds.NewKnownRound(size),
kv: kv,
key: key,
}
// Load the KnownRounds into the new buffer
err := cr.load()
err := kr.load()
// Return the loaded buffer or an error if loading failed
return cr, err
return kr, err
}
// save saves the round buffer as a versioned object to the key value store.
func (cr *CheckedRounds) save() error {
func (kr *KnownRounds) save() error {
now := time.Now()
// Marshal list of rounds
data, err := cr.rounds.Marshal()
data, err := kr.rounds.Marshal()
if err != nil {
return err
}
// Create versioned object with data
obj := versioned.Object{
Version: currentCheckedRoundsVersion,
Version: currentKnownRoundsVersion,
Timestamp: now,
Data: data,
}
// Save versioned object
return cr.kv.Set(cr.key, &obj)
return kr.kv.Set(makeKnownRoundsSubKey(kr.key), &obj)
}
// load retrieves the list of rounds from the key value store and stores them
// in the buffer.
func (cr *CheckedRounds) load() error {
func (kr *KnownRounds) load() error {
// Load the versioned object
vo, err := cr.kv.Get(cr.key)
vo, err := kr.kv.Get(makeKnownRoundsSubKey(kr.key))
if err != nil {
return err
}
// Unmarshal the list of rounds
err = cr.rounds.Unmarshal(vo.Data)
err = kr.rounds.Unmarshal(vo.Data)
if err != nil {
return err
}
......@@ -98,34 +101,34 @@ func (cr *CheckedRounds) load() error {
}
// Checked determines if the round has been checked.
func (cr *CheckedRounds) Checked(rid id.Round) bool {
cr.mux.RLock()
defer cr.mux.RUnlock()
func (kr *KnownRounds) Checked(rid id.Round) bool {
kr.mux.RLock()
defer kr.mux.RUnlock()
return cr.rounds.Checked(rid)
return kr.rounds.Checked(rid)
}
// Check denotes a round has been checked.
func (cr *CheckedRounds) Check(rid id.Round) {
cr.mux.Lock()
defer cr.mux.Unlock()
func (kr *KnownRounds) Check(rid id.Round) {
kr.mux.Lock()
defer kr.mux.Unlock()
cr.rounds.Check(rid)
kr.rounds.Check(rid)
err := cr.save()
err := kr.save()
if err != nil {
jww.FATAL.Panicf("Error saving list of checked rounds: %v", err)
}
}
// Forward sets all rounds before the given round ID as checked.
func (cr *CheckedRounds) Forward(rid id.Round) {
cr.mux.Lock()
defer cr.mux.Unlock()
func (kr *KnownRounds) Forward(rid id.Round) {
kr.mux.Lock()
defer kr.mux.Unlock()
cr.rounds.Forward(rid)
kr.rounds.Forward(rid)
err := cr.save()
err := kr.save()
if err != nil {
jww.FATAL.Panicf("Error saving list of checked rounds: %v", err)
}
......@@ -133,29 +136,34 @@ func (cr *CheckedRounds) Forward(rid id.Round) {
// RangeUnchecked runs the passed function over the range of all unchecked round
// IDs up to the passed newestRound to determine if they should be checked.
func (cr *CheckedRounds) RangeUnchecked(newestRid id.Round,
func (kr *KnownRounds) RangeUnchecked(newestRid id.Round,
roundCheck func(id id.Round) bool) {
cr.mux.Lock()
defer cr.mux.Unlock()
kr.mux.Lock()
defer kr.mux.Unlock()
cr.rounds.RangeUnchecked(newestRid, roundCheck)
kr.rounds.RangeUnchecked(newestRid, roundCheck)
err := cr.save()
err := kr.save()
if err != nil {
jww.FATAL.Panicf("Error saving list of checked rounds: %v", err)
}
}
// RangeUncheckedMasked checks rounds based off the provided mask.
func (cr *CheckedRounds) RangeUncheckedMasked(mask *knownRounds.KnownRounds,
func (kr *KnownRounds) RangeUncheckedMasked(mask *knownRounds.KnownRounds,
roundCheck func(id id.Round) bool, maxChecked int) {
cr.mux.Lock()
defer cr.mux.Unlock()
kr.mux.Lock()
defer kr.mux.Unlock()
cr.rounds.RangeUncheckedMasked(mask, roundCheck, maxChecked)
kr.rounds.RangeUncheckedMasked(mask, roundCheck, maxChecked)
err := cr.save()
err := kr.save()
if err != nil {
jww.FATAL.Panicf("Error saving list of checked rounds: %v", err)
}
}
// makeKnownRoundsSubKey generates a new key for the known rounds buffer.
func makeKnownRoundsSubKey(key string) string {
return key + knownRoundsSubKey
}
......@@ -9,34 +9,34 @@ import (
"testing"
)
// Tests happy path of NewCheckedRounds.
func TestNewCheckedRounds(t *testing.T) {
// Tests happy path of NewKnownRounds.
func TestNewKnownRounds(t *testing.T) {
// Set up expected value
size := 10
expectedCR := &CheckedRounds{
expectedKR := &KnownRounds{
rounds: knownRounds.NewKnownRound(size),
kv: versioned.NewKV(make(ekv.Memstore)),
key: "testKey",
}
// Create new CheckedRounds
cr, err := NewCheckedRounds(expectedCR.kv, expectedCR.key, size)
// Create new KnownRounds
kr, err := NewKnownRounds(expectedKR.kv, expectedKR.key, size)
if err != nil {
t.Errorf("NewCheckedRounds() returned an error."+
t.Errorf("NewKnownRounds() returned an error."+
"\n\texpected: %v\n\treceived: %v", nil, err)
}
if !reflect.DeepEqual(expectedCR, cr) {
t.Errorf("NewCheckedRounds() returned an incorrect CheckedRounds."+
"\n\texpected: %v\n\treceived: %v", expectedCR, cr)
if !reflect.DeepEqual(expectedKR, kr) {
t.Errorf("NewKnownRounds() returned an incorrect KnownRounds."+
"\n\texpected: %v\n\treceived: %v", expectedKR, kr)
}
}
// Tests happy path of LoadCheckedRounds.
func TestLoadCheckedRounds(t *testing.T) {
// Tests happy path of LoadKnownRounds.
func TestLoadKnownRounds(t *testing.T) {
// Set up expected value
size := 10
expectedCR := &CheckedRounds{
expectedKR := &KnownRounds{
rounds: knownRounds.NewKnownRound(size),
kv: versioned.NewKV(make(ekv.Memstore)),
key: "testKey",
......@@ -45,147 +45,149 @@ func TestLoadCheckedRounds(t *testing.T) {
// Check rounds in the buffer and save the key value store
for i := 0; i < (size * 64); i++ {
if i%7 == 0 {
expectedCR.rounds.Check(id.Round(i))
expectedKR.rounds.Check(id.Round(i))
}
}
err := expectedCR.save()
err := expectedKR.save()
if err != nil {
t.Fatalf("Error saving CheckedRounds: %v", err)
t.Fatalf("Error saving KnownRounds: %v", err)
}
cr, err := LoadCheckedRounds(expectedCR.kv, expectedCR.key, size)
kr, err := LoadKnownRounds(expectedKR.kv, expectedKR.key, size)
if err != nil {
t.Errorf("LoadCheckedRounds() returned an error."+
t.Errorf("LoadKnownRounds() returned an error."+
"\n\texpected: %v\n\treceived: %v", nil, err)
}
if !reflect.DeepEqual(expectedCR, cr) {
t.Errorf("LoadCheckedRounds() returned an incorrect CheckedRounds."+
"\n\texpected: %+v\n\treceived: %+v", expectedCR, cr)
if !reflect.DeepEqual(expectedKR, kr) {
t.Errorf("LoadKnownRounds() returned an incorrect KnownRounds."+
"\n\texpected: %+v\n\treceived: %+v", expectedKR, kr)
}
}
// Tests happy path of CheckedRounds.save().
func TestCheckedRounds_save(t *testing.T) {
// Tests happy path of KnownRounds.save().
func TestKnownRounds_save(t *testing.T) {
// Set up expected value
size := 10
expectedCR := &CheckedRounds{
expectedKR := &KnownRounds{
rounds: knownRounds.NewKnownRound(size),
kv: versioned.NewKV(make(ekv.Memstore)),
key: "testKey",
}
for i := 0; i < (size * 64); i++ {
if i%7 == 0 {
expectedCR.rounds.Check(id.Round(i))
expectedKR.rounds.Check(id.Round(i))
}
}
expectedData, err := expectedCR.rounds.Marshal()
expectedData, err := expectedKR.rounds.Marshal()
if err != nil {
t.Fatalf("Marshal() returned an error: %v", err)
}
cr := &CheckedRounds{
kr := &KnownRounds{
rounds: knownRounds.NewKnownRound(size),
kv: expectedCR.kv,
key: expectedCR.key,
kv: expectedKR.kv,
key: expectedKR.key,
}
err = expectedCR.save()
err = expectedKR.save()
if err != nil {
t.Errorf("save() returned an error: %v", err)
}
obj, err := expectedCR.kv.Get(expectedCR.key)
obj, err := expectedKR.kv.Get(makeKnownRoundsSubKey(expectedKR.key))
if err != nil {
t.Errorf("Get() returned an error: %v", err)
}
if !reflect.DeepEqual(expectedData, obj.Data) {
t.Errorf("save() did not save the correct CheckedRounds."+
"\n\texpected: %+v\n\treceived: %+v", expectedData, cr)
t.Errorf("save() did not save the correct KnownRounds."+
"\n\texpected: %+v\n\treceived: %+v", expectedData, kr)
}
}
// Tests happy path of CheckedRounds.load().
func TestCheckedRounds_load(t *testing.T) {
// Tests happy path of KnownRounds.load().
func TestKnownRounds_load(t *testing.T) {
// Set up expected value
size := 10
expectedCR := &CheckedRounds{
expectedKR := &KnownRounds{
rounds: knownRounds.NewKnownRound(size),
kv: versioned.NewKV(make(ekv.Memstore)),
key: "testKey",
}
for i := 0; i < (size * 64); i++ {
if i%7 == 0 {
expectedCR.rounds.Check(id.Round(i))
expectedKR.rounds.Check(id.Round(i))
}
}
cr := &CheckedRounds{
kr := &KnownRounds{
rounds: knownRounds.NewKnownRound(size),
kv: expectedCR.kv,
key: expectedCR.key,
kv: expectedKR.kv,
key: expectedKR.key,
}
err := expectedCR.save()
err := expectedKR.save()
if err != nil {
t.Errorf("save() returned an error: %v", err)
}
err = cr.load()
err = kr.load()
if err != nil {
t.Errorf("load() returned an error: %v", err)
}
if !reflect.DeepEqual(expectedCR, cr) {
t.Errorf("load() did not produce the correct CheckedRounds."+
"\n\texpected: %+v\n\treceived: %+v", expectedCR, cr)
if !reflect.DeepEqual(expectedKR, kr) {
t.Errorf("load() did not produce the correct KnownRounds."+
"\n\texpected: %+v\n\treceived: %+v", expectedKR, kr)
}
}
func TestCheckedRounds_Smoke(t *testing.T) {
cr, err := NewCheckedRounds(versioned.NewKV(make(ekv.Memstore)), "testKey", 10)
func TestKnownRounds_Smoke(t *testing.T) {
kr, err := NewKnownRounds(versioned.NewKV(make(ekv.Memstore)), "testKey", 10)
if err != nil {
t.Fatalf("Failed to create new CheckedRounds: %v", err)
t.Fatalf("Failed to create new KnownRounds: %v", err)
}
if cr.Checked(10) {
if kr.Checked(10) {
t.Errorf("Checked() on round ID %d did not return the expected value."+
"\n\texpected: %v\n\treceived: %v", 10, false, cr.Checked(10))
"\n\texpected: %v\n\treceived: %v", 10, false, kr.Checked(10))
}
cr.Check(10)
kr.Check(10)
if !cr.Checked(10) {
if !kr.Checked(10) {
t.Errorf("Checked() on round ID %d did not return the expected value."+
"\n\texpected: %v\n\treceived: %v", 10, true, cr.Checked(10))
}
cr.Forward(20)
if !cr.Checked(15) {
t.Errorf("Checked() on round ID %d did not return the expected value."+
"\n\texpected: %v\n\treceived: %v", 15, true, cr.Checked(15))
"\n\texpected: %v\n\treceived: %v", 10, true, kr.Checked(10))
}
roundCheck := func(id id.Round) bool {
return id%2 == 1
}
cr.RangeUnchecked(30, roundCheck)
kr.RangeUnchecked(30, roundCheck)
newCR := &CheckedRounds{
newKR := &KnownRounds{
rounds: knownRounds.NewKnownRound(10),
kv: cr.kv,
key: cr.key,
kv: kr.kv,
key: kr.key,
}
err = newCR.load()
err = newKR.load()
if err != nil {
t.Errorf("load() returned an error: %v", err)
}
if !reflect.DeepEqual(cr, newCR) {
t.Errorf("load() did not produce the correct CheckedRounds."+
"\n\texpected: %+v\n\treceived: %+v", cr, newCR)
if !reflect.DeepEqual(kr, newKR) {
t.Errorf("load() did not produce the correct KnownRounds."+
"\n\texpected: %+v\n\treceived: %+v", kr, newKR)
}
// TODO: Test CheckedRounds.RangeUncheckedMasked
mask := knownRounds.NewKnownRound(1)
mask.Check(17)
kr.RangeUncheckedMasked(mask, roundCheck, 15)
kr.Forward(20)
if !kr.Checked(15) {
t.Errorf("Checked() on round ID %d did not return the expected value."+
"\n\texpected: %v\n\treceived: %v", 15, true, kr.Checked(15))
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment