github.com/devseccon/trivy@v0.47.1-0.20231123133102-bd902a0bd996/pkg/fanal/cache/s3_test.go (about)

     1  package cache
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"reflect"
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/aws/aws-sdk-go-v2/feature/s3/manager"
    11  	"github.com/aws/aws-sdk-go-v2/service/s3"
    12  	"golang.org/x/xerrors"
    13  
    14  	"github.com/devseccon/trivy/pkg/fanal/types"
    15  )
    16  
    17  type mockS3Client struct {
    18  	s3API
    19  }
    20  
    21  const (
    22  	correctHash = "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7"
    23  )
    24  
    25  func (m *mockS3Client) PutObject(ctx context.Context, in *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error) {
    26  	return &s3.PutObjectOutput{}, nil
    27  }
    28  
    29  func (m *mockS3Client) HeadObject(ctx context.Context, params *s3.HeadObjectInput, optFns ...func(*s3.Options)) (*s3.HeadObjectOutput, error) {
    30  	return &s3.HeadObjectOutput{}, nil
    31  }
    32  
    33  func (m *mockS3Client) DeleteBucket(ctx context.Context, in *s3.DeleteBucketInput, optFns ...func(*s3.Options)) (*s3.DeleteBucketOutput, error) {
    34  	if in != nil && *in.Bucket == blobBucket+"/prefix/"+correctHash {
    35  		return &s3.DeleteBucketOutput{}, nil
    36  	}
    37  	return nil, errors.New("unknown bucket")
    38  }
    39  
    40  func TestS3Cache_PutBlob(t *testing.T) {
    41  	mockSvc := &mockS3Client{}
    42  
    43  	type fields struct {
    44  		S3         s3API
    45  		Downloader *manager.Downloader
    46  		BucketName string
    47  		Prefix     string
    48  	}
    49  	type args struct {
    50  		blobID   string
    51  		blobInfo types.BlobInfo
    52  	}
    53  	tests := []struct {
    54  		name    string
    55  		fields  fields
    56  		args    args
    57  		wantErr bool
    58  	}{
    59  		{
    60  			name: "happy path",
    61  			fields: fields{
    62  				S3:         mockSvc,
    63  				BucketName: "test",
    64  				Prefix:     "prefix",
    65  			},
    66  			args: args{
    67  				blobID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7",
    68  				blobInfo: types.BlobInfo{
    69  					SchemaVersion: 1,
    70  					OS: types.OS{
    71  						Family: "alpine",
    72  						Name:   "3.10",
    73  					},
    74  				}},
    75  		},
    76  	}
    77  	for _, tt := range tests {
    78  		t.Run(tt.name, func(t *testing.T) {
    79  			c := NewS3Cache(tt.fields.BucketName, tt.fields.Prefix, tt.fields.S3, tt.fields.Downloader)
    80  			if err := c.PutBlob(tt.args.blobID, tt.args.blobInfo); (err != nil) != tt.wantErr {
    81  				t.Errorf("S3Cache.PutBlob() error = %v, wantErr %v", err, tt.wantErr)
    82  			}
    83  		})
    84  	}
    85  }
    86  
    87  func TestS3Cache_PutArtifact(t *testing.T) {
    88  	mockSvc := &mockS3Client{}
    89  
    90  	type fields struct {
    91  		S3         s3API
    92  		Downloader *manager.Downloader
    93  		BucketName string
    94  		Prefix     string
    95  	}
    96  	type args struct {
    97  		artifactID     string
    98  		artifactConfig types.ArtifactInfo
    99  	}
   100  	tests := []struct {
   101  		name    string
   102  		fields  fields
   103  		args    args
   104  		wantErr bool
   105  	}{
   106  		{
   107  			name: "happy path",
   108  			fields: fields{
   109  				S3:         mockSvc,
   110  				BucketName: "test",
   111  				Prefix:     "prefix",
   112  			},
   113  			args: args{
   114  				artifactID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4",
   115  				artifactConfig: types.ArtifactInfo{
   116  					SchemaVersion: 1,
   117  					Architecture:  "amd64",
   118  					Created:       time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC),
   119  					DockerVersion: "18.06.1-ce",
   120  					OS:            "linux",
   121  					HistoryPackages: []types.Package{
   122  						{
   123  							Name:    "musl",
   124  							Version: "1.2.3",
   125  						},
   126  					},
   127  				}},
   128  		},
   129  	}
   130  	for _, tt := range tests {
   131  		t.Run(tt.name, func(t *testing.T) {
   132  			c := NewS3Cache(tt.fields.BucketName, tt.fields.Prefix, tt.fields.S3, tt.fields.Downloader)
   133  			if err := c.PutArtifact(tt.args.artifactID, tt.args.artifactConfig); (err != nil) != tt.wantErr {
   134  				t.Errorf("S3Cache.PutArtifact() error = %v, wantErr %v", err, tt.wantErr)
   135  			}
   136  		})
   137  	}
   138  }
   139  
   140  func TestS3Cache_getIndex(t *testing.T) {
   141  	mockSvc := &mockS3Client{}
   142  
   143  	type fields struct {
   144  		S3         s3API
   145  		Downloader *manager.Downloader
   146  		BucketName string
   147  		Prefix     string
   148  	}
   149  	type args struct {
   150  		key     string
   151  		keyType string
   152  	}
   153  	tests := []struct {
   154  		name    string
   155  		fields  fields
   156  		args    args
   157  		wantErr bool
   158  	}{
   159  		{
   160  			name: "happy path",
   161  			fields: fields{
   162  				S3:         mockSvc,
   163  				BucketName: "test",
   164  				Prefix:     "prefix",
   165  			},
   166  			args: args{
   167  				key:     "key",
   168  				keyType: "artifactBucket",
   169  			},
   170  			wantErr: false,
   171  		},
   172  	}
   173  	for _, tt := range tests {
   174  		t.Run(tt.name, func(t *testing.T) {
   175  			c := NewS3Cache(tt.fields.BucketName, tt.fields.Prefix, tt.fields.S3, tt.fields.Downloader)
   176  			if err := c.getIndex(tt.args.key, tt.args.keyType); (err != nil) != tt.wantErr {
   177  				t.Errorf("S3Cache.getIndex() error = %v, wantErr %v", err, tt.wantErr)
   178  			}
   179  		})
   180  	}
   181  }
   182  
   183  type mockS3ClientMissingBlobs struct {
   184  	s3API
   185  }
   186  
   187  func (m *mockS3ClientMissingBlobs) PutObject(ctx context.Context, in *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error) {
   188  	return &s3.PutObjectOutput{}, nil
   189  }
   190  
   191  func (m *mockS3ClientMissingBlobs) HeadObject(ctx context.Context, params *s3.HeadObjectInput, optFns ...func(*s3.Options)) (*s3.HeadObjectOutput, error) {
   192  	return &s3.HeadObjectOutput{}, xerrors.Errorf("the object doesn't exist in S3")
   193  }
   194  
   195  func TestS3Cache_MissingBlobs(t *testing.T) {
   196  	mockSvc := &mockS3ClientMissingBlobs{}
   197  
   198  	type fields struct {
   199  		S3         s3API
   200  		Downloader *manager.Downloader
   201  		BucketName string
   202  		Prefix     string
   203  	}
   204  	type args struct {
   205  		artifactID             string
   206  		blobIDs                []string
   207  		analyzerVersions       map[string]int
   208  		configAnalyzerVersions map[string]int
   209  	}
   210  	tests := []struct {
   211  		name            string
   212  		fields          fields
   213  		args            args
   214  		want            bool
   215  		wantStringSlice []string
   216  		wantErr         bool
   217  	}{{
   218  		name: "happy path",
   219  		fields: fields{
   220  			S3:         mockSvc,
   221  			BucketName: "test",
   222  			Prefix:     "prefix",
   223  		},
   224  		args: args{
   225  			artifactID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4/1",
   226  			blobIDs:    []string{"sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7/10011"},
   227  		},
   228  		want:            true,
   229  		wantStringSlice: []string{"sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7/10011"},
   230  		wantErr:         false,
   231  	},
   232  	}
   233  	for _, tt := range tests {
   234  		t.Run(tt.name, func(t *testing.T) {
   235  			c := NewS3Cache(tt.fields.BucketName, tt.fields.Prefix, tt.fields.S3, tt.fields.Downloader)
   236  			got, got1, err := c.MissingBlobs(tt.args.artifactID, tt.args.blobIDs)
   237  			if (err != nil) != tt.wantErr {
   238  				t.Errorf("S3Cache.MissingBlobs() error = %v, wantErr %v", err, tt.wantErr)
   239  				return
   240  			}
   241  			if got != tt.want {
   242  				t.Errorf("S3Cache.MissingBlobs() got = %v, want %v", got, tt.want)
   243  			}
   244  			if !reflect.DeepEqual(got1, tt.wantStringSlice) {
   245  				t.Errorf("S3Cache.MissingBlobs() got1 = %v, want %v", got1, tt.wantStringSlice)
   246  			}
   247  		})
   248  	}
   249  }
   250  
   251  func TestS3Cache_DeleteBlobs(t *testing.T) {
   252  	mockSvc := &mockS3Client{}
   253  
   254  	type fields struct {
   255  		S3         s3API
   256  		Downloader *manager.Downloader
   257  		BucketName string
   258  		Prefix     string
   259  	}
   260  	type args struct {
   261  		blobIDs []string
   262  	}
   263  	tests := []struct {
   264  		name    string
   265  		fields  fields
   266  		args    args
   267  		wantErr bool
   268  	}{
   269  		{
   270  			name: "happy path",
   271  			fields: fields{
   272  				S3:         mockSvc,
   273  				BucketName: "test",
   274  				Prefix:     "prefix",
   275  			},
   276  			args: args{
   277  				blobIDs: []string{correctHash},
   278  			},
   279  		},
   280  		{
   281  			name: "delete blob with bad ID",
   282  			fields: fields{
   283  				S3:         mockSvc,
   284  				BucketName: "test",
   285  				Prefix:     "prefix",
   286  			},
   287  			args: args{
   288  				blobIDs: []string{"unde"},
   289  			},
   290  			wantErr: true,
   291  		},
   292  		{
   293  			name: "delete blobs with bad ID",
   294  			fields: fields{
   295  				S3:         mockSvc,
   296  				BucketName: "test",
   297  				Prefix:     "prefix",
   298  			},
   299  			args: args{
   300  				blobIDs: []string{correctHash},
   301  			},
   302  		},
   303  	}
   304  	for _, tt := range tests {
   305  		t.Run(tt.name, func(t *testing.T) {
   306  			c := NewS3Cache(tt.fields.BucketName, tt.fields.Prefix, tt.fields.S3, tt.fields.Downloader)
   307  			if err := c.DeleteBlobs(tt.args.blobIDs); (err != nil) != tt.wantErr {
   308  				t.Errorf("S3Cache.PutBlob() error = %v, wantErr %v", err, tt.wantErr)
   309  			}
   310  		})
   311  	}
   312  }