mirror of
https://github.com/containerd/containerd.git
synced 2026-08-08 17:11:15 +00:00
Add a test for the erofs differ using tar index mode
Signed-off-by: Aadhar Agarwal <aadagarwal@microsoft.com>
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user