You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
7.3 KiB
289 lines
7.3 KiB
package chanbackup |
|
|
|
import ( |
|
"bytes" |
|
"fmt" |
|
"io/ioutil" |
|
"math/rand" |
|
"os" |
|
"path/filepath" |
|
"testing" |
|
) |
|
|
|
func makeFakePackedMulti() (PackedMulti, error) { |
|
newPackedMulti := make([]byte, 50) |
|
if _, err := rand.Read(newPackedMulti[:]); err != nil { |
|
return nil, fmt.Errorf("unable to make test backup: %v", err) |
|
} |
|
|
|
return PackedMulti(newPackedMulti), nil |
|
} |
|
|
|
func assertBackupMatches(t *testing.T, filePath string, |
|
currentBackup PackedMulti) { |
|
|
|
t.Helper() |
|
|
|
packedBackup, err := ioutil.ReadFile(filePath) |
|
if err != nil { |
|
t.Fatalf("unable to test file: %v", err) |
|
} |
|
|
|
if !bytes.Equal(packedBackup, currentBackup) { |
|
t.Fatalf("backups don't match after first swap: "+ |
|
"expected %x got %x", packedBackup[:], |
|
currentBackup) |
|
} |
|
} |
|
|
|
func assertFileDeleted(t *testing.T, filePath string) { |
|
t.Helper() |
|
|
|
_, err := os.Stat(filePath) |
|
if err == nil { |
|
t.Fatalf("file %v still exists: ", filePath) |
|
} |
|
} |
|
|
|
// TestUpdateAndSwap test that we're able to properly swap out old backups on |
|
// disk with new ones. Additionally, after a swap operation succeeds, then each |
|
// time we should only have the main backup file on disk, as the temporary file |
|
// has been removed. |
|
func TestUpdateAndSwap(t *testing.T) { |
|
t.Parallel() |
|
|
|
tempTestDir, err := ioutil.TempDir("", "") |
|
if err != nil { |
|
t.Fatalf("unable to make temp dir: %v", err) |
|
} |
|
defer os.Remove(tempTestDir) |
|
|
|
testCases := []struct { |
|
fileName string |
|
tempFileName string |
|
|
|
oldTempExists bool |
|
|
|
valid bool |
|
}{ |
|
// Main file name is blank, should fail. |
|
{ |
|
fileName: "", |
|
valid: false, |
|
}, |
|
|
|
// Old temporary file still exists, should be removed. Only one |
|
// file should remain. |
|
{ |
|
fileName: filepath.Join( |
|
tempTestDir, DefaultBackupFileName, |
|
), |
|
tempFileName: filepath.Join( |
|
tempTestDir, DefaultTempBackupFileName, |
|
), |
|
oldTempExists: true, |
|
valid: true, |
|
}, |
|
|
|
// Old temp doesn't exist, should swap out file, only a single |
|
// file remains. |
|
{ |
|
fileName: filepath.Join( |
|
tempTestDir, DefaultBackupFileName, |
|
), |
|
tempFileName: filepath.Join( |
|
tempTestDir, DefaultTempBackupFileName, |
|
), |
|
valid: true, |
|
}, |
|
} |
|
for i, testCase := range testCases { |
|
// Ensure that all created files are removed at the end of the |
|
// test case. |
|
defer os.Remove(testCase.fileName) |
|
defer os.Remove(testCase.tempFileName) |
|
|
|
backupFile := NewMultiFile(testCase.fileName) |
|
|
|
// To start with, we'll make a random byte slice that'll pose |
|
// as our packed multi backup. |
|
newPackedMulti, err := makeFakePackedMulti() |
|
if err != nil { |
|
t.Fatalf("unable to make test backup: %v", err) |
|
} |
|
|
|
// If the old temporary file is meant to exist, then we'll |
|
// create it now as an empty file. |
|
if testCase.oldTempExists { |
|
_, err := os.Create(testCase.tempFileName) |
|
if err != nil { |
|
t.Fatalf("unable to create temp file: %v", err) |
|
} |
|
|
|
// TODO(roasbeef): mock out fs calls? |
|
} |
|
|
|
// With our backup created, we'll now attempt to swap out this |
|
// backup, for the old one. |
|
err = backupFile.UpdateAndSwap(PackedMulti(newPackedMulti)) |
|
switch { |
|
// If this is a valid test case, and we failed, then we'll |
|
// return an error. |
|
case err != nil && testCase.valid: |
|
t.Fatalf("#%v, unable to swap file: %v", i, err) |
|
|
|
// If this is an invalid test case, and we passed it, then |
|
// we'll return an error. |
|
case err == nil && !testCase.valid: |
|
t.Fatalf("#%v file swap should have failed: %v", i, err) |
|
} |
|
|
|
if !testCase.valid { |
|
continue |
|
} |
|
|
|
// If we read out the file on disk, then it should match |
|
// exactly what we wrote. The temp backup file should also be |
|
// gone. |
|
assertBackupMatches(t, testCase.fileName, newPackedMulti) |
|
assertFileDeleted(t, testCase.tempFileName) |
|
|
|
// Now that we know this is a valid test case, we'll make a new |
|
// packed multi to swap out this current one. |
|
newPackedMulti2, err := makeFakePackedMulti() |
|
if err != nil { |
|
t.Fatalf("unable to make test backup: %v", err) |
|
} |
|
|
|
// We'll then attempt to swap the old version for this new one. |
|
err = backupFile.UpdateAndSwap(PackedMulti(newPackedMulti2)) |
|
if err != nil { |
|
t.Fatalf("unable to swap file: %v", err) |
|
} |
|
|
|
// Once again, the file written on disk should have been |
|
// properly swapped out with the new instance. |
|
assertBackupMatches(t, testCase.fileName, newPackedMulti2) |
|
|
|
// Additionally, we shouldn't be able to find the temp backup |
|
// file on disk, as it should be deleted each time. |
|
assertFileDeleted(t, testCase.tempFileName) |
|
} |
|
} |
|
|
|
func assertMultiEqual(t *testing.T, a, b *Multi) { |
|
|
|
if len(a.StaticBackups) != len(b.StaticBackups) { |
|
t.Fatalf("expected %v backups, got %v", len(a.StaticBackups), |
|
len(b.StaticBackups)) |
|
} |
|
|
|
for i := 0; i < len(a.StaticBackups); i++ { |
|
assertSingleEqual(t, a.StaticBackups[i], b.StaticBackups[i]) |
|
} |
|
} |
|
|
|
// TestExtractMulti tests that given a valid packed multi file on disk, we're |
|
// able to read it multiple times repeatedly. |
|
func TestExtractMulti(t *testing.T) { |
|
t.Parallel() |
|
|
|
keyRing := &mockKeyRing{} |
|
|
|
// First, as prep, we'll create a single chan backup, then pack that |
|
// fully into a multi backup. |
|
channel, err := genRandomOpenChannelShell() |
|
if err != nil { |
|
t.Fatalf("unable to gen chan: %v", err) |
|
} |
|
|
|
singleBackup := NewSingle(channel, nil) |
|
|
|
var b bytes.Buffer |
|
unpackedMulti := Multi{ |
|
StaticBackups: []Single{singleBackup}, |
|
} |
|
err = unpackedMulti.PackToWriter(&b, keyRing) |
|
if err != nil { |
|
t.Fatalf("unable to pack to writer: %v", err) |
|
} |
|
|
|
packedMulti := PackedMulti(b.Bytes()) |
|
|
|
// Finally, we'll make a new temporary file, then write out the packed |
|
// multi directly to to it. |
|
tempFile, err := ioutil.TempFile("", "") |
|
if err != nil { |
|
t.Fatalf("unable to create temp file: %v", err) |
|
} |
|
defer os.Remove(tempFile.Name()) |
|
|
|
_, err = tempFile.Write(packedMulti) |
|
if err != nil { |
|
t.Fatalf("unable to write temp file: %v", err) |
|
} |
|
if err := tempFile.Sync(); err != nil { |
|
t.Fatalf("unable to sync temp file: %v", err) |
|
} |
|
|
|
testCases := []struct { |
|
fileName string |
|
pass bool |
|
}{ |
|
// Main file not read, file name not present. |
|
{ |
|
fileName: "", |
|
pass: false, |
|
}, |
|
|
|
// Main file not read, file name is there, but file doesn't |
|
// exist. |
|
{ |
|
fileName: "kek", |
|
pass: false, |
|
}, |
|
|
|
// Main file not read, should be able to read multiple times. |
|
{ |
|
fileName: tempFile.Name(), |
|
pass: true, |
|
}, |
|
} |
|
for i, testCase := range testCases { |
|
// First, we'll make our backup file with the specified name. |
|
backupFile := NewMultiFile(testCase.fileName) |
|
|
|
// With our file made, we'll now attempt to read out the |
|
// multi-file. |
|
freshUnpackedMulti, err := backupFile.ExtractMulti(keyRing) |
|
switch { |
|
// If this is a valid test case, and we failed, then we'll |
|
// return an error. |
|
case err != nil && testCase.pass: |
|
t.Fatalf("#%v, unable to extract file: %v", i, err) |
|
|
|
// If this is an invalid test case, and we passed it, then |
|
// we'll return an error. |
|
case err == nil && !testCase.pass: |
|
t.Fatalf("#%v file extraction should have "+ |
|
"failed: %v", i, err) |
|
} |
|
|
|
if !testCase.pass { |
|
continue |
|
} |
|
|
|
// We'll now ensure that the unpacked multi we read is |
|
// identical to the one we wrote out above. |
|
assertMultiEqual(t, &unpackedMulti, freshUnpackedMulti) |
|
|
|
// We should also be able to read the file again, as we have an |
|
// existing handle to it. |
|
freshUnpackedMulti, err = backupFile.ExtractMulti(keyRing) |
|
if err != nil { |
|
t.Fatalf("unable to unpack multi: %v", err) |
|
} |
|
|
|
assertMultiEqual(t, &unpackedMulti, freshUnpackedMulti) |
|
} |
|
}
|
|
|