github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/cmd/snap/cmd_auto_import_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package main_test
    21  
    22  import (
    23  	"fmt"
    24  	"io/ioutil"
    25  	"net/http"
    26  	"os"
    27  	"path/filepath"
    28  
    29  	. "gopkg.in/check.v1"
    30  
    31  	"github.com/snapcore/snapd/boot"
    32  	snap "github.com/snapcore/snapd/cmd/snap"
    33  	"github.com/snapcore/snapd/dirs"
    34  	"github.com/snapcore/snapd/logger"
    35  	"github.com/snapcore/snapd/osutil"
    36  	"github.com/snapcore/snapd/release"
    37  	"github.com/snapcore/snapd/snap/snaptest"
    38  	"github.com/snapcore/snapd/testutil"
    39  )
    40  
    41  func makeMockMountInfo(c *C, content string) string {
    42  	fn := filepath.Join(c.MkDir(), "mountinfo")
    43  	err := ioutil.WriteFile(fn, []byte(content), 0644)
    44  	c.Assert(err, IsNil)
    45  	return fn
    46  }
    47  
    48  func (s *SnapSuite) TestAutoImportAssertsHappy(c *C) {
    49  	restore := release.MockOnClassic(false)
    50  	defer restore()
    51  
    52  	fakeAssertData := []byte("my-assertion")
    53  
    54  	n := 0
    55  	total := 2
    56  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
    57  		switch n {
    58  		case 0:
    59  			c.Check(r.Method, Equals, "POST")
    60  			c.Check(r.URL.Path, Equals, "/v2/assertions")
    61  			postData, err := ioutil.ReadAll(r.Body)
    62  			c.Assert(err, IsNil)
    63  			c.Check(postData, DeepEquals, fakeAssertData)
    64  			fmt.Fprintln(w, `{"type": "sync", "result": {"ready": true, "status": "Done"}}`)
    65  			n++
    66  		case 1:
    67  			c.Check(r.Method, Equals, "POST")
    68  			c.Check(r.URL.Path, Equals, "/v2/users")
    69  			postData, err := ioutil.ReadAll(r.Body)
    70  			c.Assert(err, IsNil)
    71  			c.Check(string(postData), Equals, `{"action":"create","sudoer":true,"known":true}`)
    72  
    73  			fmt.Fprintln(w, `{"type": "sync", "result": [{"username": "foo"}]}`)
    74  			n++
    75  		default:
    76  			c.Fatalf("unexpected request: %v (expected %d got %d)", r, total, n)
    77  		}
    78  
    79  	})
    80  
    81  	fakeAssertsFn := filepath.Join(c.MkDir(), "auto-import.assert")
    82  	err := ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
    83  	c.Assert(err, IsNil)
    84  
    85  	mockMountInfoFmt := `
    86  24 0 8:18 / %s rw,relatime shared:1 - ext4 /dev/sdb2 rw,errors=remount-ro,data=ordered`
    87  	content := fmt.Sprintf(mockMountInfoFmt, filepath.Dir(fakeAssertsFn))
    88  	restore = snap.MockMountInfoPath(makeMockMountInfo(c, content))
    89  	defer restore()
    90  
    91  	logbuf, restore := logger.MockLogger()
    92  	defer restore()
    93  
    94  	rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
    95  	c.Assert(err, IsNil)
    96  	c.Assert(rest, DeepEquals, []string{})
    97  	c.Check(s.Stdout(), Equals, `created user "foo"`+"\n")
    98  	// matches because we may get a:
    99  	//   "WARNING: cannot create syslog logger\n"
   100  	// in the output
   101  	c.Check(logbuf.String(), Matches, fmt.Sprintf("(?ms).*imported %s\n", fakeAssertsFn))
   102  	c.Check(n, Equals, total)
   103  }
   104  
   105  func (s *SnapSuite) TestAutoImportAssertsNotImportedFromLoop(c *C) {
   106  	restore := release.MockOnClassic(false)
   107  	defer restore()
   108  
   109  	fakeAssertData := []byte("bad-assertion")
   110  
   111  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
   112  		// assertion is ignored, nothing is posted to this endpoint
   113  		panic("not reached")
   114  	})
   115  
   116  	fakeAssertsFn := filepath.Join(c.MkDir(), "auto-import.assert")
   117  	err := ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
   118  	c.Assert(err, IsNil)
   119  
   120  	mockMountInfoFmtWithLoop := `
   121  24 0 8:18 / %s rw,relatime shared:1 - squashfs /dev/loop1 rw,errors=remount-ro,data=ordered`
   122  	content := fmt.Sprintf(mockMountInfoFmtWithLoop, filepath.Dir(fakeAssertsFn))
   123  	restore = snap.MockMountInfoPath(makeMockMountInfo(c, content))
   124  	defer restore()
   125  
   126  	rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   127  	c.Assert(err, IsNil)
   128  	c.Assert(rest, DeepEquals, []string{})
   129  	c.Check(s.Stdout(), Equals, "")
   130  	c.Check(s.Stderr(), Equals, "")
   131  }
   132  
   133  func (s *SnapSuite) TestAutoImportCandidatesHappy(c *C) {
   134  	dirs := make([]string, 4)
   135  	args := make([]interface{}, len(dirs))
   136  	files := make([]string, len(dirs))
   137  	for i := range dirs {
   138  		dirs[i] = c.MkDir()
   139  		args[i] = dirs[i]
   140  		files[i] = filepath.Join(dirs[i], "auto-import.assert")
   141  		err := ioutil.WriteFile(files[i], nil, 0644)
   142  		c.Assert(err, IsNil)
   143  	}
   144  
   145  	mockMountInfoFmtWithLoop := `
   146  too short
   147  24 0 8:18 / %[1]s rw,relatime foo ext3 /dev/meep2 no,separator
   148  24 0 8:18 / %[2]s rw,relatime - ext3 /dev/meep2 rw,errors=remount-ro,data=ordered
   149  24 0 8:18 / %[3]s rw,relatime opt:1 - ext4 /dev/meep3 rw,errors=remount-ro,data=ordered
   150  24 0 8:18 / %[4]s rw,relatime opt:1 opt:2 - ext2 /dev/meep1 rw,errors=remount-ro,data=ordered
   151  `
   152  
   153  	content := fmt.Sprintf(mockMountInfoFmtWithLoop, args...)
   154  	restore := snap.MockMountInfoPath(makeMockMountInfo(c, content))
   155  	defer restore()
   156  
   157  	l, err := snap.AutoImportCandidates()
   158  	c.Check(err, IsNil)
   159  	c.Check(l, DeepEquals, files[1:])
   160  }
   161  
   162  func (s *SnapSuite) TestAutoImportAssertsHappyNotOnClassic(c *C) {
   163  	restore := release.MockOnClassic(true)
   164  	defer restore()
   165  
   166  	fakeAssertData := []byte("my-assertion")
   167  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
   168  		c.Errorf("auto-import on classic is disabled, but something tried to do a %q with %s", r.Method, r.URL.Path)
   169  	})
   170  
   171  	fakeAssertsFn := filepath.Join(c.MkDir(), "auto-import.assert")
   172  	err := ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
   173  	c.Assert(err, IsNil)
   174  
   175  	mockMountInfoFmt := `
   176  24 0 8:18 / %s rw,relatime shared:1 - ext4 /dev/sdb2 rw,errors=remount-ro,data=ordered`
   177  	content := fmt.Sprintf(mockMountInfoFmt, filepath.Dir(fakeAssertsFn))
   178  	restore = snap.MockMountInfoPath(makeMockMountInfo(c, content))
   179  	defer restore()
   180  
   181  	rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   182  	c.Assert(err, IsNil)
   183  	c.Assert(rest, DeepEquals, []string{})
   184  	c.Check(s.Stdout(), Equals, "")
   185  	c.Check(s.Stderr(), Equals, "auto-import is disabled on classic\n")
   186  }
   187  
   188  func (s *SnapSuite) TestAutoImportIntoSpool(c *C) {
   189  	restore := release.MockOnClassic(false)
   190  	defer restore()
   191  
   192  	logbuf, restore := logger.MockLogger()
   193  	defer restore()
   194  
   195  	fakeAssertData := []byte("good-assertion")
   196  
   197  	// ensure we can not connect
   198  	snap.ClientConfig.BaseURL = "can-not-connect-to-this-url"
   199  
   200  	fakeAssertsFn := filepath.Join(c.MkDir(), "auto-import.assert")
   201  	err := ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
   202  	c.Assert(err, IsNil)
   203  
   204  	mockMountInfoFmt := `
   205  24 0 8:18 / %s rw,relatime shared:1 - squashfs /dev/sc1 rw,errors=remount-ro,data=ordered`
   206  	content := fmt.Sprintf(mockMountInfoFmt, filepath.Dir(fakeAssertsFn))
   207  	restore = snap.MockMountInfoPath(makeMockMountInfo(c, content))
   208  	defer restore()
   209  
   210  	rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   211  	c.Assert(err, IsNil)
   212  	c.Assert(rest, DeepEquals, []string{})
   213  	c.Check(s.Stdout(), Equals, "")
   214  	// matches because we may get a:
   215  	//   "WARNING: cannot create syslog logger\n"
   216  	// in the output
   217  	c.Check(logbuf.String(), Matches, "(?ms).*queuing for later.*\n")
   218  
   219  	files, err := ioutil.ReadDir(dirs.SnapAssertsSpoolDir)
   220  	c.Assert(err, IsNil)
   221  	c.Check(files, HasLen, 1)
   222  	c.Check(files[0].Name(), Equals, "iOkaeet50rajLvL-0Qsf2ELrTdn3XIXRIBlDewcK02zwRi3_TJlUOTl9AaiDXmDn.assert")
   223  }
   224  
   225  func (s *SnapSuite) TestAutoImportFromSpoolHappy(c *C) {
   226  	restore := release.MockOnClassic(false)
   227  	defer restore()
   228  
   229  	fakeAssertData := []byte("my-assertion")
   230  
   231  	n := 0
   232  	total := 2
   233  	s.RedirectClientToTestServer(func(w http.ResponseWriter, r *http.Request) {
   234  		switch n {
   235  		case 0:
   236  			c.Check(r.Method, Equals, "POST")
   237  			c.Check(r.URL.Path, Equals, "/v2/assertions")
   238  			postData, err := ioutil.ReadAll(r.Body)
   239  			c.Assert(err, IsNil)
   240  			c.Check(postData, DeepEquals, fakeAssertData)
   241  			fmt.Fprintln(w, `{"type": "sync", "result": {"ready": true, "status": "Done"}}`)
   242  			n++
   243  		case 1:
   244  			c.Check(r.Method, Equals, "POST")
   245  			c.Check(r.URL.Path, Equals, "/v2/users")
   246  			postData, err := ioutil.ReadAll(r.Body)
   247  			c.Assert(err, IsNil)
   248  			c.Check(string(postData), Equals, `{"action":"create","sudoer":true,"known":true}`)
   249  
   250  			fmt.Fprintln(w, `{"type": "sync", "result": [{"username": "foo"}]}`)
   251  			n++
   252  		default:
   253  			c.Fatalf("unexpected request: %v (expected %d got %d)", r, total, n)
   254  		}
   255  
   256  	})
   257  
   258  	fakeAssertsFn := filepath.Join(dirs.SnapAssertsSpoolDir, "1234343")
   259  	err := os.MkdirAll(filepath.Dir(fakeAssertsFn), 0755)
   260  	c.Assert(err, IsNil)
   261  	err = ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
   262  	c.Assert(err, IsNil)
   263  
   264  	logbuf, restore := logger.MockLogger()
   265  	defer restore()
   266  
   267  	rest, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   268  	c.Assert(err, IsNil)
   269  	c.Assert(rest, DeepEquals, []string{})
   270  	c.Check(s.Stdout(), Equals, `created user "foo"`+"\n")
   271  	// matches because we may get a:
   272  	//   "WARNING: cannot create syslog logger\n"
   273  	// in the output
   274  	c.Check(logbuf.String(), Matches, fmt.Sprintf("(?ms).*imported %s\n", fakeAssertsFn))
   275  	c.Check(n, Equals, total)
   276  
   277  	c.Check(osutil.FileExists(fakeAssertsFn), Equals, false)
   278  }
   279  
   280  func (s *SnapSuite) TestAutoImportIntoSpoolUnhappyTooBig(c *C) {
   281  	restore := release.MockOnClassic(false)
   282  	defer restore()
   283  
   284  	_, restoreLogger := logger.MockLogger()
   285  	defer restoreLogger()
   286  
   287  	// fake data is bigger than the default assertion limit
   288  	fakeAssertData := make([]byte, 641*1024)
   289  
   290  	// ensure we can not connect
   291  	snap.ClientConfig.BaseURL = "can-not-connect-to-this-url"
   292  
   293  	fakeAssertsFn := filepath.Join(c.MkDir(), "auto-import.assert")
   294  	err := ioutil.WriteFile(fakeAssertsFn, fakeAssertData, 0644)
   295  	c.Assert(err, IsNil)
   296  
   297  	mockMountInfoFmt := `
   298  24 0 8:18 / %s rw,relatime shared:1 - squashfs /dev/sc1 rw,errors=remount-ro,data=ordered`
   299  	content := fmt.Sprintf(mockMountInfoFmt, filepath.Dir(fakeAssertsFn))
   300  	restore = snap.MockMountInfoPath(makeMockMountInfo(c, content))
   301  	defer restore()
   302  
   303  	_, err = snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   304  	c.Assert(err, ErrorMatches, "cannot queue .*, file size too big: 656384")
   305  }
   306  
   307  func (s *SnapSuite) TestAutoImportUnhappyInInstallMode(c *C) {
   308  	restore := release.MockOnClassic(false)
   309  	defer restore()
   310  
   311  	_, restoreLogger := logger.MockLogger()
   312  	defer restoreLogger()
   313  
   314  	mockProcCmdlinePath := filepath.Join(c.MkDir(), "cmdline")
   315  	err := ioutil.WriteFile(mockProcCmdlinePath, []byte("foo=bar snapd_recovery_mode=install snapd_recovery_system=20191118"), 0644)
   316  	c.Assert(err, IsNil)
   317  
   318  	restore = boot.MockProcCmdline(mockProcCmdlinePath)
   319  	defer restore()
   320  
   321  	_, err = snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   322  	c.Assert(err, IsNil)
   323  	c.Check(s.Stdout(), Equals, "")
   324  	c.Check(s.Stderr(), Equals, "auto-import is disabled in install-mode\n")
   325  }
   326  
   327  var mountStatic = []string{"mount", "-t", "ext4,vfat", "-o", "ro", "--make-private"}
   328  
   329  func (s *SnapSuite) TestAutoImportFromRemovable(c *C) {
   330  	restore := release.MockOnClassic(false)
   331  	defer restore()
   332  
   333  	_, restoreLogger := logger.MockLogger()
   334  	defer restoreLogger()
   335  
   336  	rootdir := c.MkDir()
   337  	dirs.SetRootDir(rootdir)
   338  
   339  	var umounts []string
   340  	restore = snap.MockSyscallUmount(func(p string, _ int) error {
   341  		umounts = append(umounts, p)
   342  		return nil
   343  	})
   344  	defer restore()
   345  
   346  	var tmpdirIdx int
   347  	restore = snap.MockIoutilTempDir(func(where string, p string) (string, error) {
   348  		c.Check(where, Equals, "")
   349  		tmpdirIdx++
   350  		return filepath.Join(rootdir, fmt.Sprintf("/tmp/%s%d", p, tmpdirIdx)), nil
   351  	})
   352  	defer restore()
   353  
   354  	mountCmd := testutil.MockCommand(c, "mount", "")
   355  	defer mountCmd.Restore()
   356  
   357  	snaptest.PopulateDir(rootdir, [][]string{
   358  		// removable without partitions
   359  		{"sys/block/sdremovable/removable", "1\n"},
   360  		// fixed disk
   361  		{"sys/block/sdfixed/removable", "0\n"},
   362  		// removable with partitions
   363  		{"sys/block/sdpart/removable", "1\n"},
   364  		{"sys/block/sdpart/sdpart1/partition", "1\n"},
   365  		{"sys/block/sdpart/sdpart2/partition", "0\n"},
   366  		{"sys/block/sdpart/sdpart3/partition", "1\n"},
   367  		// removable but subdevices are not partitions?
   368  		{"sys/block/sdother/removable", "1\n"},
   369  		{"sys/block/sdother/sdother1/partition", "0\n"},
   370  	})
   371  
   372  	// do not mock mountinfo contents, we just want to observe whether we
   373  	// try to mount and umount the right stuff
   374  
   375  	_, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   376  	c.Assert(err, IsNil)
   377  	c.Check(s.Stdout(), Equals, "")
   378  	c.Check(s.Stderr(), Equals, "")
   379  	c.Check(mountCmd.Calls(), DeepEquals, [][]string{
   380  		append(mountStatic, "/dev/sdpart1", filepath.Join(rootdir, "/tmp/snapd-auto-import-mount-1")),
   381  		append(mountStatic, "/dev/sdpart3", filepath.Join(rootdir, "/tmp/snapd-auto-import-mount-2")),
   382  		append(mountStatic, "/dev/sdremovable", filepath.Join(rootdir, "/tmp/snapd-auto-import-mount-3")),
   383  	})
   384  	c.Check(umounts, DeepEquals, []string{
   385  		filepath.Join(rootdir, "/tmp/snapd-auto-import-mount-3"),
   386  		filepath.Join(rootdir, "/tmp/snapd-auto-import-mount-2"),
   387  		filepath.Join(rootdir, "/tmp/snapd-auto-import-mount-1"),
   388  	})
   389  }
   390  
   391  func (s *SnapSuite) TestAutoImportNoRemovable(c *C) {
   392  	restore := release.MockOnClassic(false)
   393  	defer restore()
   394  
   395  	rootdir := c.MkDir()
   396  	dirs.SetRootDir(rootdir)
   397  
   398  	var umounts []string
   399  	restore = snap.MockSyscallUmount(func(p string, _ int) error {
   400  		return fmt.Errorf("unexpected call")
   401  	})
   402  	defer restore()
   403  
   404  	mountCmd := testutil.MockCommand(c, "mount", "exit 1")
   405  	defer mountCmd.Restore()
   406  
   407  	snaptest.PopulateDir(rootdir, [][]string{
   408  		// fixed disk
   409  		{"sys/block/sdfixed/removable", "0\n"},
   410  		// removable but subdevices are not partitions?
   411  		{"sys/block/sdother/removable", "1\n"},
   412  		{"sys/block/sdother/sdother1/partition", "0\n"},
   413  	})
   414  
   415  	_, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import"})
   416  	c.Assert(err, IsNil)
   417  	c.Check(s.Stdout(), Equals, "")
   418  	c.Check(s.Stderr(), Equals, "")
   419  	c.Check(mountCmd.Calls(), HasLen, 0)
   420  	c.Check(umounts, HasLen, 0)
   421  }
   422  
   423  func (s *SnapSuite) TestAutoImportFromMount(c *C) {
   424  	restore := release.MockOnClassic(false)
   425  	defer restore()
   426  
   427  	_, restoreLogger := logger.MockLogger()
   428  	defer restoreLogger()
   429  
   430  	mountCmd := testutil.MockCommand(c, "mount", "")
   431  
   432  	rootdir := c.MkDir()
   433  	dirs.SetRootDir(rootdir)
   434  
   435  	var umounts []string
   436  	restore = snap.MockSyscallUmount(func(p string, _ int) error {
   437  		c.Assert(umounts, HasLen, 0)
   438  		umounts = append(umounts, p)
   439  		return nil
   440  	})
   441  	defer restore()
   442  
   443  	var tmpdircalls int
   444  	restore = snap.MockIoutilTempDir(func(where string, p string) (string, error) {
   445  		c.Check(where, Equals, "")
   446  		c.Assert(tmpdircalls, Equals, 0)
   447  		tmpdircalls++
   448  		return filepath.Join(rootdir, fmt.Sprintf("/tmp/%s1", p)), nil
   449  	})
   450  	defer restore()
   451  
   452  	// do not mock mountinfo contents, we just want to observe whether we
   453  	// try to mount and umount the right stuff
   454  
   455  	_, err := snap.Parser(snap.Client()).ParseArgs([]string{"auto-import", "--mount", "/dev/foobar"})
   456  	c.Assert(err, IsNil)
   457  	c.Check(s.Stdout(), Equals, "")
   458  	c.Check(s.Stderr(), Equals, "")
   459  	c.Check(mountCmd.Calls(), DeepEquals, [][]string{
   460  		append(mountStatic, "/dev/foobar", filepath.Join(rootdir, "/tmp/snapd-auto-import-mount-1")),
   461  	})
   462  	c.Check(umounts, DeepEquals, []string{
   463  		filepath.Join(rootdir, "/tmp/snapd-auto-import-mount-1"),
   464  	})
   465  }
   466  
   467  func (s *SnapSuite) TestAutoImportUC20CandidatesIgnoresSystemPartitions(c *C) {
   468  
   469  	mountDirs := []string{
   470  		"/writable/system-data/var/lib/snapd/seed",
   471  		"/var/lib/snapd/seed",
   472  		"/run/mnt/ubuntu-boot",
   473  		"/run/mnt/ubuntu-seed",
   474  		"/run/mnt/ubuntu-data",
   475  		"/mnt/real-device",
   476  	}
   477  
   478  	rootDir := c.MkDir()
   479  	dirs.SetRootDir(rootDir)
   480  	defer func() { dirs.SetRootDir("") }()
   481  
   482  	args := make([]interface{}, 0, len(mountDirs)+1)
   483  	args = append(args, dirs.GlobalRootDir)
   484  	// pretend there are auto-import.asserts on all of them
   485  	for _, dir := range mountDirs {
   486  		args = append(args, dir)
   487  		file := filepath.Join(rootDir, dir, "auto-import.assert")
   488  		c.Assert(os.MkdirAll(filepath.Dir(file), 0755), IsNil)
   489  		c.Assert(ioutil.WriteFile(file, nil, 0644), IsNil)
   490  	}
   491  
   492  	mockMountInfoFmtWithLoop := `
   493  24 0 8:18 / %[1]s%[2]s rw,relatime foo ext3 /dev/meep2 no,separator
   494  24 0 8:18 / %[1]s%[3]s rw,relatime - ext3 /dev/meep2 rw,errors=remount-ro,data=ordered
   495  24 0 8:18 / %[1]s%[4]s rw,relatime opt:1 - ext4 /dev/meep3 rw,errors=remount-ro,data=ordered
   496  24 0 8:18 / %[1]s%[5]s rw,relatime opt:1 opt:2 - ext2 /dev/meep4 rw,errors=remount-ro,data=ordered
   497  24 0 8:18 / %[1]s%[6]s rw,relatime opt:1 opt:2 - ext2 /dev/meep5 rw,errors=remount-ro,data=ordered
   498  24 0 8:18 / %[1]s%[7]s rw,relatime opt:1 opt:2 - ext2 /dev/meep78 rw,errors=remount-ro,data=ordered
   499  `
   500  
   501  	content := fmt.Sprintf(mockMountInfoFmtWithLoop, args...)
   502  	restore := snap.MockMountInfoPath(makeMockMountInfo(c, content))
   503  	defer restore()
   504  
   505  	l, err := snap.AutoImportCandidates()
   506  	c.Check(err, IsNil)
   507  
   508  	// only device should be the /mnt/real-device one
   509  	c.Check(l, DeepEquals, []string{filepath.Join(rootDir, "/mnt/real-device", "auto-import.assert")})
   510  }