mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix: implement fake DeleteOldWorkspaceAgentLogs (#11042)
This commit is contained in:
@@ -1154,8 +1154,29 @@ func (q *FakeQuerier) DeleteOldProvisionerDaemons(_ context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*FakeQuerier) DeleteOldWorkspaceAgentLogs(_ context.Context) error {
|
||||
// no-op
|
||||
func (q *FakeQuerier) DeleteOldWorkspaceAgentLogs(_ context.Context) error {
|
||||
q.mutex.Lock()
|
||||
defer q.mutex.Unlock()
|
||||
|
||||
now := dbtime.Now()
|
||||
weekInterval := 7 * 24 * time.Hour
|
||||
weekAgo := now.Add(-weekInterval)
|
||||
|
||||
var validLogs []database.WorkspaceAgentLog
|
||||
for _, log := range q.workspaceAgentLogs {
|
||||
var toBeDeleted bool
|
||||
for _, agent := range q.workspaceAgents {
|
||||
if agent.ID == log.AgentID && agent.LastConnectedAt.Valid && agent.LastConnectedAt.Time.Before(weekAgo) {
|
||||
toBeDeleted = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !toBeDeleted {
|
||||
validLogs = append(validLogs, log)
|
||||
}
|
||||
}
|
||||
q.workspaceAgentLogs = validLogs
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"cdr.dev/slog/sloggers/slogtest"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/database"
|
||||
"github.com/coder/coder/v2/coderd/database/dbgen"
|
||||
"github.com/coder/coder/v2/coderd/database/dbmem"
|
||||
"github.com/coder/coder/v2/coderd/database/dbpurge"
|
||||
"github.com/coder/coder/v2/coderd/database/dbtestutil"
|
||||
@@ -33,6 +34,118 @@ func TestPurge(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDeleteOldWorkspaceAgentLogs(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
db, _ := dbtestutil.NewDB(t)
|
||||
org := dbgen.Organization(t, db, database.Organization{})
|
||||
user := dbgen.User(t, db, database.User{})
|
||||
_ = dbgen.OrganizationMember(t, db, database.OrganizationMember{UserID: user.ID, OrganizationID: org.ID})
|
||||
tv := dbgen.TemplateVersion(t, db, database.TemplateVersion{OrganizationID: org.ID, CreatedBy: user.ID})
|
||||
tmpl := dbgen.Template(t, db, database.Template{OrganizationID: org.ID, ActiveVersionID: tv.ID, CreatedBy: user.ID})
|
||||
|
||||
logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true})
|
||||
now := dbtime.Now()
|
||||
|
||||
t.Run("AgentHasNotConnectedSinceWeek_LogsExpired", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
|
||||
defer cancel()
|
||||
|
||||
// given
|
||||
agent := mustCreateAgentWithLogs(ctx, t, db, user, org, tmpl, tv, now.Add(-8*24*time.Hour), t.Name())
|
||||
|
||||
// when
|
||||
closer := dbpurge.New(ctx, logger, db)
|
||||
defer closer.Close()
|
||||
|
||||
// then
|
||||
require.Eventually(t, func() bool {
|
||||
agentLogs, err := db.GetWorkspaceAgentLogsAfter(ctx, database.GetWorkspaceAgentLogsAfterParams{
|
||||
AgentID: agent,
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return !containsAgentLog(agentLogs, t.Name())
|
||||
}, testutil.WaitShort, testutil.IntervalFast)
|
||||
})
|
||||
|
||||
t.Run("AgentConnectedSixDaysAgo_LogsValid", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
|
||||
defer cancel()
|
||||
|
||||
// given
|
||||
agent := mustCreateAgentWithLogs(ctx, t, db, user, org, tmpl, tv, now.Add(-6*24*time.Hour), t.Name())
|
||||
|
||||
// when
|
||||
closer := dbpurge.New(ctx, logger, db)
|
||||
defer closer.Close()
|
||||
|
||||
// then
|
||||
require.Eventually(t, func() bool {
|
||||
agentLogs, err := db.GetWorkspaceAgentLogsAfter(ctx, database.GetWorkspaceAgentLogsAfterParams{
|
||||
AgentID: agent,
|
||||
})
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return containsAgentLog(agentLogs, t.Name())
|
||||
}, testutil.WaitShort, testutil.IntervalFast)
|
||||
})
|
||||
}
|
||||
|
||||
func mustCreateAgentWithLogs(ctx context.Context, t *testing.T, db database.Store, user database.User, org database.Organization, tmpl database.Template, tv database.TemplateVersion, agentLastConnectedAt time.Time, output string) uuid.UUID {
|
||||
agent := mustCreateAgent(t, db, user, org, tmpl, tv)
|
||||
|
||||
err := db.UpdateWorkspaceAgentConnectionByID(ctx, database.UpdateWorkspaceAgentConnectionByIDParams{
|
||||
ID: agent.ID,
|
||||
LastConnectedAt: sql.NullTime{Time: agentLastConnectedAt, Valid: true},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
_, err = db.InsertWorkspaceAgentLogs(ctx, database.InsertWorkspaceAgentLogsParams{
|
||||
AgentID: agent.ID,
|
||||
CreatedAt: agentLastConnectedAt,
|
||||
Output: []string{output},
|
||||
Level: []database.LogLevel{database.LogLevelDebug},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
return agent.ID
|
||||
}
|
||||
|
||||
func mustCreateAgent(t *testing.T, db database.Store, user database.User, org database.Organization, tmpl database.Template, tv database.TemplateVersion) database.WorkspaceAgent {
|
||||
workspace := dbgen.Workspace(t, db, database.Workspace{OwnerID: user.ID, OrganizationID: org.ID, TemplateID: tmpl.ID})
|
||||
job := dbgen.ProvisionerJob(t, db, nil, database.ProvisionerJob{
|
||||
OrganizationID: org.ID,
|
||||
Type: database.ProvisionerJobTypeWorkspaceBuild,
|
||||
Provisioner: database.ProvisionerTypeEcho,
|
||||
StorageMethod: database.ProvisionerStorageMethodFile,
|
||||
})
|
||||
_ = dbgen.WorkspaceBuild(t, db, database.WorkspaceBuild{
|
||||
WorkspaceID: workspace.ID,
|
||||
JobID: job.ID,
|
||||
TemplateVersionID: tv.ID,
|
||||
Transition: database.WorkspaceTransitionStart,
|
||||
Reason: database.BuildReasonInitiator,
|
||||
})
|
||||
resource := dbgen.WorkspaceResource(t, db, database.WorkspaceResource{
|
||||
JobID: job.ID,
|
||||
Transition: database.WorkspaceTransitionStart,
|
||||
})
|
||||
return dbgen.WorkspaceAgent(t, db, database.WorkspaceAgent{
|
||||
ResourceID: resource.ID,
|
||||
})
|
||||
}
|
||||
|
||||
func containsAgentLog(daemons []database.WorkspaceAgentLog, output string) bool {
|
||||
return slices.ContainsFunc(daemons, func(d database.WorkspaceAgentLog) bool {
|
||||
return d.Output == output
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteOldProvisionerDaemons(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -91,12 +204,14 @@ func TestDeleteOldProvisionerDaemons(t *testing.T) {
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return contains(daemons, "external-0") &&
|
||||
contains(daemons, "external-3")
|
||||
return containsProvisionerDaemon(daemons, "external-0") &&
|
||||
!containsProvisionerDaemon(daemons, "external-1") &&
|
||||
!containsProvisionerDaemon(daemons, "external-2") &&
|
||||
containsProvisionerDaemon(daemons, "external-3")
|
||||
}, testutil.WaitShort, testutil.IntervalFast)
|
||||
}
|
||||
|
||||
func contains(daemons []database.ProvisionerDaemon, name string) bool {
|
||||
func containsProvisionerDaemon(daemons []database.ProvisionerDaemon, name string) bool {
|
||||
return slices.ContainsFunc(daemons, func(d database.ProvisionerDaemon) bool {
|
||||
return d.Name == name
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user