github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/local/diff_test.go (about)

     1  package local_test
     2  
     3  import (
     4  	"io/fs"
     5  	"os"
     6  	"path/filepath"
     7  	"sort"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/go-openapi/swag"
    12  	"github.com/stretchr/testify/require"
    13  	"github.com/treeverse/lakefs/pkg/api/apigen"
    14  	"github.com/treeverse/lakefs/pkg/local"
    15  )
    16  
    17  const (
    18  	diffTestCorrectTime = 1691570412
    19  )
    20  
    21  func TestDiffLocal(t *testing.T) {
    22  	cases := []struct {
    23  		Name       string
    24  		LocalPath  string
    25  		RemoteList []apigen.ObjectStats
    26  		Expected   []*local.Change
    27  	}{
    28  		{
    29  			Name:      "t1_no_diff",
    30  			LocalPath: "testdata/localdiff/t1",
    31  			RemoteList: []apigen.ObjectStats{
    32  				{
    33  					Path:      ".hidden-file",
    34  					SizeBytes: swag.Int64(64),
    35  					Mtime:     diffTestCorrectTime,
    36  				}, {
    37  					Path:      "sub/f.txt",
    38  					SizeBytes: swag.Int64(3),
    39  					Mtime:     diffTestCorrectTime,
    40  				}, {
    41  					Path:      "sub/folder/f.txt",
    42  					SizeBytes: swag.Int64(6),
    43  					Mtime:     diffTestCorrectTime,
    44  				},
    45  			},
    46  			Expected: []*local.Change{},
    47  		},
    48  		{
    49  			Name:      "t1_modified",
    50  			LocalPath: "testdata/localdiff/t1",
    51  			RemoteList: []apigen.ObjectStats{
    52  				{
    53  					Path:      ".hidden-file",
    54  					SizeBytes: swag.Int64(64),
    55  					Mtime:     diffTestCorrectTime,
    56  				}, {
    57  					Path:      "sub/f.txt",
    58  					SizeBytes: swag.Int64(3),
    59  					Mtime:     169095766,
    60  				}, {
    61  					Path:      "sub/folder/f.txt",
    62  					SizeBytes: swag.Int64(12),
    63  					Mtime:     1690957665,
    64  				},
    65  			},
    66  			Expected: []*local.Change{
    67  				{
    68  					Path: "sub/f.txt",
    69  					Type: local.ChangeTypeModified,
    70  				}, {
    71  					Path: "sub/folder/f.txt",
    72  					Type: local.ChangeTypeModified,
    73  				},
    74  			},
    75  		},
    76  		{
    77  			Name:      "t1_local_before",
    78  			LocalPath: "testdata/localdiff/t1",
    79  			RemoteList: []apigen.ObjectStats{
    80  				{
    81  					Path:      ".hidden-file",
    82  					SizeBytes: swag.Int64(64),
    83  					Mtime:     diffTestCorrectTime,
    84  				}, {
    85  					Path:      "sub/folder/f.txt",
    86  					SizeBytes: swag.Int64(6),
    87  					Mtime:     diffTestCorrectTime,
    88  				},
    89  			},
    90  			Expected: []*local.Change{
    91  				{
    92  					Path: "sub/f.txt",
    93  					Type: local.ChangeTypeAdded,
    94  				},
    95  			},
    96  		},
    97  		{
    98  			Name:      "t1_local_after",
    99  			LocalPath: "testdata/localdiff/t1",
   100  			RemoteList: []apigen.ObjectStats{{
   101  				Path:      ".hidden-file",
   102  				SizeBytes: swag.Int64(64),
   103  				Mtime:     diffTestCorrectTime,
   104  			}, {
   105  				Path:      "tub/r.txt",
   106  				SizeBytes: swag.Int64(6),
   107  				Mtime:     1690957665,
   108  			},
   109  			},
   110  			Expected: []*local.Change{
   111  				{
   112  					Path: "sub/f.txt",
   113  					Type: local.ChangeTypeAdded,
   114  				},
   115  				{
   116  					Path: "sub/folder/f.txt",
   117  					Type: local.ChangeTypeAdded,
   118  				},
   119  				{
   120  					Path: "tub/r.txt",
   121  					Type: local.ChangeTypeRemoved,
   122  				},
   123  			},
   124  		},
   125  		{
   126  			Name:      "t1_hidden_changed",
   127  			LocalPath: "testdata/localdiff/t1",
   128  			RemoteList: []apigen.ObjectStats{
   129  				{
   130  					Path:      ".hidden-file",
   131  					SizeBytes: swag.Int64(17),
   132  					Mtime:     diffTestCorrectTime,
   133  				}, {
   134  					Path:      "sub/f.txt",
   135  					SizeBytes: swag.Int64(3),
   136  					Mtime:     diffTestCorrectTime,
   137  				}, {
   138  					Path:      "sub/folder/f.txt",
   139  					SizeBytes: swag.Int64(6),
   140  					Mtime:     diffTestCorrectTime,
   141  				},
   142  			},
   143  			Expected: []*local.Change{
   144  				{
   145  					Path: ".hidden-file",
   146  					Type: local.ChangeTypeModified,
   147  				},
   148  			},
   149  		},
   150  	}
   151  
   152  	for _, tt := range cases {
   153  		t.Run(tt.Name, func(t *testing.T) {
   154  			fixTime(t, tt.LocalPath)
   155  			left := tt.RemoteList
   156  			sort.SliceStable(left, func(i, j int) bool {
   157  				return left[i].Path < left[j].Path
   158  			})
   159  			lc := make(chan apigen.ObjectStats, len(left))
   160  			makeChan(lc, left)
   161  			changes, err := local.DiffLocalWithHead(lc, tt.LocalPath)
   162  			if err != nil {
   163  				t.Fatal(err)
   164  			}
   165  			if len(changes) != len(tt.Expected) {
   166  				t.Fatalf("expected %d changes, got %d\n\n%v", len(tt.Expected), len(changes), changes)
   167  			}
   168  			for i, c := range changes {
   169  				require.Equal(t, c.Path, tt.Expected[i].Path, "wrong path")
   170  				require.Equal(t, c.Type, tt.Expected[i].Type, "wrong type")
   171  			}
   172  		})
   173  	}
   174  }
   175  
   176  func makeChan[T any](c chan<- T, l []T) {
   177  	for _, o := range l {
   178  		c <- o
   179  	}
   180  	close(c)
   181  }
   182  
   183  func fixTime(t *testing.T, localPath string) {
   184  	err := filepath.WalkDir(localPath, func(path string, d fs.DirEntry, err error) error {
   185  		if !d.IsDir() {
   186  			return os.Chtimes(path, time.Now(), time.Unix(diffTestCorrectTime, 0))
   187  		}
   188  		return nil
   189  	})
   190  	require.NoError(t, err)
   191  }