github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/file/cataloger/filemetadata/cataloger_test.go (about)

     1  package filemetadata
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
    12  	"github.com/anchore/stereoscope/pkg/imagetest"
    13  	"github.com/anchore/syft/syft/file"
    14  	"github.com/anchore/syft/syft/source"
    15  	"github.com/anchore/syft/syft/source/stereoscopesource"
    16  )
    17  
    18  func TestFileMetadataCataloger(t *testing.T) {
    19  	testImage := "image-file-type-mix"
    20  
    21  	img := imagetest.GetFixtureImage(t, "docker-archive", testImage)
    22  
    23  	c := NewCataloger()
    24  
    25  	src := stereoscopesource.New(img, stereoscopesource.ImageConfig{
    26  		Reference: testImage,
    27  	})
    28  
    29  	resolver, err := src.FileResolver(source.SquashedScope)
    30  	require.NoError(t, err)
    31  
    32  	actual, err := c.Catalog(context.Background(), resolver)
    33  	require.NoError(t, err)
    34  
    35  	tests := []struct {
    36  		path     string
    37  		exists   bool
    38  		expected file.Metadata
    39  		err      bool
    40  	}{
    41  		// note: it is difficult to add a hardlink-based test in a cross-platform way and is already covered well in stereoscope
    42  		{
    43  			path:   "/file-1.txt",
    44  			exists: true,
    45  			expected: file.Metadata{
    46  				FileInfo: stereoscopeFile.ManualInfo{
    47  					NameValue: "file-1.txt",
    48  					ModeValue: 0644,
    49  					SizeValue: 7,
    50  				},
    51  				Path:     "/file-1.txt",
    52  				Type:     stereoscopeFile.TypeRegular,
    53  				UserID:   1,
    54  				GroupID:  2,
    55  				MIMEType: "text/plain",
    56  			},
    57  		},
    58  		{
    59  			path:   "/symlink-1",
    60  			exists: true,
    61  			expected: file.Metadata{
    62  				Path: "/symlink-1",
    63  				FileInfo: stereoscopeFile.ManualInfo{
    64  					NameValue: "symlink-1",
    65  					ModeValue: 0777 | os.ModeSymlink,
    66  				},
    67  				Type:            stereoscopeFile.TypeSymLink,
    68  				LinkDestination: "file-1.txt",
    69  				UserID:          0,
    70  				GroupID:         0,
    71  				MIMEType:        "",
    72  			},
    73  		},
    74  		{
    75  			path:   "/char-device-1",
    76  			exists: true,
    77  			expected: file.Metadata{
    78  				Path: "/char-device-1",
    79  				FileInfo: stereoscopeFile.ManualInfo{
    80  					NameValue: "char-device-1",
    81  					ModeValue: 0644 | os.ModeDevice | os.ModeCharDevice,
    82  				},
    83  				Type:     stereoscopeFile.TypeCharacterDevice,
    84  				UserID:   0,
    85  				GroupID:  0,
    86  				MIMEType: "",
    87  			},
    88  		},
    89  		{
    90  			path:   "/block-device-1",
    91  			exists: true,
    92  			expected: file.Metadata{
    93  				Path: "/block-device-1",
    94  				FileInfo: stereoscopeFile.ManualInfo{
    95  					NameValue: "block-device-1",
    96  					ModeValue: 0644 | os.ModeDevice,
    97  				},
    98  				Type:     stereoscopeFile.TypeBlockDevice,
    99  				UserID:   0,
   100  				GroupID:  0,
   101  				MIMEType: "",
   102  			},
   103  		},
   104  		{
   105  			path:   "/fifo-1",
   106  			exists: true,
   107  			expected: file.Metadata{
   108  				Path: "/fifo-1",
   109  				FileInfo: stereoscopeFile.ManualInfo{
   110  					NameValue: "fifo-1",
   111  					ModeValue: 0644 | os.ModeNamedPipe,
   112  				},
   113  				Type:     stereoscopeFile.TypeFIFO,
   114  				UserID:   0,
   115  				GroupID:  0,
   116  				MIMEType: "",
   117  			},
   118  		},
   119  		{
   120  			path:   "/bin",
   121  			exists: true,
   122  			expected: file.Metadata{
   123  				Path: "/bin",
   124  				FileInfo: stereoscopeFile.ManualInfo{
   125  					NameValue: "bin",
   126  					ModeValue: 0755 | os.ModeDir,
   127  				},
   128  				Type:     stereoscopeFile.TypeDirectory,
   129  				UserID:   0,
   130  				GroupID:  0,
   131  				MIMEType: "",
   132  			},
   133  		},
   134  	}
   135  
   136  	for _, test := range tests {
   137  		t.Run(test.path, func(t *testing.T) {
   138  			_, ref, err := img.SquashedTree().File(stereoscopeFile.Path(test.path))
   139  			require.NoError(t, err)
   140  
   141  			l := file.NewLocationFromImage(test.path, *ref.Reference, img)
   142  
   143  			if _, ok := actual[l.Coordinates]; ok {
   144  				// we're not interested in keeping the test fixtures up to date with the latest file modification times
   145  				// thus ModTime is not under test
   146  				fi := test.expected.FileInfo.(stereoscopeFile.ManualInfo)
   147  				fi.ModTimeValue = actual[l.Coordinates].ModTime()
   148  				test.expected.FileInfo = fi
   149  			}
   150  
   151  			assert.True(t, test.expected.Equal(actual[l.Coordinates]))
   152  		})
   153  	}
   154  
   155  }
   156  
   157  func TestFileMetadataCataloger_GivenCoordinates(t *testing.T) {
   158  	testImage := "image-file-type-mix"
   159  
   160  	img := imagetest.GetFixtureImage(t, "docker-archive", testImage)
   161  
   162  	c := NewCataloger()
   163  
   164  	src := stereoscopesource.New(img, stereoscopesource.ImageConfig{
   165  		Reference: testImage,
   166  	})
   167  
   168  	resolver, err := src.FileResolver(source.SquashedScope)
   169  	require.NoError(t, err)
   170  
   171  	tests := []struct {
   172  		path     string
   173  		exists   bool
   174  		expected file.Metadata
   175  	}{
   176  		{
   177  			path:   "/file-1.txt",
   178  			exists: true,
   179  			expected: file.Metadata{
   180  				FileInfo: stereoscopeFile.ManualInfo{
   181  					NameValue: "file-1.txt",
   182  					ModeValue: 0644,
   183  					SizeValue: 7,
   184  				},
   185  				Path:     "/file-1.txt",
   186  				Type:     stereoscopeFile.TypeRegular,
   187  				UserID:   1,
   188  				GroupID:  2,
   189  				MIMEType: "text/plain",
   190  			},
   191  		},
   192  	}
   193  
   194  	for _, test := range tests {
   195  		t.Run(test.path, func(t *testing.T) {
   196  			_, ref, err := img.SquashedTree().File(stereoscopeFile.Path(test.path))
   197  			require.NoError(t, err)
   198  
   199  			l := file.NewLocationFromImage(test.path, *ref.Reference, img)
   200  
   201  			// note: an important difference between this test and the previous is that this test is using a list
   202  			// of specific coordinates to catalog
   203  			actual, err := c.Catalog(context.Background(), resolver, l.Coordinates)
   204  			require.NoError(t, err)
   205  			require.Len(t, actual, 1)
   206  
   207  			if _, ok := actual[l.Coordinates]; ok {
   208  				// we're not interested in keeping the test fixtures up to date with the latest file modification times
   209  				// thus ModTime is not under test
   210  				fi := test.expected.FileInfo.(stereoscopeFile.ManualInfo)
   211  				fi.ModTimeValue = actual[l.Coordinates].ModTime()
   212  				test.expected.FileInfo = fi
   213  			}
   214  
   215  			assert.True(t, test.expected.Equal(actual[l.Coordinates]))
   216  		})
   217  	}
   218  
   219  }