Skip to content

Commit 764a85f

Browse files
committed
add basic integration tests / update proto docs
1 parent bb278a5 commit 764a85f

File tree

5 files changed

+275
-10
lines changed

5 files changed

+275
-10
lines changed

models/fixtures/action_run.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,22 @@
1717
updated: 1683636626
1818
need_approval: 0
1919
approved_by: 0
20+
-
21+
id: 792
22+
title: "update actions"
23+
repo_id: 4
24+
owner_id: 1
25+
workflow_id: "artifact.yaml"
26+
index: 188
27+
trigger_user_id: 1
28+
ref: "refs/heads/master"
29+
commit_sha: "c2d72f548424103f01ee1dc02889c1e2bff816b0"
30+
event: "push"
31+
is_fork_pull_request: 0
32+
status: 1
33+
started: 1683636528
34+
stopped: 1683636626
35+
created: 1683636108
36+
updated: 1683636626
37+
need_approval: 0
38+
approved_by: 0

models/fixtures/action_run_job.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,17 @@
1212
status: 1
1313
started: 1683636528
1414
stopped: 1683636626
15+
-
16+
id: 193
17+
run_id: 792
18+
repo_id: 4
19+
owner_id: 1
20+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
21+
is_fork_pull_request: 0
22+
name: job_2
23+
attempt: 1
24+
job_id: job_2
25+
task_id: 48
26+
status: 1
27+
started: 1683636528
28+
stopped: 1683636626

models/fixtures/action_task.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,23 @@
1818
log_length: 707
1919
log_size: 90179
2020
log_expired: 0
21+
-
22+
id: 48
23+
job_id: 193
24+
attempt: 1
25+
runner_id: 1
26+
status: 6 # 6 is the status code for "running", running task can upload artifacts
27+
started: 1683636528
28+
stopped: 1683636626
29+
repo_id: 4
30+
owner_id: 1
31+
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
32+
is_fork_pull_request: 0
33+
token_hash: ffffcfffffffbffffffffffffffffefffffffafffffffffffffffffffffffffffffdffffffffffffffffffffffffffffffff
34+
token_salt: ffffffffff
35+
token_last_eight: ffffffff
36+
log_filename: artifact-test2/2f/47.log
37+
log_in_storage: 1
38+
log_length: 707
39+
log_size: 90179
40+
log_expired: 0

routers/api/actions/artifactsv4.go

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,80 @@
33

44
package actions
55

6-
// GitHub Actions Artifacts API Simple Description
6+
// GitHub Actions Artifacts V4 API Simple Description
77
//
88
// 1. Upload artifact
9-
// 1.1. Post upload url
9+
// 1.1. CreateArtifact
1010
// Post: /twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact
1111
// Request:
12-
// "{\"workflow_run_backend_id\":\"21\",\"workflow_job_run_backend_id\":\"49\",\"name\":\"test\",\"version\":4}"
12+
// {
13+
// "workflow_run_backend_id": "21",
14+
// "workflow_job_run_backend_id": "49",
15+
// "name": "test",
16+
// "version": 4
17+
// }
1318
// Response:
14-
// "{\"ok\":true,\"signedUploadUrl\":\"http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75\"}"
19+
// {
20+
// "ok": true,
21+
// "signedUploadUrl": "http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75"
22+
// }
23+
// 1.2. Upload Zip Content to Blobstorage (unauthenticated request)
24+
// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=block
25+
// 1.3. Continue Upload Zip Content to Blobstorage (unauthenticated request), repeat until everything is uploaded
26+
// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=appendBlock
27+
// 1.4. Unknown xml payload to Blobstorage (unauthenticated request), ignored for now
28+
// PUT: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact?sig=mO7y35r4GyjN7fwg0DTv3-Fv1NDXD84KLEgLpoPOtDI=&expires=2024-01-23+21%3A48%3A37.20833956+%2B0100+CET&artifactName=test&taskID=75&comp=blockList
29+
// 1.5. FinalizeArtifact
1530
// Post: /twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact
1631
// Request
17-
// "{\"workflow_run_backend_id\":\"21\",\"workflow_job_run_backend_id\":\"49\",\"name\":\"test\",\"size\":\"2097\",\"hash\":\"sha256:b6325614d5649338b87215d9536b3c0477729b8638994c74cdefacb020a2cad4\"}"
32+
// {
33+
// "workflow_run_backend_id": "21",
34+
// "workflow_job_run_backend_id": "49",
35+
// "name": "test",
36+
// "size": "2097",
37+
// "hash": "sha256:b6325614d5649338b87215d9536b3c0477729b8638994c74cdefacb020a2cad4"
38+
// }
1839
// Response
19-
// "{\"ok\":true,\"artifactId\":\"4\"}"
40+
// {
41+
// "ok": true,
42+
// "artifactId": "4"
43+
// }
44+
// 2. Download artifact
45+
// 2.1. ListArtifacts and optionally filter by artifact exact name or id
2046
// Post: /twirp/github.actions.results.api.v1.ArtifactService/ListArtifacts
2147
// Request
22-
// "{\"workflow_run_backend_id\":\"21\",\"workflow_job_run_backend_id\":\"49\",\"name_filter\":\"test\"}"
48+
// {
49+
// "workflow_run_backend_id": "21",
50+
// "workflow_job_run_backend_id": "49",
51+
// "name_filter": "test"
52+
// }
2353
// Response
24-
// "{\"artifacts\":[{\"workflowRunBackendId\":\"21\",\"workflowJobRunBackendId\":\"49\",\"databaseId\":\"4\",\"name\":\"test\",\"size\":\"2093\",\"createdAt\":\"2024-01-23T00:13:28Z\"}]}"
54+
// {
55+
// "artifacts": [
56+
// {
57+
// "workflowRunBackendId": "21",
58+
// "workflowJobRunBackendId": "49",
59+
// "databaseId": "4",
60+
// "name": "test",
61+
// "size": "2093",
62+
// "createdAt": "2024-01-23T00:13:28Z"
63+
// }
64+
// ]
65+
// }
66+
// 2.2. GetSignedArtifactURL get the URL to download the artifact zip file of a specfic artifact
2567
// Post: /twirp/github.actions.results.api.v1.ArtifactService/GetSignedArtifactURL
2668
// Request
27-
// "{\"workflow_run_backend_id\":\"21\",\"workflow_job_run_backend_id\":\"49\",\"name\":\"test\"}"
69+
// {
70+
// "workflow_run_backend_id": "21",
71+
// "workflow_job_run_backend_id": "49",
72+
// "name": "test"
73+
// }
2874
// Response
29-
// "{\"signedUrl\":\"http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/DownloadArtifact?sig=wHzFOwpF-6220-5CA0CIRmAX9VbiTC2Mji89UOqo1E8=&expires=2024-01-23+21%3A51%3A56.872846295+%2B0100+CET&artifactName=test&taskID=76\"}"
75+
// {
76+
// "signedUrl": "http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/DownloadArtifact?sig=wHzFOwpF-6220-5CA0CIRmAX9VbiTC2Mji89UOqo1E8=&expires=2024-01-23+21%3A51%3A56.872846295+%2B0100+CET&artifactName=test&taskID=76"
77+
// }
78+
// 2.3. Download Zip from Blobstorage (unauthenticated request)
79+
// GET: http://localhost:3000/twirp/github.actions.results.api.v1.ArtifactService/DownloadArtifact?sig=wHzFOwpF-6220-5CA0CIRmAX9VbiTC2Mji89UOqo1E8=&expires=2024-01-23+21%3A51%3A56.872846295+%2B0100+CET&artifactName=test&taskID=76
3080

