github.com/mckael/restic@v0.8.3/internal/restic/node_test.go (about)

     1  package restic_test
     2  
     3  import (
     4  	"context"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"runtime"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/restic/restic/internal/restic"
    13  	rtest "github.com/restic/restic/internal/test"
    14  )
    15  
    16  func BenchmarkNodeFillUser(t *testing.B) {
    17  	tempfile, err := ioutil.TempFile("", "restic-test-temp-")
    18  	if err != nil {
    19  		t.Fatal(err)
    20  	}
    21  
    22  	fi, err := tempfile.Stat()
    23  	if err != nil {
    24  		t.Fatal(err)
    25  	}
    26  
    27  	path := tempfile.Name()
    28  
    29  	t.ResetTimer()
    30  
    31  	for i := 0; i < t.N; i++ {
    32  		restic.NodeFromFileInfo(path, fi)
    33  	}
    34  
    35  	rtest.OK(t, tempfile.Close())
    36  	rtest.RemoveAll(t, tempfile.Name())
    37  }
    38  
    39  func BenchmarkNodeFromFileInfo(t *testing.B) {
    40  	tempfile, err := ioutil.TempFile("", "restic-test-temp-")
    41  	if err != nil {
    42  		t.Fatal(err)
    43  	}
    44  
    45  	fi, err := tempfile.Stat()
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  
    50  	path := tempfile.Name()
    51  
    52  	t.ResetTimer()
    53  
    54  	for i := 0; i < t.N; i++ {
    55  		_, err := restic.NodeFromFileInfo(path, fi)
    56  		if err != nil {
    57  			t.Fatal(err)
    58  		}
    59  	}
    60  
    61  	rtest.OK(t, tempfile.Close())
    62  	rtest.RemoveAll(t, tempfile.Name())
    63  }
    64  
    65  func parseTime(s string) time.Time {
    66  	t, err := time.Parse("2006-01-02 15:04:05.999", s)
    67  	if err != nil {
    68  		panic(err)
    69  	}
    70  
    71  	return t.Local()
    72  }
    73  
    74  var nodeTests = []restic.Node{
    75  	{
    76  		Name:       "testFile",
    77  		Type:       "file",
    78  		Content:    restic.IDs{},
    79  		UID:        uint32(os.Getuid()),
    80  		GID:        uint32(os.Getgid()),
    81  		Mode:       0604,
    82  		ModTime:    parseTime("2015-05-14 21:07:23.111"),
    83  		AccessTime: parseTime("2015-05-14 21:07:24.222"),
    84  		ChangeTime: parseTime("2015-05-14 21:07:25.333"),
    85  	},
    86  	{
    87  		Name:       "testSuidFile",
    88  		Type:       "file",
    89  		Content:    restic.IDs{},
    90  		UID:        uint32(os.Getuid()),
    91  		GID:        uint32(os.Getgid()),
    92  		Mode:       0755 | os.ModeSetuid,
    93  		ModTime:    parseTime("2015-05-14 21:07:23.111"),
    94  		AccessTime: parseTime("2015-05-14 21:07:24.222"),
    95  		ChangeTime: parseTime("2015-05-14 21:07:25.333"),
    96  	},
    97  	{
    98  		Name:       "testSuidFile2",
    99  		Type:       "file",
   100  		Content:    restic.IDs{},
   101  		UID:        uint32(os.Getuid()),
   102  		GID:        uint32(os.Getgid()),
   103  		Mode:       0755 | os.ModeSetgid,
   104  		ModTime:    parseTime("2015-05-14 21:07:23.111"),
   105  		AccessTime: parseTime("2015-05-14 21:07:24.222"),
   106  		ChangeTime: parseTime("2015-05-14 21:07:25.333"),
   107  	},
   108  	{
   109  		Name:       "testSticky",
   110  		Type:       "file",
   111  		Content:    restic.IDs{},
   112  		UID:        uint32(os.Getuid()),
   113  		GID:        uint32(os.Getgid()),
   114  		Mode:       0755 | os.ModeSticky,
   115  		ModTime:    parseTime("2015-05-14 21:07:23.111"),
   116  		AccessTime: parseTime("2015-05-14 21:07:24.222"),
   117  		ChangeTime: parseTime("2015-05-14 21:07:25.333"),
   118  	},
   119  	{
   120  		Name:       "testDir",
   121  		Type:       "dir",
   122  		Subtree:    nil,
   123  		UID:        uint32(os.Getuid()),
   124  		GID:        uint32(os.Getgid()),
   125  		Mode:       0750 | os.ModeDir,
   126  		ModTime:    parseTime("2015-05-14 21:07:23.111"),
   127  		AccessTime: parseTime("2015-05-14 21:07:24.222"),
   128  		ChangeTime: parseTime("2015-05-14 21:07:25.333"),
   129  	},
   130  	{
   131  		Name:       "testSymlink",
   132  		Type:       "symlink",
   133  		LinkTarget: "invalid",
   134  		UID:        uint32(os.Getuid()),
   135  		GID:        uint32(os.Getgid()),
   136  		Mode:       0777 | os.ModeSymlink,
   137  		ModTime:    parseTime("2015-05-14 21:07:23.111"),
   138  		AccessTime: parseTime("2015-05-14 21:07:24.222"),
   139  		ChangeTime: parseTime("2015-05-14 21:07:25.333"),
   140  	},
   141  
   142  	// include "testFile" and "testDir" again with slightly different
   143  	// metadata, so we can test if CreateAt works with pre-existing files.
   144  	{
   145  		Name:       "testFile",
   146  		Type:       "file",
   147  		Content:    restic.IDs{},
   148  		UID:        uint32(os.Getuid()),
   149  		GID:        uint32(os.Getgid()),
   150  		Mode:       0604,
   151  		ModTime:    parseTime("2005-05-14 21:07:03.111"),
   152  		AccessTime: parseTime("2005-05-14 21:07:04.222"),
   153  		ChangeTime: parseTime("2005-05-14 21:07:05.333"),
   154  	},
   155  	{
   156  		Name:       "testDir",
   157  		Type:       "dir",
   158  		Subtree:    nil,
   159  		UID:        uint32(os.Getuid()),
   160  		GID:        uint32(os.Getgid()),
   161  		Mode:       0750 | os.ModeDir,
   162  		ModTime:    parseTime("2005-05-14 21:07:03.111"),
   163  		AccessTime: parseTime("2005-05-14 21:07:04.222"),
   164  		ChangeTime: parseTime("2005-05-14 21:07:05.333"),
   165  	},
   166  }
   167  
   168  func TestNodeRestoreAt(t *testing.T) {
   169  	tempdir, err := ioutil.TempDir(rtest.TestTempDir, "restic-test-")
   170  	rtest.OK(t, err)
   171  
   172  	defer func() {
   173  		if rtest.TestCleanupTempDirs {
   174  			rtest.RemoveAll(t, tempdir)
   175  		} else {
   176  			t.Logf("leaving tempdir at %v", tempdir)
   177  		}
   178  	}()
   179  
   180  	idx := restic.NewHardlinkIndex()
   181  
   182  	for _, test := range nodeTests {
   183  		nodePath := filepath.Join(tempdir, test.Name)
   184  		rtest.OK(t, test.CreateAt(context.TODO(), nodePath, nil, idx))
   185  
   186  		if test.Type == "symlink" && runtime.GOOS == "windows" {
   187  			continue
   188  		}
   189  		if test.Type == "dir" {
   190  			rtest.OK(t, test.RestoreTimestamps(nodePath))
   191  		}
   192  
   193  		fi, err := os.Lstat(nodePath)
   194  		rtest.OK(t, err)
   195  
   196  		n2, err := restic.NodeFromFileInfo(nodePath, fi)
   197  		rtest.OK(t, err)
   198  
   199  		rtest.Assert(t, test.Name == n2.Name,
   200  			"%v: name doesn't match (%v != %v)", test.Type, test.Name, n2.Name)
   201  		rtest.Assert(t, test.Type == n2.Type,
   202  			"%v: type doesn't match (%v != %v)", test.Type, test.Type, n2.Type)
   203  		rtest.Assert(t, test.Size == n2.Size,
   204  			"%v: size doesn't match (%v != %v)", test.Size, test.Size, n2.Size)
   205  
   206  		if runtime.GOOS != "windows" {
   207  			rtest.Assert(t, test.UID == n2.UID,
   208  				"%v: UID doesn't match (%v != %v)", test.Type, test.UID, n2.UID)
   209  			rtest.Assert(t, test.GID == n2.GID,
   210  				"%v: GID doesn't match (%v != %v)", test.Type, test.GID, n2.GID)
   211  			if test.Type != "symlink" {
   212  				// On OpenBSD only root can set sticky bit (see sticky(8)).
   213  				if runtime.GOOS != "openbsd" && test.Name == "testSticky" {
   214  					rtest.Assert(t, test.Mode == n2.Mode,
   215  						"%v: mode doesn't match (0%o != 0%o)", test.Type, test.Mode, n2.Mode)
   216  				}
   217  			}
   218  		}
   219  
   220  		AssertFsTimeEqual(t, "AccessTime", test.Type, test.AccessTime, n2.AccessTime)
   221  		AssertFsTimeEqual(t, "ModTime", test.Type, test.ModTime, n2.ModTime)
   222  	}
   223  }
   224  
   225  func AssertFsTimeEqual(t *testing.T, label string, nodeType string, t1 time.Time, t2 time.Time) {
   226  	var equal bool
   227  
   228  	// Go currently doesn't support setting timestamps of symbolic links on darwin and bsd
   229  	if nodeType == "symlink" {
   230  		switch runtime.GOOS {
   231  		case "darwin", "freebsd", "openbsd":
   232  			return
   233  		}
   234  	}
   235  
   236  	switch runtime.GOOS {
   237  	case "darwin":
   238  		// HFS+ timestamps don't support sub-second precision,
   239  		// see https://en.wikipedia.org/wiki/Comparison_of_file_systems
   240  		diff := int(t1.Sub(t2).Seconds())
   241  		equal = diff == 0
   242  	default:
   243  		equal = t1.Equal(t2)
   244  	}
   245  
   246  	rtest.Assert(t, equal, "%s: %s doesn't match (%v != %v)", label, nodeType, t1, t2)
   247  }