@@ -22,20 +22,20 @@ import (
22
22
"fmt"
23
23
"os"
24
24
"path/filepath"
25
- "strings "
25
+ "strconv "
26
26
"testing"
27
27
28
- "github.com/moby/sys/userns"
29
28
"gotest.tools/v3/assert"
30
29
31
30
"github.com/containerd/cgroups/v3"
32
31
containerd "github.com/containerd/containerd/v2/client"
33
32
"github.com/containerd/continuity/testutil/loopback"
33
+ "github.com/containerd/nerdctl/mod/tigron/expect"
34
34
"github.com/containerd/nerdctl/mod/tigron/require"
35
+ "github.com/containerd/nerdctl/mod/tigron/test"
35
36
36
37
"github.com/containerd/nerdctl/v2/pkg/cmd/container"
37
38
"github.com/containerd/nerdctl/v2/pkg/idutil/containerwalker"
38
- "github.com/containerd/nerdctl/v2/pkg/infoutil"
39
39
"github.com/containerd/nerdctl/v2/pkg/testutil"
40
40
"github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest"
41
41
)
@@ -224,53 +224,99 @@ func TestIssue3781(t *testing.T) {
224
224
}
225
225
226
226
func TestRunDevice (t * testing.T ) {
227
- if os .Geteuid () != 0 || userns .RunningInUserNS () {
228
- t .Skip ("test requires the root in the initial user namespace" )
229
- }
227
+ testCase := nerdtest .Setup ()
230
228
231
- if unameR := infoutil .UnameR (); strings .Contains (unameR , ".el8" ) {
232
- t .Logf ("Assuming to be running on EL8 (kernel release %q)" , unameR )
233
- t .Skip ("FIXME: loopback.New fails on EL8 (when the test is executed inside a container) https://github.com/containerd/nerdctl/pull/3904#issuecomment-2670917820" )
234
- // > === FAIL: cmd/nerdctl/container TestRunDevice (0.44s)
235
- // > container_run_cgroup_linux_test.go:236: assertion failed: error is not nil: loopback setup failed ([losetup --find --show /tmp/containerd-test-loopback3931357228]):
236
- // > stdout="", stderr="losetup: /tmp/containerd-test-loopback3931357228: failed to set up loop device: No such file or directory\n": exit status 1
237
- }
229
+ testCase .Require = nerdtest .Rootful
238
230
239
231
const n = 3
240
232
lo := make ([]* loopback.Loopback , n )
241
- loContent := make ([]string , n )
242
233
243
- for i := 0 ; i < n ; i ++ {
244
- var err error
245
- lo [i ], err = loopback .New (4096 )
246
- assert .NilError (t , err )
247
- t .Logf ("lo[%d] = %+v" , i , lo [i ])
248
- defer lo [i ].Close ()
249
- loContent [i ] = fmt .Sprintf ("lo%d-content" , i )
250
- assert .NilError (t , os .WriteFile (lo [i ].Device , []byte (loContent [i ]), 0700 ))
234
+ testCase .Setup = func (data test.Data , helpers test.Helpers ) {
235
+
236
+ for i := 0 ; i < n ; i ++ {
237
+ var err error
238
+ lo [i ], err = loopback .New (4096 )
239
+ assert .NilError (t , err )
240
+ t .Logf ("lo[%d] = %+v" , i , lo [i ])
241
+ loContent := fmt .Sprintf ("lo%d-content" , i )
242
+ assert .NilError (t , os .WriteFile (lo [i ].Device , []byte (loContent ), 0o700 ))
243
+ data .Set ("loContent" + strconv .Itoa (i ), loContent )
244
+ }
245
+
246
+ // lo0 is readable but not writable.
247
+ // lo1 is readable and writable
248
+ // lo2 is not accessible.
249
+ helpers .Ensure ("run" ,
250
+ "-d" ,
251
+ "--name" , data .Identifier (),
252
+ "--device" , lo [0 ].Device + ":r" ,
253
+ "--device" , lo [1 ].Device ,
254
+ testutil .AlpineImage , "sleep" , nerdtest .Infinity )
255
+ data .Set ("id" , data .Identifier ())
256
+ }
257
+
258
+ testCase .Cleanup = func (data test.Data , helpers test.Helpers ) {
259
+ for i := 0 ; i < n ; i ++ {
260
+ if lo [i ] != nil {
261
+ _ = lo [i ].Close ()
262
+ }
263
+ }
264
+ helpers .Anyhow ("rm" , "-f" , data .Identifier ())
251
265
}
252
266
253
- base := testutil .NewBase (t )
254
- containerName := testutil .Identifier (t )
255
- defer base .Cmd ("rm" , "-f" , containerName ).AssertOK ()
256
- // lo0 is readable but not writable.
257
- // lo1 is readable and writable
258
- // lo2 is not accessible.
259
- base .Cmd ("run" ,
260
- "-d" ,
261
- "--name" , containerName ,
262
- "--device" , lo [0 ].Device + ":r" ,
263
- "--device" , lo [1 ].Device ,
264
- testutil .AlpineImage , "sleep" , nerdtest .Infinity ).Run ()
265
-
266
- base .Cmd ("exec" , containerName , "cat" , lo [0 ].Device ).AssertOutContains (loContent [0 ])
267
- base .Cmd ("exec" , containerName , "cat" , lo [1 ].Device ).AssertOutContains (loContent [1 ])
268
- base .Cmd ("exec" , containerName , "cat" , lo [2 ].Device ).AssertFail ()
269
- base .Cmd ("exec" , containerName , "sh" , "-ec" , "echo -n \" overwritten-lo0-content\" >" + lo [0 ].Device ).AssertFail ()
270
- base .Cmd ("exec" , containerName , "sh" , "-ec" , "echo -n \" overwritten-lo1-content\" >" + lo [1 ].Device ).AssertOK ()
271
- lo1Read , err := os .ReadFile (lo [1 ].Device )
272
- assert .NilError (t , err )
273
- assert .Equal (t , string (bytes .Trim (lo1Read , "\x00 " )), "overwritten-lo1-content" )
267
+ testCase .SubTests = []* test.Case {
268
+ {
269
+ Description : "can read lo0" ,
270
+ Command : func (data test.Data , helpers test.Helpers ) test.TestableCommand {
271
+ return helpers .Command ("exec" , data .Get ("id" ), "cat" , lo [0 ].Device )
272
+ },
273
+ Expected : func (data test.Data , helpers test.Helpers ) * test.Expected {
274
+ return & test.Expected {
275
+ Output : expect .Contains (data .Get ("locontent0" )),
276
+ }
277
+ },
278
+ },
279
+ {
280
+ Description : "cannot write lo0" ,
281
+ Command : func (data test.Data , helpers test.Helpers ) test.TestableCommand {
282
+ return helpers .Command ("exec" , data .Get ("id" ), "sh" , "-ec" , "echo -n \" overwritten-lo1-content\" >" + lo [0 ].Device )
283
+ },
284
+ Expected : test .Expects (expect .ExitCodeGenericFail , nil , nil ),
285
+ },
286
+ {
287
+ Description : "cannot read lo2" ,
288
+ Command : func (data test.Data , helpers test.Helpers ) test.TestableCommand {
289
+ return helpers .Command ("exec" , data .Get ("id" ), "cat" , lo [2 ].Device )
290
+ },
291
+ Expected : test .Expects (expect .ExitCodeGenericFail , nil , nil ),
292
+ },
293
+ {
294
+ Description : "can read lo1" ,
295
+ NoParallel : true ,
296
+ Command : func (data test.Data , helpers test.Helpers ) test.TestableCommand {
297
+ return helpers .Command ("exec" , data .Get ("id" ), "cat" , lo [1 ].Device )
298
+ },
299
+ Expected : func (data test.Data , helpers test.Helpers ) * test.Expected {
300
+ return & test.Expected {
301
+ Output : expect .Contains (data .Get ("locontent1" )),
302
+ }
303
+ },
304
+ },
305
+ {
306
+ Description : "can write lo1 and read back updated value" ,
307
+ NoParallel : true ,
308
+ Command : func (data test.Data , helpers test.Helpers ) test.TestableCommand {
309
+ return helpers .Command ("exec" , data .Get ("id" ), "sh" , "-ec" , "echo -n \" overwritten-lo1-content\" >" + lo [1 ].Device )
310
+ },
311
+ Expected : test .Expects (expect .ExitCodeSuccess , nil , func (stdout string , info string , t * testing.T ) {
312
+ lo1Read , err := os .ReadFile (lo [1 ].Device )
313
+ assert .NilError (t , err )
314
+ assert .Equal (t , string (bytes .Trim (lo1Read , "\x00 " )), "overwritten-lo1-content" )
315
+ }),
316
+ },
317
+ }
318
+
319
+ testCase .Run (t )
274
320
}
275
321
276
322
func TestParseDevice (t * testing.T ) {
0 commit comments