3181
import (
3282
"crypto/hmac"
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package integration
5+
6+
import (
7+
"bytes"
8+
"crypto/sha256"
9+
"encoding/hex"
10+
"io"
11+
"net/http"
12+
"strings"
13+
"testing"
14+
"time"
15+
16+
"code.gitea.io/gitea/routers/api/actions"
17+
actions_service "code.gitea.io/gitea/services/actions"
18+
"code.gitea.io/gitea/tests"
19+
"google.golang.org/protobuf/encoding/protojson"
20+
"google.golang.org/protobuf/reflect/protoreflect"
21+
"google.golang.org/protobuf/types/known/timestamppb"
22+
"google.golang.org/protobuf/types/known/wrapperspb"
23+
24+
"github.com/stretchr/testify/assert"
25+
)
26+
27+
func toProtoJson(m protoreflect.ProtoMessage) io.Reader {
28+
resp, _ := protojson.Marshal(m)
29+
buf := bytes.Buffer{}
30+
buf.Write(resp)
31+
return &buf
32+
}
33+
34+
func TestActionsArtifactV4UploadSingleFile(t *testing.T) {
35+
defer tests.PrepareTestEnv(t)()
36+
37+
token, err := actions_service.CreateAuthorizationToken(48, 792, 193)
38+
assert.NoError(t, err)
39+
40+
// acquire artifact upload url
41+
req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact", toProtoJson(&actions.CreateArtifactRequest{
42+
Version: 4,
43+
Name: "artifact",
44+
WorkflowRunBackendId: "792",
45+
WorkflowJobRunBackendId: "193",
46+
})).AddTokenAuth(token)
47+
resp := MakeRequest(t, req, http.StatusOK)
48+
var uploadResp actions.CreateArtifactResponse
49+
protojson.Unmarshal(resp.Body.Bytes(), &uploadResp)
50+
assert.True(t, uploadResp.Ok)
51+
assert.Contains(t, uploadResp.SignedUploadUrl, "/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact")
52+
53+
// get upload url
54+
idx := strings.Index(uploadResp.SignedUploadUrl, "/twirp/")
55+
url := uploadResp.SignedUploadUrl[idx:] + "&comp=block"
56+
57+
// upload artifact chunk
58+
body := strings.Repeat("A", 1024)
59+
req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body))
60+
MakeRequest(t, req, http.StatusCreated)
61+
62+
t.Logf("Create artifact confirm")
63+
64+
sha := sha256.Sum256([]byte(body))
65+
66+
// confirm artifact upload
67+
req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact", toProtoJson(&actions.FinalizeArtifactRequest{
68+
Name: "artifact",
69+
Size: 1024,
70+
Hash: wrapperspb.String("sha256:" + hex.EncodeToString(sha[:])),
71+
WorkflowRunBackendId: "792",
72+
WorkflowJobRunBackendId: "193",
73+
})).
74+
AddTokenAuth(token)
75+
resp = MakeRequest(t, req, http.StatusOK)
76+
var finalizeResp actions.FinalizeArtifactResponse
77+
protojson.Unmarshal(resp.Body.Bytes(), &finalizeResp)
78+
assert.True(t, finalizeResp.Ok)
79+
}
80+
81+
func TestActionsArtifactV4UploadSingleFileWithRetentionDays(t *testing.T) {
82+
defer tests.PrepareTestEnv(t)()
83+
84+
token, err := actions_service.CreateAuthorizationToken(48, 792, 193)
85+
assert.NoError(t, err)
86+
87+
// acquire artifact upload url
88+
req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/CreateArtifact", toProtoJson(&actions.CreateArtifactRequest{
89+
Version: 4,
90+
ExpiresAt: timestamppb.New(time.Now().Add(5 * 24 * time.Hour)),
91+
Name: "artifactWithRetentionDays",
92+
WorkflowRunBackendId: "792",
93+
WorkflowJobRunBackendId: "193",
94+
})).AddTokenAuth(token)
95+
resp := MakeRequest(t, req, http.StatusOK)
96+
var uploadResp actions.CreateArtifactResponse
97+
protojson.Unmarshal(resp.Body.Bytes(), &uploadResp)
98+
assert.True(t, uploadResp.Ok)
99+
assert.Contains(t, uploadResp.SignedUploadUrl, "/twirp/github.actions.results.api.v1.ArtifactService/UploadArtifact")
100+
101+
// get upload url
102+
idx := strings.Index(uploadResp.SignedUploadUrl, "/twirp/")
103+
url := uploadResp.SignedUploadUrl[idx:] + "&comp=block"
104+
105+
// upload artifact chunk
106+
body := strings.Repeat("A", 1024)
107+
req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body))
108+
MakeRequest(t, req, http.StatusCreated)
109+
110+
t.Logf("Create artifact confirm")
111+
112+
sha := sha256.Sum256([]byte(body))
113+
114+
// confirm artifact upload
115+
req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/FinalizeArtifact", toProtoJson(&actions.FinalizeArtifactRequest{
116+
Name: "artifactWithRetentionDays",
117+
Size: 1024,
118+
Hash: wrapperspb.String("sha256:" + hex.EncodeToString(sha[:])),
119+
WorkflowRunBackendId: "792",
120+
WorkflowJobRunBackendId: "193",
121+
})).
122+
AddTokenAuth(token)
123+
resp = MakeRequest(t, req, http.StatusOK)
124+
var finalizeResp actions.FinalizeArtifactResponse
125+
protojson.Unmarshal(resp.Body.Bytes(), &finalizeResp)
126+
assert.True(t, finalizeResp.Ok)
127+
}
128+
129+
func TestActionsArtifactV4DownloadSingle(t *testing.T) {
130+
defer tests.PrepareTestEnv(t)()
131+
132+
token, err := actions_service.CreateAuthorizationToken(48, 792, 193)
133+
assert.NoError(t, err)
134+
135+
// acquire artifact upload url
136+
req := NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/ListArtifacts", toProtoJson(&actions.ListArtifactsRequest{
137+
NameFilter: wrapperspb.String("artifact"),
138+
WorkflowRunBackendId: "792",
139+
WorkflowJobRunBackendId: "193",
140+
})).AddTokenAuth(token)
141+
resp := MakeRequest(t, req, http.StatusOK)
142+
var listResp actions.ListArtifactsResponse
143+
protojson.Unmarshal(resp.Body.Bytes(), &listResp)
144+
assert.Len(t, listResp.Artifacts, 1)
145+
146+
// confirm artifact upload
147+
req = NewRequestWithBody(t, "POST", "/twirp/github.actions.results.api.v1.ArtifactService/GetSignedArtifactURL", toProtoJson(&actions.GetSignedArtifactURLRequest{
148+
Name: "artifact",
149+
WorkflowRunBackendId: "792",
150+
WorkflowJobRunBackendId: "193",
151+
})).
152+
AddTokenAuth(token)
153+
resp = MakeRequest(t, req, http.StatusOK)
154+
var finalizeResp actions.GetSignedArtifactURLResponse
155+
protojson.Unmarshal(resp.Body.Bytes(), &finalizeResp)
156+
assert.NotEmpty(t, finalizeResp.SignedUrl)
157+
158+
req = NewRequest(t, "GET", finalizeResp.SignedUrl)
159+
resp = MakeRequest(t, req, http.StatusOK)
160+
body := strings.Repeat("A", 1024)
161+
assert.Equal(t, resp.Body.String(), body)
162+
}

0 commit comments

Comments
 (0)