github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/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 type mockFileInfo struct { 191 os.FileInfo 192 inode uint64 193 } 194 195 func mockFileInfoInode(info os.FileInfo) uint64 { 196 return info.(mockFileInfo).inode 197 }