blob: fbd1af1fec5a68413f1f4d70511403a2f75b1c5a [file] [log] [blame]
Lorenz Brun378a4452021-01-26 13:47:41 +01001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package erofs
18
19import (
20 "io"
Lorenz Brun378a4452021-01-26 13:47:41 +010021 "log"
22 "math/rand"
23 "os"
24 "testing"
25
26 "github.com/stretchr/testify/assert"
27 "github.com/stretchr/testify/require"
28 "golang.org/x/sys/unix"
29)
30
31func TestKernelInterop(t *testing.T) {
32 if os.Getenv("IN_KTEST") != "true" {
33 t.Skip("Not in ktest")
34 }
35
36 type testCase struct {
37 name string
38 setup func(w *Writer) error
39 validate func(t *testing.T) error
40 }
41
42 tests := []testCase{
43 {
44 name: "SimpleFolder",
45 setup: func(w *Writer) error {
46 return w.Create(".", &Directory{
47 Base: Base{GID: 123, UID: 124, Permissions: 0753},
48 Children: []string{},
49 })
50 },
51 validate: func(t *testing.T) error {
52 var stat unix.Stat_t
53 if err := unix.Stat("/test", &stat); err != nil {
54 t.Errorf("failed to stat output: %v", err)
55 }
56 require.EqualValues(t, 124, stat.Uid, "wrong Uid")
57 require.EqualValues(t, 123, stat.Gid, "wrong Gid")
58 require.EqualValues(t, 0753, stat.Mode&^unix.S_IFMT, "wrong mode")
59 return nil
60 },
61 },
62 {
63 name: "FolderHierarchy",
64 setup: func(w *Writer) error {
65 if err := w.Create(".", &Directory{
66 Base: Base{GID: 123, UID: 124, Permissions: 0753},
67 Children: []string{"subdir"},
68 }); err != nil {
69 return err
70 }
71 if err := w.Create("subdir", &Directory{
72 Base: Base{GID: 123, UID: 124, Permissions: 0753},
73 Children: []string{},
74 }); err != nil {
75 return err
76 }
77 return nil
78 },
79 validate: func(t *testing.T) error {
Lorenz Brun764a2de2021-11-22 16:26:36 +010080 dirInfo, err := os.ReadDir("/test")
Lorenz Brun378a4452021-01-26 13:47:41 +010081 if err != nil {
82 t.Fatalf("Failed to read top-level directory: %v", err)
83 }
84 require.Len(t, dirInfo, 1, "more subdirs than expected")
85 require.Equal(t, "subdir", dirInfo[0].Name(), "unexpected subdir")
86 require.True(t, dirInfo[0].IsDir(), "subdir not a directory")
Lorenz Brun764a2de2021-11-22 16:26:36 +010087 subdirInfo, err := os.ReadDir("/test/subdir")
Lorenz Brun378a4452021-01-26 13:47:41 +010088 assert.NoError(t, err, "cannot read empty subdir")
89 require.Len(t, subdirInfo, 0, "unexpected subdirs in empty directory")
90 return nil
91 },
92 },
93 {
94 name: "SmallFile",
95 setup: func(w *Writer) error {
96 if err := w.Create(".", &Directory{
97 Base: Base{GID: 123, UID: 123, Permissions: 0755},
98 Children: []string{"test.bin"},
99 }); err != nil {
100 return err
101 }
102 writer := w.CreateFile("test.bin", &FileMeta{
103 Base: Base{GID: 123, UID: 124, Permissions: 0644},
104 })
105 r := rand.New(rand.NewSource(0)) // Random but deterministic data
106 if _, err := io.CopyN(writer, r, 128); err != nil {
107 return err
108 }
109 if err := writer.Close(); err != nil {
110 return err
111 }
112 return nil
113 },
114 validate: func(t *testing.T) error {
115 var stat unix.Stat_t
116 err := unix.Stat("/test/test.bin", &stat)
117 assert.NoError(t, err, "failed to stat file")
118 require.EqualValues(t, 124, stat.Uid, "wrong Uid")
119 require.EqualValues(t, 123, stat.Gid, "wrong Gid")
120 require.EqualValues(t, 0644, stat.Mode&^unix.S_IFMT, "wrong mode")
121 file, err := os.Open("/test/test.bin")
122 assert.NoError(t, err, "failed to open test file")
123 defer file.Close()
124 r := io.LimitReader(rand.New(rand.NewSource(0)), 128) // Random but deterministic data
Lorenz Brun764a2de2021-11-22 16:26:36 +0100125 expected, _ := io.ReadAll(r)
126 actual, err := io.ReadAll(file)
Lorenz Brun378a4452021-01-26 13:47:41 +0100127 assert.NoError(t, err, "failed to read test file")
128 assert.Equal(t, expected, actual, "content not identical")
129 return nil
130 },
131 },
132 {
133 name: "LargeFile",
134 setup: func(w *Writer) error {
135 if err := w.Create(".", &Directory{
136 Base: Base{GID: 123, UID: 123, Permissions: 0755},
137 Children: []string{"test.bin"},
138 }); err != nil {
139 return err
140 }
141 writer := w.CreateFile("test.bin", &FileMeta{
142 Base: Base{GID: 123, UID: 124, Permissions: 0644},
143 })
144 r := rand.New(rand.NewSource(1)) // Random but deterministic data
145 if _, err := io.CopyN(writer, r, 6500); err != nil {
146 return err
147 }
148 if err := writer.Close(); err != nil {
149 return err
150 }
151 return nil
152 },
153 validate: func(t *testing.T) error {
154 var stat unix.Stat_t
Lorenz Brun764a2de2021-11-22 16:26:36 +0100155 rawContents, err := os.ReadFile("/dev/ram0")
Lorenz Brun378a4452021-01-26 13:47:41 +0100156 assert.NoError(t, err, "failed to read test data")
157 log.Printf("%x", rawContents)
158 err = unix.Stat("/test/test.bin", &stat)
159 assert.NoError(t, err, "failed to stat file")
160 require.EqualValues(t, 124, stat.Uid, "wrong Uid")
161 require.EqualValues(t, 123, stat.Gid, "wrong Gid")
162 require.EqualValues(t, 0644, stat.Mode&^unix.S_IFMT, "wrong mode")
163 require.EqualValues(t, 6500, stat.Size, "wrong size")
164 file, err := os.Open("/test/test.bin")
165 assert.NoError(t, err, "failed to open test file")
166 defer file.Close()
167 r := io.LimitReader(rand.New(rand.NewSource(1)), 6500) // Random but deterministic data
Lorenz Brun764a2de2021-11-22 16:26:36 +0100168 expected, _ := io.ReadAll(r)
169 actual, err := io.ReadAll(file)
Lorenz Brun378a4452021-01-26 13:47:41 +0100170 assert.NoError(t, err, "failed to read test file")
171 assert.Equal(t, expected, actual, "content not identical")
172 return nil
173 },
174 },
175 {
176 name: "MultipleMetaBlocks",
177 setup: func(w *Writer) error {
178 testFileNames := []string{"test1.bin", "test2.bin", "test3.bin"}
179 if err := w.Create(".", &Directory{
180 Base: Base{GID: 123, UID: 123, Permissions: 0755},
181 Children: testFileNames,
182 }); err != nil {
183 return err
184 }
185 for i, fileName := range testFileNames {
186 writer := w.CreateFile(fileName, &FileMeta{
187 Base: Base{GID: 123, UID: 124, Permissions: 0644},
188 })
189 r := rand.New(rand.NewSource(int64(i))) // Random but deterministic data
190 if _, err := io.CopyN(writer, r, 2053); err != nil {
191 return err
192 }
193 if err := writer.Close(); err != nil {
194 return err
195 }
196 }
197 return nil
198 },
199 validate: func(t *testing.T) error {
200 testFileNames := []string{"test1.bin", "test2.bin", "test3.bin"}
201 for i, fileName := range testFileNames {
202 file, err := os.Open("/test/" + fileName)
203 assert.NoError(t, err, "failed to open test file")
204 defer file.Close()
205 r := io.LimitReader(rand.New(rand.NewSource(int64(i))), 2053) // Random but deterministic data
Lorenz Brun764a2de2021-11-22 16:26:36 +0100206 expected, _ := io.ReadAll(r)
207 actual, err := io.ReadAll(file)
Lorenz Brun378a4452021-01-26 13:47:41 +0100208 assert.NoError(t, err, "failed to read test file")
209 require.Equal(t, expected, actual, "content not identical")
210 }
211 return nil
212 },
213 },
214 }
215
216 for _, test := range tests {
217 t.Run(test.name, func(t *testing.T) {
218 file, err := os.OpenFile("/dev/ram0", os.O_WRONLY, 0644)
219 if err != nil {
220 t.Fatalf("failed to create test image: %v", err)
221 }
222 defer file.Close()
223 w, err := NewWriter(file)
224 if err != nil {
225 t.Fatalf("failed to initialize EROFS writer: %v", err)
226 }
227 if err := test.setup(w); err != nil {
228 t.Fatalf("setup failed: %v", err)
229 }
230 if err := w.Close(); err != nil {
231 t.Errorf("failed close: %v", err)
232 }
233 _ = file.Close()
234 if err := os.MkdirAll("/test", 0755); err != nil {
235 t.Error(err)
236 }
237 if err := unix.Mount("/dev/ram0", "/test", "erofs", unix.MS_NOEXEC|unix.MS_NODEV, ""); err != nil {
238 t.Fatal(err)
239 }
240 if err := test.validate(t); err != nil {
241 t.Errorf("validation failure: %v", err)
242 }
243 if err := unix.Unmount("/test", 0); err != nil {
244 t.Fatalf("failed to unmount: %v", err)
245 }
246 })
247
248 }
249}