github.com/evdatsion/aphelion-dpos-bft@v0.32.1/libs/common/tempfile_test.go (about)

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