| 
									
										
										
										
											2022-03-28 22:23:47 +02:00
										 |  |  | //go:build !windows | 
					
						
							|  |  |  | // +build !windows | 
					
						
							| 
									
										
										
										
											2018-09-27 08:59:33 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | package restorer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"syscall" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							| 
									
										
										
										
											2023-05-08 20:49:41 +02:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2018-09-27 08:59:33 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/repository" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/restic" | 
					
						
							|  |  |  | 	rtest "github.com/restic/restic/internal/test" | 
					
						
							| 
									
										
										
										
											2023-05-08 20:49:41 +02:00
										 |  |  | 	restoreui "github.com/restic/restic/internal/ui/restore" | 
					
						
							| 
									
										
										
										
											2018-09-27 08:59:33 -04:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestRestorerRestoreEmptyHardlinkedFileds(t *testing.T) { | 
					
						
							| 
									
										
										
										
											2022-12-11 10:41:22 +01:00
										 |  |  | 	repo := repository.TestRepository(t) | 
					
						
							| 
									
										
										
										
											2018-09-27 08:59:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-03 14:48:14 +02:00
										 |  |  | 	sn, _ := saveSnapshot(t, repo, Snapshot{ | 
					
						
							| 
									
										
										
										
											2018-09-27 08:59:33 -04:00
										 |  |  | 		Nodes: map[string]Node{ | 
					
						
							|  |  |  | 			"dirtest": Dir{ | 
					
						
							|  |  |  | 				Nodes: map[string]Node{ | 
					
						
							|  |  |  | 					"file1": File{Links: 2, Inode: 1}, | 
					
						
							|  |  |  | 					"file2": File{Links: 2, Inode: 1}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-28 17:44:34 +02:00
										 |  |  | 	res := NewRestorer(context.TODO(), repo, sn, false, nil) | 
					
						
							| 
									
										
										
										
											2018-09-27 08:59:33 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	res.SelectFilter = func(item string, dstpath string, node *restic.Node) (selectedForRestore bool, childMayBeSelected bool) { | 
					
						
							|  |  |  | 		return true, true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-09 13:42:33 +01:00
										 |  |  | 	tempdir := rtest.TempDir(t) | 
					
						
							| 
									
										
										
										
											2018-09-27 08:59:33 -04:00
										 |  |  | 	ctx, cancel := context.WithCancel(context.Background()) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-03 14:48:14 +02:00
										 |  |  | 	err := res.RestoreTo(ctx, tempdir) | 
					
						
							| 
									
										
										
										
											2018-09-27 08:59:33 -04:00
										 |  |  | 	rtest.OK(t, err) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	f1, err := os.Stat(filepath.Join(tempdir, "dirtest/file1")) | 
					
						
							|  |  |  | 	rtest.OK(t, err) | 
					
						
							|  |  |  | 	rtest.Equals(t, int64(0), f1.Size()) | 
					
						
							|  |  |  | 	s1, ok1 := f1.Sys().(*syscall.Stat_t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	f2, err := os.Stat(filepath.Join(tempdir, "dirtest/file2")) | 
					
						
							|  |  |  | 	rtest.OK(t, err) | 
					
						
							|  |  |  | 	rtest.Equals(t, int64(0), f2.Size()) | 
					
						
							|  |  |  | 	s2, ok2 := f2.Sys().(*syscall.Stat_t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ok1 && ok2 { | 
					
						
							|  |  |  | 		rtest.Equals(t, s1.Ino, s2.Ino) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-02-26 21:48:05 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-04 11:23:31 +02:00
										 |  |  | func getBlockCount(t *testing.T, filename string) int64 { | 
					
						
							| 
									
										
										
										
											2020-02-26 21:48:05 +01:00
										 |  |  | 	fi, err := os.Stat(filename) | 
					
						
							|  |  |  | 	rtest.OK(t, err) | 
					
						
							|  |  |  | 	st := fi.Sys().(*syscall.Stat_t) | 
					
						
							|  |  |  | 	if st == nil { | 
					
						
							| 
									
										
										
										
											2022-09-04 11:23:31 +02:00
										 |  |  | 		return -1 | 
					
						
							| 
									
										
										
										
											2020-02-26 21:48:05 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-09-04 11:23:31 +02:00
										 |  |  | 	return st.Blocks | 
					
						
							| 
									
										
										
										
											2020-02-26 21:48:05 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2023-05-08 20:49:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | type printerMock struct { | 
					
						
							|  |  |  | 	filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *printerMock) Update(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration) { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | func (p *printerMock) Finish(filesFinished, filesTotal, allBytesWritten, allBytesTotal uint64, duration time.Duration) { | 
					
						
							|  |  |  | 	p.filesFinished = filesFinished | 
					
						
							|  |  |  | 	p.filesTotal = filesTotal | 
					
						
							|  |  |  | 	p.allBytesWritten = allBytesWritten | 
					
						
							|  |  |  | 	p.allBytesTotal = allBytesTotal | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func TestRestorerProgressBar(t *testing.T) { | 
					
						
							|  |  |  | 	repo := repository.TestRepository(t) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sn, _ := saveSnapshot(t, repo, Snapshot{ | 
					
						
							|  |  |  | 		Nodes: map[string]Node{ | 
					
						
							|  |  |  | 			"dirtest": Dir{ | 
					
						
							|  |  |  | 				Nodes: map[string]Node{ | 
					
						
							|  |  |  | 					"file1": File{Links: 2, Inode: 1, Data: "foo"}, | 
					
						
							|  |  |  | 					"file2": File{Links: 2, Inode: 1, Data: "foo"}, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			"file2": File{Links: 1, Inode: 2, Data: "example"}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mock := &printerMock{} | 
					
						
							|  |  |  | 	progress := restoreui.NewProgress(mock, 0) | 
					
						
							|  |  |  | 	res := NewRestorer(context.TODO(), repo, sn, false, progress) | 
					
						
							|  |  |  | 	res.SelectFilter = func(item string, dstpath string, node *restic.Node) (selectedForRestore bool, childMayBeSelected bool) { | 
					
						
							|  |  |  | 		return true, true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tempdir := rtest.TempDir(t) | 
					
						
							|  |  |  | 	ctx, cancel := context.WithCancel(context.Background()) | 
					
						
							|  |  |  | 	defer cancel() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	err := res.RestoreTo(ctx, tempdir) | 
					
						
							|  |  |  | 	rtest.OK(t, err) | 
					
						
							|  |  |  | 	progress.Finish() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	const filesFinished = 4 | 
					
						
							|  |  |  | 	const filesTotal = filesFinished | 
					
						
							|  |  |  | 	const allBytesWritten = 10 | 
					
						
							|  |  |  | 	const allBytesTotal = allBytesWritten | 
					
						
							|  |  |  | 	rtest.Assert(t, mock.filesFinished == filesFinished, "filesFinished: expected %v, got %v", filesFinished, mock.filesFinished) | 
					
						
							|  |  |  | 	rtest.Assert(t, mock.filesTotal == filesTotal, "filesTotal: expected %v, got %v", filesTotal, mock.filesTotal) | 
					
						
							|  |  |  | 	rtest.Assert(t, mock.allBytesWritten == allBytesWritten, "allBytesWritten: expected %v, got %v", allBytesWritten, mock.allBytesWritten) | 
					
						
							|  |  |  | 	rtest.Assert(t, mock.allBytesTotal == allBytesTotal, "allBytesTotal: expected %v, got %v", allBytesTotal, mock.allBytesTotal) | 
					
						
							|  |  |  | } |