github.com/quay/claircore@v1.5.28/whiteout/resolver_test.go (about)

     1  package whiteout
     2  
     3  import (
     4  	"context"
     5  	"crypto/sha256"
     6  	"io"
     7  	"testing"
     8  
     9  	"github.com/quay/claircore"
    10  
    11  	"github.com/quay/zlog"
    12  )
    13  
    14  func Digest(name string) claircore.Digest {
    15  	h := sha256.New()
    16  	io.WriteString(h, name)
    17  	d, err := claircore.NewDigest("sha256", h.Sum(nil))
    18  	if err != nil {
    19  		panic(err)
    20  	}
    21  	return d
    22  }
    23  
    24  func TestResolver(t *testing.T) {
    25  	firstLayerHash := Digest("first layer")
    26  	secondLayerHash := Digest("second layer")
    27  	thirdLayerHash := Digest("third layer")
    28  
    29  	type testcase struct {
    30  		Name                string
    31  		Report              *claircore.IndexReport
    32  		Layers              []*claircore.Layer
    33  		LenPackage, LenEnvs int
    34  	}
    35  
    36  	tests := []testcase{
    37  		{
    38  			Name: "Simple",
    39  			Report: &claircore.IndexReport{
    40  				Packages: map[string]*claircore.Package{
    41  					"1": {
    42  						Name:     "something interesting",
    43  						Filepath: "a/path/to/some/file/site-packages/a_package/METADATA",
    44  					},
    45  					"2": {
    46  						Name:     "something uninteresting",
    47  						Filepath: "a/path/to/some/file/site-packages/b_package/METADATA",
    48  					},
    49  				},
    50  				Environments: map[string][]*claircore.Environment{
    51  					"1": {{IntroducedIn: firstLayerHash}},
    52  					"2": {{IntroducedIn: firstLayerHash}},
    53  				},
    54  				Files: map[string]claircore.File{
    55  					secondLayerHash.String(): {
    56  						Path: "a/path/to/some/file/site-packages/.wh.a_package",
    57  						Kind: claircore.FileKindWhiteout,
    58  					},
    59  				},
    60  			},
    61  			Layers: []*claircore.Layer{
    62  				{Hash: firstLayerHash},
    63  				{Hash: secondLayerHash},
    64  			},
    65  			LenPackage: 1,
    66  			LenEnvs:    1,
    67  		},
    68  		{
    69  			Name: "SimpleNoDelete",
    70  			Report: &claircore.IndexReport{
    71  				Packages: map[string]*claircore.Package{
    72  					"1": {
    73  						Name:     "something interesting",
    74  						Filepath: "a/path/to/some/file/site-packages/a_package/METADATA",
    75  					},
    76  					"2": {
    77  						Name:     "something uninteresting",
    78  						Filepath: "a/path/to/some/file/site-packages/b_package/METADATA",
    79  					},
    80  				},
    81  				Environments: map[string][]*claircore.Environment{
    82  					"1": {{IntroducedIn: firstLayerHash}},
    83  					"2": {{IntroducedIn: firstLayerHash}},
    84  				},
    85  				Files: map[string]claircore.File{
    86  					secondLayerHash.String(): {
    87  						Path: "a/path/to/some/different_file/site-packages/.wh.a_package",
    88  						Kind: claircore.FileKindWhiteout,
    89  					},
    90  					secondLayerHash.String(): {
    91  						Path: "a/path/to/some/different_file/.wh.site-packages",
    92  						Kind: claircore.FileKindWhiteout,
    93  					},
    94  					secondLayerHash.String(): {
    95  						Path: "a/path/to/some/.wh.different_file",
    96  						Kind: claircore.FileKindWhiteout,
    97  					},
    98  				},
    99  			},
   100  			Layers: []*claircore.Layer{
   101  				{Hash: firstLayerHash},
   102  				{Hash: secondLayerHash},
   103  			},
   104  			LenPackage: 2,
   105  			LenEnvs:    2,
   106  		},
   107  		{
   108  			Name: "FatFinger",
   109  			Report: &claircore.IndexReport{
   110  				Packages: map[string]*claircore.Package{
   111  					"1": {
   112  						Name:     "something interesting",
   113  						Filepath: "a/path/to/some/file/site-packages/a_package/METADATA",
   114  					},
   115  					"2": {
   116  						Name:     "something uninteresting",
   117  						Filepath: "a/path/to/some/file/site-packages/b_package/METADATA",
   118  					},
   119  				},
   120  				Environments: map[string][]*claircore.Environment{
   121  					"1": {{IntroducedIn: firstLayerHash}},
   122  					"2": {{IntroducedIn: firstLayerHash}},
   123  				},
   124  				Files: map[string]claircore.File{
   125  					secondLayerHash.String(): {
   126  						Path: "a/path/to/some/file/.wh.site-packages",
   127  						Kind: claircore.FileKindWhiteout,
   128  					},
   129  				},
   130  			},
   131  			Layers: []*claircore.Layer{
   132  				{Hash: firstLayerHash},
   133  				{Hash: secondLayerHash},
   134  			},
   135  			LenPackage: 0,
   136  			LenEnvs:    0,
   137  		},
   138  		{
   139  			Name: "MaskedDirectory",
   140  			Report: &claircore.IndexReport{
   141  				Packages: map[string]*claircore.Package{
   142  					"1": {
   143  						Name:     "something interesting",
   144  						Filepath: "a/path/to/some/file/site-packages/a_package/METADATA",
   145  					},
   146  					"2": {
   147  						Name:     "something uninteresting",
   148  						Filepath: "a/path/to/some/file/site-packages/b_package/METADATA",
   149  					},
   150  				},
   151  				Environments: map[string][]*claircore.Environment{
   152  					"1": {{IntroducedIn: firstLayerHash}},
   153  					"2": {{IntroducedIn: firstLayerHash}},
   154  				},
   155  				Files: map[string]claircore.File{
   156  					firstLayerHash.String(): { // whiteout is in the same layer as packages
   157  						Path: "a/path/to/some/file/site-packages/.wh.b_package",
   158  						Kind: claircore.FileKindWhiteout,
   159  					},
   160  				},
   161  			},
   162  			Layers: []*claircore.Layer{
   163  				{Hash: firstLayerHash},
   164  				{Hash: secondLayerHash},
   165  			},
   166  			LenPackage: 2,
   167  			LenEnvs:    2,
   168  		},
   169  		{
   170  			Name: "CommonPrefixDistinctDirs",
   171  			Report: &claircore.IndexReport{
   172  				Packages: map[string]*claircore.Package{
   173  					"1": {
   174  						Name:     "something interesting",
   175  						Filepath: "a/path/to/some/file/site-packages/a_package/METADATA",
   176  					},
   177  					"2": {
   178  						Name:     "something uninteresting",
   179  						Filepath: "a/path/to/some/file/site-packages/b_package/METADATA",
   180  					},
   181  				},
   182  				Environments: map[string][]*claircore.Environment{
   183  					"1": {{IntroducedIn: firstLayerHash}},
   184  					"2": {{IntroducedIn: firstLayerHash}},
   185  				},
   186  				Files: map[string]claircore.File{
   187  					secondLayerHash.String(): {
   188  						Path: "a/path/to/some/file/site/.wh..wh..opq",
   189  						Kind: claircore.FileKindWhiteout,
   190  					},
   191  				},
   192  			},
   193  			Layers: []*claircore.Layer{
   194  				{Hash: firstLayerHash},
   195  				{Hash: secondLayerHash},
   196  			},
   197  			LenPackage: 2,
   198  			LenEnvs:    2,
   199  		},
   200  		{
   201  			Name: "Opaque",
   202  			Report: &claircore.IndexReport{
   203  				Packages: map[string]*claircore.Package{
   204  					"1": {
   205  						Name:     "something interesting",
   206  						Filepath: "a/path/to/some/file/site-packages/a_package/METADATA",
   207  					},
   208  					"2": {
   209  						Name:     "something uninteresting",
   210  						Filepath: "a/path/to/some/file/site-packages/b_package/METADATA",
   211  					},
   212  				},
   213  				Environments: map[string][]*claircore.Environment{
   214  					"1": {{IntroducedIn: firstLayerHash}},
   215  					"2": {{IntroducedIn: firstLayerHash}},
   216  				},
   217  				Files: map[string]claircore.File{
   218  					secondLayerHash.String(): {
   219  						Path: "a/path/to/some/file/site-packages/.wh..wh..opq",
   220  						Kind: claircore.FileKindWhiteout,
   221  					},
   222  				},
   223  			},
   224  			Layers: []*claircore.Layer{
   225  				{Hash: firstLayerHash},
   226  				{Hash: secondLayerHash},
   227  			},
   228  			LenPackage: 0,
   229  			LenEnvs:    0,
   230  		},
   231  		{
   232  			Name: "AddDeleteAdd",
   233  			Report: &claircore.IndexReport{
   234  				Packages: map[string]*claircore.Package{
   235  					"1": {
   236  						Name:     "something interesting",
   237  						Filepath: "a/path/to/some/file/site-packages/a_package/METADATA",
   238  					},
   239  				},
   240  				Environments: map[string][]*claircore.Environment{
   241  					"1": {{IntroducedIn: firstLayerHash}, {IntroducedIn: thirdLayerHash}},
   242  				},
   243  				Files: map[string]claircore.File{
   244  					secondLayerHash.String(): { // whiteout is sandwiched
   245  						Path: "a/path/to/some/file/site-packages/.wh.a_package",
   246  						Kind: claircore.FileKindWhiteout,
   247  					},
   248  				},
   249  			},
   250  			Layers: []*claircore.Layer{
   251  				{Hash: firstLayerHash},
   252  				{Hash: secondLayerHash},
   253  				{Hash: thirdLayerHash},
   254  			},
   255  			LenPackage: 1,
   256  			LenEnvs:    1,
   257  		},
   258  	}
   259  
   260  	r := &Resolver{}
   261  	for _, tc := range tests {
   262  		t.Run(tc.Name, func(t *testing.T) {
   263  			ctx := zlog.Test(context.Background(), t)
   264  			report := r.Resolve(ctx, tc.Report, tc.Layers)
   265  			if tc.LenPackage != len(report.Packages) {
   266  				t.Fatalf("wrong number of packages: expected: %d got: %d", tc.LenPackage, len(report.Packages))
   267  			}
   268  			if tc.LenEnvs != len(report.Environments) {
   269  				t.Fatalf("wrong number of environments: expected: %d got: %d", tc.LenEnvs, len(report.Environments))
   270  			}
   271  		})
   272  
   273  	}
   274  }
   275  
   276  func TestIsDeleted(t *testing.T) {
   277  	type testcase struct {
   278  		Path     string
   279  		Whiteout string
   280  		Deleted  bool
   281  	}
   282  
   283  	for _, tc := range []testcase{
   284  		{
   285  			Path:     "a/b",
   286  			Whiteout: "a/.wh.b",
   287  			Deleted:  true,
   288  		},
   289  		{
   290  			Path:     "a/c",
   291  			Whiteout: "a/.wh.b",
   292  			Deleted:  false,
   293  		},
   294  		{
   295  			Path:     "a/b/c/foo",
   296  			Whiteout: "a/.wh..wh..opq",
   297  			Deleted:  true,
   298  		},
   299  		{
   300  			Path:     "c/foo",
   301  			Whiteout: "a/.wh..wh..opq",
   302  			Deleted:  false,
   303  		},
   304  		{
   305  			Path:     "a/file.wh.txt",
   306  			Whiteout: "a/.wh.file.wh.txt",
   307  			Deleted:  true,
   308  		},
   309  		{
   310  			Path:     "file.wh.d/file.conf",
   311  			Whiteout: "file.wh.d/.wh.file.conf",
   312  			Deleted:  true,
   313  		},
   314  		{
   315  			Path:     "some/file",
   316  			Whiteout: "not/a/white/out",
   317  			Deleted:  false,
   318  		},
   319  		{
   320  			Path:     "a",
   321  			Whiteout: "a/b/.wh..wh..opq",
   322  			Deleted:  false,
   323  		},
   324  		{
   325  			Path:     "a",
   326  			Whiteout: "a/.wh..wh..opq",
   327  			Deleted:  false,
   328  		},
   329  	} {
   330  		got, want := fileIsDeleted(tc.Path, tc.Whiteout), tc.Deleted
   331  		if got != want {
   332  			t.Fail()
   333  		}
   334  		t.Logf("%s, %s\tgot: %v, want: %v", tc.Whiteout, tc.Path, got, want)
   335  	}
   336  }