github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/countlog/output/lumberjack/lumberjack_test.go (about)

     1  package lumberjack
     2  
     3  import (
     4  	"bytes"
     5  	"compress/gzip"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/BurntSushi/toml"
    15  	"gopkg.in/yaml.v2"
    16  )
    17  
    18  // !!!NOTE!!!
    19  //
    20  // Running these tests in parallel will almost certainly cause sporadic (or even
    21  // regular) failures, because they're all messing with the same global variable
    22  // that controls the logic's mocked time.Now.  So... don't do that.
    23  
    24  // Since all the tests uses the time to determine filenames etc, we need to
    25  // control the wall clock as much as possible, which means having a wall clock
    26  // that doesn't change unless we want it to.
    27  var fakeCurrentTime = time.Now()
    28  
    29  func fakeTime() time.Time {
    30  	return fakeCurrentTime
    31  }
    32  
    33  func TestNewFile(t *testing.T) {
    34  	currentTime = fakeTime
    35  
    36  	dir := makeTempDir("TestNewFile", t)
    37  	defer os.RemoveAll(dir)
    38  	l := &Logger{
    39  		Filename: logFile(dir),
    40  	}
    41  	defer l.Close()
    42  	b := []byte("boo!")
    43  	n, err := l.Write(b)
    44  	isNil(err, t)
    45  	equals(len(b), n, t)
    46  	existsWithContent(logFile(dir), b, t)
    47  	fileCount(dir, 1, t)
    48  }
    49  
    50  func TestOpenExisting(t *testing.T) {
    51  	currentTime = fakeTime
    52  	dir := makeTempDir("TestOpenExisting", t)
    53  	defer os.RemoveAll(dir)
    54  
    55  	filename := logFile(dir)
    56  	data := []byte("foo!")
    57  	err := ioutil.WriteFile(filename, data, 0644)
    58  	isNil(err, t)
    59  	existsWithContent(filename, data, t)
    60  
    61  	l := &Logger{
    62  		Filename: filename,
    63  	}
    64  	defer l.Close()
    65  	b := []byte("boo!")
    66  	n, err := l.Write(b)
    67  	isNil(err, t)
    68  	equals(len(b), n, t)
    69  
    70  	// make sure the file got appended
    71  	existsWithContent(filename, append(data, b...), t)
    72  
    73  	// make sure no other files were created
    74  	fileCount(dir, 1, t)
    75  }
    76  
    77  func TestWriteTooLong(t *testing.T) {
    78  	currentTime = fakeTime
    79  	megabyte = 1
    80  	dir := makeTempDir("TestWriteTooLong", t)
    81  	defer os.RemoveAll(dir)
    82  	l := &Logger{
    83  		Filename: logFile(dir),
    84  		MaxSize:  5,
    85  	}
    86  	defer l.Close()
    87  	b := []byte("booooooooooooooo!")
    88  	n, err := l.Write(b)
    89  	notNil(err, t)
    90  	equals(0, n, t)
    91  	equals(err.Error(),
    92  		fmt.Sprintf("write length %d exceeds maximum file size %d", len(b), l.MaxSize), t)
    93  	_, err = os.Stat(logFile(dir))
    94  	assert(os.IsNotExist(err), t, "File exists, but should not have been created")
    95  }
    96  
    97  func TestMakeLogDir(t *testing.T) {
    98  	currentTime = fakeTime
    99  	dir := time.Now().Format("TestMakeLogDir" + backupTimeFormat)
   100  	dir = filepath.Join(os.TempDir(), dir)
   101  	defer os.RemoveAll(dir)
   102  	filename := logFile(dir)
   103  	l := &Logger{
   104  		Filename: filename,
   105  	}
   106  	defer l.Close()
   107  	b := []byte("boo!")
   108  	n, err := l.Write(b)
   109  	isNil(err, t)
   110  	equals(len(b), n, t)
   111  	existsWithContent(logFile(dir), b, t)
   112  	fileCount(dir, 1, t)
   113  }
   114  
   115  func TestDefaultFilename(t *testing.T) {
   116  	currentTime = fakeTime
   117  	dir := os.TempDir()
   118  	filename := filepath.Join(dir, filepath.Base(os.Args[0])+"-lumberjack.log")
   119  	defer os.Remove(filename)
   120  	l := &Logger{}
   121  	defer l.Close()
   122  	b := []byte("boo!")
   123  	n, err := l.Write(b)
   124  
   125  	isNil(err, t)
   126  	equals(len(b), n, t)
   127  	existsWithContent(filename, b, t)
   128  }
   129  
   130  func TestAutoRotate(t *testing.T) {
   131  	currentTime = fakeTime
   132  	megabyte = 1
   133  
   134  	dir := makeTempDir("TestAutoRotate", t)
   135  	defer os.RemoveAll(dir)
   136  
   137  	filename := logFile(dir)
   138  	l := &Logger{
   139  		Filename: filename,
   140  		MaxSize:  10,
   141  	}
   142  	defer l.Close()
   143  	b := []byte("boo!")
   144  	n, err := l.Write(b)
   145  	isNil(err, t)
   146  	equals(len(b), n, t)
   147  
   148  	existsWithContent(filename, b, t)
   149  	fileCount(dir, 1, t)
   150  
   151  	newFakeTime()
   152  
   153  	b2 := []byte("foooooo!")
   154  	n, err = l.Write(b2)
   155  	isNil(err, t)
   156  	equals(len(b2), n, t)
   157  
   158  	// the old logfile should be moved aside and the main logfile should have
   159  	// only the last write in it.
   160  	existsWithContent(filename, b2, t)
   161  
   162  	// the backup file will use the current fake time and have the old contents.
   163  	existsWithContent(backupFile(dir), b, t)
   164  
   165  	fileCount(dir, 2, t)
   166  }
   167  
   168  func TestFirstWriteRotate(t *testing.T) {
   169  	currentTime = fakeTime
   170  	megabyte = 1
   171  	dir := makeTempDir("TestFirstWriteRotate", t)
   172  	defer os.RemoveAll(dir)
   173  
   174  	filename := logFile(dir)
   175  	l := &Logger{
   176  		Filename: filename,
   177  		MaxSize:  10,
   178  	}
   179  	defer l.Close()
   180  
   181  	start := []byte("boooooo!")
   182  	err := ioutil.WriteFile(filename, start, 0600)
   183  	isNil(err, t)
   184  
   185  	newFakeTime()
   186  
   187  	// this would make us rotate
   188  	b := []byte("fooo!")
   189  	n, err := l.Write(b)
   190  	isNil(err, t)
   191  	equals(len(b), n, t)
   192  
   193  	existsWithContent(filename, b, t)
   194  	existsWithContent(backupFile(dir), start, t)
   195  
   196  	fileCount(dir, 2, t)
   197  }
   198  
   199  func TestMaxBackups(t *testing.T) {
   200  	currentTime = fakeTime
   201  	megabyte = 1
   202  	dir := makeTempDir("TestMaxBackups", t)
   203  	defer os.RemoveAll(dir)
   204  
   205  	filename := logFile(dir)
   206  	l := &Logger{
   207  		Filename:   filename,
   208  		MaxSize:    10,
   209  		MaxBackups: 1,
   210  	}
   211  	defer l.Close()
   212  	b := []byte("boo!")
   213  	n, err := l.Write(b)
   214  	isNil(err, t)
   215  	equals(len(b), n, t)
   216  
   217  	existsWithContent(filename, b, t)
   218  	fileCount(dir, 1, t)
   219  
   220  	newFakeTime()
   221  
   222  	// this will put us over the max
   223  	b2 := []byte("foooooo!")
   224  	n, err = l.Write(b2)
   225  	isNil(err, t)
   226  	equals(len(b2), n, t)
   227  
   228  	// this will use the new fake time
   229  	secondFilename := backupFile(dir)
   230  	existsWithContent(secondFilename, b, t)
   231  
   232  	// make sure the old file still exists with the same content.
   233  	existsWithContent(filename, b2, t)
   234  
   235  	fileCount(dir, 2, t)
   236  
   237  	newFakeTime()
   238  
   239  	// this will make us rotate again
   240  	b3 := []byte("baaaaaar!")
   241  	n, err = l.Write(b3)
   242  	isNil(err, t)
   243  	equals(len(b3), n, t)
   244  
   245  	// this will use the new fake time
   246  	thirdFilename := backupFile(dir)
   247  	existsWithContent(thirdFilename, b2, t)
   248  
   249  	existsWithContent(filename, b3, t)
   250  
   251  	// we need to wait a little bit since the files get deleted on a different
   252  	// goroutine.
   253  	<-time.After(time.Millisecond * 10)
   254  
   255  	// should only have two files in the dir still
   256  	fileCount(dir, 2, t)
   257  
   258  	// second file name should still exist
   259  	existsWithContent(thirdFilename, b2, t)
   260  
   261  	// should have deleted the first backup
   262  	notExist(secondFilename, t)
   263  
   264  	// now test that we don't delete directories or non-logfile files
   265  
   266  	newFakeTime()
   267  
   268  	// create a file that is close to but different from the logfile name.
   269  	// It shouldn't get caught by our deletion filters.
   270  	notlogfile := logFile(dir) + ".foo"
   271  	err = ioutil.WriteFile(notlogfile, []byte("data"), 0644)
   272  	isNil(err, t)
   273  
   274  	// Make a directory that exactly matches our log file filters... it still
   275  	// shouldn't get caught by the deletion filter since it's a directory.
   276  	notlogfiledir := backupFile(dir)
   277  	err = os.Mkdir(notlogfiledir, 0700)
   278  	isNil(err, t)
   279  
   280  	newFakeTime()
   281  
   282  	// this will use the new fake time
   283  	fourthFilename := backupFile(dir)
   284  
   285  	// Create a log file that is/was being compressed - this should
   286  	// not be counted since both the compressed and the uncompressed
   287  	// log files still exist.
   288  	compLogFile := fourthFilename+compressSuffix
   289  	err = ioutil.WriteFile(compLogFile, []byte("compress"), 0644)
   290  	isNil(err, t)
   291  
   292  	// this will make us rotate again
   293  	b4 := []byte("baaaaaaz!")
   294  	n, err = l.Write(b4)
   295  	isNil(err, t)
   296  	equals(len(b4), n, t)
   297  
   298  	existsWithContent(fourthFilename, b3, t)
   299  	existsWithContent(fourthFilename+compressSuffix, []byte("compress"), t)
   300  
   301  	// we need to wait a little bit since the files get deleted on a different
   302  	// goroutine.
   303  	<-time.After(time.Millisecond * 10)
   304  
   305  	// We should have four things in the directory now - the 2 log files, the
   306  	// not log file, and the directory
   307  	fileCount(dir, 5, t)
   308  
   309  	// third file name should still exist
   310  	existsWithContent(filename, b4, t)
   311  
   312  	existsWithContent(fourthFilename, b3, t)
   313  
   314  	// should have deleted the first filename
   315  	notExist(thirdFilename, t)
   316  
   317  	// the not-a-logfile should still exist
   318  	exists(notlogfile, t)
   319  
   320  	// the directory
   321  	exists(notlogfiledir, t)
   322  }
   323  
   324  func TestCleanupExistingBackups(t *testing.T) {
   325  	// test that if we start with more backup files than we're supposed to have
   326  	// in total, that extra ones get cleaned up when we rotate.
   327  
   328  	currentTime = fakeTime
   329  	megabyte = 1
   330  
   331  	dir := makeTempDir("TestCleanupExistingBackups", t)
   332  	defer os.RemoveAll(dir)
   333  
   334  	// make 3 backup files
   335  
   336  	data := []byte("data")
   337  	backup := backupFile(dir)
   338  	err := ioutil.WriteFile(backup, data, 0644)
   339  	isNil(err, t)
   340  
   341  	newFakeTime()
   342  
   343  	backup = backupFile(dir)
   344  	err = ioutil.WriteFile(backup+compressSuffix, data, 0644)
   345  	isNil(err, t)
   346  
   347  	newFakeTime()
   348  
   349  	backup = backupFile(dir)
   350  	err = ioutil.WriteFile(backup, data, 0644)
   351  	isNil(err, t)
   352  
   353  	// now create a primary log file with some data
   354  	filename := logFile(dir)
   355  	err = ioutil.WriteFile(filename, data, 0644)
   356  	isNil(err, t)
   357  
   358  	l := &Logger{
   359  		Filename:   filename,
   360  		MaxSize:    10,
   361  		MaxBackups: 1,
   362  	}
   363  	defer l.Close()
   364  
   365  	newFakeTime()
   366  
   367  	b2 := []byte("foooooo!")
   368  	n, err := l.Write(b2)
   369  	isNil(err, t)
   370  	equals(len(b2), n, t)
   371  
   372  	// we need to wait a little bit since the files get deleted on a different
   373  	// goroutine.
   374  	<-time.After(time.Millisecond * 10)
   375  
   376  	// now we should only have 2 files left - the primary and one backup
   377  	fileCount(dir, 2, t)
   378  }
   379  
   380  func TestMaxAge(t *testing.T) {
   381  	currentTime = fakeTime
   382  	megabyte = 1
   383  
   384  	dir := makeTempDir("TestMaxAge", t)
   385  	defer os.RemoveAll(dir)
   386  
   387  	filename := logFile(dir)
   388  	l := &Logger{
   389  		Filename: filename,
   390  		MaxSize:  10,
   391  		MaxAge:   1,
   392  	}
   393  	defer l.Close()
   394  	b := []byte("boo!")
   395  	n, err := l.Write(b)
   396  	isNil(err, t)
   397  	equals(len(b), n, t)
   398  
   399  	existsWithContent(filename, b, t)
   400  	fileCount(dir, 1, t)
   401  
   402  	// two days later
   403  	newFakeTime()
   404  
   405  	b2 := []byte("foooooo!")
   406  	n, err = l.Write(b2)
   407  	isNil(err, t)
   408  	equals(len(b2), n, t)
   409  	existsWithContent(backupFile(dir), b, t)
   410  
   411  	// we need to wait a little bit since the files get deleted on a different
   412  	// goroutine.
   413  	<-time.After(10 * time.Millisecond)
   414  
   415  	// We should still have 2 log files, since the most recent backup was just
   416  	// created.
   417  	fileCount(dir, 2, t)
   418  
   419  	existsWithContent(filename, b2, t)
   420  
   421  	// we should have deleted the old file due to being too old
   422  	existsWithContent(backupFile(dir), b, t)
   423  
   424  	// two days later
   425  	newFakeTime()
   426  
   427  	b3 := []byte("baaaaar!")
   428  	n, err = l.Write(b3)
   429  	isNil(err, t)
   430  	equals(len(b3), n, t)
   431  	existsWithContent(backupFile(dir), b2, t)
   432  
   433  	// we need to wait a little bit since the files get deleted on a different
   434  	// goroutine.
   435  	<-time.After(10 * time.Millisecond)
   436  
   437  	// We should have 2 log files - the main log file, and the most recent
   438  	// backup.  The earlier backup is past the cutoff and should be gone.
   439  	fileCount(dir, 2, t)
   440  
   441  	existsWithContent(filename, b3, t)
   442  
   443  	// we should have deleted the old file due to being too old
   444  	existsWithContent(backupFile(dir), b2, t)
   445  }
   446  
   447  func TestOldLogFiles(t *testing.T) {
   448  	currentTime = fakeTime
   449  	megabyte = 1
   450  
   451  	dir := makeTempDir("TestOldLogFiles", t)
   452  	defer os.RemoveAll(dir)
   453  
   454  	filename := logFile(dir)
   455  	data := []byte("data")
   456  	err := ioutil.WriteFile(filename, data, 07)
   457  	isNil(err, t)
   458  
   459  	// This gives us a time with the same precision as the time we get from the
   460  	// timestamp in the name.
   461  	t1, err := time.Parse(backupTimeFormat, fakeTime().UTC().Format(backupTimeFormat))
   462  	isNil(err, t)
   463  
   464  	backup := backupFile(dir)
   465  	err = ioutil.WriteFile(backup, data, 07)
   466  	isNil(err, t)
   467  
   468  	newFakeTime()
   469  
   470  	t2, err := time.Parse(backupTimeFormat, fakeTime().UTC().Format(backupTimeFormat))
   471  	isNil(err, t)
   472  
   473  	backup2 := backupFile(dir)
   474  	err = ioutil.WriteFile(backup2, data, 07)
   475  	isNil(err, t)
   476  
   477  	l := &Logger{Filename: filename}
   478  	files, err := l.oldLogFiles()
   479  	isNil(err, t)
   480  	equals(2, len(files), t)
   481  
   482  	// should be sorted by newest file first, which would be t2
   483  	equals(t2, files[0].timestamp, t)
   484  	equals(t1, files[1].timestamp, t)
   485  }
   486  
   487  func TestTimeFromName(t *testing.T) {
   488  	l := &Logger{Filename: "/var/log/myfoo/foo.log"}
   489  	prefix, ext := l.prefixAndExt()
   490  
   491  	tests := []struct {
   492  		filename string
   493  		want     time.Time
   494  		wantErr  bool
   495  	}{
   496  		{"foo-2014-05-04T14-44-33.555.log", time.Date(2014, 5, 4, 14, 44, 33, 555000000, time.UTC), false},
   497  		{"foo-2014-05-04T14-44-33.555", time.Time{}, true},
   498  		{"2014-05-04T14-44-33.555.log", time.Time{}, true},
   499  		{"foo.log", time.Time{}, true},
   500  	}
   501  
   502  	for _, test := range tests {
   503  		got, err := l.timeFromName(test.filename, prefix, ext)
   504  		equals(got, test.want, t)
   505  		equals(err != nil, test.wantErr, t)
   506  	}
   507  }
   508  
   509  func TestLocalTime(t *testing.T) {
   510  	currentTime = fakeTime
   511  	megabyte = 1
   512  
   513  	dir := makeTempDir("TestLocalTime", t)
   514  	defer os.RemoveAll(dir)
   515  
   516  	l := &Logger{
   517  		Filename:  logFile(dir),
   518  		MaxSize:   10,
   519  		LocalTime: true,
   520  	}
   521  	defer l.Close()
   522  	b := []byte("boo!")
   523  	n, err := l.Write(b)
   524  	isNil(err, t)
   525  	equals(len(b), n, t)
   526  
   527  	b2 := []byte("fooooooo!")
   528  	n2, err := l.Write(b2)
   529  	isNil(err, t)
   530  	equals(len(b2), n2, t)
   531  
   532  	existsWithContent(logFile(dir), b2, t)
   533  	existsWithContent(backupFileLocal(dir), b, t)
   534  }
   535  
   536  func TestRotate(t *testing.T) {
   537  	currentTime = fakeTime
   538  	dir := makeTempDir("TestRotate", t)
   539  	defer os.RemoveAll(dir)
   540  
   541  	filename := logFile(dir)
   542  
   543  	l := &Logger{
   544  		Filename:   filename,
   545  		MaxBackups: 1,
   546  		MaxSize:    100, // megabytes
   547  	}
   548  	defer l.Close()
   549  	b := []byte("boo!")
   550  	n, err := l.Write(b)
   551  	isNil(err, t)
   552  	equals(len(b), n, t)
   553  
   554  	existsWithContent(filename, b, t)
   555  	fileCount(dir, 1, t)
   556  
   557  	newFakeTime()
   558  
   559  	err = l.Rotate()
   560  	isNil(err, t)
   561  
   562  	// we need to wait a little bit since the files get deleted on a different
   563  	// goroutine.
   564  	<-time.After(10 * time.Millisecond)
   565  
   566  	filename2 := backupFile(dir)
   567  	existsWithContent(filename2, b, t)
   568  	existsWithContent(filename, []byte{}, t)
   569  	fileCount(dir, 2, t)
   570  	newFakeTime()
   571  
   572  	err = l.Rotate()
   573  	isNil(err, t)
   574  
   575  	// we need to wait a little bit since the files get deleted on a different
   576  	// goroutine.
   577  	<-time.After(10 * time.Millisecond)
   578  
   579  	filename3 := backupFile(dir)
   580  	existsWithContent(filename3, []byte{}, t)
   581  	existsWithContent(filename, []byte{}, t)
   582  	fileCount(dir, 2, t)
   583  
   584  	b2 := []byte("foooooo!")
   585  	n, err = l.Write(b2)
   586  	isNil(err, t)
   587  	equals(len(b2), n, t)
   588  
   589  	// this will use the new fake time
   590  	existsWithContent(filename, b2, t)
   591  }
   592  
   593  func TestCompressOnRotate(t *testing.T) {
   594  	currentTime = fakeTime
   595  	megabyte = 1
   596  
   597  	dir := makeTempDir("TestCompressOnRotate", t)
   598  	defer os.RemoveAll(dir)
   599  
   600  	filename := logFile(dir)
   601  	l := &Logger{
   602  		Compress: true,
   603  		Filename: filename,
   604  		MaxSize:  10,
   605  	}
   606  	defer l.Close()
   607  	b := []byte("boo!")
   608  	n, err := l.Write(b)
   609  	isNil(err, t)
   610  	equals(len(b), n, t)
   611  
   612  	existsWithContent(filename, b, t)
   613  	fileCount(dir, 1, t)
   614  
   615  	newFakeTime()
   616  
   617  	err = l.Rotate()
   618  	isNil(err, t)
   619  
   620  	// the old logfile should be moved aside and the main logfile should have
   621  	// nothing in it.
   622  	existsWithContent(filename, []byte{}, t)
   623  
   624  	// we need to wait a little bit since the files get compressed on a different
   625  	// goroutine.
   626  	<-time.After(10 * time.Millisecond)
   627  
   628  	// a compressed version of the log file should now exist and the original
   629  	// should have been removed.
   630  	bc := new(bytes.Buffer)
   631  	gz := gzip.NewWriter(bc)
   632  	_, err = gz.Write(b)
   633  	isNil(err, t)
   634  	err = gz.Close()
   635  	isNil(err, t)
   636  	existsWithContent(backupFile(dir)+compressSuffix, bc.Bytes(), t)
   637  	notExist(backupFile(dir), t)
   638  
   639  	fileCount(dir, 2, t)
   640  }
   641  
   642  func TestCompressOnResume(t *testing.T) {
   643  	currentTime = fakeTime
   644  	megabyte = 1
   645  
   646  	dir := makeTempDir("TestCompressOnResume", t)
   647  	defer os.RemoveAll(dir)
   648  
   649  	filename := logFile(dir)
   650  	l := &Logger{
   651  		Compress: true,
   652  		Filename: filename,
   653  		MaxSize:  10,
   654  	}
   655  	defer l.Close()
   656  
   657  	// Create a backup file and empty "compressed" file.
   658  	filename2 := backupFile(dir)
   659  	b := []byte("foo!")
   660  	err := ioutil.WriteFile(filename2, b, 0644)
   661  	isNil(err, t)
   662  	err = ioutil.WriteFile(filename2+compressSuffix, []byte{}, 0644)
   663  	isNil(err, t)
   664  
   665  	newFakeTime()
   666  
   667  	b2 := []byte("boo!")
   668  	n, err := l.Write(b2)
   669  	isNil(err, t)
   670  	equals(len(b2), n, t)
   671  	existsWithContent(filename, b2, t)
   672  
   673  	// we need to wait a little bit since the files get compressed on a different
   674  	// goroutine.
   675  	<-time.After(10 * time.Millisecond)
   676  
   677  	// The write should have started the compression - a compressed version of
   678  	// the log file should now exist and the original should have been removed.
   679  	bc := new(bytes.Buffer)
   680  	gz := gzip.NewWriter(bc)
   681  	_, err = gz.Write(b)
   682  	isNil(err, t)
   683  	err = gz.Close()
   684  	isNil(err, t)
   685  	existsWithContent(filename2+compressSuffix, bc.Bytes(), t)
   686  	notExist(filename2, t)
   687  
   688  	fileCount(dir, 2, t)
   689  }
   690  
   691  func TestJson(t *testing.T) {
   692  	data := []byte(`
   693  {
   694  	"filename": "foo",
   695  	"maxsize": 5,
   696  	"maxage": 10,
   697  	"maxbackups": 3,
   698  	"localtime": true,
   699  	"compress": true
   700  }`[1:])
   701  
   702  	l := Logger{}
   703  	err := json.Unmarshal(data, &l)
   704  	isNil(err, t)
   705  	equals("foo", l.Filename, t)
   706  	equals(5, l.MaxSize, t)
   707  	equals(10, l.MaxAge, t)
   708  	equals(3, l.MaxBackups, t)
   709  	equals(true, l.LocalTime, t)
   710  	equals(true, l.Compress, t)
   711  }
   712  
   713  func TestYaml(t *testing.T) {
   714  	data := []byte(`
   715  filename: foo
   716  maxsize: 5
   717  maxage: 10
   718  maxbackups: 3
   719  localtime: true
   720  compress: true`[1:])
   721  
   722  	l := Logger{}
   723  	err := yaml.Unmarshal(data, &l)
   724  	isNil(err, t)
   725  	equals("foo", l.Filename, t)
   726  	equals(5, l.MaxSize, t)
   727  	equals(10, l.MaxAge, t)
   728  	equals(3, l.MaxBackups, t)
   729  	equals(true, l.LocalTime, t)
   730  	equals(true, l.Compress, t)
   731  }
   732  
   733  func TestToml(t *testing.T) {
   734  	data := `
   735  filename = "foo"
   736  maxsize = 5
   737  maxage = 10
   738  maxbackups = 3
   739  localtime = true
   740  compress = true`[1:]
   741  
   742  	l := Logger{}
   743  	md, err := toml.Decode(data, &l)
   744  	isNil(err, t)
   745  	equals("foo", l.Filename, t)
   746  	equals(5, l.MaxSize, t)
   747  	equals(10, l.MaxAge, t)
   748  	equals(3, l.MaxBackups, t)
   749  	equals(true, l.LocalTime, t)
   750  	equals(true, l.Compress, t)
   751  	equals(0, len(md.Undecoded()), t)
   752  }
   753  
   754  // makeTempDir creates a file with a semi-unique name in the OS temp directory.
   755  // It should be based on the name of the test, to keep parallel tests from
   756  // colliding, and must be cleaned up after the test is finished.
   757  func makeTempDir(name string, t testing.TB) string {
   758  	dir := time.Now().Format(name + backupTimeFormat)
   759  	dir = filepath.Join(os.TempDir(), dir)
   760  	isNilUp(os.Mkdir(dir, 0700), t, 1)
   761  	return dir
   762  }
   763  
   764  // existsWithContent checks that the given file exists and has the correct content.
   765  func existsWithContent(path string, content []byte, t testing.TB) {
   766  	info, err := os.Stat(path)
   767  	isNilUp(err, t, 1)
   768  	equalsUp(int64(len(content)), info.Size(), t, 1)
   769  
   770  	b, err := ioutil.ReadFile(path)
   771  	isNilUp(err, t, 1)
   772  	equalsUp(content, b, t, 1)
   773  }
   774  
   775  // logFile returns the log file name in the given directory for the current fake
   776  // time.
   777  func logFile(dir string) string {
   778  	return filepath.Join(dir, "foobar.log")
   779  }
   780  
   781  func backupFile(dir string) string {
   782  	return filepath.Join(dir, "foobar-"+fakeTime().UTC().Format(backupTimeFormat)+".log")
   783  }
   784  
   785  func backupFileLocal(dir string) string {
   786  	return filepath.Join(dir, "foobar-"+fakeTime().Format(backupTimeFormat)+".log")
   787  }
   788  
   789  // logFileLocal returns the log file name in the given directory for the current
   790  // fake time using the local timezone.
   791  func logFileLocal(dir string) string {
   792  	return filepath.Join(dir, fakeTime().Format(backupTimeFormat))
   793  }
   794  
   795  // fileCount checks that the number of files in the directory is exp.
   796  func fileCount(dir string, exp int, t testing.TB) {
   797  	files, err := ioutil.ReadDir(dir)
   798  	isNilUp(err, t, 1)
   799  	// Make sure no other files were created.
   800  	equalsUp(exp, len(files), t, 1)
   801  }
   802  
   803  // newFakeTime sets the fake "current time" to two days later.
   804  func newFakeTime() {
   805  	fakeCurrentTime = fakeCurrentTime.Add(time.Hour * 24 * 2)
   806  }
   807  
   808  func notExist(path string, t testing.TB) {
   809  	_, err := os.Stat(path)
   810  	assertUp(os.IsNotExist(err), t, 1, "expected to get os.IsNotExist, but instead got %v", err)
   811  }
   812  
   813  func exists(path string, t testing.TB) {
   814  	_, err := os.Stat(path)
   815  	assertUp(err == nil, t, 1, "expected file to exist, but got error from os.Stat: %v", err)
   816  }