github.com/kolyshkin/goploop@v0.0.0-20151005223236-44c2656a655c/ploop_test.go (about) 1 package ploop 2 3 // A test suite, also serving as an example of how to use the package 4 5 import ( 6 "bufio" 7 "fmt" 8 "io/ioutil" 9 "os" 10 "os/exec" 11 "testing" 12 13 "github.com/dustin/go-humanize" 14 ) 15 16 var ( 17 oldPwd string 18 testDir string 19 d Ploop 20 snap string 21 ) 22 23 const baseDelta = "root.hdd" 24 25 // abort is used when the tests after the current one 26 // can't be run as one of their prerequisite(s) failed 27 func abort(format string, args ...interface{}) { 28 s := fmt.Sprintf("ABORT: "+format+"\n", args...) 29 f := bufio.NewWriter(os.Stderr) 30 f.Write([]byte(s)) 31 f.Flush() 32 cleanup() 33 os.Exit(1) 34 } 35 36 // Check for a fatal error, call abort() if it is 37 func chk(err error) { 38 if err != nil { 39 abort("%s", err) 40 } 41 } 42 43 func prepare(dir string) { 44 var err error 45 46 oldPwd, err = os.Getwd() 47 chk(err) 48 49 testDir, err = ioutil.TempDir(oldPwd, dir) 50 chk(err) 51 52 err = os.Chdir(testDir) 53 chk(err) 54 55 SetVerboseLevel(NoStdout) 56 SetLogLevel(1) 57 SetLogFile("ploop.log") 58 } 59 60 func TestPrepare(t *testing.T) { 61 prepare("tmp-test") 62 } 63 64 func TestUUID(t *testing.T) { 65 uuid, e := UUID() 66 if e != nil { 67 t.Errorf("UUID: %s", e) 68 } 69 70 t.Logf("Got uuid %s", uuid) 71 } 72 73 func create() { 74 size := "384M" 75 var p CreateParam 76 77 s, e := humanize.ParseBytes(size) 78 if e != nil { 79 abort("humanize.ParseBytes: can't parse %s: %s", size, e) 80 } 81 p.Size = s / 1024 82 p.File = baseDelta 83 84 e = Create(&p) 85 if e != nil { 86 abort("Create: %s", e) 87 } 88 } 89 90 func TestCreate(t *testing.T) { 91 create() 92 } 93 94 func open() { 95 var e error 96 97 d, e = Open("DiskDescriptor.xml") 98 if e != nil { 99 abort("Open: %s", e) 100 } 101 } 102 103 func TestOpen(t *testing.T) { 104 open() 105 } 106 107 func TestMount(t *testing.T) { 108 mnt := "mnt" 109 110 e := os.Mkdir(mnt, 0755) 111 chk(e) 112 113 p := MountParam{Target: mnt} 114 dev, e := d.Mount(&p) 115 if e != nil { 116 abort("Mount: %s", e) 117 } 118 119 t.Logf("Mounted; ploop device %s", dev) 120 } 121 122 func resize(t *testing.T, size string, offline bool) { 123 if offline && testing.Short() { 124 t.Skip("skipping offline resize test in short mode.") 125 } 126 s, e := humanize.ParseBytes(size) 127 if e != nil { 128 t.Fatalf("humanize.ParseBytes: can't parse %s: %s", size, e) 129 } 130 s = s / 1024 131 132 e = d.Resize(s, offline) 133 if e != nil { 134 t.Fatalf("Resize to %s (%d bytes) failed: %s", size, s, e) 135 } 136 } 137 138 func TestResizeOnlineShrink(t *testing.T) { 139 resize(t, "256MB", false) 140 } 141 142 func TestResizeOnlineGrow(t *testing.T) { 143 resize(t, "512MB", false) 144 } 145 146 func TestSnapshot(t *testing.T) { 147 uuid, e := d.Snapshot() 148 if e != nil { 149 abort("Snapshot: %s", e) 150 } 151 152 t.Logf("Created online snapshot; uuid %s", uuid) 153 snap = uuid 154 } 155 156 func TestTopDeltaFile(t *testing.T) { 157 f, e := d.TopDeltaFile() 158 if e != nil { 159 t.Fatalf("TopDeltaFile: %s", e) 160 } 161 t.Logf("Got TopDeltaFile %s", f) 162 } 163 164 func copyFile(src, dst string) error { 165 return exec.Command("cp", "-a", src, dst).Run() 166 } 167 168 func testReplace(t *testing.T) { 169 var p ReplaceParam 170 newDelta := baseDelta + ".new" 171 e := copyFile(baseDelta, newDelta) 172 if e != nil { 173 t.Fatalf("copyFile: %s", e) 174 } 175 176 p.File = newDelta 177 p.CurFile = baseDelta 178 p.Flags = KeepName 179 e = d.Replace(&p) 180 if e != nil { 181 t.Fatalf("Replace: %s", e) 182 } 183 } 184 185 func TestReplaceOnline(t *testing.T) { 186 testReplace(t) 187 } 188 189 func TestSwitchSnapshotOnline(t *testing.T) { 190 e := d.SwitchSnapshot(snap) 191 // should fail with E_PARAM 192 if IsError(e, E_PARAM) { 193 t.Logf("SwitchSnapshot: (online) good, expected error") 194 } else { 195 t.Fatalf("SwitchSnapshot: (should fail): %s", e) 196 } 197 } 198 199 func TestDeleteSnapshot(t *testing.T) { 200 e := d.DeleteSnapshot(snap) 201 if e != nil { 202 t.Fatalf("DeleteSnapshot: %s", e) 203 } else { 204 t.Logf("Deleted snapshot %s", snap) 205 } 206 } 207 208 func TestIsMounted1(t *testing.T) { 209 m, e := d.IsMounted() 210 if e != nil { 211 t.Fatalf("IsMounted: %s", e) 212 } 213 if !m { 214 t.Fatalf("IsMounted: unexpectedly returned false") 215 } 216 } 217 218 func TestUmount(t *testing.T) { 219 e := d.Umount() 220 if e != nil { 221 t.Fatalf("Umount: %s", e) 222 } 223 } 224 225 func TestIsMounted2(t *testing.T) { 226 m, e := d.IsMounted() 227 if e != nil { 228 t.Fatalf("IsMounted: %s", e) 229 } 230 if m { 231 t.Fatalf("IsMounted: unexpectedly returned true") 232 } 233 } 234 235 func TestUmountAgain(t *testing.T) { 236 e := d.Umount() 237 if IsNotMounted(e) { 238 t.Logf("Umount: (not mounted) good, expected error") 239 } else { 240 t.Fatalf("Umount: %s", e) 241 } 242 } 243 244 func TestResizeOfflineShrink(t *testing.T) { 245 resize(t, "256MB", true) 246 } 247 248 func TestResizeOfflineGrow(t *testing.T) { 249 resize(t, "512MB", true) 250 } 251 252 func TestResizeOfflineShrinkAgain(t *testing.T) { 253 resize(t, "256MB", true) 254 } 255 256 func TestSnapshotOffline(t *testing.T) { 257 uuid, e := d.Snapshot() 258 if e != nil { 259 t.Fatalf("Snapshot: %s", e) 260 } else { 261 t.Logf("Created offline snapshot; uuid %s", uuid) 262 } 263 264 snap = uuid 265 } 266 267 func TestReplaceOffline(t *testing.T) { 268 testReplace(t) 269 } 270 271 func TestSwitchSnapshot(t *testing.T) { 272 e := d.SwitchSnapshot(snap) 273 if e != nil { 274 t.Fatalf("SwitchSnapshot: %s", e) 275 } else { 276 t.Logf("Switched to snapshot %s", snap) 277 } 278 } 279 280 func TestFSInfo(t *testing.T) { 281 i, e := FSInfo("DiskDescriptor.xml") 282 283 if e != nil { 284 t.Errorf("FSInfo: %v", e) 285 } else { 286 bTotal := i.Blocks * i.BlockSize 287 bAvail := i.BlocksFree * i.BlockSize 288 bUsed := bTotal - bAvail 289 290 iTotal := i.Inodes 291 iAvail := i.InodesFree 292 iUsed := iTotal - iAvail 293 294 t.Logf("\n Size Used Avail Use%%\n%7s %9s %10s %10s %3d%%\n%7s %9d %10d %10d %3d%%", 295 "Blocks", 296 humanize.Bytes(bTotal), 297 humanize.Bytes(bUsed), 298 humanize.Bytes(bAvail), 299 100*bUsed/bTotal, 300 "Inodes", 301 iTotal, 302 iUsed, 303 iAvail, 304 100*iUsed/iTotal) 305 t.Logf("\nInode ratio: 1 inode per %s of disk space", 306 humanize.Bytes(bTotal/iTotal)) 307 } 308 } 309 310 func TestImageInfo(t *testing.T) { 311 i, e := d.ImageInfo() 312 if e != nil { 313 t.Errorf("ImageInfo: %v", e) 314 } else { 315 t.Logf("\n Blocks Blocksize Size Ver\n%20d %10d %10s %4d", 316 i.Blocks, i.BlockSize, 317 humanize.Bytes(512*i.Blocks), 318 i.Version) 319 } 320 321 } 322 323 func cleanup() { 324 if d.d != nil { 325 if m, _ := d.IsMounted(); m { 326 d.Umount() 327 } 328 d.Close() 329 } 330 if oldPwd != "" { 331 os.Chdir(oldPwd) 332 } 333 if testDir != "" { 334 os.RemoveAll(testDir) 335 } 336 } 337 338 // TestCleanup is the last test, removing files created by previous tests 339 func TestCleanup(t *testing.T) { 340 cleanup() 341 } 342 343 func BenchmarkMountUmount(b *testing.B) { 344 b.StopTimer() 345 prepare("tmp-bench") 346 SetVerboseLevel(NoStdout) 347 create() 348 open() 349 mnt := "mnt" 350 e := os.Mkdir(mnt, 0755) 351 chk(e) 352 p := MountParam{Target: mnt, Readonly: true} 353 354 b.StartTimer() 355 for n := 0; n < b.N; n++ { 356 _, e := d.Mount(&p) 357 if e != nil { 358 b.Fatalf("Mount: %s", e) 359 } 360 e = d.Umount() 361 if e != nil { 362 b.Fatalf("Umount: %s", e) 363 } 364 } 365 b.StopTimer() 366 cleanup() 367 } 368 369 func BenchmarkIsMounted(b *testing.B) { 370 b.StopTimer() 371 prepare("tmp-bench") 372 SetVerboseLevel(NoStdout) 373 create() 374 open() 375 mnt := "mnt" 376 e := os.Mkdir(mnt, 0755) 377 chk(e) 378 p := MountParam{Target: mnt, Readonly: true} 379 _, e = d.Mount(&p) 380 if e != nil { 381 b.Fatalf("Mount: %s", e) 382 } 383 384 b.StartTimer() 385 for n := 0; n < b.N; n++ { 386 _, e := d.IsMounted() 387 if e != nil { 388 b.Fatalf("IsMounted: %s", e) 389 } 390 } 391 b.StopTimer() 392 cleanup() 393 } 394 395 func BenchmarkFSInfo(b *testing.B) { 396 b.StopTimer() 397 prepare("tmp-bench") 398 SetVerboseLevel(NoStdout) 399 create() 400 open() 401 mnt := "mnt" 402 e := os.Mkdir(mnt, 0755) 403 chk(e) 404 p := MountParam{Target: mnt, Readonly: true} 405 _, e = d.Mount(&p) 406 if e != nil { 407 b.Fatalf("Mount: %s", e) 408 } 409 410 b.StartTimer() 411 for n := 0; n < b.N; n++ { 412 _, e := FSInfo("DiskDescriptor.xml") 413 if e != nil { 414 b.Fatalf("FSInfo: %s", e) 415 } 416 } 417 b.StopTimer() 418 cleanup() 419 } 420 421 func BenchmarkImageInfo(b *testing.B) { 422 b.StopTimer() 423 prepare("tmp-bench") 424 SetVerboseLevel(NoStdout) 425 create() 426 open() 427 mnt := "mnt" 428 e := os.Mkdir(mnt, 0755) 429 chk(e) 430 p := MountParam{Target: mnt, Readonly: true} 431 _, e = d.Mount(&p) 432 if e != nil { 433 b.Fatalf("Mount: %s", e) 434 } 435 436 b.StartTimer() 437 for n := 0; n < b.N; n++ { 438 _, e := d.ImageInfo() 439 if e != nil { 440 b.Fatalf("ImageInfo: %s", e) 441 } 442 } 443 b.StopTimer() 444 cleanup() 445 }