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  }