@@ -22,20 +22,20 @@ import (
2222 "fmt"
2323 "os"
2424 "path/filepath"
25- "strings "
25+ "strconv "
2626 "testing"
2727
28- "github.com/moby/sys/userns"
2928 "gotest.tools/v3/assert"
3029
3130 "github.com/containerd/cgroups/v3"
3231 containerd "github.com/containerd/containerd/v2/client"
3332 "github.com/containerd/continuity/testutil/loopback"
33+ "github.com/containerd/nerdctl/mod/tigron/expect"
3434 "github.com/containerd/nerdctl/mod/tigron/require"
35+ "github.com/containerd/nerdctl/mod/tigron/test"
3536
3637 "github.com/containerd/nerdctl/v2/pkg/cmd/container"
3738 "github.com/containerd/nerdctl/v2/pkg/idutil/containerwalker"
38- "github.com/containerd/nerdctl/v2/pkg/infoutil"
3939 "github.com/containerd/nerdctl/v2/pkg/testutil"
4040 "github.com/containerd/nerdctl/v2/pkg/testutil/nerdtest"
4141)
@@ -224,53 +224,99 @@ func TestIssue3781(t *testing.T) {
224224}
225225
226226func 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 ()
230228
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
238230
239231 const n = 3
240232 lo := make ([]* loopback.Loopback , n )
241- loContent := make ([]string , n )
242233
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 ())
251265 }
252266
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 )
274320}
275321
276322func TestParseDevice (t * testing.T ) {
0 commit comments