Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'internal/serving/disk/projectroot')
-rw-r--r--internal/serving/disk/projectroot/root.go47
-rw-r--r--internal/serving/disk/projectroot/root_test.go89
2 files changed, 136 insertions, 0 deletions
diff --git a/internal/serving/disk/projectroot/root.go b/internal/serving/disk/projectroot/root.go
new file mode 100644
index 00000000..64f830c0
--- /dev/null
+++ b/internal/serving/disk/projectroot/root.go
@@ -0,0 +1,47 @@
+package projectroot
+
+import (
+ "context"
+ "os"
+ "path/filepath"
+
+ "gitlab.com/gitlab-org/gitlab-pages/internal/feature"
+ "gitlab.com/gitlab-org/gitlab-pages/internal/vfs"
+)
+
+// projectRoot implements the more low-level vfs.Root interface and can be used in its
+// stead. The difference is, it always resolves the files inside the project's
+// rootDirectory by prepending that dir to any open request.
+type projectRoot struct {
+ rootDirectory string
+ vfsRoot vfs.Root
+}
+
+func New(rootDirectory string, vfsRoot vfs.Root) vfs.Root {
+ if !feature.ConfigurableRoot.Enabled() || rootDirectory == "" {
+ // In case the GitLab API is not up-to-date this string may be empty.
+ // In that case default to the legacy behavior
+ rootDirectory = "public"
+ }
+
+ return &projectRoot{
+ rootDirectory: rootDirectory,
+ vfsRoot: vfsRoot,
+ }
+}
+
+func (r *projectRoot) Open(ctx context.Context, name string) (vfs.File, error) {
+ return r.vfsRoot.Open(ctx, r.getPath(name))
+}
+
+func (r *projectRoot) Lstat(ctx context.Context, name string) (os.FileInfo, error) {
+ return r.vfsRoot.Lstat(ctx, r.getPath(name))
+}
+
+func (r *projectRoot) Readlink(ctx context.Context, name string) (string, error) {
+ return r.vfsRoot.Readlink(ctx, r.getPath(name))
+}
+
+func (r *projectRoot) getPath(name string) string {
+ return filepath.Join(r.rootDirectory, name)
+}
diff --git a/internal/serving/disk/projectroot/root_test.go b/internal/serving/disk/projectroot/root_test.go
new file mode 100644
index 00000000..b8549d10
--- /dev/null
+++ b/internal/serving/disk/projectroot/root_test.go
@@ -0,0 +1,89 @@
+package projectroot
+
+import (
+ "context"
+ "os"
+ "strconv"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ "gitlab.com/gitlab-org/gitlab-pages/internal/feature"
+ "gitlab.com/gitlab-org/gitlab-pages/internal/vfs"
+)
+
+// In case this moch struct ever grows in complexity,
+// consider using mockgen instead:
+// e.g. internal/domain/mock/resolver_mock.go
+type mockRoot struct {
+ lstatCalledWith string
+ readlinkCalledWith string
+ openCalledWith string
+}
+
+func (m *mockRoot) Lstat(ctx context.Context, name string) (os.FileInfo, error) {
+ m.lstatCalledWith = name
+ return nil, nil
+}
+
+func (m *mockRoot) Readlink(ctx context.Context, name string) (string, error) {
+ m.readlinkCalledWith = name
+ return "", nil
+}
+
+func (m *mockRoot) Open(ctx context.Context, name string) (vfs.File, error) {
+ m.openCalledWith = name
+ return nil, nil
+}
+
+func TestProjectRoot(t *testing.T) {
+ tests := map[string]struct {
+ path string
+ rootDir string
+ expectedPath string
+ featureEnabled bool
+ }{
+ "when the root dir is provided": {
+ path: "some/path",
+ rootDir: "my_root_dir",
+ expectedPath: "my_root_dir/some/path",
+ featureEnabled: true,
+ },
+ "when the root dir is not provided": {
+ path: "some/path",
+ rootDir: "",
+ expectedPath: "public/some/path",
+ featureEnabled: true,
+ },
+ "when the feature is disabled": {
+ path: "some/path",
+ rootDir: "my_root_dir",
+ expectedPath: "public/some/path",
+ featureEnabled: false,
+ },
+ "when the feature is disabled and no root path is provided": {
+ path: "some/path",
+ rootDir: "",
+ expectedPath: "public/some/path",
+ featureEnabled: false,
+ },
+ }
+
+ for name, test := range tests {
+ t.Run(name, func(t *testing.T) {
+ t.Setenv(feature.ConfigurableRoot.EnvVariable,
+ strconv.FormatBool(test.featureEnabled))
+ originalRoot := &mockRoot{}
+ wrappedRoot := New(test.rootDir, originalRoot)
+
+ wrappedRoot.Lstat(context.Background(), test.path)
+ require.Equal(t, test.expectedPath, originalRoot.lstatCalledWith)
+
+ wrappedRoot.Readlink(context.Background(), test.path)
+ require.Equal(t, test.expectedPath, originalRoot.readlinkCalledWith)
+
+ wrappedRoot.Open(context.Background(), test.path)
+ require.Equal(t, test.expectedPath, originalRoot.openCalledWith)
+ })
+ }
+}