Include latest and earliest record times in state (#34)
Badges / coveralls (push) Successful in 1m1s
Badges / coveralls (push) Successful in 1m1s
Reviewed-on: #34 Co-authored-by: Natercio Moniz <[email protected]>
This commit was merged in pull request #34.
This commit is contained in:
1 parent
47f38fce2b
commit
41b287c804
3 files changed
+47
-11
No files matched your search
+19
-6
@@ -96,11 +96,9 @@ func (fs *JSONStore) Load(ctx context.Context) (map[string]*FillerQueue, error)
|
||||
// the same directory followed by an atomic rename so a crash mid-write cannot
|
||||
// leave a half-written state file.
|
||||
func (fs *JSONStore) Save(ctx context.Context, queue map[string]*FillerQueue) error {
|
||||
state := State{
|
||||
Version: StateVersion,
|
||||
Platform: fs.platform,
|
||||
Queues: make(map[string][]persistedFiller),
|
||||
}
|
||||
queues := make(map[string][]persistedFiller)
|
||||
latest := time.Time{}
|
||||
earliest := time.Time{}
|
||||
|
||||
for symbol, q := range queue {
|
||||
if q == nil || q.Len() == 0 {
|
||||
@@ -119,8 +117,23 @@ func (fs *JSONStore) Save(ctx context.Context, queue map[string]*FillerQueue) er
|
||||
Price: f.Price(),
|
||||
Filled: f.Filled(),
|
||||
})
|
||||
|
||||
if f.Timestamp().After(latest) {
|
||||
latest = f.Timestamp()
|
||||
}
|
||||
if f.Timestamp().Before(earliest) || earliest.IsZero() {
|
||||
earliest = f.Timestamp()
|
||||
}
|
||||
}
|
||||
state.Queues[symbol] = persisted
|
||||
queues[symbol] = persisted
|
||||
}
|
||||
|
||||
state := State{
|
||||
Version: StateVersion,
|
||||
Platform: fs.platform,
|
||||
Queues: queues,
|
||||
Latest: latest,
|
||||
Earliest: earliest,
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/nmoniz/any2anexoj/internal"
|
||||
"github.com/nmoniz/any2anexoj/internal/mocks"
|
||||
@@ -84,13 +85,25 @@ func TestJSONStore_RoundTrip(t *testing.T) {
|
||||
// confirming the inline form is parseable guards against accidentally
|
||||
// double-encoding it again in the future).
|
||||
var parsed struct {
|
||||
Queues map[string][]struct {
|
||||
Latest time.Time `json:"latest"`
|
||||
Earliest time.Time `json:"earliest"`
|
||||
Queues map[string][]struct {
|
||||
RecordData json.RawMessage `json:"record_data"`
|
||||
} `json:"queues"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &parsed); err != nil {
|
||||
t.Fatalf("saved state file is not valid JSON: %v", err)
|
||||
}
|
||||
|
||||
// The latest/earliest bounds must be persisted alongside the queues.
|
||||
// Every record in this test returns testRecordTime, so both bounds must
|
||||
// equal it exactly.
|
||||
if !parsed.Latest.Equal(testRecordTime) {
|
||||
t.Errorf("state latest = %v; want %v", parsed.Latest, testRecordTime)
|
||||
}
|
||||
if !parsed.Earliest.Equal(testRecordTime) {
|
||||
t.Errorf("state earliest = %v; want %v", parsed.Earliest, testRecordTime)
|
||||
}
|
||||
for symbol, lots := range parsed.Queues {
|
||||
for i, lot := range lots {
|
||||
if len(lot.RecordData) == 0 {
|
||||
@@ -341,13 +354,20 @@ func TestNewJSONStore_ValidatesArguments(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// newRecord builds a MockRecord whose Symbol() returns the given symbol.
|
||||
// The JSONStore only reads Symbol() off the loaded Record during tests
|
||||
// (quantity/price/filled come from the persisted struct fields), so all
|
||||
// other Record methods can be left as default-mocked values.
|
||||
// testRecordTime is the deterministic timestamp returned by every record
|
||||
// built in this file. Using a fixed value keeps the latest/earliest bounds
|
||||
// written by JSONStore.Save predictable and assertable.
|
||||
var testRecordTime = time.Date(2024, 6, 15, 12, 0, 0, 0, time.UTC)
|
||||
|
||||
// newRecord builds a MockRecord whose Symbol() returns the given symbol and
|
||||
// whose Timestamp() returns testRecordTime. The JSONStore only reads Symbol()
|
||||
// and Timestamp() off the Record during tests (quantity/price/filled come
|
||||
// from the persisted struct fields), so all other Record methods can be left
|
||||
// as default-mocked values.
|
||||
func newRecord(ctrl *gomock.Controller, symbol string) *mocks.MockRecord {
|
||||
r := mocks.NewMockRecord(ctrl)
|
||||
r.EXPECT().Symbol().Return(symbol).AnyTimes()
|
||||
r.EXPECT().Timestamp().Return(testRecordTime).AnyTimes()
|
||||
return r
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package internal
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
@@ -15,6 +16,8 @@ const StateVersion = "2"
|
||||
type State struct {
|
||||
Version string `json:"version"`
|
||||
Platform string `json:"platform"`
|
||||
Latest time.Time `json:"latest"`
|
||||
Earliest time.Time `json:"earliest"`
|
||||
Queues map[string][]persistedFiller `json:"queues"`
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user