loading up the forgejo repo on tangled to test page performance
at forgejo 395 lines 15 kB view raw
1// Copyright 2023 The Gitea Authors. All rights reserved. 2// SPDX-License-Identifier: MIT 3 4package integration 5 6import ( 7 "net/http" 8 "strings" 9 "testing" 10 11 "forgejo.org/tests" 12 13 "github.com/stretchr/testify/assert" 14) 15 16type uploadArtifactResponse struct { 17 FileContainerResourceURL string `json:"fileContainerResourceUrl"` 18} 19 20type getUploadArtifactRequest struct { 21 Type string 22 Name string 23 RetentionDays int64 24} 25 26func prepareTestEnvActionsArtifacts(t *testing.T) func() { 27 t.Helper() 28 f := tests.PrepareTestEnv(t, 1) 29 tests.PrepareArtifactsStorage(t) 30 return f 31} 32 33func TestActionsArtifactUploadSingleFile(t *testing.T) { 34 defer prepareTestEnvActionsArtifacts(t)() 35 36 // acquire artifact upload url 37 req := NewRequestWithJSON(t, "POST", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts", getUploadArtifactRequest{ 38 Type: "actions_storage", 39 Name: "artifact", 40 }).AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 41 resp := MakeRequest(t, req, http.StatusOK) 42 var uploadResp uploadArtifactResponse 43 DecodeJSON(t, resp, &uploadResp) 44 assert.Contains(t, uploadResp.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts") 45 46 // get upload url 47 idx := strings.Index(uploadResp.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/") 48 url := uploadResp.FileContainerResourceURL[idx:] + "?itemPath=artifact/abc-2.txt" 49 50 // upload artifact chunk 51 body := strings.Repeat("C", 1024) 52 req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body)). 53 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a"). 54 SetHeader("Content-Range", "bytes 0-1023/1024"). 55 SetHeader("x-tfs-filelength", "1024"). 56 SetHeader("x-actions-results-md5", "XVlf820rMInUi64wmMi6EA==") // base64(md5(body)) 57 MakeRequest(t, req, http.StatusOK) 58 59 t.Logf("Create artifact confirm") 60 61 // confirm artifact upload 62 req = NewRequest(t, "PATCH", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts?artifactName=artifact-single"). 63 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 64 MakeRequest(t, req, http.StatusOK) 65} 66 67func TestActionsArtifactUploadInvalidHash(t *testing.T) { 68 defer prepareTestEnvActionsArtifacts(t)() 69 70 // artifact id 54321 not exist 71 url := "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts/8e5b948a454515dbabfc7eb718ddddddd/upload?itemPath=artifact/abc.txt" 72 body := strings.Repeat("A", 1024) 73 req := NewRequestWithBody(t, "PUT", url, strings.NewReader(body)). 74 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a"). 75 SetHeader("Content-Range", "bytes 0-1023/1024"). 76 SetHeader("x-tfs-filelength", "1024"). 77 SetHeader("x-actions-results-md5", "1HsSe8LeLWh93ILaw1TEFQ==") // base64(md5(body)) 78 resp := MakeRequest(t, req, http.StatusBadRequest) 79 assert.Contains(t, resp.Body.String(), "Invalid artifact hash") 80} 81 82func TestActionsArtifactConfirmUploadWithoutName(t *testing.T) { 83 defer prepareTestEnvActionsArtifacts(t)() 84 85 req := NewRequest(t, "PATCH", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts"). 86 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 87 resp := MakeRequest(t, req, http.StatusBadRequest) 88 assert.Contains(t, resp.Body.String(), "artifact name is empty") 89} 90 91func TestActionsArtifactUploadWithoutToken(t *testing.T) { 92 defer prepareTestEnvActionsArtifacts(t)() 93 94 req := NewRequestWithJSON(t, "POST", "/api/actions_pipeline/_apis/pipelines/workflows/1/artifacts", nil) 95 MakeRequest(t, req, http.StatusUnauthorized) 96} 97 98type ( 99 listArtifactsResponseItem struct { 100 Name string `json:"name"` 101 FileContainerResourceURL string `json:"fileContainerResourceUrl"` 102 } 103 listArtifactsResponse struct { 104 Count int64 `json:"count"` 105 Value []listArtifactsResponseItem `json:"value"` 106 } 107 downloadArtifactResponseItem struct { 108 Path string `json:"path"` 109 ItemType string `json:"itemType"` 110 ContentLocation string `json:"contentLocation"` 111 } 112 downloadArtifactResponse struct { 113 Value []downloadArtifactResponseItem `json:"value"` 114 } 115) 116 117func TestActionsArtifactDownload(t *testing.T) { 118 defer prepareTestEnvActionsArtifacts(t)() 119 120 req := NewRequest(t, "GET", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts"). 121 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 122 resp := MakeRequest(t, req, http.StatusOK) 123 var listResp listArtifactsResponse 124 DecodeJSON(t, resp, &listResp) 125 assert.Equal(t, int64(2), listResp.Count) 126 127 // Return list might be in any order. Get one file. 128 var artifactIdx int 129 for i, artifact := range listResp.Value { 130 if artifact.Name == "artifact-download" { 131 artifactIdx = i 132 break 133 } 134 } 135 assert.NotNil(t, artifactIdx) 136 assert.Equal(t, "artifact-download", listResp.Value[artifactIdx].Name) 137 assert.Contains(t, listResp.Value[artifactIdx].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts") 138 139 idx := strings.Index(listResp.Value[artifactIdx].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/") 140 url := listResp.Value[artifactIdx].FileContainerResourceURL[idx+1:] + "?itemPath=artifact-download" 141 req = NewRequest(t, "GET", url). 142 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 143 resp = MakeRequest(t, req, http.StatusOK) 144 var downloadResp downloadArtifactResponse 145 DecodeJSON(t, resp, &downloadResp) 146 assert.Len(t, downloadResp.Value, 1) 147 assert.Equal(t, "artifact-download/abc.txt", downloadResp.Value[0].Path) 148 assert.Equal(t, "file", downloadResp.Value[0].ItemType) 149 assert.Contains(t, downloadResp.Value[0].ContentLocation, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts") 150 151 idx = strings.Index(downloadResp.Value[0].ContentLocation, "/api/actions_pipeline/_apis/pipelines/") 152 url = downloadResp.Value[0].ContentLocation[idx:] 153 req = NewRequest(t, "GET", url). 154 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 155 resp = MakeRequest(t, req, http.StatusOK) 156 157 body := strings.Repeat("A", 1024) 158 assert.Equal(t, body, resp.Body.String()) 159} 160 161func TestActionsArtifactUploadMultipleFile(t *testing.T) { 162 defer prepareTestEnvActionsArtifacts(t)() 163 164 const testArtifactName = "multi-files" 165 166 // acquire artifact upload url 167 req := NewRequestWithJSON(t, "POST", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts", getUploadArtifactRequest{ 168 Type: "actions_storage", 169 Name: testArtifactName, 170 }).AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 171 resp := MakeRequest(t, req, http.StatusOK) 172 var uploadResp uploadArtifactResponse 173 DecodeJSON(t, resp, &uploadResp) 174 assert.Contains(t, uploadResp.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts") 175 176 type uploadingFile struct { 177 Path string 178 Content string 179 MD5 string 180 } 181 182 files := []uploadingFile{ 183 { 184 Path: "abc-3.txt", 185 Content: strings.Repeat("D", 1024), 186 MD5: "9nqj7E8HZmfQtPifCJ5Zww==", 187 }, 188 { 189 Path: "xyz/def-2.txt", 190 Content: strings.Repeat("E", 1024), 191 MD5: "/s1kKvxeHlUX85vaTaVxuA==", 192 }, 193 } 194 195 for _, f := range files { 196 // get upload url 197 idx := strings.Index(uploadResp.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/") 198 url := uploadResp.FileContainerResourceURL[idx:] + "?itemPath=" + testArtifactName + "/" + f.Path 199 200 // upload artifact chunk 201 req = NewRequestWithBody(t, "PUT", url, strings.NewReader(f.Content)). 202 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a"). 203 SetHeader("Content-Range", "bytes 0-1023/1024"). 204 SetHeader("x-tfs-filelength", "1024"). 205 SetHeader("x-actions-results-md5", f.MD5) // base64(md5(body)) 206 MakeRequest(t, req, http.StatusOK) 207 } 208 209 t.Logf("Create artifact confirm") 210 211 // confirm artifact upload 212 req = NewRequest(t, "PATCH", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts?artifactName="+testArtifactName). 213 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 214 MakeRequest(t, req, http.StatusOK) 215} 216 217func TestActionsArtifactDownloadMultiFiles(t *testing.T) { 218 defer prepareTestEnvActionsArtifacts(t)() 219 220 const testArtifactName = "multi-file-download" 221 222 req := NewRequest(t, "GET", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts"). 223 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 224 resp := MakeRequest(t, req, http.StatusOK) 225 var listResp listArtifactsResponse 226 DecodeJSON(t, resp, &listResp) 227 assert.Equal(t, int64(2), listResp.Count) 228 229 var fileContainerResourceURL string 230 for _, v := range listResp.Value { 231 if v.Name == testArtifactName { 232 fileContainerResourceURL = v.FileContainerResourceURL 233 break 234 } 235 } 236 assert.Contains(t, fileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts") 237 238 idx := strings.Index(fileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/") 239 url := fileContainerResourceURL[idx+1:] + "?itemPath=" + testArtifactName 240 req = NewRequest(t, "GET", url). 241 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 242 resp = MakeRequest(t, req, http.StatusOK) 243 var downloadResp downloadArtifactResponse 244 DecodeJSON(t, resp, &downloadResp) 245 assert.Len(t, downloadResp.Value, 2) 246 247 downloads := [][]string{{"multi-file-download/abc.txt", "B"}, {"multi-file-download/xyz/def.txt", "C"}} 248 for _, v := range downloadResp.Value { 249 var bodyChar string 250 var path string 251 for _, d := range downloads { 252 if v.Path == d[0] { 253 path = d[0] 254 bodyChar = d[1] 255 break 256 } 257 } 258 value := v 259 assert.Equal(t, path, value.Path) 260 assert.Equal(t, "file", value.ItemType) 261 assert.Contains(t, value.ContentLocation, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts") 262 263 idx = strings.Index(value.ContentLocation, "/api/actions_pipeline/_apis/pipelines/") 264 url = value.ContentLocation[idx:] 265 req = NewRequest(t, "GET", url). 266 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 267 resp = MakeRequest(t, req, http.StatusOK) 268 assert.Equal(t, strings.Repeat(bodyChar, 1024), resp.Body.String()) 269 } 270} 271 272func TestActionsArtifactUploadWithRetentionDays(t *testing.T) { 273 defer prepareTestEnvActionsArtifacts(t)() 274 275 // acquire artifact upload url 276 req := NewRequestWithJSON(t, "POST", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts", getUploadArtifactRequest{ 277 Type: "actions_storage", 278 Name: "artifact-retention-days", 279 RetentionDays: 9, 280 }).AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 281 resp := MakeRequest(t, req, http.StatusOK) 282 var uploadResp uploadArtifactResponse 283 DecodeJSON(t, resp, &uploadResp) 284 assert.Contains(t, uploadResp.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts") 285 assert.Contains(t, uploadResp.FileContainerResourceURL, "?retentionDays=9") 286 287 // get upload url 288 idx := strings.Index(uploadResp.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/") 289 url := uploadResp.FileContainerResourceURL[idx:] + "&itemPath=artifact-retention-days/abc.txt" 290 291 // upload artifact chunk 292 body := strings.Repeat("A", 1024) 293 req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body)). 294 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a"). 295 SetHeader("Content-Range", "bytes 0-1023/1024"). 296 SetHeader("x-tfs-filelength", "1024"). 297 SetHeader("x-actions-results-md5", "1HsSe8LeLWh93ILaw1TEFQ==") // base64(md5(body)) 298 MakeRequest(t, req, http.StatusOK) 299 300 t.Logf("Create artifact confirm") 301 302 // confirm artifact upload 303 req = NewRequest(t, "PATCH", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts?artifactName=artifact-retention-days"). 304 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 305 MakeRequest(t, req, http.StatusOK) 306} 307 308func TestActionsArtifactOverwrite(t *testing.T) { 309 defer prepareTestEnvActionsArtifacts(t)() 310 311 { 312 // download old artifact uploaded by tests above, it should 1024 A 313 req := NewRequest(t, "GET", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts"). 314 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 315 resp := MakeRequest(t, req, http.StatusOK) 316 var listResp listArtifactsResponse 317 DecodeJSON(t, resp, &listResp) 318 319 idx := strings.Index(listResp.Value[0].FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/") 320 url := listResp.Value[0].FileContainerResourceURL[idx+1:] + "?itemPath=artifact-download" 321 req = NewRequest(t, "GET", url). 322 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 323 resp = MakeRequest(t, req, http.StatusOK) 324 var downloadResp downloadArtifactResponse 325 DecodeJSON(t, resp, &downloadResp) 326 327 idx = strings.Index(downloadResp.Value[0].ContentLocation, "/api/actions_pipeline/_apis/pipelines/") 328 url = downloadResp.Value[0].ContentLocation[idx:] 329 req = NewRequest(t, "GET", url). 330 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 331 resp = MakeRequest(t, req, http.StatusOK) 332 body := strings.Repeat("A", 1024) 333 assert.Equal(t, resp.Body.String(), body) 334 } 335 336 { 337 // upload same artifact, it uses 4096 B 338 req := NewRequestWithJSON(t, "POST", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts", getUploadArtifactRequest{ 339 Type: "actions_storage", 340 Name: "artifact-download", 341 }).AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 342 resp := MakeRequest(t, req, http.StatusOK) 343 var uploadResp uploadArtifactResponse 344 DecodeJSON(t, resp, &uploadResp) 345 346 idx := strings.Index(uploadResp.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/") 347 url := uploadResp.FileContainerResourceURL[idx:] + "?itemPath=artifact-download/abc.txt" 348 body := strings.Repeat("B", 4096) 349 req = NewRequestWithBody(t, "PUT", url, strings.NewReader(body)). 350 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a"). 351 SetHeader("Content-Range", "bytes 0-4095/4096"). 352 SetHeader("x-tfs-filelength", "4096"). 353 SetHeader("x-actions-results-md5", "wUypcJFeZCK5T6r4lfqzqg==") // base64(md5(body)) 354 MakeRequest(t, req, http.StatusOK) 355 356 // confirm artifact upload 357 req = NewRequest(t, "PATCH", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts?artifactName=artifact-download"). 358 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 359 MakeRequest(t, req, http.StatusOK) 360 } 361 362 { 363 // download artifact again, it should 4096 B 364 req := NewRequest(t, "GET", "/api/actions_pipeline/_apis/pipelines/workflows/791/artifacts"). 365 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 366 resp := MakeRequest(t, req, http.StatusOK) 367 var listResp listArtifactsResponse 368 DecodeJSON(t, resp, &listResp) 369 370 var uploadedItem listArtifactsResponseItem 371 for _, item := range listResp.Value { 372 if item.Name == "artifact-download" { 373 uploadedItem = item 374 break 375 } 376 } 377 assert.Equal(t, "artifact-download", uploadedItem.Name) 378 379 idx := strings.Index(uploadedItem.FileContainerResourceURL, "/api/actions_pipeline/_apis/pipelines/") 380 url := uploadedItem.FileContainerResourceURL[idx+1:] + "?itemPath=artifact-download" 381 req = NewRequest(t, "GET", url). 382 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 383 resp = MakeRequest(t, req, http.StatusOK) 384 var downloadResp downloadArtifactResponse 385 DecodeJSON(t, resp, &downloadResp) 386 387 idx = strings.Index(downloadResp.Value[0].ContentLocation, "/api/actions_pipeline/_apis/pipelines/") 388 url = downloadResp.Value[0].ContentLocation[idx:] 389 req = NewRequest(t, "GET", url). 390 AddTokenAuth("8061e833a55f6fc0157c98b883e91fcfeeb1a71a") 391 resp = MakeRequest(t, req, http.StatusOK) 392 body := strings.Repeat("B", 4096) 393 assert.Equal(t, resp.Body.String(), body) 394 } 395}