Skip to content

Commit e3f9ca5

Browse files
easyCZroboquat
authored andcommitted
[usage] Fix report generation
1 parent 5176a90 commit e3f9ca5

File tree

3 files changed

+76
-24
lines changed

3 files changed

+76
-24
lines changed

components/usage/pkg/controller/reconciler.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,16 @@ func (u *UsageReconciler) ReconcileTimeRange(ctx context.Context, from, to time.
131131
func generateUsageReport(teams []teamWithWorkspaces, maxStopTime time.Time) ([]TeamUsage, error) {
132132
var report []TeamUsage
133133
for _, team := range teams {
134-
var teamTotalRuntime time.Duration
134+
var teamTotalRuntime float64
135135
for _, workspace := range team.Workspaces {
136136
for _, instance := range workspace.Instances {
137-
teamTotalRuntime += instance.TotalRuntime(maxStopTime)
137+
teamTotalRuntime += instance.WorkspaceRuntimeSeconds(maxStopTime)
138138
}
139139
}
140140

141141
report = append(report, TeamUsage{
142-
TeamID: team.TeamID.String(),
143-
WorkspacesRuntime: teamTotalRuntime,
142+
TeamID: team.TeamID.String(),
143+
WorkspaceSeconds: teamTotalRuntime,
144144
})
145145
}
146146
return report, nil
@@ -312,6 +312,6 @@ func toSet(items []string) []string {
312312
}
313313

314314
type TeamUsage struct {
315-
TeamID string `json:"team_id"`
316-
WorkspacesRuntime time.Duration `json:"workspaces_runtime"`
315+
TeamID string `json:"team_id"`
316+
WorkspaceSeconds float64 `json:"workspace_seconds"`
317317
}

components/usage/pkg/controller/reconciler_test.go

Lines changed: 67 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func TestUsageReconciler_ReconcileTimeRange(t *testing.T) {
4343
Role: db.TeamMembershipRole_Member,
4444
}
4545
workspace := dbtest.NewWorkspace(t, db.Workspace{
46-
ID: "gitpodio-gitpod-gyjr82jkfnd",
46+
ID: "gitpodio-gitpod-gyjr82jkfna",
4747
OwnerID: userID,
4848
})
4949
instances := []db.WorkspaceInstance{
@@ -71,7 +71,7 @@ func TestUsageReconciler_ReconcileTimeRange(t *testing.T) {
7171
},
7272
}
7373

74-
expectedRuntime := instances[0].TotalRuntime(scenarioRunTime) + instances[1].TotalRuntime(scenarioRunTime)
74+
expectedRuntime := instances[0].WorkspaceRuntimeSeconds(scenarioRunTime) + instances[1].WorkspaceRuntimeSeconds(scenarioRunTime)
7575

7676
return Scenario{
7777
Name: "oen team with one workspace",
@@ -88,8 +88,57 @@ func TestUsageReconciler_ReconcileTimeRange(t *testing.T) {
8888
Teams: 1,
8989
Report: []TeamUsage{
9090
{
91-
TeamID: teamID.String(),
92-
WorkspacesRuntime: expectedRuntime,
91+
TeamID: teamID.String(),
92+
WorkspaceSeconds: expectedRuntime,
93+
},
94+
},
95+
},
96+
}
97+
})(),
98+
(func() Scenario {
99+
runTime := time.Date(2022, 05, 31, 23, 59, 59, 999999, time.UTC)
100+
teamID, userID := uuid.New(), uuid.New()
101+
workspaceID := "gitpodio-gitpod-gyjr82jkfnd"
102+
var instances []db.WorkspaceInstance
103+
for i := 0; i < 100; i++ {
104+
instances = append(instances, db.WorkspaceInstance{
105+
ID: uuid.New(),
106+
WorkspaceID: workspaceID,
107+
CreationTime: db.NewVarcharTime(time.Date(2022, 05, 01, 00, 00, 00, 00, time.UTC)),
108+
StoppedTime: db.NewVarcharTime(time.Date(2022, 05, 31, 23, 59, 59, 999999, time.UTC)),
109+
Status: instanceStatus,
110+
})
111+
}
112+
113+
return Scenario{
114+
Name: "many long running instances do not overflow number of seconds in usage",
115+
NowFunc: func() time.Time { return runTime },
116+
Memberships: []db.TeamMembership{
117+
{
118+
ID: uuid.New(),
119+
TeamID: teamID,
120+
UserID: userID,
121+
Role: db.TeamMembershipRole_Member,
122+
},
123+
},
124+
Workspaces: []db.Workspace{
125+
dbtest.NewWorkspace(t, db.Workspace{
126+
ID: workspaceID,
127+
OwnerID: userID,
128+
}),
129+
},
130+
Instances: instances,
131+
Expected: &UsageReconcileStatus{
132+
StartTime: startOfMay,
133+
EndTime: startOfJune,
134+
WorkspaceInstances: 100,
135+
InvalidWorkspaceInstances: 0,
136+
Workspaces: 1,
137+
Teams: 1,
138+
Report: []TeamUsage{
139+
{
140+
TeamID: teamID.String(),
141+
WorkspaceSeconds: 9.223372036854766e+11,
93142
},
94143
},
95144
},
@@ -98,18 +147,21 @@ func TestUsageReconciler_ReconcileTimeRange(t *testing.T) {
98147
}
99148

100149
for _, scenario := range scenarios {
101-
conn := db.ConnectForTests(t)
102-
require.NoError(t, conn.Create(scenario.Memberships).Error)
103-
require.NoError(t, conn.Create(scenario.Workspaces).Error)
104-
require.NoError(t, conn.Create(scenario.Instances).Error)
150+
t.Run(scenario.Name, func(t *testing.T) {
151+
conn := db.ConnectForTests(t)
152+
require.NoError(t, conn.Create(scenario.Memberships).Error)
153+
require.NoError(t, conn.Create(scenario.Workspaces).Error)
154+
require.NoError(t, conn.Create(scenario.Instances).Error)
155+
156+
reconciler := &UsageReconciler{
157+
nowFunc: scenario.NowFunc,
158+
conn: conn,
159+
}
160+
status, err := reconciler.ReconcileTimeRange(context.Background(), startOfMay, startOfJune)
161+
require.NoError(t, err)
105162

106-
reconciler := &UsageReconciler{
107-
nowFunc: scenario.NowFunc,
108-
conn: conn,
109-
}
110-
status, err := reconciler.ReconcileTimeRange(context.Background(), startOfMay, startOfJune)
111-
require.NoError(t, err)
163+
require.Equal(t, scenario.Expected, status)
164+
})
112165

113-
require.Equal(t, scenario.Expected, status)
114166
}
115167
}

components/usage/pkg/db/workspace_instance.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,16 @@ type WorkspaceInstance struct {
4242
_ bool `gorm:"column:deleted;type:tinyint;default:0;" json:"deleted"`
4343
}
4444

45-
// TotalRuntime computes how long this WorkspaceInstance has been running.
45+
// WorkspaceRuntimeSeconds computes how long this WorkspaceInstance has been running.
4646
// If the instance is still running (no stop time set), maxStopTime is used to to compute the duration - this is an upper bound on stop
47-
func (i *WorkspaceInstance) TotalRuntime(maxStopTime time.Time) time.Duration {
47+
func (i *WorkspaceInstance) WorkspaceRuntimeSeconds(maxStopTime time.Time) float64 {
4848
start := i.StartedTime.Time()
4949
stop := maxStopTime
5050
if i.StoppedTime.IsSet() {
5151
stop = i.StoppedTime.Time()
5252
}
5353

54-
return stop.Sub(start)
54+
return stop.Sub(start).Seconds()
5555
}
5656

5757
// TableName sets the insert table name for this struct type

0 commit comments

Comments
 (0)