Skip to content

Commit fd061b8

Browse files
pauloappbrmxpv
authored andcommitted
test(oci): use fstest and mock fs for better symlink coverage
Signed-off-by: Paulo Oliveira <[email protected]>
1 parent 5d44d2c commit fd061b8

1 file changed

Lines changed: 41 additions & 14 deletions

File tree

pkg/oci/spec_test.go

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,17 @@ package oci
1919
import (
2020
"context"
2121
"io"
22+
"io/fs"
2223
"os"
2324
"path/filepath"
2425
"runtime"
2526
"testing"
2627

27-
"github.com/opencontainers/runtime-spec/specs-go"
28-
2928
"github.com/containerd/containerd/v2/core/containers"
3029
"github.com/containerd/containerd/v2/pkg/namespaces"
3130
"github.com/containerd/containerd/v2/pkg/testutil"
31+
"github.com/containerd/continuity/fs/fstest"
32+
"github.com/opencontainers/runtime-spec/specs-go"
3233
)
3334

3435
func TestGenerateSpec(t *testing.T) {
@@ -330,24 +331,35 @@ func TestWithPrivileged(t *testing.T) {
330331
}
331332

332333
func TestOpenUserFile_AbsoluteSymlink(t *testing.T) {
333-
tmpDir := t.TempDir()
334-
335-
targetName := "passwd"
336-
targetPath := filepath.Join(tmpDir, targetName)
337-
expectedContent := []byte("root:x:0:0:root:/root:/bin/bash")
338-
if err := os.WriteFile(targetPath, expectedContent, 0644); err != nil {
339-
t.Fatal(err)
334+
if runtime.GOOS == "windows" {
335+
t.Skip("absolute symlink handling is only supported on non-Windows platforms")
340336
}
341337

342-
linkName := "abs_link"
343-
linkPath := filepath.Join(tmpDir, linkName)
344-
if err := os.Symlink(targetPath, linkPath); err != nil {
338+
expectedContent := []byte("root:x:0:0:root:/root:/bin/bash" + t.Name())
339+
340+
root := t.TempDir()
341+
// Use 'continuity' library to create a directory structure simulating NixOS
342+
if err := fstest.Apply(
343+
fstest.CreateDir("/etc", 0o755),
344+
fstest.CreateDir("/nix/store/abcd", 0o755),
345+
fstest.CreateFile("/nix/store/abcd/passwd", expectedContent, 0o644),
346+
// /etc/passwd -> /nix/store/abcd/passwd (absolute symlink)
347+
fstest.Symlink("/nix/store/abcd/passwd", "/etc/passwd"),
348+
).Apply(root); err != nil {
345349
t.Fatal(err)
346350
}
347351

348-
rootFS := os.DirFS(tmpDir)
352+
rootFS := os.DirFS(root)
353+
354+
// Ensure the FS implements the ReadLink interface.
355+
// If the native os.DirFS doesn't implement it (depending on Go version),
356+
// wrap it in our readLinkFS helper.
357+
if _, ok := rootFS.(readLinker); !ok {
358+
t.Logf("os.DirFS does not implement ReadLink; wrapping to use ReadLink")
359+
rootFS = readLinkFS{root: root, fs: rootFS}
360+
}
349361

350-
f, err := openUserFile(rootFS, linkName)
362+
f, err := openUserFile(rootFS, "etc/passwd")
351363
if err != nil {
352364
t.Fatalf("openUserFile failed on absolute symlink: %v", err)
353365
}
@@ -361,3 +373,18 @@ func TestOpenUserFile_AbsoluteSymlink(t *testing.T) {
361373
t.Errorf("expected content %q, got %q", string(expectedContent), string(content))
362374
}
363375
}
376+
377+
// Helpers for testing ReadLink support
378+
type readLinkFS struct {
379+
root string
380+
fs fs.FS
381+
}
382+
383+
func (r readLinkFS) Open(name string) (fs.File, error) {
384+
return r.fs.Open(name)
385+
}
386+
387+
func (r readLinkFS) ReadLink(name string) (string, error) {
388+
// Force link reading using the actual path on disk
389+
return os.Readlink(filepath.Join(r.root, filepath.FromSlash(name)))
390+
}

0 commit comments

Comments
 (0)