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

     1  // +build !windows
     2  
     3  package restic
     4  
     5  import (
     6  	"os"
     7  	"runtime"
     8  	"syscall"
     9  	"testing"
    10  	"time"
    11  )
    12  
    13  func stat(t testing.TB, filename string) (fi os.FileInfo, ok bool) {
    14  	fi, err := os.Lstat(filename)
    15  	if err != nil && os.IsNotExist(err) {
    16  		return fi, false
    17  	}
    18  
    19  	if err != nil {
    20  		t.Fatal(err)
    21  	}
    22  
    23  	return fi, true
    24  }
    25  
    26  func checkFile(t testing.TB, stat *syscall.Stat_t, node *Node) {
    27  	if uint32(node.Mode.Perm()) != uint32(stat.Mode&0777) {
    28  		t.Errorf("Mode does not match, want %v, got %v", stat.Mode&0777, node.Mode)
    29  	}
    30  
    31  	if node.Inode != uint64(stat.Ino) {
    32  		t.Errorf("Inode does not match, want %v, got %v", stat.Ino, node.Inode)
    33  	}
    34  
    35  	if node.DeviceID != uint64(stat.Dev) {
    36  		t.Errorf("Dev does not match, want %v, got %v", stat.Dev, node.DeviceID)
    37  	}
    38  
    39  	if node.Size != uint64(stat.Size) {
    40  		t.Errorf("Size does not match, want %v, got %v", stat.Size, node.Size)
    41  	}
    42  
    43  	if node.Links != uint64(stat.Nlink) {
    44  		t.Errorf("Links does not match, want %v, got %v", stat.Nlink, node.Links)
    45  	}
    46  
    47  	if node.UID != stat.Uid {
    48  		t.Errorf("UID does not match, want %v, got %v", stat.Uid, node.UID)
    49  	}
    50  
    51  	if node.GID != stat.Gid {
    52  		t.Errorf("UID does not match, want %v, got %v", stat.Gid, node.GID)
    53  	}
    54  
    55  	// use the os dependent function to compare the timestamps
    56  	s, ok := toStatT(stat)
    57  	if !ok {
    58  		return
    59  	}
    60  
    61  	mtime := s.mtim()
    62  	if node.ModTime != time.Unix(mtime.Unix()) {
    63  		t.Errorf("ModTime does not match, want %v, got %v", time.Unix(mtime.Unix()), node.ModTime)
    64  	}
    65  
    66  	ctime := s.ctim()
    67  	if node.ChangeTime != time.Unix(ctime.Unix()) {
    68  		t.Errorf("ChangeTime does not match, want %v, got %v", time.Unix(ctime.Unix()), node.ChangeTime)
    69  	}
    70  
    71  	atime := s.atim()
    72  	if node.AccessTime != time.Unix(atime.Unix()) {
    73  		t.Errorf("AccessTime does not match, want %v, got %v", time.Unix(atime.Unix()), node.AccessTime)
    74  	}
    75  
    76  }
    77  
    78  func checkDevice(t testing.TB, stat *syscall.Stat_t, node *Node) {
    79  	if node.Device != uint64(stat.Rdev) {
    80  		t.Errorf("Rdev does not match, want %v, got %v", stat.Rdev, node.Device)
    81  	}
    82  }
    83  
    84  func TestNodeFromFileInfo(t *testing.T) {
    85  	type Test struct {
    86  		filename string
    87  		canSkip  bool
    88  	}
    89  	var tests = []Test{
    90  		{"node_test.go", false},
    91  		{"/dev/sda", true},
    92  	}
    93  
    94  	// on darwin, users are not permitted to list the extended attributes of
    95  	// /dev/null, therefore skip it.
    96  	if runtime.GOOS != "darwin" {
    97  		tests = append(tests, Test{"/dev/null", true})
    98  	}
    99  
   100  	for _, test := range tests {
   101  		t.Run("", func(t *testing.T) {
   102  			fi, found := stat(t, test.filename)
   103  			if !found && test.canSkip {
   104  				t.Skipf("%v not found in filesystem", test.filename)
   105  				return
   106  			}
   107  
   108  			if fi.Sys() == nil {
   109  				t.Skip("fi.Sys() is nil")
   110  				return
   111  			}
   112  
   113  			s, ok := fi.Sys().(*syscall.Stat_t)
   114  			if !ok {
   115  				t.Skip("fi type is %T, not stat_t", fi.Sys())
   116  				return
   117  			}
   118  
   119  			node, err := NodeFromFileInfo(test.filename, fi)
   120  			if err != nil {
   121  				t.Fatal(err)
   122  			}
   123  
   124  			switch node.Type {
   125  			case "file":
   126  				checkFile(t, s, node)
   127  			case "dev", "chardev":
   128  				checkFile(t, s, node)
   129  				checkDevice(t, s, node)
   130  			default:
   131  				t.Fatalf("invalid node type %q", node.Type)
   132  			}
   133  		})
   134  	}
   135  }