github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/libs/tempfile/tempfile_test.go (about)

     1  package tempfile
     2  
     3  // Need access to internal variables, so can't use _test package
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	testing "testing"
    11  
    12  	"github.com/stretchr/testify/require"
    13  
    14  	tmrand "github.com/franono/tendermint/libs/rand"
    15  )
    16  
    17  func TestWriteFileAtomic(t *testing.T) {
    18  	var (
    19  		data             = []byte(tmrand.Str(tmrand.Intn(2048)))
    20  		old              = tmrand.Bytes(tmrand.Intn(2048))
    21  		perm os.FileMode = 0600
    22  	)
    23  
    24  	f, err := ioutil.TempFile("/tmp", "write-atomic-test-")
    25  	if err != nil {
    26  		t.Fatal(err)
    27  	}
    28  	defer os.Remove(f.Name())
    29  
    30  	if err = ioutil.WriteFile(f.Name(), old, 0600); err != nil {
    31  		t.Fatal(err)
    32  	}
    33  
    34  	if err = WriteFileAtomic(f.Name(), data, perm); err != nil {
    35  		t.Fatal(err)
    36  	}
    37  
    38  	rData, err := ioutil.ReadFile(f.Name())
    39  	if err != nil {
    40  		t.Fatal(err)
    41  	}
    42  
    43  	if !bytes.Equal(data, rData) {
    44  		t.Fatalf("data mismatch: %v != %v", data, rData)
    45  	}
    46  
    47  	stat, err := os.Stat(f.Name())
    48  	if err != nil {
    49  		t.Fatal(err)
    50  	}
    51  
    52  	if have, want := stat.Mode().Perm(), perm; have != want {
    53  		t.Errorf("have %v, want %v", have, want)
    54  	}
    55  }
    56  
    57  // This tests atomic write file when there is a single duplicate file.
    58  // Expected behavior is for a new file to be created, and the original write file to be unaltered.
    59  func TestWriteFileAtomicDuplicateFile(t *testing.T) {
    60  	var (
    61  		defaultSeed    uint64 = 1
    62  		testString            = "This is a glorious test string"
    63  		expectedString        = "Did the test file's string appear here?"
    64  
    65  		fileToWrite = "/tmp/TestWriteFileAtomicDuplicateFile-test.txt"
    66  	)
    67  	// Create a file at the seed, and reset the seed.
    68  	atomicWriteFileRand = defaultSeed
    69  	firstFileRand := randWriteFileSuffix()
    70  	atomicWriteFileRand = defaultSeed
    71  	fname := "/tmp/" + atomicWriteFilePrefix + firstFileRand
    72  	f, err := os.OpenFile(fname, atomicWriteFileFlag, 0777)
    73  	defer os.Remove(fname)
    74  	// Defer here, in case there is a panic in WriteFileAtomic.
    75  	defer os.Remove(fileToWrite)
    76  
    77  	require.Nil(t, err)
    78  	f.WriteString(testString)
    79  	WriteFileAtomic(fileToWrite, []byte(expectedString), 0777)
    80  	// Check that the first atomic file was untouched
    81  	firstAtomicFileBytes, err := ioutil.ReadFile(fname)
    82  	require.Nil(t, err, "Error reading first atomic file")
    83  	require.Equal(t, []byte(testString), firstAtomicFileBytes, "First atomic file was overwritten")
    84  	// Check that the resultant file is correct
    85  	resultantFileBytes, err := ioutil.ReadFile(fileToWrite)
    86  	require.Nil(t, err, "Error reading resultant file")
    87  	require.Equal(t, []byte(expectedString), resultantFileBytes, "Written file had incorrect bytes")
    88  
    89  	// Check that the intermediate write file was deleted
    90  	// Get the second write files' randomness
    91  	atomicWriteFileRand = defaultSeed
    92  	_ = randWriteFileSuffix()
    93  	secondFileRand := randWriteFileSuffix()
    94  	_, err = os.Stat("/tmp/" + atomicWriteFilePrefix + secondFileRand)
    95  	require.True(t, os.IsNotExist(err), "Intermittent atomic write file not deleted")
    96  }
    97  
    98  // This tests atomic write file when there are many duplicate files.
    99  // Expected behavior is for a new file to be created under a completely new seed,
   100  // and the original write files to be unaltered.
   101  func TestWriteFileAtomicManyDuplicates(t *testing.T) {
   102  	var (
   103  		defaultSeed    uint64 = 2
   104  		testString            = "This is a glorious test string, from file %d"
   105  		expectedString        = "Did any of the test file's string appear here?"
   106  
   107  		fileToWrite = "/tmp/TestWriteFileAtomicDuplicateFile-test.txt"
   108  	)
   109  	// Initialize all of the atomic write files
   110  	atomicWriteFileRand = defaultSeed
   111  	for i := 0; i < atomicWriteFileMaxNumConflicts+2; i++ {
   112  		fileRand := randWriteFileSuffix()
   113  		fname := "/tmp/" + atomicWriteFilePrefix + fileRand
   114  		f, err := os.OpenFile(fname, atomicWriteFileFlag, 0777)
   115  		require.Nil(t, err)
   116  		f.WriteString(fmt.Sprintf(testString, i))
   117  		defer os.Remove(fname)
   118  	}
   119  
   120  	atomicWriteFileRand = defaultSeed
   121  	// Defer here, in case there is a panic in WriteFileAtomic.
   122  	defer os.Remove(fileToWrite)
   123  
   124  	WriteFileAtomic(fileToWrite, []byte(expectedString), 0777)
   125  	// Check that all intermittent atomic file were untouched
   126  	atomicWriteFileRand = defaultSeed
   127  	for i := 0; i < atomicWriteFileMaxNumConflicts+2; i++ {
   128  		fileRand := randWriteFileSuffix()
   129  		fname := "/tmp/" + atomicWriteFilePrefix + fileRand
   130  		firstAtomicFileBytes, err := ioutil.ReadFile(fname)
   131  		require.Nil(t, err, "Error reading first atomic file")
   132  		require.Equal(t, []byte(fmt.Sprintf(testString, i)), firstAtomicFileBytes,
   133  			"atomic write file %d was overwritten", i)
   134  	}
   135  
   136  	// Check that the resultant file is correct
   137  	resultantFileBytes, err := ioutil.ReadFile(fileToWrite)
   138  	require.Nil(t, err, "Error reading resultant file")
   139  	require.Equal(t, []byte(expectedString), resultantFileBytes, "Written file had incorrect bytes")
   140  }