github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/storage/looputil/loop_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package looputil_test
     5  
     6  import (
     7  	"os"
     8  
     9  	"github.com/juju/errors"
    10  	jc "github.com/juju/testing/checkers"
    11  	gc "gopkg.in/check.v1"
    12  
    13  	"github.com/juju/juju/storage/looputil"
    14  	"github.com/juju/juju/testing"
    15  )
    16  
    17  type LoopUtilSuite struct {
    18  	testing.BaseSuite
    19  }
    20  
    21  var _ = gc.Suite(&LoopUtilSuite{})
    22  
    23  func (s *LoopUtilSuite) TestDetachLoopDevicesNone(c *gc.C) {
    24  	commands := &mockRunCommand{c: c}
    25  	defer commands.assertDrained()
    26  	commands.expect("losetup", "-a")
    27  
    28  	m := looputil.NewTestLoopDeviceManager(commands.run, nil, nil)
    29  	err := m.DetachLoopDevices("", "")
    30  	c.Assert(err, jc.ErrorIsNil)
    31  }
    32  
    33  func (s *LoopUtilSuite) TestDetachLoopDevicesListError(c *gc.C) {
    34  	commands := &mockRunCommand{c: c}
    35  	defer commands.assertDrained()
    36  	commands.expect("losetup", "-a").respond("", errors.New("badness"))
    37  
    38  	m := looputil.NewTestLoopDeviceManager(commands.run, nil, nil)
    39  	err := m.DetachLoopDevices("", "")
    40  	c.Assert(err, gc.ErrorMatches, "listing loop devices: badness")
    41  }
    42  
    43  func (s *LoopUtilSuite) TestDetachLoopDevicesListBadOutput(c *gc.C) {
    44  	commands := &mockRunCommand{c: c}
    45  	defer commands.assertDrained()
    46  	commands.expect("losetup", "-a").respond("bad output", nil)
    47  
    48  	m := looputil.NewTestLoopDeviceManager(commands.run, nil, nil)
    49  	err := m.DetachLoopDevices("", "")
    50  	c.Assert(err, gc.ErrorMatches, `listing loop devices: cannot parse loop device info from "bad output"`)
    51  }
    52  
    53  func (s *LoopUtilSuite) TestDetachLoopDevicesListBadInode(c *gc.C) {
    54  	commands := &mockRunCommand{c: c}
    55  	defer commands.assertDrained()
    56  	commands.expect("losetup", "-a").respond("/dev/loop0: [0]:99999999999999999999999 (woop)", nil)
    57  
    58  	m := looputil.NewTestLoopDeviceManager(commands.run, nil, nil)
    59  	err := m.DetachLoopDevices("", "")
    60  	c.Assert(err, gc.ErrorMatches, `listing loop devices: parsing inode: strconv.ParseUint: parsing "99999999999999999999999": value out of range`)
    61  }
    62  
    63  func (s *LoopUtilSuite) TestDetachLoopDevicesNotFound(c *gc.C) {
    64  	commands := &mockRunCommand{c: c}
    65  	defer commands.assertDrained()
    66  	commands.expect("losetup", "-a").respond("/dev/loop0: [0021]:7504142 (/tmp/test.dat)", nil)
    67  	stat := func(string) (os.FileInfo, error) {
    68  		return nil, os.ErrNotExist
    69  	}
    70  	m := looputil.NewTestLoopDeviceManager(commands.run, stat, nil)
    71  	err := m.DetachLoopDevices("", "")
    72  	c.Assert(err, jc.ErrorIsNil)
    73  }
    74  
    75  func (s *LoopUtilSuite) TestDetachLoopDevicesStatError(c *gc.C) {
    76  	commands := &mockRunCommand{c: c}
    77  	defer commands.assertDrained()
    78  	commands.expect("losetup", "-a").respond("/dev/loop0: [0021]:7504142 (/tmp/test.dat)", nil)
    79  	stat := func(path string) (os.FileInfo, error) {
    80  		return nil, errors.Errorf("stat fails for %q", path)
    81  	}
    82  	m := looputil.NewTestLoopDeviceManager(commands.run, stat, nil)
    83  	err := m.DetachLoopDevices("", "")
    84  	c.Assert(err, gc.ErrorMatches, `querying backing file: stat fails for "/tmp/test.dat"`)
    85  }
    86  
    87  func (s *LoopUtilSuite) TestDetachLoopDevicesInodeMismatch(c *gc.C) {
    88  	commands := &mockRunCommand{c: c}
    89  	defer commands.assertDrained()
    90  	commands.expect("losetup", "-a").respond("/dev/loop0: [0021]:7504142 (/tmp/test.dat)", nil)
    91  	stat := func(path string) (os.FileInfo, error) {
    92  		return mockFileInfo{inode: 123}, nil
    93  	}
    94  	m := looputil.NewTestLoopDeviceManager(commands.run, stat, mockFileInfoInode)
    95  	err := m.DetachLoopDevices("", "")
    96  	c.Assert(err, jc.ErrorIsNil)
    97  }
    98  
    99  func (s *LoopUtilSuite) TestDetachLoopDevicesInodeMatch(c *gc.C) {
   100  	commands := &mockRunCommand{c: c}
   101  	defer commands.assertDrained()
   102  	commands.expect("losetup", "-a").respond("/dev/loop0: [0021]:7504142 (/tmp/test.dat)", nil)
   103  	commands.expect("losetup", "-d", "/dev/loop0")
   104  	stat := func(path string) (os.FileInfo, error) {
   105  		return mockFileInfo{inode: 7504142}, nil
   106  	}
   107  	m := looputil.NewTestLoopDeviceManager(commands.run, stat, mockFileInfoInode)
   108  	err := m.DetachLoopDevices("", "")
   109  	c.Assert(err, jc.ErrorIsNil)
   110  }
   111  
   112  func (s *LoopUtilSuite) TestDetachLoopDevicesDetachError(c *gc.C) {
   113  	commands := &mockRunCommand{c: c}
   114  	defer commands.assertDrained()
   115  	commands.expect("losetup", "-a").respond("/dev/loop0: [0021]:7504142 (/tmp/test.dat)", nil)
   116  	commands.expect("losetup", "-d", "/dev/loop0").respond("", errors.New("oh noes"))
   117  	stat := func(path string) (os.FileInfo, error) {
   118  		return mockFileInfo{inode: 7504142}, nil
   119  	}
   120  	m := looputil.NewTestLoopDeviceManager(commands.run, stat, mockFileInfoInode)
   121  	err := m.DetachLoopDevices("", "")
   122  	c.Assert(err, gc.ErrorMatches, `detaching loop device "/dev/loop0": oh noes`)
   123  }
   124  
   125  func (s *LoopUtilSuite) TestDetachLoopDevicesMultiple(c *gc.C) {
   126  	commands := &mockRunCommand{c: c}
   127  	defer commands.assertDrained()
   128  	commands.expect("losetup", "-a").respond(
   129  		"/dev/loop0: [0021]:7504142 (/tmp/test1.dat)\n"+
   130  			"/dev/loop1: [002f]:7504143 (/tmp/test2.dat (deleted))\n"+
   131  			"/dev/loop2: [002a]:7504144 (/tmp/test3.dat)",
   132  		nil,
   133  	)
   134  	commands.expect("losetup", "-d", "/dev/loop0")
   135  	commands.expect("losetup", "-d", "/dev/loop2")
   136  	var statted []string
   137  	stat := func(path string) (os.FileInfo, error) {
   138  		statted = append(statted, path)
   139  		switch path {
   140  		case "/tmp/test1.dat":
   141  			return mockFileInfo{inode: 7504142}, nil
   142  		case "/tmp/test3.dat":
   143  			return mockFileInfo{inode: 7504144}, nil
   144  		}
   145  		return nil, os.ErrNotExist
   146  	}
   147  	m := looputil.NewTestLoopDeviceManager(commands.run, stat, mockFileInfoInode)
   148  	err := m.DetachLoopDevices("", "")
   149  	c.Assert(err, jc.ErrorIsNil)
   150  	c.Assert(statted, jc.DeepEquals, []string{"/tmp/test1.dat", "/tmp/test2.dat", "/tmp/test3.dat"})
   151  }
   152  
   153  func (s *LoopUtilSuite) TestDetachLoopDevicesAlternativeRoot(c *gc.C) {
   154  	commands := &mockRunCommand{c: c}
   155  	defer commands.assertDrained()
   156  	commands.expect("losetup", "-a").respond("/dev/loop0: [0021]:7504142 (/tmp/test.dat)", nil)
   157  	var statted string
   158  	stat := func(path string) (os.FileInfo, error) {
   159  		statted = path
   160  		return nil, os.ErrNotExist
   161  	}
   162  	m := looputil.NewTestLoopDeviceManager(commands.run, stat, mockFileInfoInode)
   163  	err := m.DetachLoopDevices("/var/lib/lxc/mycontainer/rootfs", "")
   164  	c.Assert(err, jc.ErrorIsNil)
   165  	c.Assert(statted, gc.Equals, "/var/lib/lxc/mycontainer/rootfs/tmp/test.dat")
   166  }
   167  
   168  func (s *LoopUtilSuite) TestDetachLoopDevicesAlternativeRootWithPrefix(c *gc.C) {
   169  	commands := &mockRunCommand{c: c}
   170  	defer commands.assertDrained()
   171  	commands.expect("losetup", "-a").respond(
   172  		"/dev/loop0: [0021]:7504142 (/var/lib/juju/storage/loop/volume-0-0)\n"+
   173  			"/dev/loop1: [002f]:7504143 (/some/random/loop/device)",
   174  		nil,
   175  	)
   176  	commands.expect("losetup", "-d", "/dev/loop0")
   177  	var statted []string
   178  	stat := func(path string) (os.FileInfo, error) {
   179  		statted = append(statted, path)
   180  		return mockFileInfo{inode: 7504142}, nil
   181  	}
   182  	m := looputil.NewTestLoopDeviceManager(commands.run, stat, mockFileInfoInode)
   183  	err := m.DetachLoopDevices("/var/lib/lxc/mycontainer/rootfs", "/var/lib/juju")
   184  	c.Assert(err, jc.ErrorIsNil)
   185  	c.Assert(statted, jc.DeepEquals, []string{
   186  		"/var/lib/lxc/mycontainer/rootfs/var/lib/juju/storage/loop/volume-0-0",
   187  	})
   188  }
   189  
   190  func (s *LoopUtilSuite) TestDetachLoopDevicesListEmptyInodeOK(c *gc.C) {
   191  	commands := &mockRunCommand{c: c}
   192  	defer commands.assertDrained()
   193  	commands.expect("losetup", "-a").respond("/dev/loop0: []: (/var/lib/lxc-btrfs.img)", nil)
   194  	m := looputil.NewTestLoopDeviceManager(commands.run, nil, nil)
   195  	err := m.DetachLoopDevices("", "")
   196  	c.Assert(err, jc.ErrorIsNil)
   197  }
   198  
   199  type mockFileInfo struct {
   200  	os.FileInfo
   201  	inode uint64
   202  }
   203  
   204  func mockFileInfoInode(info os.FileInfo) uint64 {
   205  	return info.(mockFileInfo).inode
   206  }