Skip to content
This repository was archived by the owner on Sep 17, 2024. It is now read-only.

Commit 71d349d

Browse files
authored
fix: properly calculate GCP storage bucket URIs for PRs and snapshots (#602) (#603)
* fix: search artifacts from the right folder There is a bucket for snapshots and another for pull-requests * fix: properly calculate GCP bucket URL for snapshots and PRs * chore: include unit tests in the CI * fix: wrong copy paste
1 parent e9d810c commit 71d349d

File tree

10 files changed

+38696
-40
lines changed

10 files changed

+38696
-40
lines changed

.ci/Jenkinsfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,8 @@ pipeline {
135135
}
136136
post {
137137
always {
138-
junit(allowEmptyResults: true, keepLongStdio: true, testResults: "${BASE_DIR}/outputs/TEST-unit.xml")
139-
archiveArtifacts allowEmptyArchive: true, artifacts: "${BASE_DIR}/outputs/TEST-unit.xml"
138+
junit(allowEmptyResults: true, keepLongStdio: true, testResults: "${BASE_DIR}/outputs/TEST-unit-*.xml")
139+
archiveArtifacts allowEmptyArchive: true, artifacts: "${BASE_DIR}/outputs/TEST-unit-*.xml"
140140
}
141141
}
142142
}

.ci/scripts/build-test.sh

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,7 @@ mkdir -p $(pwd)/outputs
1515
go get -v -u gotest.tools/gotestsum
1616

1717
# See https://pkg.go.dev/gotest.tools/gotestsum/#readme-junit-xml-output
18-
GOTESTSUM_JUNITFILE="$(pwd)/outputs/TEST-unit.xml" make -C cli install test
18+
GOTESTSUM_JUNITFILE="$(pwd)/outputs/TEST-unit-cli.xml" make -C cli install test
19+
20+
# See https://pkg.go.dev/gotest.tools/gotestsum/#readme-junit-xml-output
21+
GOTESTSUM_JUNITFILE="$(pwd)/outputs/TEST-unit-e2e.xml" make -C e2e unit-test

e2e/Makefile

+6
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ GO_IMAGE_TAG?='stretch'
3131
GOOS?='linux'
3232
GOARCH?='amd64'
3333

34+
TEST_TIMEOUT?=5m
35+
3436
.PHONT: build-docs
3537
build-docs:
3638
rm -fr docs
@@ -84,3 +86,7 @@ notice:
8486
.PHONY: sync-integrations
8587
sync-integrations:
8688
OP_LOG_LEVEL=${LOG_LEVEL} ./op sync integrations --delete
89+
90+
.PHONY: unit-test
91+
unit-test:
92+
gotestsum --format testname -- -count=1 -timeout=$(TEST_TIMEOUT) ./...

e2e/_suites/fleet/services.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,13 @@ func downloadAgentBinary(artifact string, version string, OS string, arch string
197197
log.Debug("Using CI snapshots for the Elastic Agent")
198198

199199
// We will use the snapshots produced by Beats CI
200+
if extension == "tar.gz" {
201+
fileName = fmt.Sprintf("%s-%s-%s-%s.%s", artifact, version, OS, arch, extension)
202+
}
203+
200204
bucket := "beats-ci-artifacts"
201-
object := fmt.Sprintf("snapshots/%s/%s", artifact, fileName)
205+
prefix := fmt.Sprintf("snapshots/%s", artifact)
206+
object := fileName
202207

203208
// we are setting a version from a pull request: the version of the artifact will be kept as the base one
204209
// i.e. /pull-requests/pr-21100/elastic-agent/elastic-agent-7.x-SNAPSHOT-x86_64.rpm
@@ -213,12 +218,13 @@ func downloadAgentBinary(artifact string, version string, OS string, arch string
213218
"agentVersion": agentVersionBase,
214219
"PR": version,
215220
}).Debug("Using CI snapshots for a pull request")
216-
object = fmt.Sprintf("pull-requests/%s/%s/%s", version, artifact, fileName)
221+
prefix = fmt.Sprintf("pull-requests/%s", version)
222+
object = fmt.Sprintf("%s/%s", artifact, fileName)
217223
}
218224

219225
maxTimeout := time.Duration(timeoutFactor) * time.Minute
220226

