Skip to content

Commit ff0b7b5

Browse files
authored
Fix upgrade tests, so they use correct snapshots (#4191)
TestStandaloneUpgradeRetryDownload, TestStandaloneUpgradeUninstallKillWatcher were using snapshots with a matching hash instead of filtering builds by a commit hash.
1 parent de1d034 commit ff0b7b5

File tree

4 files changed

+99
-59
lines changed

4 files changed

+99
-59
lines changed

pkg/testing/tools/artifacts_api.go

+35-9
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,15 @@ const (
2424
artifactsAPIV1VersionBuildsEndpoint = "v1/versions/%s/builds/"
2525
artifactAPIV1BuildDetailsEndpoint = "v1/versions/%s/builds/%s"
2626
// artifactAPIV1SearchVersionPackage = "v1/search/%s/%s"
27+
28+
artifactElasticAgentProject = "elastic-agent-package"
2729
)
2830

2931
var (
3032
ErrLatestVersionNil = errors.New("latest version is nil")
3133
ErrSnapshotVersionsEmpty = errors.New("snapshot list is nil")
3234
ErrInvalidVersionRetrieved = errors.New("invalid version retrieved from artifact API")
35+
ErrBuildNotFound = errors.New("there are no build that satisfy given conditions")
3336

3437
ErrBadHTTPStatusCode = errors.New("bad http status code")
3538
)
@@ -146,13 +149,12 @@ func NewArtifactAPIClient(opts ...ArtifactAPIClientOpt) *ArtifactAPIClient {
146149
func (aac ArtifactAPIClient) GetVersions(ctx context.Context) (list *VersionList, err error) {
147150
joinedURL, err := aac.composeURL(artifactsAPIV1VersionsEndpoint)
148151
if err != nil {
149-
return
152+
return nil, err
150153
}
151154

152155
resp, err := aac.createAndPerformRequest(ctx, joinedURL)
153156
if err != nil {
154-
err = fmt.Errorf("getting versions: %w", err)
155-
return
157+
return nil, fmt.Errorf("getting versions: %w", err)
156158
}
157159

158160
defer resp.Body.Close()
@@ -165,32 +167,56 @@ func (aac ArtifactAPIClient) GetVersions(ctx context.Context) (list *VersionList
165167
func (aac ArtifactAPIClient) GetBuildsForVersion(ctx context.Context, version string) (builds *VersionBuilds, err error) {
166168
joinedURL, err := aac.composeURL(fmt.Sprintf(artifactsAPIV1VersionBuildsEndpoint, version))
167169
if err != nil {
168-
return
170+
return nil, err
169171
}
170172

171173
resp, err := aac.createAndPerformRequest(ctx, joinedURL)
172174
if err != nil {
173-
err = fmt.Errorf("getting builds for version %s: %w", version, err)
174-
return
175+
return nil, fmt.Errorf("getting builds for version %s: %w", version, err)
175176
}
176177

177178
defer resp.Body.Close()
178179
return checkResponseAndUnmarshal[VersionBuilds](resp)
179180
}
180181

182+
// FindBuild returns a build of the given `version` that does not match the
183+
// `excludeHash` commit hash. It searches for a matching build from the latest
184+
// to the oldest, starting the search at the `offset` index in the list of builds.
185+
// Setting `offset` to 0 includes all builds, 1 skips the latest, and so forth.
186+
// If there are no builds matching these conditions, returns `ErrBuildNotFound`.
187+
func (aac ArtifactAPIClient) FindBuild(ctx context.Context, version, excludeHash string, offset int) (buildDetails *BuildDetails, err error) {
188+
resp, err := aac.GetBuildsForVersion(ctx, version)
189+
if err != nil {
190+
return nil, fmt.Errorf("failed to get a list of builds: %w", err)
191+
}
192+
if len(resp.Builds) < offset+1 {
193+
return nil, ErrBuildNotFound
194+
}
195+
for _, buildID := range resp.Builds[offset:] {
196+
details, err := aac.GetBuildDetails(ctx, version, buildID)
197+
if err != nil {
198+
return nil, fmt.Errorf("failed to get build information for %q: %w", buildID, err)
199+
}
200+
if details.Build.Projects[artifactElasticAgentProject].CommitHash != excludeHash {
201+
return details, nil
202+
}
203+
}
204+
205+
return nil, ErrBuildNotFound
206+
}
207+
181208
// GetBuildDetails returns the list of project and artifacts related to a specific build.
182209
// Version parameter format follows semver (without build metadata) and buildID format is <major>.<minor>.<patch>-<buildhash> as returned by
183210
// GetBuildsForVersion()
184211
func (aac ArtifactAPIClient) GetBuildDetails(ctx context.Context, version string, buildID string) (buildDetails *BuildDetails, err error) {
185212
joinedURL, err := aac.composeURL(fmt.Sprintf(artifactAPIV1BuildDetailsEndpoint, version, buildID))
186213
if err != nil {
187-
return
214+
return nil, err
188215
}
189216

190217
resp, err := aac.createAndPerformRequest(ctx, joinedURL)
191218
if err != nil {
192-
err = fmt.Errorf("getting build details for version %s buildID %s: %w", version, buildID, err)
193-
return
219+
return nil, fmt.Errorf("getting build details for version %s buildID %s: %w", version, buildID, err)
194220
}
195221

196222
defer resp.Body.Close()

testing/integration/upgrade_downgrade_test.go

+24-41
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package integration
88

99
import (
1010
"context"
11+
"errors"
1112
"strings"
1213
"testing"
1314
"time"
@@ -23,10 +24,6 @@ import (
2324
"github.com/elastic/elastic-agent/testing/upgradetest"
2425
)
2526

26-
const (
27-
artifactElasticAgentProject = "elastic-agent-package"
28-
)
29-
3027
func TestStandaloneDowngradeToSpecificSnapshotBuild(t *testing.T) {
3128
define.Require(t, define.Requirements{
3229
Group: Upgrade,
@@ -61,54 +58,24 @@ func TestStandaloneDowngradeToSpecificSnapshotBuild(t *testing.T) {
6158
// as the currently running binary (so, we don't have a file system collision).
6259
// Multiple builds can have different IDs but the same commit hash.
6360
preReleaseVersion := latestSnapshotVersion.VersionWithPrerelease()
64-
resp, err := aac.GetBuildsForVersion(ctx, preReleaseVersion)
65-
require.NoError(t, err)
66-
67-
if len(resp.Builds) < 2 {
68-
t.Skipf("need at least 2 builds in the version %s", latestSnapshotVersion.VersionWithPrerelease())
69-
return
70-
}
71-
72-
t.Logf("found %d builds for version %q", len(resp.Builds), preReleaseVersion)
73-
74-
t.Logf("looking for a build that does not match the current commit hash %q", startVersion.Binary.Commit)
75-
var upgradeVersionString string
76-
for _, buildID := range resp.Builds[1:] {
77-
details, err := aac.GetBuildDetails(ctx, preReleaseVersion, buildID)
78-
require.NoError(t, err)
79-
if details.Build.Projects[artifactElasticAgentProject].CommitHash != startVersion.Binary.Commit {
80-
upgradeVersionString = buildID
81-
break
82-
}
83-
t.Logf("build %q matches the current commit hash %q, skipping...", buildID, startVersion.Binary.Commit)
84-
}
85-
86-
if upgradeVersionString == "" {
61+
buildInfo, err := aac.FindBuild(ctx, preReleaseVersion, startVersion.Binary.Commit, 1)
62+
if errors.Is(err, tools.ErrBuildNotFound) {
8763
t.Skipf("there is no other build with a non-matching commit hash in the given version %s", latestSnapshotVersion.VersionWithPrerelease())
8864
return
8965
}
90-
91-
t.Logf("found build %q available for testing", upgradeVersionString)
92-
93-
buildFragments := strings.Split(upgradeVersionString, "-")
94-
require.Lenf(t, buildFragments, 2, "version %q returned by artifact api is not in format <version>-<buildID>", upgradeVersionString)
95-
endParsedVersion := version.NewParsedSemVer(
96-
latestSnapshotVersion.Major(),
97-
latestSnapshotVersion.Minor(),
98-
latestSnapshotVersion.Patch(),
99-
latestSnapshotVersion.Prerelease(),
100-
buildFragments[1],
101-
)
66+
require.NoError(t, err)
10267

10368
// Upgrade to the specific build.
69+
t.Logf("found build %q available for testing", buildInfo.Build.BuildID)
70+
endVersion := versionWithBuildID(t, latestSnapshotVersion, buildInfo.Build.BuildID)
10471
endFixture, err := atesting.NewFixture(
10572
t,
106-
endParsedVersion.String(),
73+
endVersion,
10774
atesting.WithFetcher(atesting.ArtifactFetcher()),
10875
)
10976
require.NoError(t, err)
11077

111-
t.Logf("Testing Elastic Agent upgrade from %s to %s...", define.Version(), endParsedVersion.String())
78+
t.Logf("Testing Elastic Agent upgrade from %s to %s...", define.Version(), endVersion)
11279

11380
// We pass the upgradetest.WithDisableUpgradeWatcherUpgradeDetailsCheck option here because the endFixture
11481
// is fetched from the artifacts API and it may not contain changes in the Upgrade Watcher whose effects are
@@ -117,3 +84,19 @@ func TestStandaloneDowngradeToSpecificSnapshotBuild(t *testing.T) {
11784
err = upgradetest.PerformUpgrade(ctx, startFixture, endFixture, t, upgradetest.WithDisableUpgradeWatcherUpgradeDetailsCheck())
11885
assert.NoError(t, err)
11986
}
87+
88+
// versionWithBuildID creates a new parsed version created from the given `initialVersion` with the given `buildID` as build metadata.
89+
func versionWithBuildID(t *testing.T, initialVersion *version.ParsedSemVer, buildID string) string {
90+
buildFragments := strings.Split(buildID, "-")
91+
require.Lenf(t, buildFragments, 2, "version %q returned by artifact api is not in format <version>-<buildID>", buildID)
92+
result := version.NewParsedSemVer(
93+
initialVersion.Major(),
94+
initialVersion.Minor(),
95+
initialVersion.Patch(),
96+
initialVersion.Prerelease(),
97+
buildFragments[1],
98+
)
99+
100+
return result.String()
101+
102+
}

testing/integration/upgrade_standalone_retry_test.go

+19-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package integration
88

99
import (
1010
"context"
11+
"errors"
1112
"fmt"
1213
"net"
1314
"net/http"
@@ -22,7 +23,9 @@ import (
2223

2324
atesting "github.com/elastic/elastic-agent/pkg/testing"
2425
"github.com/elastic/elastic-agent/pkg/testing/define"
26+
"github.com/elastic/elastic-agent/pkg/testing/tools"
2527
"github.com/elastic/elastic-agent/pkg/testing/tools/testcontext"
28+
"github.com/elastic/elastic-agent/pkg/version"
2629
"github.com/elastic/elastic-agent/testing/upgradetest"
2730
)
2831

@@ -38,13 +41,27 @@ func TestStandaloneUpgradeRetryDownload(t *testing.T) {
3841

3942
// Start at the build version as we want to test the retry
4043
// logic that is in the build.
44+
startVersion, err := version.ParseVersion(define.Version())
45+
require.NoError(t, err)
4146
startFixture, err := define.NewFixture(t, define.Version())
4247
require.NoError(t, err)
48+
startVersionInfo, err := startFixture.ExecVersion(ctx)
49+
require.NoError(t, err, "failed to get end agent build version info")
50+
51+
// Upgrade to an older snapshot build of same version but with a different commit hash
52+
aac := tools.NewArtifactAPIClient()
53+
buildInfo, err := aac.FindBuild(ctx, startVersion.VersionWithPrerelease(), startVersionInfo.Binary.Commit, 0)
54+
if errors.Is(err, tools.ErrBuildNotFound) {
55+
t.Skipf("there is no other build with a non-matching commit hash in the given version %s", define.Version())
56+
return
57+
}
58+
require.NoError(t, err)
4359

44-
// Upgrade to an older snapshot build of same version.
60+
t.Logf("found build %q available for testing", buildInfo.Build.BuildID)
61+
endVersion := versionWithBuildID(t, startVersion, buildInfo.Build.BuildID)
4562
endFixture, err := atesting.NewFixture(
4663
t,
47-
define.Version(),
64+
endVersion,
4865
atesting.WithFetcher(atesting.ArtifactFetcher()),
4966
)
5067
require.NoError(t, err)

testing/integration/upgrade_uninstall_test.go

+21-7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
atesting "github.com/elastic/elastic-agent/pkg/testing"
2222
"github.com/elastic/elastic-agent/pkg/testing/define"
23+
"github.com/elastic/elastic-agent/pkg/testing/tools"
2324
"github.com/elastic/elastic-agent/testing/upgradetest"
2425
)
2526

@@ -39,21 +40,34 @@ func TestStandaloneUpgradeUninstallKillWatcher(t *testing.T) {
3940
ctx, cancel := testcontext.WithDeadline(t, context.Background(), time.Now().Add(10*time.Minute))
4041
defer cancel()
4142

43+
// Upgrades to build under test.
44+
endVersion, err := version.ParseVersion(define.Version())
45+
require.NoError(t, err)
46+
endFixture, err := define.NewFixture(t, define.Version())
47+
require.NoError(t, err)
48+
endVersionInfo, err := endFixture.ExecVersion(ctx)
49+
require.NoError(t, err, "failed to get end agent build version info")
50+
4251
// Start on a snapshot build, we want this test to upgrade to our
4352
// build to ensure that the uninstall will kill the watcher.
53+
// We need a snapshot with a non-matching commit hash to perform the upgrade
54+
aac := tools.NewArtifactAPIClient()
55+
buildInfo, err := aac.FindBuild(ctx, endVersion.VersionWithPrerelease(), endVersionInfo.Binary.Commit, 0)
56+
if errors.Is(err, tools.ErrBuildNotFound) {
57+
t.Skipf("there is no other build with a non-matching commit hash in the given version %s", endVersion.VersionWithPrerelease())
58+
return
59+
}
60+
require.NoError(t, err)
61+
62+
t.Logf("found build %q available for testing", buildInfo.Build.BuildID)
63+
startVersion := versionWithBuildID(t, endVersion, buildInfo.Build.BuildID)
4464
startFixture, err := atesting.NewFixture(
4565
t,
46-
define.Version(),
66+
startVersion,
4767
atesting.WithFetcher(atesting.ArtifactFetcher()),
4868
)
4969
require.NoError(t, err)
5070

51-
// Upgrades to build under test.
52-
endFixture, err := define.NewFixture(t, define.Version())
53-
require.NoError(t, err)
54-
endVersionInfo, err := endFixture.ExecVersion(ctx)
55-
require.NoError(t, err, "failed to get end agent build version info")
56-
5771
// Use the post-upgrade hook to bypass the remainder of the PerformUpgrade
5872
// because we want to do our own checks for the rollback.
5973
var ErrPostExit = errors.New("post exit")

0 commit comments

Comments
 (0)