Add a test for the erofs differ using tar index mode

Signed-off-by: Aadhar Agarwal <aadagarwal@microsoft.com>
This commit is contained in:
Aadhar Agarwal
2025-09-18 00:43:17 +00:00
parent 1fe15b370b
commit 6a3b10fe76

View File

@@ -17,18 +17,32 @@
package erofs
import (
"archive/tar"
"bytes"
"context"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
"github.com/containerd/containerd/v2/core/content"
"github.com/containerd/containerd/v2/core/mount"
"github.com/containerd/containerd/v2/core/snapshots"
"github.com/containerd/containerd/v2/core/snapshots/storage"
"github.com/containerd/containerd/v2/core/snapshots/testsuite"
"github.com/containerd/containerd/v2/internal/erofsutils"
"github.com/containerd/containerd/v2/internal/fsverity"
"github.com/containerd/containerd/v2/pkg/testutil"
"github.com/containerd/containerd/v2/plugins/content/local"
erofsdiffer "github.com/containerd/containerd/v2/plugins/diff/erofs"
"github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
const (
testFileContent = "Hello, this is content for testing the EROFS Snapshotter!"
testNestedFileContent = "Nested file content"
)
func newSnapshotter(t *testing.T) func(ctx context.Context, root string) (snapshots.Snapshotter, func() error, error) {
@@ -131,3 +145,208 @@ func TestErofsFsverity(t *testing.T) {
t.Fatal("Expected direct write to fsverity-enabled layer to fail")
}
}
func TestErofsDifferWithTarIndexMode(t *testing.T) {
testutil.RequiresRoot(t)
ctx := context.Background()
if !findErofs() {
t.Skip("check for erofs kernel support failed, skipping test")
}
// Check if mkfs.erofs supports tar index mode
supported, err := erofsutils.SupportGenerateFromTar()
if err != nil || !supported {
t.Skip("mkfs.erofs does not support tar mode, skipping tar index test")
}
tempDir := t.TempDir()
// Create content store for the differ
contentStore, err := local.NewStore(filepath.Join(tempDir, "content"))
if err != nil {
t.Fatal(err)
}
// Create EROFS differ with tar index mode enabled
differ := erofsdiffer.NewErofsDiffer(contentStore, erofsdiffer.WithTarIndexMode())
// Create EROFS snapshotter
snapshotRoot := filepath.Join(tempDir, "snapshots")
s, err := NewSnapshotter(snapshotRoot)
if err != nil {
t.Fatal(err)
}
defer s.Close()
// Create test tar content
tarContent := createTestTarContent(t)
// Write tar content to content store
desc := ocispec.Descriptor{
MediaType: ocispec.MediaTypeImageLayerGzip,
Digest: digest.FromBytes(tarContent.Bytes()),
Size: int64(len(tarContent.Bytes())),
}
writer, err := contentStore.Writer(ctx,
content.WithRef("test-layer"),
content.WithDescriptor(desc))
if err != nil {
t.Fatal(err)
}
if _, err := writer.Write(tarContent.Bytes()); err != nil {
writer.Close()
t.Fatal(err)
}
if err := writer.Commit(ctx, desc.Size, desc.Digest); err != nil {
writer.Close()
t.Fatal(err)
}
writer.Close()
// Prepare a snapshot using the snapshotter
snapshotKey := "test-snapshot"
mounts, err := s.Prepare(ctx, snapshotKey, "")
if err != nil {
t.Fatal(err)
}
// Apply the tar content using the EROFS differ with tar index mode
appliedDesc, err := differ.Apply(ctx, desc, mounts)
if err != nil {
t.Fatal(err)
}
t.Logf("Applied layer using EROFS differ with tar index mode:")
t.Logf(" Original: %s (%d bytes)", desc.Digest, desc.Size)
t.Logf(" Applied: %s (%d bytes)", appliedDesc.Digest, appliedDesc.Size)
t.Logf(" MediaType: %s", appliedDesc.MediaType)
// Commit the snapshot to finalize the EROFS layer creation
commitKey := "test-commit"
if err := s.Commit(ctx, commitKey, snapshotKey); err != nil {
t.Fatal(err)
}
// Get the internal snapshot ID to check the EROFS layer file
snap := s.(*snapshotter)
var id string
if err := snap.ms.WithTransaction(ctx, false, func(ctx context.Context) error {
id, _, _, err = storage.GetInfo(ctx, commitKey)
return err
}); err != nil {
t.Fatal(err)
}
// Verify the EROFS layer file was created
layerPath := snap.layerBlobPath(id)
if _, err := os.Stat(layerPath); err != nil {
t.Fatalf("EROFS layer file should exist: %v", err)
}
// Verify the layer file is not empty
stat, err := os.Stat(layerPath)
if err != nil {
t.Fatal(err)
}
if stat.Size() == 0 {
t.Fatal("EROFS layer file should not be empty")
}
t.Logf("EROFS layer file created with tar index mode: %s (%d bytes)", layerPath, stat.Size())
// Create a view to verify the content
viewKey := "test-view"
viewMounts, err := s.View(ctx, viewKey, commitKey)
if err != nil {
t.Fatal(err)
}
viewTarget := filepath.Join(tempDir, viewKey)
if err := os.MkdirAll(viewTarget, 0755); err != nil {
t.Fatal(err)
}
if err := mount.All(viewMounts, viewTarget); err != nil {
t.Fatal(err)
}
defer testutil.Unmount(t, viewTarget)
// Verify we can read the original test data
testData, err := os.ReadFile(filepath.Join(viewTarget, "test-file.txt"))
if err != nil {
t.Fatal(err)
}
expected := testFileContent
if string(testData) != expected {
t.Fatalf("Expected %q, got %q", expected, string(testData))
}
// Verify nested file
nestedData, err := os.ReadFile(filepath.Join(viewTarget, "testdir", "nested.txt"))
if err != nil {
t.Fatal(err)
}
expectedNested := testNestedFileContent
if string(nestedData) != expectedNested {
t.Fatalf("Expected %q, got %q", expectedNested, string(nestedData))
}
t.Logf("Successfully verified EROFS Snapshotter using the differ with tar index mode")
}
// Helper function to create test tar content
func createTestTarContent(t *testing.T) *bytes.Buffer {
buf := &bytes.Buffer{}
tw := tar.NewWriter(buf)
defer tw.Close()
// Add a test file to the tar
testFileContentBytes := []byte(testFileContent)
hdr := &tar.Header{
Name: "test-file.txt",
Mode: 0644,
Size: int64(len(testFileContentBytes)),
ModTime: time.Now(),
}
if err := tw.WriteHeader(hdr); err != nil {
t.Fatalf("Failed to write tar header: %v", err)
}
if _, err := tw.Write(testFileContentBytes); err != nil {
t.Fatalf("Failed to write tar content: %v", err)
}
// Add a directory and nested file
dirHdr := &tar.Header{
Name: "testdir/",
Mode: 0755,
Typeflag: tar.TypeDir,
ModTime: time.Now(),
}
if err := tw.WriteHeader(dirHdr); err != nil {
t.Fatalf("Failed to write tar directory header: %v", err)
}
nestedFileContentBytes := []byte(testNestedFileContent)
nestedHdr := &tar.Header{
Name: "testdir/nested.txt",
Mode: 0644,
Size: int64(len(nestedFileContentBytes)),
ModTime: time.Now(),
}
if err := tw.WriteHeader(nestedHdr); err != nil {
t.Fatalf("Failed to write nested tar header: %v", err)
}
if _, err := tw.Write(nestedFileContentBytes); err != nil {
t.Fatalf("Failed to write nested tar content: %v", err)
}
return buf
}