221-
downloadURL, err = e2e.GetObjectURLFromBucket(bucket, object, maxTimeout)
227+
downloadURL, err = e2e.GetObjectURLFromBucket(bucket, prefix, object, maxTimeout)
222228
if err != nil {
223229
return "", "", err
224230
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"kind": "storage#objects",
3+
"nextPageToken": "foo"
4+
}

e2e/_testresources/gcp/pull-requests.json

+19,268
Large diffs are not rendered by default.

e2e/_testresources/gcp/snapshots.json

+19,258
Large diffs are not rendered by default.

e2e/go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ require (
1616
github.com/pkg/errors v0.9.1
1717
github.com/sirupsen/logrus v1.4.2
1818
github.com/spf13/cobra v1.1.1 // indirect
19+
github.com/stretchr/testify v1.6.1
1920
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
2021
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
2122
)

e2e/utils.go

+58-34
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ func GetElasticArtifactURL(artifact string, version string, operativeSystem stri
211211

212212
// GetObjectURLFromBucket extracts the media URL for the desired artifact from the
213213
// Google Cloud Storage bucket used by the CI to push snapshots
214-
func GetObjectURLFromBucket(bucket string, object string, maxtimeout time.Duration) (string, error) {
214+
func GetObjectURLFromBucket(bucket string, prefix string, object string, maxtimeout time.Duration) (string, error) {
215215
exp := GetExponentialBackOff(maxtimeout)
216216

217217
retryCount := 1
@@ -222,14 +222,15 @@ func GetObjectURLFromBucket(bucket string, object string, maxtimeout time.Durati
222222

223223
storageAPI := func() error {
224224
r := curl.HTTPRequest{
225-
URL: fmt.Sprintf("https://storage.googleapis.com/storage/v1/b/%s/o?prefix=pull-requests%s", bucket, pageTokenQueryParam),
225+
URL: fmt.Sprintf("https://storage.googleapis.com/storage/v1/b/%s/o?prefix=%s%s", bucket, prefix, pageTokenQueryParam),
226226
}
227227

228228
response, err := curl.Get(r)
229229
if err != nil {
230230
log.WithFields(log.Fields{
231231
"bucket": bucket,
232232
"elapsedTime": exp.GetElapsedTime(),
233+
"prefix": prefix,
233234
"error": err,
234235
"object": object,
235236
"retry": retryCount,
@@ -243,6 +244,7 @@ func GetObjectURLFromBucket(bucket string, object string, maxtimeout time.Durati
243244
log.WithFields(log.Fields{
244245
"bucket": bucket,
245246
"elapsedTime": exp.GetElapsedTime(),
247+
"prefix": prefix,
246248
"object": object,
247249
"retries": retryCount,
248250
"url": r.URL,
@@ -252,6 +254,7 @@ func GetObjectURLFromBucket(bucket string, object string, maxtimeout time.Durati
252254
if err != nil {
253255
log.WithFields(log.Fields{
254256
"bucket": bucket,
257+
"prefix": prefix,
255258
"object": object,
256259
}).Warn("Could not parse the response body for the object")
257260

@@ -260,71 +263,58 @@ func GetObjectURLFromBucket(bucket string, object string, maxtimeout time.Durati
260263
return err
261264
}
262265

263-
items := jsonParsed.Path("items").Children()
264-
265-
log.WithFields(log.Fields{
266-
"bucket": bucket,
267-
"elapsedTime": exp.GetElapsedTime(),
268-
"objects": len(items),
269-
"retries": retryCount,
270-
}).Debug("Objects found")
271-
272-
for _, item := range items {
273-
itemID := item.Path("id").Data().(string)
274-
objectPath := bucket + "/" + object + "/"
275-
if strings.HasPrefix(itemID, objectPath) {
276-
mediaLink = item.Path("mediaLink").Data().(string)
277-
278-
log.WithFields(log.Fields{
279-
"bucket": bucket,
280-
"elapsedTime": exp.GetElapsedTime(),
281-
"medialink": mediaLink,
282-
"object": object,
283-
"retries": retryCount,
284-
}).Debug("Media link found for the object")
285-
return nil
286-
}
287-
266+
mediaLink, err = processBucketSearchPage(jsonParsed, currentPage, bucket, prefix, object)
267+
if err != nil {
268+
log.WithFields(log.Fields{
269+
"currentPage": currentPage,
270+
"bucket": bucket,
271+
"prefix": prefix,
272+
"object": object,
273+
}).Warn(err.Error())
274+
} else if mediaLink != "" {
288275
log.WithFields(log.Fields{
289276
"bucket": bucket,
290277
"elapsedTime": exp.GetElapsedTime(),
278+
"prefix": prefix,
279+
"medialink": mediaLink,
291280
"object": object,
292-
"itemID": itemID,
293281
"retries": retryCount,
294-
}).Trace("Media link not found")
282+
}).Debug("Media link found for the object")
283+
return nil
295284
}
296285

297-
if jsonParsed.Path("nextPageToken") == nil {
286+
pageTokenQueryParam = getBucketSearchNextPageParam(jsonParsed)
287+
if pageTokenQueryParam == "" {
298288
log.WithFields(log.Fields{
299289
"currentPage": currentPage,
300290
"bucket": bucket,
291+
"prefix": prefix,
301292
"object": object,
302293
}).Warn("Reached the end of the pages and the object was not found")
303294

304295
return nil
305296
}
306297

307-
nextPageToken := jsonParsed.Path("nextPageToken").Data().(string)
308-
pageTokenQueryParam = "&pageToken=" + nextPageToken
309298
currentPage++
310299

311300
log.WithFields(log.Fields{
312301
"currentPage": currentPage,
313302
"bucket": bucket,
314303
"elapsedTime": exp.GetElapsedTime(),
304+
"prefix": prefix,
315305
"object": object,
316306
"retries": retryCount,
317307
}).Warn("Object not found in current page. Continuing")
318308

319-
return fmt.Errorf("The %s object could not be found in the current page (%d) the %s bucket", object, currentPage, bucket)
309+
return fmt.Errorf("The %s object could not be found in the current page (%d) the %s bucket and %s prefix", object, currentPage, bucket, prefix)
320310
}
321311

322312
err := backoff.Retry(storageAPI, exp)
323313
if err != nil {
324314
return "", err
325315
}
326316
if mediaLink == "" {
327-
return "", fmt.Errorf("Reached the end of the pages and the %s object was not found for the %s bucket", object, bucket)
317+
return "", fmt.Errorf("Reached the end of the pages and the %s object was not found for the %s bucket and %s prefix", object, bucket, prefix)
328318
}
329319

330320
return mediaLink, nil
@@ -406,6 +396,40 @@ func DownloadFile(url string) (string, error) {
406396
return filepath, nil
407397
}
408398

399+
func getBucketSearchNextPageParam(jsonParsed *gabs.Container) string {
400+
token := jsonParsed.Path("nextPageToken")
401+
if token == nil {
402+
return ""
403+
}
404+
405+
nextPageToken := token.Data().(string)
406+
return "&pageToken=" + nextPageToken
407+
}
408+
409+
func processBucketSearchPage(jsonParsed *gabs.Container, currentPage int, bucket string, prefix string, object string) (string, error) {
410+
items := jsonParsed.Path("items").Children()
411+
412+
log.WithFields(log.Fields{
413+
"bucket": bucket,
414+
"prefix": prefix,
415+
"objects": len(items),
416+
"object": object,
417+
}).Debug("Objects found")
418+
419+
for _, item := range items {
420+
itemID := item.Path("id").Data().(string)
421+
objectPath := bucket + "/" + prefix + "/" + object + "/"
422+
if strings.HasPrefix(itemID, objectPath) {
423+
mediaLink := item.Path("mediaLink").Data().(string)
424+
425+
log.Infof("medialink: %s", mediaLink)
426+
return mediaLink, nil
427+
}
428+
}
429+
430+
return "", fmt.Errorf("The %s object could not be found in the current page (%d) in the %s bucket and %s prefix", object, currentPage, bucket, prefix)
431+
}
432+
409433
//nolint:unused
410434
func randomStringWithCharset(length int, charset string) string {
411435
b := make([]byte, length)

e2e/utils_test.go

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package e2e
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
10+
gabs "github.com/Jeffail/gabs/v2"
11+
)
12+
13+
const bucket = "beats-ci-artifacts"
14+
const pullRequests = "pull-requests"
15+
const snapshots = "snapshots"
16+
17+
var nextTokenParamJSON *gabs.Container
18+
var pullRequestsJSON *gabs.Container
19+
var snapshotsJSON *gabs.Container
20+
21+
func init() {
22+
nextTokenParamContent, err := ioutil.ReadFile("_testresources/gcp/nextPageParam.json")
23+
if err != nil {
24+
os.Exit(1)
25+
}
26+
nextTokenParamJSON, _ = gabs.ParseJSON([]byte(nextTokenParamContent))
27+
28+
pullRequestsContent, err := ioutil.ReadFile("_testresources/gcp/pull-requests.json")
29+
if err != nil {
30+
os.Exit(1)
31+
}
32+
pullRequestsJSON, _ = gabs.ParseJSON([]byte(pullRequestsContent))
33+
34+
snapshotsContent, err := ioutil.ReadFile("_testresources/gcp/snapshots.json")
35+
if err != nil {
36+
os.Exit(1)
37+
}
38+
snapshotsJSON, _ = gabs.ParseJSON([]byte(snapshotsContent))
39+
}
40+
41+
func TestGetBucketSearchNextPageParam_HasMorePages(t *testing.T) {
42+
expectedParam := "&pageToken=foo"
43+
44+
param := getBucketSearchNextPageParam(nextTokenParamJSON)
45+
assert.True(t, param == expectedParam)
46+
}
47+
48+
func TestGetBucketSearchNextPageParam_HasNoMorePages(t *testing.T) {
49+
// this JSON file does not contain the tokken field
50+
param := getBucketSearchNextPageParam(pullRequestsJSON)
51+
assert.True(t, param == "")
52+
}
53+
54+
func TestProcessBucketSearchPage_PullRequestsFound(t *testing.T) {
55+
// retrieving last element in pull-requests.json
56+
object := "pr-22495/filebeat/filebeat-8.0.0-SNAPSHOT-linux-amd64.docker.tar.gz"
57+
58+
mediaLink, err := processBucketSearchPage(pullRequestsJSON, 1, bucket, pullRequests, object)
59+
assert.Nil(t, err)
60+
assert.True(t, mediaLink == "https://storage.googleapis.com/download/storage/v1/b/beats-ci-artifacts/o/pull-requests%2Fpr-22495%2Ffilebeat%2Ffilebeat-8.0.0-SNAPSHOT-linux-amd64.docker.tar.gz?generation=1610634841693588&alt=media")
61+
}
62+
63+
func TestProcessBucketSearchPage_PullRequestsNotFound(t *testing.T) {
64+
object := "pr-fooo/filebeat/filebeat-8.0.0-SNAPSHOT-linux-amd64.docker.tar.gz"
65+
66+
mediaLink, err := processBucketSearchPage(pullRequestsJSON, 1, bucket, pullRequests, object)
67+
assert.NotNil(t, err)
68+
assert.True(t, mediaLink == "")
69+
}
70+
71+
func TestProcessBucketSearchPage_SnapshotsFound(t *testing.T) {
72+
// retrieving last element in snapshots.json
73+
object := "filebeat/filebeat-oss-7.10.2-SNAPSHOT-arm64.deb"
74+
75+
mediaLink, err := processBucketSearchPage(snapshotsJSON, 1, bucket, snapshots, object)
76+
assert.Nil(t, err)
77+
assert.True(t, mediaLink == "https://storage.googleapis.com/download/storage/v1/b/beats-ci-artifacts/o/snapshots%2Ffilebeat%2Ffilebeat-oss-7.10.2-SNAPSHOT-arm64.deb?generation=1610629747796392&alt=media")
78+
}
79+
80+
func TestProcessBucketSearchPage_SnapshotsNotFound(t *testing.T) {
81+
object := "filebeat/filebeat-oss-7.12.2-SNAPSHOT-arm64.deb"
82+
83+
mediaLink, err := processBucketSearchPage(snapshotsJSON, 1, bucket, snapshots, object)
84+
assert.NotNil(t, err)
85+
assert.True(t, mediaLink == "")
86+
}

0 commit comments

Comments
 (0)