mirror of
https://github.com/muety/wakapi.git
synced 2025-12-05 22:20:24 -08:00
fix: compute leaderboard with consistent time interval (resolve #749)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -11,18 +11,18 @@ type SummaryServiceMock struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
func (m *SummaryServiceMock) Aliased(t time.Time, t2 time.Time, u *models.User, r types.SummaryRetriever, f *models.Filters, b bool) (*models.Summary, error) {
|
||||
args := m.Called(t, t2, u, r, f)
|
||||
func (m *SummaryServiceMock) Aliased(t time.Time, t2 time.Time, u *models.User, r types.SummaryRetriever, f *models.Filters, d *time.Duration, b bool) (*models.Summary, error) {
|
||||
args := m.Called(t, t2, u, r, f, d, b)
|
||||
return args.Get(0).(*models.Summary), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *SummaryServiceMock) Retrieve(t time.Time, t2 time.Time, u *models.User, f *models.Filters) (*models.Summary, error) {
|
||||
args := m.Called(t, t2, u, f)
|
||||
func (m *SummaryServiceMock) Retrieve(t time.Time, t2 time.Time, u *models.User, f *models.Filters, d *time.Duration) (*models.Summary, error) {
|
||||
args := m.Called(t, t2, u, d, f)
|
||||
return args.Get(0).(*models.Summary), args.Error(1)
|
||||
}
|
||||
|
||||
func (m *SummaryServiceMock) Summarize(t time.Time, t2 time.Time, u *models.User, f *models.Filters) (*models.Summary, error) {
|
||||
args := m.Called(t, t2, u, f)
|
||||
func (m *SummaryServiceMock) Summarize(t time.Time, t2 time.Time, u *models.User, f *models.Filters, d *time.Duration) (*models.Summary, error) {
|
||||
args := m.Called(t, t2, u, d, f)
|
||||
return args.Get(0).(*models.Summary), args.Error(1)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,4 +5,4 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type SummaryRetriever func(f, t time.Time, u *models.User, filters *models.Filters) (*models.Summary, error)
|
||||
type SummaryRetriever func(f, t time.Time, u *models.User, filters *models.Filters, duration *time.Duration) (*models.Summary, error)
|
||||
|
||||
@@ -51,7 +51,7 @@ func TestBadgeHandler_Get(t *testing.T) {
|
||||
userServiceMock.On("GetUserById", "user1").Return(&user1, nil)
|
||||
|
||||
summaryServiceMock := new(mocks.SummaryServiceMock)
|
||||
summaryServiceMock.On("Aliased", mock.AnythingOfType("time.Time"), mock.AnythingOfType("time.Time"), &user1, mock.Anything, mock.Anything).Return(&summary1, nil)
|
||||
summaryServiceMock.On("Aliased", mock.AnythingOfType("time.Time"), mock.AnythingOfType("time.Time"), &user1, mock.AnythingOfType("types.SummaryRetriever"), mock.AnythingOfType("*models.Filters"), mock.AnythingOfType("*time.Duration"), mock.Anything).Return(&summary1, nil)
|
||||
|
||||
badgeHandler := NewBadgeHandler(userServiceMock, summaryServiceMock)
|
||||
badgeHandler.RegisterRoutes(apiRouter)
|
||||
|
||||
@@ -139,7 +139,7 @@ func (h *MetricsHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *MetricsHandler) getUserMetrics(user *models.User) (*mm.Metrics, error) {
|
||||
var metrics mm.Metrics
|
||||
|
||||
summaryAllTime, err := h.summarySrvc.Aliased(time.Time{}, time.Now(), user, h.summarySrvc.Retrieve, nil, false)
|
||||
summaryAllTime, err := h.summarySrvc.Aliased(time.Time{}, time.Now(), user, h.summarySrvc.Retrieve, nil, nil, false)
|
||||
if err != nil {
|
||||
conf.Log().Error("failed to retrieve all time summary for metric", "userID", user.ID, "error", err)
|
||||
return nil, err
|
||||
@@ -147,7 +147,7 @@ func (h *MetricsHandler) getUserMetrics(user *models.User) (*mm.Metrics, error)
|
||||
|
||||
from, to := helpers.MustResolveIntervalRawTZ("today", user.TZ())
|
||||
|
||||
summaryToday, err := h.summarySrvc.Aliased(from, to, user, h.summarySrvc.Retrieve, nil, false)
|
||||
summaryToday, err := h.summarySrvc.Aliased(from, to, user, h.summarySrvc.Retrieve, nil, nil, false)
|
||||
if err != nil {
|
||||
conf.Log().Error("failed to retrieve today's summary for metric", "userID", user.ID, "error", err)
|
||||
return nil, err
|
||||
@@ -463,7 +463,7 @@ func (h *MetricsHandler) getAdminMetrics(user *models.User) (*mm.Metrics, error)
|
||||
|
||||
for i := range activeUsers {
|
||||
wp.Submit(func() {
|
||||
summary, err := h.summarySrvc.Aliased(from, to, activeUsers[i], h.summarySrvc.Retrieve, nil, false) // only using aliased because aliased has caching
|
||||
summary, err := h.summarySrvc.Aliased(from, to, activeUsers[i], h.summarySrvc.Retrieve, nil, nil, false) // only using aliased because aliased has caching
|
||||
if err != nil {
|
||||
conf.Log().Error("failed to get total time for user as part of metrics", "userID", activeUsers[i].ID, "error", err)
|
||||
return
|
||||
|
||||
@@ -110,6 +110,7 @@ func (h *BadgeHandler) loadUserSummary(user *models.User, interval *models.Inter
|
||||
summaryParams.User,
|
||||
retrieveSummary,
|
||||
filters,
|
||||
nil,
|
||||
summaryParams.Recompute,
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -80,6 +80,7 @@ func (h *AllTimeHandler) loadUserSummary(user *models.User, filters *models.Filt
|
||||
summaryParams.User,
|
||||
retrieveSummary,
|
||||
filters,
|
||||
nil,
|
||||
summaryParams.Recompute,
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -145,7 +145,7 @@ func (h *StatsHandler) loadUserSummary(user *models.User, start, end time.Time,
|
||||
Recompute: false,
|
||||
}
|
||||
|
||||
summary, err := h.summarySrvc.Aliased(overallParams.From, overallParams.To, user, h.summarySrvc.Retrieve, filters, false)
|
||||
summary, err := h.summarySrvc.Aliased(overallParams.From, overallParams.To, user, h.summarySrvc.Retrieve, filters, nil, false)
|
||||
if err != nil {
|
||||
return nil, err, http.StatusInternalServerError
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ func (h *StatusBarHandler) loadUserSummary(user *models.User, start, end time.Ti
|
||||
retrieveSummary = h.summarySrvc.Summarize
|
||||
}
|
||||
|
||||
summary, err := h.summarySrvc.Aliased(summaryParams.From, summaryParams.To, summaryParams.User, retrieveSummary, nil, summaryParams.Recompute)
|
||||
summary, err := h.summarySrvc.Aliased(summaryParams.From, summaryParams.To, summaryParams.User, retrieveSummary, nil, nil, summaryParams.Recompute)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ func (h *SummariesHandler) loadUserSummaries(r *http.Request, user *models.User)
|
||||
filters := helpers.ParseSummaryFilters(r)
|
||||
|
||||
for i, interval := range intervals {
|
||||
summary, err := h.summarySrvc.Aliased(interval[0], interval[1], user, h.summarySrvc.Retrieve, filters, end.After(time.Now()))
|
||||
summary, err := h.summarySrvc.Aliased(interval[0], interval[1], user, h.summarySrvc.Retrieve, filters, nil, end.After(time.Now()))
|
||||
if err != nil {
|
||||
return nil, err, http.StatusInternalServerError
|
||||
}
|
||||
|
||||
@@ -844,7 +844,7 @@ func (h *SettingsHandler) regenerateSummaries(user *models.User) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := h.aggregationSrvc.AggregateSummaries(datastructure.New(user.ID)); err != nil {
|
||||
if err := h.aggregationSrvc.AggregateSummaries(datastructure.New(user.ID)); err != nil { // involves regenerating durations as well
|
||||
conf.Log().Error("failed to regenerate summaries", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ func (h *SummaryHandler) fetchSplitSummaries(params *models.SummaryParams) ([]*m
|
||||
summaries := make([]*models.Summary, 0)
|
||||
intervals := utils.SplitRangeByDays(params.From, params.To)
|
||||
for _, interval := range intervals {
|
||||
curSummary, err := h.summarySrvc.Aliased(interval[0], interval[1], params.User, h.summarySrvc.Retrieve, params.Filters, false)
|
||||
curSummary, err := h.summarySrvc.Aliased(interval[0], interval[1], params.User, h.summarySrvc.Retrieve, params.Filters, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ func LoadUserSummaryByParams(ss services.ISummaryService, params *models.Summary
|
||||
params.User,
|
||||
retrieveSummary,
|
||||
params.Filters,
|
||||
nil,
|
||||
params.Recompute,
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -85,7 +85,7 @@ func (s *ActivityService) getChartPastYear(user *models.User, darkTheme, hideAtt
|
||||
interval := interval
|
||||
|
||||
wp.Submit(func() {
|
||||
summary, err := s.summaryService.Retrieve(interval[0], interval[1], user, nil)
|
||||
summary, err := s.summaryService.Retrieve(interval[0], interval[1], user, nil, nil)
|
||||
if err != nil {
|
||||
config.Log().Warn("failed to retrieve summary for activity chart", "userID", user.ID, "from", from, "to", to)
|
||||
summary = models.NewEmptySummary()
|
||||
|
||||
@@ -180,7 +180,7 @@ func (srv *AggregationService) AggregateDurations(userIds datastructure.Set[stri
|
||||
func (srv *AggregationService) process(job AggregationJob) {
|
||||
// process single summary interval for single user
|
||||
slog.Info("regenerating actual user summaries as part of summary aggregation", "user", job.User.ID, "from", job.From, "to", job.To)
|
||||
if summary, err := srv.summaryService.Summarize(job.From, job.To, job.User, nil); err != nil {
|
||||
if summary, err := srv.summaryService.Summarize(job.From, job.To, job.User, nil, nil); err != nil {
|
||||
config.Log().Error("failed to regenerate summary", "from", job.From, "to", job.To, "userID", job.User.ID, "error", err)
|
||||
} else {
|
||||
slog.Info("successfully generated summary", "from", job.From, "to", job.To, "userID", job.User.ID)
|
||||
|
||||
@@ -61,16 +61,16 @@ func NewDurationService(durationRepository repositories.IDurationRepository, hea
|
||||
return srv
|
||||
}
|
||||
|
||||
func (srv *DurationService) Get(from, to time.Time, user *models.User, filters *models.Filters, customInterval *time.Duration, skipCache bool) (durations models.Durations, err error) {
|
||||
func (srv *DurationService) Get(from, to time.Time, user *models.User, filters *models.Filters, customTimeout *time.Duration, skipCache bool) (durations models.Durations, err error) {
|
||||
// note about "multi-level" durations at different intervals:
|
||||
// while durations themselves store the interval (aka. heartbeats timeout) they were computed for, we currently don't support actually storing durations at different intervals
|
||||
// if an interval different from the user's preference is requested, recompute durations live from heartbeats and skip cache
|
||||
effectiveInterval := getEffectiveInterval(user, customInterval)
|
||||
skipCache = skipCache || effectiveInterval != user.HeartbeatsTimeout()
|
||||
effectiveTimeout := getEffectiveTimeout(user, customTimeout)
|
||||
skipCache = skipCache || effectiveTimeout != user.HeartbeatsTimeout()
|
||||
|
||||
// recompute live
|
||||
if skipCache {
|
||||
durations, err = srv.getLive(from, to, user, effectiveInterval)
|
||||
durations, err = srv.getLive(from, to, user, effectiveTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -92,7 +92,7 @@ func (srv *DurationService) Get(from, to time.Time, user *models.User, filters *
|
||||
from = cached.Last().TimeEnd().Add(time.Second)
|
||||
}
|
||||
|
||||
missing, err := srv.getLive(from, to, user, effectiveInterval)
|
||||
missing, err := srv.getLive(from, to, user, effectiveTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -318,11 +318,11 @@ func (srv *DurationService) filtersToColumnMap(filters *models.Filters) map[stri
|
||||
return columnMap
|
||||
}
|
||||
|
||||
func getEffectiveInterval(user *models.User, overrideInterval *time.Duration) time.Duration {
|
||||
if overrideInterval == nil {
|
||||
func getEffectiveTimeout(user *models.User, overrideTimeout *time.Duration) time.Duration {
|
||||
if overrideTimeout == nil {
|
||||
return user.HeartbeatsTimeout()
|
||||
}
|
||||
return *overrideInterval
|
||||
return *overrideTimeout
|
||||
}
|
||||
|
||||
func updateDurationEntity(d *models.Duration, h *models.Heartbeat, entityDurations map[tuple.Tuple2[string, string]]time.Duration) *models.Duration {
|
||||
|
||||
@@ -230,7 +230,8 @@ func (srv *LeaderboardService) GenerateByUser(user *models.User, interval *model
|
||||
return nil, err
|
||||
}
|
||||
|
||||
summary, err := srv.summaryService.Aliased(from, to, user, srv.summaryService.Retrieve, nil, false)
|
||||
timeout := models.DefaultHeartbeatsTimeout
|
||||
summary, err := srv.summaryService.Aliased(from, to, user, srv.summaryService.Retrieve, nil, &timeout, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -251,7 +252,7 @@ func (srv *LeaderboardService) GenerateAggregatedByUser(user *models.User, inter
|
||||
return nil, err
|
||||
}
|
||||
|
||||
summary, err := srv.summaryService.Aliased(from, to, user, srv.summaryService.Retrieve, nil, false)
|
||||
summary, err := srv.summaryService.Aliased(from, to, user, srv.summaryService.Retrieve, nil, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ func (srv *MiscService) NotifyExpiringSubscription() {
|
||||
}
|
||||
|
||||
func (srv *MiscService) countUserTotalTime(userId string) time.Duration {
|
||||
result, err := srv.summaryService.Aliased(time.Time{}, time.Now(), &models.User{ID: userId}, srv.summaryService.Retrieve, nil, false)
|
||||
result, err := srv.summaryService.Aliased(time.Time{}, time.Now(), &models.User{ID: userId}, srv.summaryService.Retrieve, nil, nil, false)
|
||||
if err != nil {
|
||||
config.Log().Error("failed to count total for user", "userID", userId, "error", err)
|
||||
return 0
|
||||
|
||||
@@ -102,7 +102,7 @@ func (srv *ReportService) SendReport(user *models.User, duration time.Duration)
|
||||
end := time.Now().In(user.TZ())
|
||||
start := time.Now().Add(-1 * duration)
|
||||
|
||||
fullSummary, err := srv.summaryService.Aliased(start, end, user, srv.summaryService.Retrieve, nil, false)
|
||||
fullSummary, err := srv.summaryService.Aliased(start, end, user, srv.summaryService.Retrieve, nil, nil, false)
|
||||
if err != nil {
|
||||
config.Log().Error("failed to regenerate report", "userID", user.ID, "error", err)
|
||||
return err
|
||||
@@ -114,7 +114,7 @@ func (srv *ReportService) SendReport(user *models.User, duration time.Duration)
|
||||
|
||||
for i, interval := range dayIntervals {
|
||||
from, to := datetime.BeginOfDay(interval[0]), interval[1]
|
||||
summary, err := srv.summaryService.Aliased(from, to, user, srv.summaryService.Retrieve, nil, false)
|
||||
summary, err := srv.summaryService.Aliased(from, to, user, srv.summaryService.Retrieve, nil, nil, false)
|
||||
if err != nil {
|
||||
config.Log().Error("failed to regenerate day summary for report", "from", from, "to", to, "userID", user.ID, "error", err)
|
||||
break
|
||||
|
||||
@@ -97,9 +97,9 @@ type IDurationService interface {
|
||||
}
|
||||
|
||||
type ISummaryService interface {
|
||||
Aliased(time.Time, time.Time, *models.User, types.SummaryRetriever, *models.Filters, bool) (*models.Summary, error)
|
||||
Retrieve(time.Time, time.Time, *models.User, *models.Filters) (*models.Summary, error)
|
||||
Summarize(time.Time, time.Time, *models.User, *models.Filters) (*models.Summary, error)
|
||||
Aliased(time.Time, time.Time, *models.User, types.SummaryRetriever, *models.Filters, *time.Duration, bool) (*models.Summary, error)
|
||||
Retrieve(time.Time, time.Time, *models.User, *models.Filters, *time.Duration) (*models.Summary, error)
|
||||
Summarize(time.Time, time.Time, *models.User, *models.Filters, *time.Duration) (*models.Summary, error)
|
||||
GetLatestByUser() ([]*models.TimeByUser, error)
|
||||
DeleteByUser(string) error
|
||||
DeleteByUserBefore(string, time.Time) error
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/patrickmn/go-cache"
|
||||
"log/slog"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -53,9 +54,11 @@ func NewSummaryService(summaryRepo repositories.ISummaryRepository, heartbeatSer
|
||||
// Public summary generation methods
|
||||
|
||||
// Aliased retrieves or computes a new summary based on the given SummaryRetriever and augments it with entity aliases and project labels
|
||||
func (srv *SummaryService) Aliased(from, to time.Time, user *models.User, f types.SummaryRetriever, filters *models.Filters, skipCache bool) (*models.Summary, error) {
|
||||
func (srv *SummaryService) Aliased(from, to time.Time, user *models.User, f types.SummaryRetriever, filters *models.Filters, customTimeout *time.Duration, skipCache bool) (*models.Summary, error) {
|
||||
requestedTimeout := getEffectiveTimeout(user, customTimeout)
|
||||
|
||||
// Check cache (or skip for sub second-level date precision)
|
||||
cacheKey := srv.getHash(from.String(), to.String(), user.ID, filters.Hash(), "--aliased")
|
||||
cacheKey := srv.getHash(from.String(), to.String(), user.ID, filters.Hash(), strconv.Itoa(int(requestedTimeout)), "--aliased")
|
||||
if to.Truncate(time.Second).Equal(to) && from.Truncate(time.Second).Equal(from) {
|
||||
if cacheResult, ok := srv.cache.Get(cacheKey); ok && !skipCache {
|
||||
return cacheResult.(*models.Summary), nil
|
||||
@@ -79,7 +82,7 @@ func (srv *SummaryService) Aliased(from, to time.Time, user *models.User, f type
|
||||
}
|
||||
|
||||
// Get actual summary
|
||||
s, err := f(from, to, user, filters)
|
||||
s, err := f(from, to, user, filters, customTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -99,13 +102,17 @@ func (srv *SummaryService) Aliased(from, to time.Time, user *models.User, f type
|
||||
return summary.Sorted().InTZ(user.TZ()), nil
|
||||
}
|
||||
|
||||
func (srv *SummaryService) Retrieve(from, to time.Time, user *models.User, filters *models.Filters) (*models.Summary, error) {
|
||||
func (srv *SummaryService) Retrieve(from, to time.Time, user *models.User, filters *models.Filters, customTimeout *time.Duration) (*models.Summary, error) {
|
||||
summaries := make([]*models.Summary, 0)
|
||||
requestedTimeout := getEffectiveTimeout(user, customTimeout)
|
||||
|
||||
// Filtered summaries are not persisted currently
|
||||
// Filtered summaries or summaries at alternative timeouts are not persisted currently
|
||||
// Special case: if (a) filters apply to only one entity type and (b) we're only interested in the summary items of that particular entity type,
|
||||
// we can still fetch the persisted summary and drop all irrelevant parts from it
|
||||
if filters == nil || filters.IsEmpty() || (filters.CountDistinctTypes() == 1 && filters.SelectFilteredOnly) {
|
||||
requiresFiltering := filters != nil && !filters.IsEmpty() && !(filters.CountDistinctTypes() == 1 || filters.SelectFilteredOnly)
|
||||
mustRecompute := requiresFiltering || requestedTimeout != user.HeartbeatsTimeout()
|
||||
|
||||
if !mustRecompute {
|
||||
// Get all already existing, pre-generated summaries that fall into the requested interval
|
||||
result, err := srv.repository.GetByUserWithin(user, from, to)
|
||||
if err == nil {
|
||||
@@ -118,7 +125,7 @@ func (srv *SummaryService) Retrieve(from, to time.Time, user *models.User, filte
|
||||
// Generate missing slots (especially before and after existing summaries) from durations (formerly raw heartbeats)
|
||||
missingIntervals := srv.getMissingIntervals(from, to, summaries, false)
|
||||
for _, interval := range missingIntervals {
|
||||
if s, err := srv.Summarize(interval.Start, interval.End, user, filters); err == nil {
|
||||
if s, err := srv.Summarize(interval.Start, interval.End, user, filters, customTimeout); err == nil {
|
||||
if len(missingIntervals) > 2 && s.FromTime.T().Equal(s.ToTime.T()) {
|
||||
// little hack here: GetAllWithin will query for >= from_date
|
||||
// however, for "in-between" / intra-day missing intervals, we want strictly > from_date to prevent double-counting
|
||||
@@ -146,9 +153,9 @@ func (srv *SummaryService) Retrieve(from, to time.Time, user *models.User, filte
|
||||
return summary.Sorted().InTZ(user.TZ()), nil
|
||||
}
|
||||
|
||||
func (srv *SummaryService) Summarize(from, to time.Time, user *models.User, filters *models.Filters) (*models.Summary, error) {
|
||||
func (srv *SummaryService) Summarize(from, to time.Time, user *models.User, filters *models.Filters, customTimeout *time.Duration) (*models.Summary, error) {
|
||||
// Initialize and fetch data
|
||||
durations, err := srv.durationService.Get(from, to, user, filters, nil, false)
|
||||
durations, err := srv.durationService.Get(from, to, user, filters, customTimeout, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Summarize() {
|
||||
from, to = suite.TestStartTime.Add(-1*time.Hour), suite.TestStartTime.Add(-1*time.Minute)
|
||||
suite.DurationService.On("Get", from, to, suite.TestUser, mock.Anything, mock.Anything, false).Return(filterDurations(from, to, suite.TestDurations), nil)
|
||||
|
||||
result, err = sut.Summarize(from, to, suite.TestUser, nil)
|
||||
result, err = sut.Summarize(from, to, suite.TestUser, nil, nil)
|
||||
|
||||
assert.Nil(suite.T(), err)
|
||||
assert.NotNil(suite.T(), result)
|
||||
@@ -135,7 +135,7 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Summarize() {
|
||||
from, to = suite.TestStartTime.Add(-1*time.Hour), suite.TestStartTime.Add(1*time.Second)
|
||||
suite.DurationService.On("Get", from, to, suite.TestUser, mock.Anything, mock.Anything, false).Return(filterDurations(from, to, suite.TestDurations), nil)
|
||||
|
||||
result, err = sut.Summarize(from, to, suite.TestUser, nil)
|
||||
result, err = sut.Summarize(from, to, suite.TestUser, nil, nil)
|
||||
|
||||
assert.Nil(suite.T(), err)
|
||||
assert.NotNil(suite.T(), result)
|
||||
@@ -149,7 +149,7 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Summarize() {
|
||||
from, to = suite.TestStartTime, suite.TestStartTime.Add(1*time.Hour)
|
||||
suite.DurationService.On("Get", from, to, suite.TestUser, mock.Anything, mock.Anything, false).Return(filterDurations(from, to, suite.TestDurations), nil)
|
||||
|
||||
result, err = sut.Summarize(from, to, suite.TestUser, nil)
|
||||
result, err = sut.Summarize(from, to, suite.TestUser, nil, nil)
|
||||
|
||||
assert.Nil(suite.T(), err)
|
||||
assert.NotNil(suite.T(), result)
|
||||
@@ -211,7 +211,7 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Retrieve() {
|
||||
suite.DurationService.On("Get", from, summaries[0].FromTime.T(), suite.TestUser, mock.Anything, mock.Anything, false).Return(models.Durations{}, nil)
|
||||
suite.DurationService.On("Get", summaries[0].ToTime.T(), to, suite.TestUser, mock.Anything, mock.Anything, false).Return(models.Durations{}, nil)
|
||||
|
||||
result, err = sut.Retrieve(from, to, suite.TestUser, nil)
|
||||
result, err = sut.Retrieve(from, to, suite.TestUser, nil, nil)
|
||||
|
||||
assert.Nil(suite.T(), err)
|
||||
assert.NotNil(suite.T(), result)
|
||||
@@ -264,7 +264,7 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Retrieve() {
|
||||
suite.SummaryRepository.On("GetByUserWithin", suite.TestUser, from, to).Return(summaries, nil)
|
||||
suite.DurationService.On("Get", from, summaries[0].FromTime.T(), suite.TestUser, mock.Anything, mock.Anything, false).Return(filterDurations(from, summaries[0].FromTime.T(), suite.TestDurations), nil)
|
||||
|
||||
result, err = sut.Retrieve(from, to, suite.TestUser, nil)
|
||||
result, err = sut.Retrieve(from, to, suite.TestUser, nil, nil)
|
||||
|
||||
assert.Nil(suite.T(), err)
|
||||
assert.NotNil(suite.T(), result)
|
||||
@@ -320,7 +320,7 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Retrieve() {
|
||||
suite.SummaryRepository.On("GetByUserWithin", suite.TestUser, from, to).Return(summaries, nil)
|
||||
suite.DurationService.On("Get", summaries[0].ToTime.T(), summaries[1].FromTime.T(), suite.TestUser, mock.Anything, mock.Anything, false).Return(filterDurations(summaries[0].ToTime.T(), summaries[1].FromTime.T(), suite.TestDurations), nil)
|
||||
|
||||
result, err = sut.Retrieve(from, to, suite.TestUser, nil)
|
||||
result, err = sut.Retrieve(from, to, suite.TestUser, nil, nil)
|
||||
|
||||
assert.Nil(suite.T(), err)
|
||||
assert.NotNil(suite.T(), result)
|
||||
@@ -371,7 +371,7 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Retrieve_DuplicateSumma
|
||||
suite.DurationService.On("Get", from, summaries[0].FromTime.T(), suite.TestUser, mock.Anything, mock.Anything, false).Return(models.Durations{}, nil)
|
||||
suite.DurationService.On("Get", summaries[0].ToTime.T(), to, suite.TestUser, mock.Anything, mock.Anything, false).Return(models.Durations{}, nil)
|
||||
|
||||
result, err = sut.Retrieve(from, to, suite.TestUser, nil)
|
||||
result, err = sut.Retrieve(from, to, suite.TestUser, nil, nil)
|
||||
|
||||
assert.Nil(suite.T(), err)
|
||||
assert.NotNil(suite.T(), result)
|
||||
@@ -414,7 +414,7 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Aliased() {
|
||||
suite.AliasService.On("GetAliasOrDefault", TestUserId, mock.Anything, mock.Anything).Return("", nil)
|
||||
suite.ProjectLabelService.On("GetByUser", suite.TestUser.ID).Return(suite.TestLabels, nil).Once()
|
||||
|
||||
result, err = sut.Aliased(from, to, suite.TestUser, sut.Summarize, nil, false)
|
||||
result, err = sut.Aliased(from, to, suite.TestUser, sut.Summarize, nil, nil, false)
|
||||
|
||||
assert.Nil(suite.T(), err)
|
||||
assert.NotNil(suite.T(), result)
|
||||
@@ -455,7 +455,7 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Aliased_ProjectLabels()
|
||||
suite.AliasService.On("GetAliasOrDefault", TestUserId, mock.Anything, TestProject2).Return(TestProject1, nil)
|
||||
suite.AliasService.On("GetAliasOrDefault", TestUserId, mock.Anything, mock.Anything).Return("", nil)
|
||||
|
||||
result, err = sut.Aliased(from, to, suite.TestUser, sut.Summarize, nil, false)
|
||||
result, err = sut.Aliased(from, to, suite.TestUser, sut.Summarize, nil, nil, false)
|
||||
|
||||
assert.Nil(suite.T(), err)
|
||||
assert.NotNil(suite.T(), result)
|
||||
@@ -463,6 +463,34 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Aliased_ProjectLabels()
|
||||
assert.Equal(suite.T(), 6, result.NumHeartbeats)
|
||||
}
|
||||
|
||||
func (suite *SummaryServiceTestSuite) TestSummaryService_Aliased_CustomTimeout() {
|
||||
sut := NewSummaryService(suite.SummaryRepository, suite.HeartbeatService, suite.DurationService, suite.AliasService, suite.ProjectLabelService)
|
||||
|
||||
var (
|
||||
from time.Time
|
||||
to time.Time
|
||||
err error
|
||||
)
|
||||
|
||||
from, to = suite.TestStartTime, suite.TestStartTime.Add(1*time.Hour)
|
||||
testSummary := &models.Summary{
|
||||
FromTime: models.CustomTime(from),
|
||||
ToTime: models.CustomTime(to),
|
||||
}
|
||||
|
||||
suite.SummaryRepository.On("GetByUserWithin", suite.TestUser, from, to).Return([]*models.Summary{testSummary}, nil)
|
||||
|
||||
_, err = sut.Retrieve(from, to, suite.TestUser, nil, nil)
|
||||
assert.Nil(suite.T(), err)
|
||||
|
||||
suite.DurationService.On("Get", from, to, suite.TestUser, mock.Anything, mock.Anything, false).Return(models.Durations([]*models.Duration{}), nil)
|
||||
|
||||
customTimeout := 1337 * time.Minute
|
||||
_, err = sut.Retrieve(from, to, suite.TestUser, nil, &customTimeout)
|
||||
assert.Nil(suite.T(), err)
|
||||
suite.DurationService.AssertExpectations(suite.T())
|
||||
}
|
||||
|
||||
func (suite *SummaryServiceTestSuite) TestSummaryService_Filters() {
|
||||
sut := NewSummaryService(suite.SummaryRepository, suite.HeartbeatService, suite.DurationService, suite.AliasService, suite.ProjectLabelService)
|
||||
|
||||
@@ -492,7 +520,7 @@ func (suite *SummaryServiceTestSuite) TestSummaryService_Filters() {
|
||||
suite.TestLabels[1].Label: suite.TestLabels[1:2],
|
||||
}, nil).Once()
|
||||
|
||||
result, _ := sut.Aliased(from, to, suite.TestUser, sut.Summarize, filters, false)
|
||||
result, _ := sut.Aliased(from, to, suite.TestUser, sut.Summarize, filters, nil, false)
|
||||
assert.NotNil(suite.T(), result.Branches) // project filters were applied -> include branches
|
||||
assert.NotNil(suite.T(), result.Entities) // project filters were applied -> include entities
|
||||
|
||||
|
||||
Reference in New Issue
Block a user