Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

fix: fix flake in TestExecutorAutostartSkipsWhenNoProvisionersAvailable#19478

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
cstyan merged 6 commits intomainfromcallum/exec-autostart-stale-flake
Aug 28, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
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
32 changes: 23 additions & 9 deletionscoderd/autobuild/lifecycle_executor_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"errors"
"sync"
"testing"
"time"

Expand DownExpand Up@@ -1720,19 +1721,32 @@ func TestExecutorAutostartSkipsWhenNoProvisionersAvailable(t *testing.T) {
// Stop the workspace while provisioner is available
workspace = coderdtest.MustTransitionWorkspace(t, client, workspace.ID, codersdk.WorkspaceTransitionStart, codersdk.WorkspaceTransitionStop)

// Wait for provisioner to be available for this specific workspace
coderdtest.MustWaitForProvisionersAvailable(t, db, workspace)
p, err := coderdtest.GetProvisionerForTags(db, time.Now(), workspace.OrganizationID, provisionerDaemonTags)
require.NoError(t, err, "Error getting provisioner for workspace")

daemon1Closer.Close()
var wg sync.WaitGroup
wg.Add(2)

// Ensure the provisioner is stale
staleTime := sched.Next(workspace.LatestBuild.CreatedAt).Add((-1 * provisionerdserver.StaleInterval) + -10*time.Second)
coderdtest.UpdateProvisionerLastSeenAt(t, db, p.ID, staleTime)
next := sched.Next(workspace.LatestBuild.CreatedAt)
go func() {
defer wg.Done()
// Ensure the provisioner is stale
staleTime := next.Add(-(provisionerdserver.StaleInterval * 2))
coderdtest.UpdateProvisionerLastSeenAt(t, db, p.ID, staleTime)
p, err = coderdtest.GetProvisionerForTags(db, time.Now(), workspace.OrganizationID, provisionerDaemonTags)
assert.NoError(t, err, "Error getting provisioner for workspace")
assert.Eventually(t, func() bool { return p.LastSeenAt.Time.UnixNano() == staleTime.UnixNano() }, testutil.WaitMedium, testutil.IntervalFast)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

nit: Suggest instead checking less than or equal to staleTime instead instead?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This should be fine,lastSeenAt should never be updated within the execution of this testother than via this direct call tocoderdtest.UpdateProvisionerLastSeenAt, since that ensures the provisioner is stale and the autobuild will then not execute. We want to ensure it's at leaststaleTime or very close to it, as when we create a provisioner via the various test helpers it gets a defaultLastSeenAt time of like January 2024.

We could make this more explicitly enforced by also double checking that in addition to thestats.Transitions length being 0, assert that theLastSeenAt time for this provisioner is still equal tostaleTime.

}()

// Trigger autobuild
tickCh <- sched.Next(workspace.LatestBuild.CreatedAt)
go func() {
defer wg.Done()
// Ensure the provisioner is gone or stale before triggering the autobuild
coderdtest.MustWaitForProvisionersUnavailable(t, db, workspace, provisionerDaemonTags, next)
// Trigger autobuild
tickCh <- next
}()

wg.Wait()

stats := <-statsCh

Expand All@@ -1758,5 +1772,5 @@ func TestExecutorAutostartSkipsWhenNoProvisionersAvailable(t *testing.T) {
}()
stats = <-statsCh

assert.Len(t, stats.Transitions, 1, "shouldnotcreate builds whennoprovisioners available")
assert.Len(t, stats.Transitions, 1, "should create builds when provisioners are available")
}
44 changes: 36 additions & 8 deletionscoderd/coderdtest/coderdtest.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1646,19 +1646,48 @@ func UpdateProvisionerLastSeenAt(t *testing.T, db database.Store, id uuid.UUID,
func MustWaitForAnyProvisioner(t *testing.T, db database.Store) {
t.Helper()
ctx := ctxWithProvisionerPermissions(testutil.Context(t, testutil.WaitShort))
require.Eventually(t, func() bool {
// testutil.Eventually(t, func)
testutil.Eventually(ctx, t, func(ctx context.Context) (done bool) {
daemons, err := db.GetProvisionerDaemons(ctx)
return err == nil && len(daemons) > 0
}, testutil.WaitShort, testutil.IntervalFast)
}, testutil.IntervalFast, "no provisioner daemons found")
}

// MustWaitForProvisionersUnavailable waits for provisioners to become unavailable for a specific workspace
func MustWaitForProvisionersUnavailable(t *testing.T, db database.Store, workspace codersdk.Workspace, tags map[string]string, checkTime time.Time) {
t.Helper()
ctx := ctxWithProvisionerPermissions(testutil.Context(t, testutil.WaitMedium))

testutil.Eventually(ctx, t, func(ctx context.Context) (done bool) {
// Use the same logic as hasValidProvisioner but expect false
provisionerDaemons, err := db.GetProvisionerDaemonsByOrganization(ctx, database.GetProvisionerDaemonsByOrganizationParams{
OrganizationID: workspace.OrganizationID,
WantTags: tags,
})
if err != nil {
return false
}

// Check if NO provisioners are active (all are stale or gone)
for _, pd := range provisionerDaemons {
if pd.LastSeenAt.Valid {
age := checkTime.Sub(pd.LastSeenAt.Time)
if age <= provisionerdserver.StaleInterval {
return false // Found an active provisioner, keep waiting
}
}
}
return true // No active provisioners found
}, testutil.IntervalFast, "there are still provisioners available for workspace, expected none")
}

// MustWaitForProvisionersAvailable waits for provisioners to be available for a specific workspace.
func MustWaitForProvisionersAvailable(t *testing.T, db database.Store, workspace codersdk.Workspace) uuid.UUID {
func MustWaitForProvisionersAvailable(t *testing.T, db database.Store, workspace codersdk.Workspace, ts time.Time) uuid.UUID {
t.Helper()
ctx := ctxWithProvisionerPermissions(testutil.Context(t, testutil.WaitShort))
ctx := ctxWithProvisionerPermissions(testutil.Context(t, testutil.WaitLong))
id := uuid.UUID{}
// Get the workspace from the database
require.Eventually(t, func()bool {
testutil.Eventually(ctx,t, func(ctx context.Context) (donebool) {
ws, err := db.GetWorkspaceByID(ctx, workspace.ID)
if err != nil {
return false
Expand DownExpand Up@@ -1686,18 +1715,17 @@ func MustWaitForProvisionersAvailable(t *testing.T, db database.Store, workspace
}

// Check if any provisioners are active (not stale)
now := time.Now()
for _, pd := range provisionerDaemons {
if pd.LastSeenAt.Valid {
age :=now.Sub(pd.LastSeenAt.Time)
age :=ts.Sub(pd.LastSeenAt.Time)
if age <= provisionerdserver.StaleInterval {
id = pd.ID
return true // Found an active provisioner
}
}
}
return false // No active provisioners found
}, testutil.WaitLong, testutil.IntervalFast)
}, testutil.IntervalFast, "no active provisioners available for workspace, expected at least one (non-stale)")

return id
}
7 changes: 4 additions & 3 deletionsenterprise/coderd/workspaces_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2241,13 +2241,14 @@ func TestPrebuildsAutobuild(t *testing.T) {
workspace = coderdtest.MustTransitionWorkspace(t, client, workspace.ID, codersdk.WorkspaceTransitionStart, codersdk.WorkspaceTransitionStop)
coderdtest.AwaitWorkspaceBuildJobCompleted(t, client, workspace.LatestBuild.ID)

p, err := coderdtest.GetProvisionerForTags(db, time.Now(), workspace.OrganizationID, nil)
coderdtest.UpdateProvisionerLastSeenAt(t, db, p.ID, sched.Next(prebuild.LatestBuild.CreatedAt))

// Wait for provisioner to be available for this specific workspace
coderdtest.MustWaitForProvisionersAvailable(t, db, prebuild)
coderdtest.MustWaitForProvisionersAvailable(t, db, prebuild, sched.Next(prebuild.LatestBuild.CreatedAt))

tickTime := sched.Next(prebuild.LatestBuild.CreatedAt).Add(time.Minute)
p, err := coderdtest.GetProvisionerForTags(db, time.Now(), workspace.OrganizationID, nil)
require.NoError(t, err)
coderdtest.UpdateProvisionerLastSeenAt(t, db, p.ID, tickTime)

// Tick at the next scheduled time after the prebuild’s LatestBuild.CreatedAt,
// since the next allowed autostart is calculated starting from that point.
Expand Down
Loading

[8]ページ先頭

©2009-2025 Movatter.jp