github.com/avahowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/renter/persist_test.go (about)

     1  package renter
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"strconv"
     9  	"testing"
    10  
    11  	"github.com/NebulousLabs/Sia/build"
    12  	"github.com/NebulousLabs/Sia/crypto"
    13  	"github.com/NebulousLabs/Sia/encoding"
    14  )
    15  
    16  // newTestingFile initializes a file object with random parameters.
    17  func newTestingFile() *file {
    18  	key, _ := crypto.GenerateTwofishKey()
    19  	data, _ := crypto.RandBytes(8)
    20  	nData, _ := crypto.RandIntn(10)
    21  	nParity, _ := crypto.RandIntn(10)
    22  	rsc, _ := NewRSCode(nData+1, nParity+1)
    23  
    24  	return &file{
    25  		name:        "testfile-" + strconv.Itoa(int(data[0])),
    26  		size:        encoding.DecUint64(data[1:5]),
    27  		masterKey:   key,
    28  		erasureCode: rsc,
    29  		pieceSize:   encoding.DecUint64(data[6:8]),
    30  	}
    31  }
    32  
    33  // equalFiles is a helper function that compares two files for equality.
    34  func equalFiles(f1, f2 *file) error {
    35  	if f1 == nil || f2 == nil {
    36  		return fmt.Errorf("one or both files are nil")
    37  	}
    38  	if f1.name != f2.name {
    39  		return fmt.Errorf("names do not match: %v %v", f1.name, f2.name)
    40  	}
    41  	if f1.size != f2.size {
    42  		return fmt.Errorf("sizes do not match: %v %v", f1.size, f2.size)
    43  	}
    44  	if f1.masterKey != f2.masterKey {
    45  		return fmt.Errorf("keys do not match: %v %v", f1.masterKey, f2.masterKey)
    46  	}
    47  	if f1.pieceSize != f2.pieceSize {
    48  		return fmt.Errorf("pieceSizes do not match: %v %v", f1.pieceSize, f2.pieceSize)
    49  	}
    50  	return nil
    51  }
    52  
    53  // TestFileMarshalling tests the MarshalSia and UnmarshalSia functions of the
    54  // file type.
    55  func TestFileMarshalling(t *testing.T) {
    56  	savedFile := newTestingFile()
    57  	buf := new(bytes.Buffer)
    58  	savedFile.MarshalSia(buf)
    59  
    60  	loadedFile := new(file)
    61  	err := loadedFile.UnmarshalSia(buf)
    62  	if err != nil {
    63  		t.Fatal(err)
    64  	}
    65  
    66  	err = equalFiles(savedFile, loadedFile)
    67  	if err != nil {
    68  		t.Fatal(err)
    69  	}
    70  }
    71  
    72  // TestFileShareLoad tests the sharing/loading functions of the renter.
    73  func TestFileShareLoad(t *testing.T) {
    74  	if testing.Short() {
    75  		t.SkipNow()
    76  	}
    77  	rt, err := newRenterTester("TestRenterShareLoad")
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	defer rt.Close()
    82  
    83  	// Create a file and add it to the renter.
    84  	savedFile := newTestingFile()
    85  	rt.renter.files[savedFile.name] = savedFile
    86  
    87  	// Share .sia file to disk.
    88  	path := filepath.Join(build.SiaTestingDir, "renter", "TestRenterShareLoad", "test.sia")
    89  	err = rt.renter.ShareFiles([]string{savedFile.name}, path)
    90  	if err != nil {
    91  		t.Fatal(err)
    92  	}
    93  
    94  	// Remove the file from the renter.
    95  	delete(rt.renter.files, savedFile.name)
    96  
    97  	// Load the .sia file back into the renter.
    98  	names, err := rt.renter.LoadSharedFiles(path)
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  	if len(names) != 1 || names[0] != savedFile.name {
   103  		t.Fatal("nickname not loaded properly:", names)
   104  	}
   105  	err = equalFiles(rt.renter.files[savedFile.name], savedFile)
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  
   110  	// Share and load multiple files.
   111  	savedFile2 := newTestingFile()
   112  	rt.renter.files[savedFile2.name] = savedFile2
   113  	path = filepath.Join(build.SiaTestingDir, "renter", "TestRenterShareLoad", "test2.sia")
   114  	err = rt.renter.ShareFiles([]string{savedFile.name, savedFile2.name}, path)
   115  	if err != nil {
   116  		t.Fatal(err)
   117  	}
   118  
   119  	// Remove the files from the renter.
   120  	delete(rt.renter.files, savedFile.name)
   121  	delete(rt.renter.files, savedFile2.name)
   122  
   123  	names, err = rt.renter.LoadSharedFiles(path)
   124  	if err != nil {
   125  		t.Fatal(nil)
   126  	}
   127  	if len(names) != 2 || (names[0] != savedFile2.name && names[1] != savedFile2.name) {
   128  		t.Fatal("nicknames not loaded properly:", names)
   129  	}
   130  	err = equalFiles(rt.renter.files[savedFile.name], savedFile)
   131  	if err != nil {
   132  		t.Fatal(err)
   133  	}
   134  	err = equalFiles(rt.renter.files[savedFile2.name], savedFile2)
   135  	if err != nil {
   136  		t.Fatal(err)
   137  	}
   138  }
   139  
   140  // TestFileShareLoadASCII tests the ASCII sharing/loading functions.
   141  func TestFileShareLoadASCII(t *testing.T) {
   142  	if testing.Short() {
   143  		t.SkipNow()
   144  	}
   145  	rt, err := newRenterTester("TestRenterShareLoadASCII")
   146  	if err != nil {
   147  		t.Fatal(err)
   148  	}
   149  	defer rt.Close()
   150  
   151  	// Create a file and add it to the renter.
   152  	savedFile := newTestingFile()
   153  	rt.renter.files[savedFile.name] = savedFile
   154  
   155  	ascii, err := rt.renter.ShareFilesAscii([]string{savedFile.name})
   156  	if err != nil {
   157  		t.Fatal(err)
   158  	}
   159  
   160  	// Remove the file from the renter.
   161  	delete(rt.renter.files, savedFile.name)
   162  
   163  	names, err := rt.renter.LoadSharedFilesAscii(ascii)
   164  	if err != nil {
   165  		t.Fatal(err)
   166  	}
   167  	if len(names) != 1 || names[0] != savedFile.name {
   168  		t.Fatal("nickname not loaded properly")
   169  	}
   170  
   171  	err = equalFiles(rt.renter.files[savedFile.name], savedFile)
   172  	if err != nil {
   173  		t.Fatal(err)
   174  	}
   175  }
   176  
   177  // TestRenterSaveLoad probes the save and load methods of the renter type.
   178  func TestRenterSaveLoad(t *testing.T) {
   179  	if testing.Short() {
   180  		t.SkipNow()
   181  	}
   182  	rt, err := newRenterTester("TestRenterSaveLoad")
   183  	if err != nil {
   184  		t.Fatal(err)
   185  	}
   186  	defer rt.Close()
   187  
   188  	// Create and save some files
   189  	var f1, f2, f3 *file
   190  	f1 = newTestingFile()
   191  	f2 = newTestingFile()
   192  	f3 = newTestingFile()
   193  	// names must not conflict
   194  	for f2.name == f1.name || f2.name == f3.name {
   195  		f2 = newTestingFile()
   196  	}
   197  	for f3.name == f1.name || f3.name == f2.name {
   198  		f3 = newTestingFile()
   199  	}
   200  	rt.renter.saveFile(f1)
   201  	rt.renter.saveFile(f2)
   202  	rt.renter.saveFile(f3)
   203  
   204  	err = rt.renter.save() // save metadata
   205  	if err != nil {
   206  		t.Fatal(err)
   207  	}
   208  
   209  	// load should now load the files into memory.
   210  	id := rt.renter.mu.Lock()
   211  	err = rt.renter.load()
   212  	rt.renter.mu.Unlock(id)
   213  	if err != nil && !os.IsNotExist(err) {
   214  		t.Fatal(err)
   215  	}
   216  
   217  	if err := equalFiles(f1, rt.renter.files[f1.name]); err != nil {
   218  		t.Fatal(err)
   219  	}
   220  	if err := equalFiles(f2, rt.renter.files[f2.name]); err != nil {
   221  		t.Fatal(err)
   222  	}
   223  	if err := equalFiles(f3, rt.renter.files[f3.name]); err != nil {
   224  		t.Fatal(err)
   225  	}
   226  }
   227  
   228  // TestRenterPaths checks that the renter properly handles nicknames
   229  // containing the path separator ("/").
   230  func TestRenterPaths(t *testing.T) {
   231  	if testing.Short() {
   232  		t.SkipNow()
   233  	}
   234  	rt, err := newRenterTester("TestRenterPaths")
   235  	if err != nil {
   236  		t.Fatal(err)
   237  	}
   238  	defer rt.Close()
   239  
   240  	// Create and save some files.
   241  	// The result of saving these files should be a directory containing:
   242  	//   foo.sia
   243  	//   foo/bar.sia
   244  	//   foo/bar/baz.sia
   245  	f1 := newTestingFile()
   246  	f1.name = "foo"
   247  	f2 := newTestingFile()
   248  	f2.name = "foo/bar"
   249  	f3 := newTestingFile()
   250  	f3.name = "foo/bar/baz"
   251  	rt.renter.saveFile(f1)
   252  	rt.renter.saveFile(f2)
   253  	rt.renter.saveFile(f3)
   254  
   255  	// Load the files into the renter.
   256  	id := rt.renter.mu.Lock()
   257  	err = rt.renter.load()
   258  	rt.renter.mu.Unlock(id)
   259  	if err != nil && !os.IsNotExist(err) {
   260  		t.Fatal(err)
   261  	}
   262  	// Check that the files were loaded properly.
   263  	if err := equalFiles(f1, rt.renter.files[f1.name]); err != nil {
   264  		t.Fatal(err)
   265  	}
   266  	if err := equalFiles(f2, rt.renter.files[f2.name]); err != nil {
   267  		t.Fatal(err)
   268  	}
   269  	if err := equalFiles(f3, rt.renter.files[f3.name]); err != nil {
   270  		t.Fatal(err)
   271  	}
   272  
   273  	// To confirm that the file structure was preserved, we walk the renter
   274  	// folder and emit the name of each .sia file encountered (filepath.Walk
   275  	// is deterministic; it orders the files lexically).
   276  	var walkStr string
   277  	filepath.Walk(rt.renter.persistDir, func(path string, _ os.FileInfo, _ error) error {
   278  		// capture only .sia files
   279  		if filepath.Ext(path) != ".sia" {
   280  			return nil
   281  		}
   282  		rel, _ := filepath.Rel(rt.renter.persistDir, path) // strip testdir prefix
   283  		walkStr += rel
   284  		return nil
   285  	})
   286  	// walk will descend into foo/bar/, reading baz, bar, and finally foo
   287  	expWalkStr := (f3.name + ".sia") + (f2.name + ".sia") + (f1.name + ".sia")
   288  	if walkStr != expWalkStr {
   289  		t.Fatalf("Bad walk string: expected %v, got %v", expWalkStr, walkStr)
   290  	}
   291  }
   292  
   293  // TestSiafileCompatibility tests that the renter is able to load v0.4.8 .sia files.
   294  func TestSiafileCompatibility(t *testing.T) {
   295  	if testing.Short() {
   296  		t.SkipNow()
   297  	}
   298  	rt, err := newRenterTester("TestSiafileCompatibility")
   299  	if err != nil {
   300  		t.Fatal(err)
   301  	}
   302  	defer rt.Close()
   303  
   304  	// Load the compatibility file into the renter.
   305  	path := filepath.Join("..", "..", "compatibility", "siafile_v0.4.8.sia")
   306  	names, err := rt.renter.LoadSharedFiles(path)
   307  	if err != nil {
   308  		t.Fatal(err)
   309  	}
   310  	if len(names) != 1 || names[0] != "testfile-183" {
   311  		t.Fatal("nickname not loaded properly:", names)
   312  	}
   313  }