Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VAULT-15395: Support mocking time functions in the activity log #20720

Merged
merged 5 commits into from
May 23, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions helper/timeutil/timeutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ type Clock interface {

type DefaultClock struct{}
miagilepner marked this conversation as resolved.
Show resolved Hide resolved

var _ Clock = (*DefaultClock)(nil)

func (_ DefaultClock) Now() time.Time {
return time.Now()
}
Expand Down
3 changes: 1 addition & 2 deletions vault/activity_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -1327,8 +1327,7 @@ func (a *ActivityLog) activeFragmentWorker(ctx context.Context) {

// Simpler, but ticker.Reset was introduced in go 1.15:
// ticker.Reset(activitySegmentInterval)
case <-endOfMonthChannel:
currentTime := a.clock.Now()
case currentTime := <-endOfMonthChannel:
err := a.HandleEndOfMonth(ctx, currentTime.UTC())
if err != nil {
a.logger.Error("failed to perform end of month rotation", "error", err)
Expand Down
31 changes: 25 additions & 6 deletions vault/activity_log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4692,16 +4692,31 @@ func newMockTimeNowClock(startAt time.Time) timeutil.Clock {
return &mockTimeNowClock{start: startAt, created: time.Now()}
}

// NewTimer returns a timer with a channel that will return the correct time,
// relative to the starting time
func (m mockTimeNowClock) NewTimer(d time.Duration) *time.Timer {
hghaf099 marked this conversation as resolved.
Show resolved Hide resolved
timerStarted := m.Now()
t := time.NewTimer(d)
readCh := t.C
writeCh := make(chan time.Time, 1)
go func() {
<-readCh
writeCh <- timerStarted.Add(d)
}()
t.C = writeCh
return t
}

func (m mockTimeNowClock) Now() time.Time {
return m.start.Add(time.Since(m.created))
}

// TestActivityLog_HandleEndOfMonth runs the activity log with a mock clock. The current
// time is set to be 3 seconds before the end of a month. The test verifies that
// the precomputedQueryWorker runs and writes precomputed queries with the
// proper start and end times when the end of the month is triggered
// TestActivityLog_HandleEndOfMonth runs the activity log with a mock clock.
// The current time is set to be 3 seconds before the end of a month. The test
// verifies that the precomputedQueryWorker runs and writes precomputed queries
// with the proper start and end times when the end of the month is triggered
func TestActivityLog_HandleEndOfMonth(t *testing.T) {
// 5 seconds until a new month
// 3 seconds until a new month
now := time.Date(2021, 1, 31, 23, 59, 57, 0, time.UTC)
core, _, _ := TestCoreUnsealedWithConfig(t, &CoreConfig{ActivityLogConfig: ActivityLogCoreConfig{Clock: newMockTimeNowClock(now)}})
done := make(chan struct{})
Expand All @@ -4714,7 +4729,11 @@ func TestActivityLog_HandleEndOfMonth(t *testing.T) {
core.activityLog.AddClientToFragment("id", "ns", now.Unix(), false, "mount")

// wait for the end of month to be triggered
<-done
select {
case <-done:
case <-time.After(10 * time.Second):
t.Fatal("timeout waiting for precomputed query")
}

// verify that a precomputed query was written
exists, err := core.activityLog.queryStore.QueriesAvailable(context.Background())
Expand Down