Skip to content

Commit 6574299

Browse files
authored
fix: fix TestExecutorAutostartSkipsWhenNoProvisionersAvailable flake, part 2 (#19649)
This test still flakes occasionally, see coder/internal#954 (comment) The cause appears to be related to the assignment of `time.Now()` as the `LastSeenAt` time when creating a provisioner which can flake with the calculated scheduled next autostart and the code to set then `require.Eventually` the updated provisioner LastSeenAt. Instead we should simply calculate all time values for the stale portion of the test based on the provisioners LastSeenAt value to avoid such issues. Signed-off-by: Callum Styan <callumstyan@gmail.com>
1 parent 3470632 commit 6574299

File tree

1 file changed

+25
-27
lines changed

1 file changed

+25
-27
lines changed

coderd/autobuild/lifecycle_executor_test.go

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"database/sql"
66
"errors"
7-
"sync"
87
"testing"
98
"time"
109

@@ -1724,34 +1723,27 @@ func TestExecutorAutostartSkipsWhenNoProvisionersAvailable(t *testing.T) {
17241723
p, err := coderdtest.GetProvisionerForTags(db, time.Now(), workspace.OrganizationID, provisionerDaemonTags)
17251724
require.NoError(t, err, "Error getting provisioner for workspace")
17261725

1727-
var wg sync.WaitGroup
1728-
wg.Add(2)
1726+
// We're going to use an artificial next scheduled autostart time, as opposed to calculating it via sched.Next, since
1727+
// we want to assert/require specific behavior here around the provisioner being stale, and therefore we need to be
1728+
// able to give the provisioner(s) specific `LastSeenAt` times while dealing with the contraint that we cannot set
1729+
// that value to some time in the past (relative to it's current value).
1730+
next := p.LastSeenAt.Time.Add(5 * time.Minute)
1731+
staleTime := next.Add(-(provisionerdserver.StaleInterval + time.Second))
1732+
coderdtest.UpdateProvisionerLastSeenAt(t, db, p.ID, staleTime)
17291733

1730-
next := sched.Next(workspace.LatestBuild.CreatedAt)
1731-
go func() {
1732-
defer wg.Done()
1733-
// Ensure the provisioner is stale
1734-
staleTime := next.Add(-(provisionerdserver.StaleInterval * 2))
1735-
coderdtest.UpdateProvisionerLastSeenAt(t, db, p.ID, staleTime)
1736-
p, err = coderdtest.GetProvisionerForTags(db, time.Now(), workspace.OrganizationID, provisionerDaemonTags)
1737-
assert.NoError(t, err, "Error getting provisioner for workspace")
1738-
assert.Eventually(t, func() bool { return p.LastSeenAt.Time.UnixNano() == staleTime.UnixNano() }, testutil.WaitMedium, testutil.IntervalFast)
1739-
}()
1740-
1741-
go func() {
1742-
defer wg.Done()
1743-
// Ensure the provisioner is gone or stale before triggering the autobuild
1744-
coderdtest.MustWaitForProvisionersUnavailable(t, db, workspace, provisionerDaemonTags, next)
1745-
// Trigger autobuild
1746-
tickCh <- next
1747-
}()
1734+
// Require that the provisioners LastSeenAt has been updated to the expected time.
1735+
p, err = coderdtest.GetProvisionerForTags(db, time.Now(), workspace.OrganizationID, provisionerDaemonTags)
1736+
require.NoError(t, err, "Error getting provisioner for workspace")
1737+
// This assertion *may* no longer need to be `Eventually`.
1738+
require.Eventually(t, func() bool { return p.LastSeenAt.Time.UnixNano() == staleTime.UnixNano() },
1739+
testutil.WaitMedium, testutil.IntervalFast, "expected provisioner LastSeenAt to be:%+v, saw :%+v", staleTime.UTC(), p.LastSeenAt.Time.UTC())
17481740

1749-
wg.Wait()
1741+
// Ensure the provisioner is gone or stale, relative to the artificial next autostart time, before triggering the autobuild.
1742+
coderdtest.MustWaitForProvisionersUnavailable(t, db, workspace, provisionerDaemonTags, next)
17501743

1744+
// Trigger autobuild.
1745+
tickCh <- next
17511746
stats := <-statsCh
1752-
1753-
// This assertion should FAIL when provisioner is available (not stale), can confirm by commenting out the
1754-
// UpdateProvisionerLastSeenAt call above.
17551747
assert.Len(t, stats.Transitions, 0, "should not create builds when no provisioners available")
17561748

17571749
daemon2Closer := coderdtest.NewTaggedProvisionerDaemon(t, api, "name", provisionerDaemonTags)
@@ -1762,12 +1754,18 @@ func TestExecutorAutostartSkipsWhenNoProvisionersAvailable(t *testing.T) {
17621754
// Ensure the provisioner is NOT stale, and see if we get a successful state transition.
17631755
p, err = coderdtest.GetProvisionerForTags(db, time.Now(), workspace.OrganizationID, provisionerDaemonTags)
17641756
require.NoError(t, err, "Error getting provisioner for workspace")
1765-
notStaleTime := sched.Next(workspace.LatestBuild.CreatedAt).Add((-1 * provisionerdserver.StaleInterval) + 10*time.Second)
1757+
1758+
next = sched.Next(workspace.LatestBuild.CreatedAt)
1759+
notStaleTime := next.Add((-1 * provisionerdserver.StaleInterval) + 10*time.Second)
17661760
coderdtest.UpdateProvisionerLastSeenAt(t, db, p.ID, notStaleTime)
1761+
// Require that the provisioner time has actually been updated to the expected value.
1762+
p, err = coderdtest.GetProvisionerForTags(db, time.Now(), workspace.OrganizationID, provisionerDaemonTags)
1763+
require.NoError(t, err, "Error getting provisioner for workspace")
1764+
require.True(t, next.UnixNano() > p.LastSeenAt.Time.UnixNano())
17671765

17681766
// Trigger autobuild
17691767
go func() {
1770-
tickCh <- sched.Next(workspace.LatestBuild.CreatedAt)
1768+
tickCh <- next
17711769
close(tickCh)
17721770
}()
17731771
stats = <-statsCh

0 commit comments

Comments
 (0)