diff options
author | Daniel Baumann <daniel@debian.org> | 2024-10-20 23:07:42 +0200 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-11-09 15:38:42 +0100 |
commit | 714c83b2736d7e308bc33c49057952490eb98be2 (patch) | |
tree | 1d9ba7035798368569cd49056f4d596efc908cd8 /pkg/artifacts/server_test.go | |
parent | Initial commit. (diff) | |
download | forgejo-act-714c83b2736d7e308bc33c49057952490eb98be2.tar.xz forgejo-act-714c83b2736d7e308bc33c49057952490eb98be2.zip |
Adding upstream version 1.21.4.HEADupstream/1.21.4upstreamdebian
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'pkg/artifacts/server_test.go')
-rw-r--r-- | pkg/artifacts/server_test.go | 395 |
1 files changed, 395 insertions, 0 deletions
diff --git a/pkg/artifacts/server_test.go b/pkg/artifacts/server_test.go new file mode 100644 index 0000000..aeeb059 --- /dev/null +++ b/pkg/artifacts/server_test.go @@ -0,0 +1,395 @@ +package artifacts + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "path" + "path/filepath" + "strings" + "testing" + "testing/fstest" + + "github.com/julienschmidt/httprouter" + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" + + "github.com/nektos/act/pkg/model" + "github.com/nektos/act/pkg/runner" +) + +type writableMapFile struct { + fstest.MapFile +} + +func (f *writableMapFile) Write(data []byte) (int, error) { + f.Data = data + return len(data), nil +} + +func (f *writableMapFile) Close() error { + return nil +} + +type writeMapFS struct { + fstest.MapFS +} + +func (fsys writeMapFS) OpenWritable(name string) (WritableFile, error) { + var file = &writableMapFile{ + MapFile: fstest.MapFile{ + Data: []byte("content2"), + }, + } + fsys.MapFS[name] = &file.MapFile + + return file, nil +} + +func (fsys writeMapFS) OpenAppendable(name string) (WritableFile, error) { + var file = &writableMapFile{ + MapFile: fstest.MapFile{ + Data: []byte("content2"), + }, + } + fsys.MapFS[name] = &file.MapFile + + return file, nil +} + +func TestNewArtifactUploadPrepare(t *testing.T) { + assert := assert.New(t) + + var memfs = fstest.MapFS(map[string]*fstest.MapFile{}) + + router := httprouter.New() + uploads(router, "artifact/server/path", writeMapFS{memfs}) + + req, _ := http.NewRequest("POST", "http://localhost/_apis/pipelines/workflows/1/artifacts", nil) + rr := httptest.NewRecorder() + + router.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + assert.Fail("Wrong status") + } + + response := FileContainerResourceURL{} + err := json.Unmarshal(rr.Body.Bytes(), &response) + if err != nil { + panic(err) + } + + assert.Equal("http://localhost/upload/1", response.FileContainerResourceURL) +} + +func TestArtifactUploadBlob(t *testing.T) { + assert := assert.New(t) + + var memfs = fstest.MapFS(map[string]*fstest.MapFile{}) + + router := httprouter.New() + uploads(router, "artifact/server/path", writeMapFS{memfs}) + + req, _ := http.NewRequest("PUT", "http://localhost/upload/1?itemPath=some/file", strings.NewReader("content")) + rr := httptest.NewRecorder() + + router.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + assert.Fail("Wrong status") + } + + response := ResponseMessage{} + err := json.Unmarshal(rr.Body.Bytes(), &response) + if err != nil { + panic(err) + } + + assert.Equal("success", response.Message) + assert.Equal("content", string(memfs["artifact/server/path/1/some/file"].Data)) +} + +func TestFinalizeArtifactUpload(t *testing.T) { + assert := assert.New(t) + + var memfs = fstest.MapFS(map[string]*fstest.MapFile{}) + + router := httprouter.New() + uploads(router, "artifact/server/path", writeMapFS{memfs}) + + req, _ := http.NewRequest("PATCH", "http://localhost/_apis/pipelines/workflows/1/artifacts", nil) + rr := httptest.NewRecorder() + + router.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + assert.Fail("Wrong status") + } + + response := ResponseMessage{} + err := json.Unmarshal(rr.Body.Bytes(), &response) + if err != nil { + panic(err) + } + + assert.Equal("success", response.Message) +} + +func TestListArtifacts(t *testing.T) { + assert := assert.New(t) + + var memfs = fstest.MapFS(map[string]*fstest.MapFile{ + "artifact/server/path/1/file.txt": { + Data: []byte(""), + }, + }) + + router := httprouter.New() + downloads(router, "artifact/server/path", memfs) + + req, _ := http.NewRequest("GET", "http://localhost/_apis/pipelines/workflows/1/artifacts", nil) + rr := httptest.NewRecorder() + + router.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + assert.FailNow(fmt.Sprintf("Wrong status: %d", status)) + } + + response := NamedFileContainerResourceURLResponse{} + err := json.Unmarshal(rr.Body.Bytes(), &response) + if err != nil { + panic(err) + } + + assert.Equal(1, response.Count) + assert.Equal("file.txt", response.Value[0].Name) + assert.Equal("http://localhost/download/1", response.Value[0].FileContainerResourceURL) +} + +func TestListArtifactContainer(t *testing.T) { + assert := assert.New(t) + + var memfs = fstest.MapFS(map[string]*fstest.MapFile{ + "artifact/server/path/1/some/file": { + Data: []byte(""), + }, + }) + + router := httprouter.New() + downloads(router, "artifact/server/path", memfs) + + req, _ := http.NewRequest("GET", "http://localhost/download/1?itemPath=some/file", nil) + rr := httptest.NewRecorder() + + router.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + assert.FailNow(fmt.Sprintf("Wrong status: %d", status)) + } + + response := ContainerItemResponse{} + err := json.Unmarshal(rr.Body.Bytes(), &response) + if err != nil { + panic(err) + } + + assert.Equal(1, len(response.Value)) + assert.Equal("some/file", response.Value[0].Path) + assert.Equal("file", response.Value[0].ItemType) + assert.Equal("http://localhost/artifact/1/some/file/.", response.Value[0].ContentLocation) +} + +func TestDownloadArtifactFile(t *testing.T) { + assert := assert.New(t) + + var memfs = fstest.MapFS(map[string]*fstest.MapFile{ + "artifact/server/path/1/some/file": { + Data: []byte("content"), + }, + }) + + router := httprouter.New() + downloads(router, "artifact/server/path", memfs) + + req, _ := http.NewRequest("GET", "http://localhost/artifact/1/some/file", nil) + rr := httptest.NewRecorder() + + router.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + assert.FailNow(fmt.Sprintf("Wrong status: %d", status)) + } + + data := rr.Body.Bytes() + + assert.Equal("content", string(data)) +} + +type TestJobFileInfo struct { + workdir string + workflowPath string + eventName string + errorMessage string + platforms map[string]string + containerArchitecture string +} + +var ( + artifactsPath = path.Join(os.TempDir(), "test-artifacts") + artifactsAddr = "127.0.0.1" + artifactsPort = "12345" +) + +func TestArtifactFlow(t *testing.T) { + if testing.Short() { + t.Skip("skipping integration test") + } + + ctx := context.Background() + + cancel := Serve(ctx, artifactsPath, artifactsAddr, artifactsPort) + defer cancel() + + platforms := map[string]string{ + "ubuntu-latest": "node:16-buster", // Don't use node:16-buster-slim because it doesn't have curl command, which is used in the tests + } + + tables := []TestJobFileInfo{ + {"testdata", "upload-and-download", "push", "", platforms, ""}, + {"testdata", "GHSL-2023-004", "push", "", platforms, ""}, + } + log.SetLevel(log.DebugLevel) + + for _, table := range tables { + runTestJobFile(ctx, t, table) + } +} + +func runTestJobFile(ctx context.Context, t *testing.T, tjfi TestJobFileInfo) { + t.Run(tjfi.workflowPath, func(t *testing.T) { + fmt.Printf("::group::%s\n", tjfi.workflowPath) + + if err := os.RemoveAll(artifactsPath); err != nil { + panic(err) + } + + workdir, err := filepath.Abs(tjfi.workdir) + assert.Nil(t, err, workdir) + fullWorkflowPath := filepath.Join(workdir, tjfi.workflowPath) + runnerConfig := &runner.Config{ + Workdir: workdir, + BindWorkdir: false, + EventName: tjfi.eventName, + Platforms: tjfi.platforms, + ReuseContainers: false, + ContainerArchitecture: tjfi.containerArchitecture, + GitHubInstance: "github.com", + ArtifactServerPath: artifactsPath, + ArtifactServerAddr: artifactsAddr, + ArtifactServerPort: artifactsPort, + } + + runner, err := runner.New(runnerConfig) + assert.Nil(t, err, tjfi.workflowPath) + + planner, err := model.NewWorkflowPlanner(fullWorkflowPath, true) + assert.Nil(t, err, fullWorkflowPath) + + plan, err := planner.PlanEvent(tjfi.eventName) + if err == nil { + err = runner.NewPlanExecutor(plan)(ctx) + if tjfi.errorMessage == "" { + assert.Nil(t, err, fullWorkflowPath) + } else { + assert.Error(t, err, tjfi.errorMessage) + } + } else { + assert.Nil(t, plan) + } + + fmt.Println("::endgroup::") + }) +} + +func TestMkdirFsImplSafeResolve(t *testing.T) { + assert := assert.New(t) + + baseDir := "/foo/bar" + + tests := map[string]struct { + input string + want string + }{ + "simple": {input: "baz", want: "/foo/bar/baz"}, + "nested": {input: "baz/blue", want: "/foo/bar/baz/blue"}, + "dots in middle": {input: "baz/../../blue", want: "/foo/bar/blue"}, + "leading dots": {input: "../../parent", want: "/foo/bar/parent"}, + "root path": {input: "/root", want: "/foo/bar/root"}, + "root": {input: "/", want: "/foo/bar"}, + "empty": {input: "", want: "/foo/bar"}, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + assert.Equal(tc.want, safeResolve(baseDir, tc.input)) + }) + } +} + +func TestDownloadArtifactFileUnsafePath(t *testing.T) { + assert := assert.New(t) + + var memfs = fstest.MapFS(map[string]*fstest.MapFile{ + "artifact/server/path/some/file": { + Data: []byte("content"), + }, + }) + + router := httprouter.New() + downloads(router, "artifact/server/path", memfs) + + req, _ := http.NewRequest("GET", "http://localhost/artifact/2/../../some/file", nil) + rr := httptest.NewRecorder() + + router.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + assert.FailNow(fmt.Sprintf("Wrong status: %d", status)) + } + + data := rr.Body.Bytes() + + assert.Equal("content", string(data)) +} + +func TestArtifactUploadBlobUnsafePath(t *testing.T) { + assert := assert.New(t) + + var memfs = fstest.MapFS(map[string]*fstest.MapFile{}) + + router := httprouter.New() + uploads(router, "artifact/server/path", writeMapFS{memfs}) + + req, _ := http.NewRequest("PUT", "http://localhost/upload/1?itemPath=../../some/file", strings.NewReader("content")) + rr := httptest.NewRecorder() + + router.ServeHTTP(rr, req) + + if status := rr.Code; status != http.StatusOK { + assert.Fail("Wrong status") + } + + response := ResponseMessage{} + err := json.Unmarshal(rr.Body.Bytes(), &response) + if err != nil { + panic(err) + } + + assert.Equal("success", response.Message) + assert.Equal("content", string(memfs["artifact/server/path/1/some/file"].Data)) +} |