feat: artifacts client
All checks were successful
default / ensure tests work (push) Successful in 28s
All checks were successful
default / ensure tests work (push) Successful in 28s
This commit is contained in:
parent
24ad00274d
commit
0f40c0b375
1 changed files with 1160 additions and 6 deletions
114
artifact/e2e_test.go
Normal file
114
artifact/e2e_test.go
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
package artifact
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TestE2E_ArtifactRoundTrip exercises the real results service. It only runs
|
||||
// inside a CI pipeline (GITHUB_ACTIONS=true) and is skipped locally so that
|
||||
// `go test ./...` stays hermetic. Its purpose is to detect drift between the
|
||||
// results service the runner talks to and the API this client expects.
|
||||
func TestE2E_ArtifactRoundTrip(t *testing.T) {
|
||||
if os.Getenv("GITHUB_ACTIONS") != "true" {
|
||||
t.Skip("e2e test only runs in CI")
|
||||
}
|
||||
|
||||
resultsURL := os.Getenv("ACTIONS_RESULTS_URL")
|
||||
runtimeToken := os.Getenv("ACTIONS_RUNTIME_TOKEN")
|
||||
if resultsURL == "" || runtimeToken == "" {
|
||||
t.Skip("ACTIONS_RESULTS_URL and ACTIONS_RUNTIME_TOKEN are required")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
||||
defer cancel()
|
||||
|
||||
run, job, err := JobInfo()
|
||||
if err != nil {
|
||||
t.Fatalf("JobInfo: %v", err)
|
||||
}
|
||||
|
||||
client := NewClient(resultsURL, runtimeToken)
|
||||
name := fmt.Sprintf("e2e-%d-%d", os.Getpid(), time.Now().UnixNano())
|
||||
|
||||
expire := time.Now().Add(1 * time.Hour)
|
||||
create, err := client.CreateArtifact(ctx, CreateArtifactRequest{
|
||||
RunID: run,
|
||||
JobRunID: job,
|
||||
Name: name,
|
||||
Version: 4,
|
||||
ExpiresAt: &expire,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateArtifact: %v", err)
|
||||
}
|
||||
if !create.Ok {
|
||||
t.Fatalf("CreateArtifact not ok: %+v", create)
|
||||
}
|
||||
|
||||
t.Cleanup(func() {
|
||||
if _, err := client.DeleteArtifact(context.Background(), DeleteArtifactRequest{RunID: run, JobRunID: job, Name: name}); err != nil {
|
||||
t.Logf("cleanup DeleteArtifact: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
content := []byte("artifact e2e " + name)
|
||||
pushed, err := PushBlob(ctx, nil, bytes.NewReader(content), create.SignedUploadUrl, 0, 0)
|
||||
if err != nil {
|
||||
t.Fatalf("PushBlob: %v", err)
|
||||
}
|
||||
|
||||
finalize, err := client.FinalizeArtifact(ctx, FinalizeArtifactRequest{
|
||||
RunID: run,
|
||||
JobRunID: job,
|
||||
Name: name,
|
||||
Size: pushed.Size,
|
||||
Hash: pushed.SHA256Sum,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("FinalizeArtifact: %v", err)
|
||||
}
|
||||
if !finalize.Ok {
|
||||
t.Fatalf("FinalizeArtifact not ok: %+v", finalize)
|
||||
}
|
||||
|
||||
signed := getSignedArtifactURL(t, ctx, client, run, job, name)
|
||||
|
||||
var buf bytes.Buffer
|
||||
pulled, err := PullBlob(ctx, nil, &buf, signed.SignedUrl)
|
||||
if err != nil {
|
||||
t.Fatalf("PullBlob: %v", err)
|
||||
}
|
||||
if !bytes.Equal(buf.Bytes(), content) {
|
||||
t.Errorf("round trip mismatch: got %q want %q", buf.String(), content)
|
||||
}
|
||||
if pulled.SHA256Sum != pushed.SHA256Sum {
|
||||
t.Errorf("hash mismatch: got %q want %q", pulled.SHA256Sum, pushed.SHA256Sum)
|
||||
}
|
||||
}
|
||||
|
||||
// getSignedArtifactURL retries briefly because a freshly finalized artifact may
|
||||
// not be signed yet.
|
||||
func getSignedArtifactURL(t *testing.T, ctx context.Context, client *Client, run, job, name string) *GetSignedArtifactURLResponse {
|
||||
t.Helper()
|
||||
|
||||
var lastErr error
|
||||
for attempt := 0; attempt < 5; attempt++ {
|
||||
signed, err := client.GetSignedArtifactURL(ctx, GetSignedArtifactURLRequest{RunID: run, JobRunID: job, Name: name})
|
||||
if err == nil && signed.SignedUrl != "" {
|
||||
return signed
|
||||
}
|
||||
lastErr = err
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
t.Fatalf("GetSignedArtifactURL: %v", ctx.Err())
|
||||
case <-time.After(time.Duration(attempt+1) * time.Second):
|
||||
}
|
||||
}
|
||||
t.Fatalf("GetSignedArtifactURL: %v", lastErr)
|
||||
return nil
|
||||
}
|
||||
Loading…
Reference in a new issue