Skip to content

Commit f160829

Browse files
committed
Add integration test for manual rollback after grace period
1 parent 6eb8d95 commit f160829

File tree

1 file changed

+91
-26
lines changed

1 file changed

+91
-26
lines changed

testing/integration/ess/upgrade_rollback_test.go

Lines changed: 91 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ agent.upgrade.watcher:
4444
const fastWatcherCfgWithRollbackWindow = `
4545
agent.upgrade:
4646
watcher:
47-
grace_period: 2m
47+
grace_period: 1m
4848
error_check.interval: 5s
4949
rollback:
5050
window: 10m
@@ -338,6 +338,8 @@ func TestFleetManagedUpgradeRollbackOnRestarts(t *testing.T) {
338338
}
339339
}
340340

341+
type rollbackTriggerFunc func(ctx context.Context, t *testing.T, client client.Client, startFixture, endFixture *atesting.Fixture)
342+
341343
// TestStandaloneUpgradeManualRollback tests the scenario where, after upgrading to a new version
342344
// of Agent, a manual rollback is triggered. It checks that the Agent is rolled back to the previous version.
343345
func TestStandaloneUpgradeManualRollback(t *testing.T) {
@@ -348,12 +350,16 @@ func TestStandaloneUpgradeManualRollback(t *testing.T) {
348350
})
349351

350352
type fixturesSetupFunc func(t *testing.T) (from *atesting.Fixture, to *atesting.Fixture)
353+
351354
testcases := []struct {
352-
name string
353-
fixturesSetup fixturesSetupFunc
355+
name string
356+
fixturesSetup fixturesSetupFunc
357+
agentConfig string
358+
rollbackTrigger rollbackTriggerFunc
354359
}{
355360
{
356-
name: "upgrade to a repackaged agent built from the same commit",
361+
name: "upgrade to a repackaged agent built from the same commit, rollback during grace period",
362+
agentConfig: fastWatcherCfgWithRollbackWindow,
357363
fixturesSetup: func(t *testing.T) (from *atesting.Fixture, to *atesting.Fixture) {
358364
// Upgrade from the current build to the same build as Independent Agent Release.
359365

@@ -389,23 +395,93 @@ func TestStandaloneUpgradeManualRollback(t *testing.T) {
389395

390396
return fromFixture, toFixture
391397
},
398+
rollbackTrigger: func(ctx context.Context, t *testing.T, client client.Client, startFixture, endFixture *atesting.Fixture) {
399+
t.Logf("sending version=%s rollback=%v upgrade to agent", startFixture.Version(), true)
400+
retVal, err := client.Upgrade(ctx, startFixture.Version(), true, "", false, false)
401+
require.NoError(t, err, "error triggering manual rollback to version %s", startFixture.Version())
402+
t.Logf("received output %s from upgrade command", retVal)
403+
},
392404
},
393-
}
405+
{
406+
name: "upgrade to a repackaged agent built from the same commit, rollback after grace period",
407+
agentConfig: fastWatcherCfgWithRollbackWindow,
408+
fixturesSetup: func(t *testing.T) (from *atesting.Fixture, to *atesting.Fixture) {
409+
// Upgrade from the current build to the same build as Independent Agent Release.
394410

395-
// set up start ficture with a rollback window of 1h
396-
rollbackWindowConfig := `
397-
agent.upgrade.rollback.window: 1h
398-
`
411+
// Start from the build under test.
412+
fromFixture, err := define.NewFixtureFromLocalBuild(t, define.Version())
413+
require.NoError(t, err)
414+
415+
// Create a new package with a different version (IAR-style)
416+
// modify the version with the "+buildYYYYMMDDHHMMSS"
417+
currentVersion, err := version.ParseVersion(define.Version())
418+
require.NoErrorf(t, err, "define.Version() %q is not parsable.", define.Version())
419+
420+
newVersionBuildMetadata := "build" + time.Now().Format("20060102150405")
421+
parsedNewVersion := version.NewParsedSemVer(currentVersion.Major(), currentVersion.Minor(), currentVersion.Patch(), "", newVersionBuildMetadata)
422+
423+
err = fromFixture.EnsurePrepared(t.Context())
424+
require.NoErrorf(t, err, "fixture should be prepared")
425+
426+
// retrieve the compressed package file location
427+
srcPackage, err := fromFixture.SrcPackage(t.Context())
428+
require.NoErrorf(t, err, "error retrieving start fixture source package")
429+
430+
versionForFixture, repackagedArchiveFile, err := repackageArchive(t, srcPackage, newVersionBuildMetadata, currentVersion, parsedNewVersion)
431+
require.NoError(t, err, "error repackaging the archive built from the same commit")
432+
433+
repackagedLocalFetcher := atesting.LocalFetcher(filepath.Dir(repackagedArchiveFile))
434+
toFixture, err := atesting.NewFixture(
435+
t,
436+
versionForFixture.String(),
437+
atesting.WithFetcher(repackagedLocalFetcher),
438+
)
439+
require.NoError(t, err)
440+
441+
return fromFixture, toFixture
442+
},
443+
rollbackTrigger: func(ctx context.Context, t *testing.T, client client.Client, startFixture, endFixture *atesting.Fixture) {
444+
// trim -SNAPSHOT at the end of the fixture version as that is reported as a separate flag
445+
expectedVersion := endFixture.Version()
446+
expectedSnapshot := false
447+
if strings.HasSuffix(expectedVersion, "-SNAPSHOT") {
448+
expectedVersion = strings.TrimSuffix(endFixture.Version(), "-SNAPSHOT")
449+
expectedSnapshot = true
450+
}
451+
452+
// It will take at least 2 minutes before the agent exits the grace period (see fastWatcherCfgWithRollbackWindow)
453+
// let's shoot for up to 4 minutes to exit grace period, checking every 10 seconds
454+
require.EventuallyWithT(t, func(collect *assert.CollectT) {
455+
state, err := client.State(ctx)
456+
require.NoError(collect, err)
457+
t.Logf("checking agent state: %+v", state)
458+
require.NotNil(collect, state)
459+
assert.Nil(collect, state.UpgradeDetails)
460+
assert.Equal(t, cproto.State_HEALTHY, state.State)
461+
assert.Equal(collect, expectedVersion, state.Info.Version)
462+
assert.Equal(collect, expectedSnapshot, state.Info.Snapshot)
463+
assert.NoFileExists(collect, filepath.Join(startFixture.WorkDir(), "data", ".update-marker"))
464+
}, 4*time.Minute, 10*time.Second)
465+
t.Log("elastic agent is out of grace period.")
466+
t.Logf("sending version=%s rollback=%v upgrade to agent", startFixture.Version(), true)
467+
retVal, err := client.Upgrade(ctx, startFixture.Version(), true, "", false, false)
468+
require.NoError(t, err, "error triggering manual rollback to version %s", startFixture.Version())
469+
t.Logf("received output %s from upgrade command", retVal)
470+
},
471+
},
472+
}
399473

400474
for _, tc := range testcases {
401475
t.Run(tc.name, func(t *testing.T) {
402476
ctx, cancel := testcontext.WithDeadline(t, t.Context(), time.Now().Add(10*time.Minute))
403477
defer cancel()
404478
from, to := tc.fixturesSetup(t)
405479

406-
err := from.Configure(ctx, []byte(rollbackWindowConfig))
407-
require.NoError(t, err, "error setting up rollback window")
408-
standaloneManualRollbackTest(ctx, t, from, to)
480+
err := from.Configure(ctx, []byte(tc.agentConfig))
481+
require.NoError(t, err, "error configuring starting fixture")
482+
standaloneRollbackTest(
483+
ctx, t, from, to, fastWatcherCfgWithRollbackWindow, fmt.Sprintf(details.ReasonManualRollbackPattern, from.Version()),
484+
tc.rollbackTrigger)
409485
})
410486
}
411487

@@ -490,23 +566,12 @@ func managedRollbackRestartTest(ctx context.Context, t *testing.T, info *define.
490566

491567
func standaloneRollbackRestartTest(ctx context.Context, t *testing.T, startFixture *atesting.Fixture, endFixture *atesting.Fixture) {
492568
standaloneRollbackTest(ctx, t, startFixture, endFixture, reallyFastWatcherCfg, details.ReasonWatchFailed,
493-
func(t *testing.T, _ client.Client) {
569+
func(ctx context.Context, t *testing.T, _ client.Client, _ *atesting.Fixture, _ *atesting.Fixture) {
494570
restartAgentNTimes(t, 3, 10*time.Second)
495571
})
496572
}
497573

498-
func standaloneManualRollbackTest(ctx context.Context, t *testing.T, startFixture *atesting.Fixture, endFixture *atesting.Fixture) {
499-
standaloneRollbackTest(ctx, t, startFixture, endFixture, fastWatcherCfgWithRollbackWindow, fmt.Sprintf(details.ReasonManualRollbackPattern, startFixture.Version()),
500-
func(t *testing.T, client client.Client) {
501-
t.Logf("sending version=%s rollback=%v upgrade to agent", startFixture.Version(), true)
502-
retVal, err := client.Upgrade(ctx, startFixture.Version(), true, "", false, false)
503-
require.NoError(t, err, "error triggering manual rollback to version %s", startFixture.Version())
504-
t.Logf("received output %s from upgrade command", retVal)
505-
},
506-
)
507-
}
508-
509-
func standaloneRollbackTest(ctx context.Context, t *testing.T, startFixture *atesting.Fixture, endFixture *atesting.Fixture, customConfig string, rollbackReason string, rollbackTrigger func(t *testing.T, client client.Client)) {
574+
func standaloneRollbackTest(ctx context.Context, t *testing.T, startFixture *atesting.Fixture, endFixture *atesting.Fixture, customConfig string, rollbackReason string, rollbackTrigger rollbackTriggerFunc) {
510575

511576
startVersionInfo, err := startFixture.ExecVersion(ctx)
512577
require.NoError(t, err, "failed to get start agent build version info")
@@ -539,7 +604,7 @@ func standaloneRollbackTest(ctx context.Context, t *testing.T, startFixture *ate
539604
defer elasticAgentClient.Disconnect()
540605

541606
// A few seconds after the upgrade, trigger a rollback using the passed trigger
542-
rollbackTrigger(t, elasticAgentClient)
607+
rollbackTrigger(ctx, t, elasticAgentClient, startFixture, endFixture)
543608

544609
// wait for the agent to be healthy and back at the start version
545610
err = upgradetest.WaitHealthyAndVersion(ctx, startFixture, startVersionInfo.Binary, 2*time.Minute, 10*time.Second, t)

0 commit comments

Comments
 (0)