From 492eb3031609abab12a5e65ef0d369dbe3833d34 Mon Sep 17 00:00:00 2001 From: Gabriel Handford Date: Mon, 20 Jul 2020 11:58:51 -0700 Subject: [PATCH] events: Timestamp (ms) --- docs/document_test.go | 8 +++---- docs/events/events.go | 3 +-- docs/events/events_test.go | 21 +++++++++---------- docs/mem.go | 15 ++++++------- docs/mem_test.go | 8 +++---- sigchainstore.go | 23 +++++++------------- sigchainstore_test.go | 4 ++-- tsutil/clock.go | 43 +++++++++++++++++++++++++++----------- user/search_test.go | 24 ++++++++++----------- 9 files changed, 80 insertions(+), 69 deletions(-) diff --git a/docs/document_test.go b/docs/document_test.go index 7e8516e..f3195b1 100644 --- a/docs/document_test.go +++ b/docs/document_test.go @@ -16,21 +16,21 @@ import ( ) func TestDocument(t *testing.T) { - db := docs.NewMem() + mem := docs.NewMem() clock := tsutil.NewTestClock() - db.SetTimeNow(clock.Now) + mem.SetClock(clock) ctx := context.TODO() paths := []string{} for i := 0; i < 4; i++ { p := docs.Path("test", strconv.Itoa(i)) - err := db.Create(ctx, p, []byte(fmt.Sprintf("value%d", i))) + err := mem.Create(ctx, p, []byte(fmt.Sprintf("value%d", i))) require.NoError(t, err) paths = append(paths, p) } sort.Strings(paths) - iter, err := db.DocumentIterator(ctx, "test") + iter, err := mem.DocumentIterator(ctx, "test") require.NoError(t, err) out1, err := iter.Next() require.NoError(t, err) diff --git a/docs/events/events.go b/docs/events/events.go index c9d9cb2..d495c54 100644 --- a/docs/events/events.go +++ b/docs/events/events.go @@ -2,7 +2,6 @@ package events import ( "context" - "time" ) // Event in an event log. @@ -16,7 +15,7 @@ type Event struct { Index int64 `json:"idx" msgpack:"idx" firestore:"idx"` // Timestamp (read only). The time at which the event was created. // Firestore sets this to the document create time. - Timestamp time.Time `json:"ts" msgpack:"ts" firestore:"-"` + Timestamp int64 `json:"ts" msgpack:"ts" firestore:"-"` } // Events describes an append only event log. diff --git a/docs/events/events_test.go b/docs/events/events_test.go index 3c332ce..1581bcb 100644 --- a/docs/events/events_test.go +++ b/docs/events/events_test.go @@ -20,7 +20,7 @@ func TestEvents(t *testing.T) { // keys.SetLogger(keys.NewLogger(keys.DebugLevel)) eds := docs.NewMem() clock := tsutil.NewTestClock() - eds.SetTimeNow(clock.Now) + eds.SetClock(clock) ctx := context.TODO() path := docs.Path("test", "eds") @@ -37,7 +37,7 @@ func TestEvents(t *testing.T) { require.NoError(t, err) require.Equal(t, 40, len(out)) for i, event := range out { - require.False(t, event.Timestamp.IsZero()) + require.NotEmpty(t, event.Timestamp) require.Equal(t, int64(i+1), event.Index) } @@ -52,7 +52,7 @@ func TestEvents(t *testing.T) { if event == nil { break } - require.False(t, event.Timestamp.IsZero()) + require.NotEmpty(t, event.Timestamp) require.Equal(t, int64(i+1), event.Index) eventsValues = append(eventsValues, string(event.Data)) index = event.Index @@ -159,25 +159,24 @@ func TestEventMarshal(t *testing.T) { event := events.Event{ Data: []byte{0x01, 0x02, 0x03}, Index: 123, - Timestamp: clock.Now(), + Timestamp: tsutil.Millis(clock.Now()), } out, err := msgpack.Marshal(event) require.NoError(t, err) - expected := `([]uint8) (len=36 cap=64) { + expected := `([]uint8) (len=35 cap=64) { 00000000 83 a3 64 61 74 c4 03 01 02 03 a3 69 64 78 d3 00 |..dat......idx..| - 00000010 00 00 00 00 00 00 7b a2 74 73 d7 ff 00 3d 09 00 |......{.ts...=..| - 00000020 49 96 02 d2 |I...| + 00000010 00 00 00 00 00 00 7b a2 74 73 d3 00 00 01 1f 71 |......{.ts.....q| + 00000020 fb 04 51 |..Q| } ` require.Equal(t, expected, spew.Sdump(out)) out, err = json.Marshal(event) require.NoError(t, err) - expected = `([]uint8) (len=57 cap=64) { + expected = `([]uint8) (len=44 cap=48) { 00000000 7b 22 64 61 74 61 22 3a 22 41 51 49 44 22 2c 22 |{"data":"AQID","| - 00000010 69 64 78 22 3a 31 32 33 2c 22 74 73 22 3a 22 32 |idx":123,"ts":"2| - 00000020 30 30 39 2d 30 32 2d 31 33 54 32 33 3a 33 31 3a |009-02-13T23:31:| - 00000030 33 30 2e 30 30 31 5a 22 7d |30.001Z"}| + 00000010 69 64 78 22 3a 31 32 33 2c 22 74 73 22 3a 31 32 |idx":123,"ts":12| + 00000020 33 34 35 36 37 38 39 30 30 30 31 7d |34567890001}| } ` require.Equal(t, expected, spew.Sdump(out)) diff --git a/docs/mem.go b/docs/mem.go index dca7b4a..486e62c 100644 --- a/docs/mem.go +++ b/docs/mem.go @@ -11,6 +11,7 @@ import ( "github.com/keys-pub/keys/docs/events" "github.com/keys-pub/keys/encoding" + "github.com/keys-pub/keys/tsutil" "github.com/pkg/errors" ) @@ -23,7 +24,7 @@ type Mem struct { paths *StringSet values map[string][]byte metadata map[string]*metadata - nowFn func() time.Time + clock tsutil.Clock inc map[string]int64 } @@ -39,18 +40,18 @@ func NewMem() *Mem { values: map[string][]byte{}, metadata: map[string]*metadata{}, inc: map[string]int64{}, - nowFn: time.Now, + clock: tsutil.NewClock(), } } // Now returns current time. func (m *Mem) Now() time.Time { - return m.nowFn() + return m.clock.Now() } -// SetTimeNow to use a custom time.Now. -func (m *Mem) SetTimeNow(nowFn func() time.Time) { - m.nowFn = nowFn +// SetClock to use a custom Clock (for testing). +func (m *Mem) SetClock(clock tsutil.Clock) { + m.clock = clock } // Create at path. @@ -301,7 +302,7 @@ func (m *Mem) EventsAdd(ctx context.Context, path string, data [][]byte) ([]*eve event := &events.Event{ Data: b, Index: inc, - Timestamp: m.nowFn(), + Timestamp: tsutil.Millis(m.clock.Now()), } b, err := json.Marshal(event) if err != nil { diff --git a/docs/mem_test.go b/docs/mem_test.go index 1c35003..0ef05fc 100644 --- a/docs/mem_test.go +++ b/docs/mem_test.go @@ -23,19 +23,19 @@ func TestClock(t *testing.T) { func TestMem(t *testing.T) { mem := docs.NewMem() - mem.SetTimeNow(tsutil.NewTestClock().Now) + mem.SetClock(tsutil.NewTestClock()) testDocumentStore(t, mem) } func TestMemListOptions(t *testing.T) { mem := docs.NewMem() - mem.SetTimeNow(tsutil.NewTestClock().Now) + mem.SetClock(tsutil.NewTestClock()) testDocumentStoreListOptions(t, mem) } func TestMemMetadata(t *testing.T) { mem := docs.NewMem() - mem.SetTimeNow(tsutil.NewTestClock().Now) + mem.SetClock(tsutil.NewTestClock()) testMetadata(t, mem) } @@ -143,7 +143,7 @@ func testDocumentStore(t *testing.T, ds docs.Documents) { func TestDocumentStorePath(t *testing.T) { ds := docs.NewMem() - ds.SetTimeNow(tsutil.NewTestClock().Now) + ds.SetClock(tsutil.NewTestClock()) ctx := context.TODO() err := ds.Create(ctx, "test/1", []byte("value1")) diff --git a/sigchainstore.go b/sigchainstore.go index bb374ab..a4a780a 100644 --- a/sigchainstore.go +++ b/sigchainstore.go @@ -4,9 +4,9 @@ import ( "context" "encoding/json" "strings" - "time" "github.com/keys-pub/keys/docs" + "github.com/keys-pub/keys/tsutil" "github.com/pkg/errors" ) @@ -26,18 +26,16 @@ type SigchainStore interface { // SigchainExists if true, has sigchain. SigchainExists(kid ID) (bool, error) - // Now is current time. - Now() time.Time - // SetTimeNow sets clock. - SetTimeNow(nowFn func() time.Time) + // SetClock sets custom Clock. + SetClock(clock tsutil.Clock) } type sigchainStore struct { ds docs.Documents - nowFn func() time.Time + clock tsutil.Clock } -// NewSigchainStore creates a SigchainStore from a DocumentStore. +// NewSigchainStore creates a SigchainStore from Documents. func NewSigchainStore(ds docs.Documents) SigchainStore { return newSigchainStore(ds) } @@ -45,18 +43,13 @@ func NewSigchainStore(ds docs.Documents) SigchainStore { func newSigchainStore(ds docs.Documents) *sigchainStore { return &sigchainStore{ ds: ds, - nowFn: time.Now, + clock: tsutil.NewClock(), } } -// Now returns current time. -func (s sigchainStore) Now() time.Time { - return s.nowFn() -} - // SetTimeNow to use a custom time.Now. -func (s sigchainStore) SetTimeNow(nowFn func() time.Time) { - s.nowFn = nowFn +func (s sigchainStore) SetClock(clock tsutil.Clock) { + s.clock = clock } func (s sigchainStore) KIDs() ([]ID, error) { diff --git a/sigchainstore_test.go b/sigchainstore_test.go index d6f6d67..b6b4b25 100644 --- a/sigchainstore_test.go +++ b/sigchainstore_test.go @@ -11,9 +11,9 @@ import ( func testSigchainStore(t *testing.T, clock tsutil.Clock) keys.SigchainStore { mem := docs.NewMem() - mem.SetTimeNow(clock.Now) + mem.SetClock(clock) scs := keys.NewSigchainStore(mem) - scs.SetTimeNow(clock.Now) + scs.SetClock(clock) return scs } diff --git a/tsutil/clock.go b/tsutil/clock.go index bf6dc10..59e98c0 100644 --- a/tsutil/clock.go +++ b/tsutil/clock.go @@ -2,13 +2,6 @@ package tsutil import "time" -// clock increments a millisecond on each access. -// This is for testing. -type clock struct { - t time.Time - tick time.Duration -} - // Clock returns time.Time. type Clock interface { // Now returns current clock time. @@ -18,37 +11,63 @@ type Clock interface { Add(dt time.Duration) } +// testClock increments a millisecond on each access. +// This is for testing. +type testClock struct { + t time.Time + tick time.Duration +} + // NewTestClock returns a test Clock starting at 1234567890000 millseconds since // epoch. Each access to Now() increases time by 1 millisecond. func NewTestClock() Clock { t := ConvertMillis(1234567890000) - return &clock{ + return &testClock{ t: t, tick: time.Millisecond, } } // Now returns current clock time. -func (c *clock) Now() time.Time { +func (c *testClock) Now() time.Time { c.t = c.t.Add(c.tick) return c.t } // SetTick sets tick increment for clock. -func (c *clock) SetTick(tick time.Duration) { +func (c *testClock) SetTick(tick time.Duration) { c.tick = tick } // Add to clock. -func (c *clock) Add(dt time.Duration) { +func (c *testClock) Add(dt time.Duration) { c.t = c.t.Add(dt) } // NewTestClockAt creates a Clock starting at timestamp (millis). func NewTestClockAt(ts int64) Clock { t := ConvertMillis(ts) - return &clock{ + return &testClock{ t: t, tick: time.Millisecond, } } + +// NewClock returns current clock time. +func NewClock() Clock { + return &clock{ + add: time.Duration(0), + } +} + +type clock struct { + add time.Duration +} + +func (c *clock) Now() time.Time { + return time.Now().Add(c.add) +} + +func (c *clock) Add(dt time.Duration) { + c.add = c.add + dt +} diff --git a/user/search_test.go b/user/search_test.go index 6198cb9..8595c10 100644 --- a/user/search_test.go +++ b/user/search_test.go @@ -22,9 +22,9 @@ func TestSearchUsers(t *testing.T) { clock := tsutil.NewTestClock() ds := docs.NewMem() - ds.SetTimeNow(clock.Now) + ds.SetClock(clock) scs := keys.NewSigchainStore(ds) - scs.SetTimeNow(clock.Now) + scs.SetClock(clock) req := request.NewMockRequestor() ust := testStore(t, ds, scs, req, clock) @@ -152,9 +152,9 @@ func TestSearchUsers(t *testing.T) { func TestUserStoreEmpty(t *testing.T) { clock := tsutil.NewTestClock() ds := docs.NewMem() - ds.SetTimeNow(clock.Now) + ds.SetClock(clock) scs := keys.NewSigchainStore(ds) - scs.SetTimeNow(clock.Now) + scs.SetClock(clock) req := request.NewMockRequestor() ust := testStore(t, ds, scs, req, clock) @@ -175,9 +175,9 @@ func TestUserStoreEmpty(t *testing.T) { func TestUserValidateName(t *testing.T) { clock := tsutil.NewTestClock() ds := docs.NewMem() - ds.SetTimeNow(clock.Now) + ds.SetClock(clock) scs := keys.NewSigchainStore(ds) - scs.SetTimeNow(clock.Now) + scs.SetClock(clock) req := request.NewMockRequestor() ust := testStore(t, ds, scs, req, clock) @@ -204,9 +204,9 @@ func TestUserValidateName(t *testing.T) { func TestUserValidateUpdateInvalid(t *testing.T) { clock := tsutil.NewTestClock() ds := docs.NewMem() - ds.SetTimeNow(clock.Now) + ds.SetClock(clock) scs := keys.NewSigchainStore(ds) - scs.SetTimeNow(clock.Now) + scs.SetClock(clock) req := request.NewMockRequestor() ust := testStore(t, ds, scs, req, clock) @@ -254,9 +254,9 @@ func TestUserValidateUpdateInvalid(t *testing.T) { func TestReddit(t *testing.T) { clock := tsutil.NewTestClock() ds := docs.NewMem() - ds.SetTimeNow(clock.Now) + ds.SetClock(clock) scs := keys.NewSigchainStore(ds) - scs.SetTimeNow(clock.Now) + scs.SetClock(clock) req := request.NewMockRequestor() ust := testStore(t, ds, scs, req, clock) @@ -309,9 +309,9 @@ func TestSearchUsersRequestErrors(t *testing.T) { clock := tsutil.NewTestClock() ds := docs.NewMem() - ds.SetTimeNow(clock.Now) + ds.SetClock(clock) scs := keys.NewSigchainStore(ds) - scs.SetTimeNow(clock.Now) + scs.SetClock(clock) req := request.NewMockRequestor() ust := testStore(t, ds, scs, req, clock)