github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/mongo/prealloc_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package mongo_test 5 6 import ( 7 "fmt" 8 "io/ioutil" 9 "os" 10 "path/filepath" 11 12 "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 16 "github.com/juju/juju/mongo" 17 coretesting "github.com/juju/juju/testing" 18 ) 19 20 type preallocSuite struct { 21 coretesting.BaseSuite 22 } 23 24 var _ = gc.Suite(&preallocSuite{}) 25 26 func (s *preallocSuite) TestOplogSize(c *gc.C) { 27 type test struct { 28 hostWordSize int 29 runtimeGOOS string 30 availSpace int 31 expected int 32 } 33 tests := []test{{ 34 hostWordSize: 64, 35 runtimeGOOS: "darwin", 36 availSpace: 99999, 37 expected: 183, 38 }, { 39 hostWordSize: 64, 40 runtimeGOOS: "windows", 41 availSpace: 99999, 42 expected: 512, 43 }, { 44 hostWordSize: 32, 45 runtimeGOOS: "linux", 46 availSpace: 48, 47 expected: 48, 48 }, { 49 hostWordSize: 64, 50 runtimeGOOS: "linux", 51 availSpace: 1024, 52 expected: 512, 53 }, { 54 hostWordSize: 64, 55 runtimeGOOS: "linux", 56 availSpace: 420 * 1024, 57 expected: 1024, 58 }, { 59 hostWordSize: 64, 60 runtimeGOOS: "linux", 61 availSpace: 1024 * 1024, 62 expected: 1024, 63 }} 64 var availSpace int 65 getAvailSpace := func(dir string) (float64, error) { 66 return float64(availSpace), nil 67 } 68 s.PatchValue(mongo.AvailSpace, getAvailSpace) 69 for i, test := range tests { 70 c.Logf("test %d: %+v", i, test) 71 s.PatchValue(mongo.HostWordSize, test.hostWordSize) 72 s.PatchValue(mongo.RuntimeGOOS, test.runtimeGOOS) 73 availSpace = test.availSpace 74 size, err := mongo.DefaultOplogSize("") 75 c.Check(err, jc.ErrorIsNil) 76 c.Check(size, gc.Equals, test.expected) 77 } 78 } 79 80 func (s *preallocSuite) TestFsAvailSpace(c *gc.C) { 81 output := `Filesystem 1K-blocks Used Available Use% Mounted on 82 /dev/vda1 8124856 1365292 12345 18% /` 83 testing.PatchExecutable(c, s, "df", "#!/bin/sh\ncat<<EOF\n"+output+"\nEOF") 84 85 mb, err := mongo.FsAvailSpace("") 86 c.Assert(err, jc.ErrorIsNil) 87 c.Assert(mb, gc.Equals, float64(12345)/1024) 88 } 89 90 func (s *preallocSuite) TestFsAvailSpaceErrors(c *gc.C) { 91 tests := []struct { 92 desc string 93 output string 94 err string 95 }{{ 96 desc: "result is non-numeric", 97 output: `Filesystem 1K-blocks Used Available Use% Mounted on 98 /dev/vda1 8124856 1365292 abc 18% /`, 99 err: `strconv.(ParseInt|Atoi): parsing "abc": invalid syntax`, 100 }, { 101 desc: "not enough lines", 102 output: "abc", 103 err: `could not determine available space on ""`, 104 }, { 105 desc: "not enough fields on second line", 106 output: "abc\ndef", 107 err: `could not determine available space on ""`, 108 }} 109 for i, test := range tests { 110 c.Logf("test %d: %s", i, test.desc) 111 testing.PatchExecutable(c, s, "df", "#!/bin/sh\ncat<<EOF\n"+test.output+"\nEOF") 112 _, err := mongo.FsAvailSpace("") 113 c.Check(err, gc.ErrorMatches, test.err) 114 } 115 } 116 117 func (s *preallocSuite) TestPreallocFileSizes(c *gc.C) { 118 const MB = 1024 * 1024 119 120 tests := []struct { 121 desc string 122 size int 123 result []int 124 }{{ 125 desc: "zero size, zero files", 126 size: 0, 127 result: nil, 128 }, { 129 desc: "exactly divides the max chunk size", 130 size: 1024 * MB, 131 result: []int{512 * MB, 512 * MB}, 132 }, { 133 desc: "remainder comes at the beginning", 134 size: 1025 * MB, 135 result: []int{1 * MB, 512 * MB, 512 * MB}, 136 }, { 137 desc: "remaining one byte must be padded out to 4096 bytes", 138 size: 1024*MB + 1, 139 result: []int{4096, 512 * MB, 512 * MB}, 140 }} 141 142 for i, test := range tests { 143 c.Logf("test %d: %s", i, test.desc) 144 sizes := mongo.PreallocFileSizes(test.size) 145 c.Check(sizes, gc.DeepEquals, test.result) 146 } 147 } 148 149 func (s *preallocSuite) TestPreallocFiles(c *gc.C) { 150 dir := c.MkDir() 151 prefix := filepath.Join(dir, "test.") 152 err := mongo.PreallocFiles(prefix, 0, 4096, 8192) 153 c.Assert(err, jc.ErrorIsNil) 154 155 zeroes := [8192]byte{} 156 for i := 0; i < 3; i++ { 157 filename := fmt.Sprintf("%s%d", prefix, i) 158 data, err := ioutil.ReadFile(filename) 159 c.Check(err, jc.ErrorIsNil) 160 c.Check(data, gc.DeepEquals, zeroes[:i*4096]) 161 } 162 163 _, err = os.Stat(prefix + "3") 164 c.Assert(err, jc.Satisfies, os.IsNotExist) 165 } 166 167 func (s *preallocSuite) TestPreallocFilesErrors(c *gc.C) { 168 err := mongo.PreallocFiles("", 123) 169 c.Assert(err, gc.ErrorMatches, `specified size 123 for file "0" is not a multiple of 4096`) 170 } 171 172 func (s *preallocSuite) TestPreallocFilesWriteErrors(c *gc.C) { 173 dir := c.MkDir() 174 prefix := filepath.Join(dir, "test.") 175 err := ioutil.WriteFile(prefix+"0", nil, 0644) 176 c.Assert(err, jc.ErrorIsNil) 177 err = ioutil.WriteFile(prefix+"1", nil, 0644) 178 c.Assert(err, jc.ErrorIsNil) 179 180 var called int 181 s.PatchValue(mongo.PreallocFile, func(filename string, size int) (bool, error) { 182 var created bool 183 var err error 184 called++ 185 if called == 2 { 186 created = true 187 err = fmt.Errorf("failed to zero test.1") 188 } 189 return created, err 190 }) 191 192 err = mongo.PreallocFiles(prefix, 4096, 8192) 193 c.Assert(err, gc.ErrorMatches, "failed to zero test.1") 194 195 // test.0 still exists because we said we didn't 196 // create it (i.e. it already existed) 197 _, err = os.Stat(prefix + "0") 198 c.Assert(err, jc.ErrorIsNil) 199 200 // test.1 no longer exists because we said we created 201 // it, but then failed to write to it. 202 _, err = os.Stat(prefix + "1") 203 c.Assert(err, jc.Satisfies, os.IsNotExist) 204 }