github.com/quay/claircore@v1.5.28/datastore/postgres/index_e2e_test.go (about)

     1  package postgres
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/google/go-cmp/cmp"
     8  	"github.com/quay/zlog"
     9  
    10  	"github.com/quay/claircore"
    11  	"github.com/quay/claircore/indexer"
    12  	"github.com/quay/claircore/test"
    13  	"github.com/quay/claircore/test/integration"
    14  	pgtest "github.com/quay/claircore/test/postgres"
    15  )
    16  
    17  // mockScnr is a kind-agnostic scanner we will
    18  // use for testing purposes.
    19  type mockScnr struct {
    20  	name    string
    21  	kind    string
    22  	version string
    23  }
    24  
    25  func (m mockScnr) Name() string {
    26  	return m.name
    27  }
    28  func (m mockScnr) Kind() string {
    29  	return m.kind
    30  }
    31  func (m mockScnr) Version() string {
    32  	return m.version
    33  }
    34  
    35  type indexE2e struct {
    36  	name       string
    37  	store      indexer.Store
    38  	ctx        context.Context
    39  	manifest   claircore.Manifest
    40  	scnrs      indexer.VersionedScanners
    41  	packageGen int
    42  	distGen    int
    43  	repoGen    int
    44  }
    45  
    46  func TestIndexE2E(t *testing.T) {
    47  	integration.NeedDB(t)
    48  	ctx := context.Background()
    49  
    50  	e2es := []indexE2e{
    51  		{
    52  			name: "3 scanners gen small",
    53  			scnrs: indexer.VersionedScanners{
    54  				mockScnr{
    55  					name:    "test-scanner",
    56  					kind:    "test",
    57  					version: "v0.0.1",
    58  				},
    59  				mockScnr{
    60  					name:    "test-scanner1",
    61  					kind:    "test",
    62  					version: "v0.0.11",
    63  				},
    64  				mockScnr{
    65  					name:    "test-scanner2",
    66  					kind:    "test",
    67  					version: "v0.0.8",
    68  				},
    69  			},
    70  			packageGen: 100,
    71  			distGen:    150,
    72  			repoGen:    50,
    73  		},
    74  		{
    75  			name: "6 scanners gen small",
    76  			scnrs: indexer.VersionedScanners{
    77  				mockScnr{
    78  					name:    "test-scanner",
    79  					kind:    "test",
    80  					version: "v0.0.1",
    81  				},
    82  				mockScnr{
    83  					name:    "test-scanner1",
    84  					kind:    "test",
    85  					version: "v0.0.11",
    86  				},
    87  				mockScnr{
    88  					name:    "test-scanner2",
    89  					kind:    "test",
    90  					version: "v0.0.8",
    91  				},
    92  				mockScnr{
    93  					name:    "test-scanner3",
    94  					kind:    "test",
    95  					version: "v0.0.8",
    96  				},
    97  				mockScnr{
    98  					name:    "test-scanner4",
    99  					kind:    "test",
   100  					version: "v0.0.8",
   101  				},
   102  				mockScnr{
   103  					name:    "test-scanner5",
   104  					kind:    "test",
   105  					version: "v0.0.8",
   106  				},
   107  			},
   108  			packageGen: 100,
   109  			distGen:    150,
   110  			repoGen:    50,
   111  		},
   112  		{
   113  			name: "3 scanners gen large",
   114  			scnrs: indexer.VersionedScanners{
   115  				mockScnr{
   116  					name:    "test-scanner",
   117  					kind:    "test",
   118  					version: "v0.0.1",
   119  				},
   120  				mockScnr{
   121  					name:    "test-scanner1",
   122  					kind:    "test",
   123  					version: "v0.0.11",
   124  				},
   125  				mockScnr{
   126  					name:    "test-scanner2",
   127  					kind:    "test",
   128  					version: "v0.0.8",
   129  				},
   130  			},
   131  			packageGen: 1000,
   132  			distGen:    1500,
   133  			repoGen:    500,
   134  		},
   135  		{
   136  			name: "6 scanners gen large",
   137  			scnrs: indexer.VersionedScanners{
   138  				mockScnr{
   139  					name:    "test-scanner",
   140  					kind:    "test",
   141  					version: "v0.0.1",
   142  				},
   143  				mockScnr{
   144  					name:    "test-scanner1",
   145  					kind:    "test",
   146  					version: "v0.0.11",
   147  				},
   148  				mockScnr{
   149  					name:    "test-scanner2",
   150  					kind:    "test",
   151  					version: "v0.0.8",
   152  				},
   153  				mockScnr{
   154  					name:    "test-scanner3",
   155  					kind:    "test",
   156  					version: "v0.0.8",
   157  				},
   158  				mockScnr{
   159  					name:    "test-scanner4",
   160  					kind:    "test",
   161  					version: "v0.0.8",
   162  				},
   163  				mockScnr{
   164  					name:    "test-scanner5",
   165  					kind:    "test",
   166  					version: "v0.0.8",
   167  				},
   168  			},
   169  			packageGen: 1000,
   170  			distGen:    1500,
   171  			repoGen:    500,
   172  		},
   173  	}
   174  
   175  	for _, e := range e2es {
   176  		pool := pgtest.TestIndexerDB(ctx, t)
   177  		store := NewIndexerStore(pool)
   178  
   179  		layer := &claircore.Layer{
   180  			Hash: claircore.MustParseDigest(`sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef`),
   181  		}
   182  		manifest := claircore.Manifest{
   183  			Hash:   claircore.MustParseDigest(`sha256:fc92eec5cac70b0c324cec2933cd7db1c0eae7c9e2649e42d02e77eb6da0d15f`),
   184  			Layers: []*claircore.Layer{layer},
   185  		}
   186  
   187  		e.store = store
   188  		e.ctx = ctx
   189  		e.manifest = manifest
   190  
   191  		t.Run(e.name, e.Run)
   192  	}
   193  }
   194  
   195  func (e *indexE2e) Run(t *testing.T) {
   196  	type subtest struct {
   197  		name string
   198  		do   func(t *testing.T)
   199  	}
   200  	subtests := [...]subtest{
   201  		{"RegisterScanner", e.RegisterScanner},
   202  		{"PersistManifest", e.PersistManifest},
   203  		{"IndexAndRetrievePackages", e.IndexAndRetrievePackages},
   204  		{"IndexAndRetrieveDistributions", e.IndexAndRetrieveDistributions},
   205  		{"IndexAndRetrieveRepos", e.IndexAndRetrieveRepos},
   206  		{"LayerScanned", e.LayerScanned},
   207  		{"LayerScannedNotExists", e.LayerScannedNotExists},
   208  		{"LayerScannedFalse", e.LayerScannedFalse},
   209  		{"IndexReport", e.IndexReport},
   210  	}
   211  	for _, subtest := range subtests {
   212  		if !t.Run(subtest.name, subtest.do) {
   213  			t.FailNow()
   214  		}
   215  	}
   216  }
   217  
   218  // PersistManifest confirms we create the necessary
   219  // Manifest and Layer identifies so layer code
   220  // foreign key references do not fail.
   221  func (e *indexE2e) PersistManifest(t *testing.T) {
   222  	ctx := zlog.Test(e.ctx, t)
   223  	err := e.store.PersistManifest(ctx, e.manifest)
   224  	if err != nil {
   225  		t.Fatalf("failed to persist manifest: %v", err)
   226  	}
   227  }
   228  
   229  // RegisterScanner confirms a scanner can be registered
   230  // and provides this scanner for other subtests to use
   231  func (e *indexE2e) RegisterScanner(t *testing.T) {
   232  	ctx := zlog.Test(e.ctx, t)
   233  	err := e.store.RegisterScanners(ctx, e.scnrs)
   234  	if err != nil {
   235  		t.Fatalf("failed to register scnr: %v", err)
   236  	}
   237  }
   238  
   239  // IndexAndRetreivePackages confirms inserting and
   240  // selecting packages associated with a layer works
   241  // correctly.
   242  func (e *indexE2e) IndexAndRetrievePackages(t *testing.T) {
   243  	ctx := zlog.Test(e.ctx, t)
   244  	A := test.GenUniquePackages(e.packageGen)
   245  
   246  	for _, scnr := range e.scnrs {
   247  		err := e.store.IndexPackages(ctx, A, e.manifest.Layers[0], scnr)
   248  		if err != nil {
   249  			t.Fatalf("failed to index package: %v", err)
   250  		}
   251  	}
   252  
   253  	B, err := e.store.PackagesByLayer(ctx, e.manifest.Layers[0].Hash, e.scnrs)
   254  	if err != nil {
   255  		t.Fatalf("failed to retrieve packages by layer: %v", err)
   256  	}
   257  
   258  	if len(e.scnrs)*e.packageGen != len(B) {
   259  		t.Fatalf("wanted len: %v got: %v", len(e.scnrs)*e.packageGen, len(B))
   260  	}
   261  }
   262  
   263  // IndexAndRetreiveDistributions confirms inserting and
   264  // selecting distributions associated with a layer works
   265  // correctly.
   266  func (e *indexE2e) IndexAndRetrieveDistributions(t *testing.T) {
   267  	ctx := zlog.Test(e.ctx, t)
   268  	A := test.GenUniqueDistributions(e.distGen)
   269  
   270  	for _, scnr := range e.scnrs {
   271  		err := e.store.IndexDistributions(ctx, A, e.manifest.Layers[0], scnr)
   272  		if err != nil {
   273  			t.Fatalf("failed to index distributions: %v", err)
   274  		}
   275  	}
   276  
   277  	B, err := e.store.DistributionsByLayer(ctx, e.manifest.Layers[0].Hash, e.scnrs)
   278  	if err != nil {
   279  		t.Fatalf("failed to retrieve distributions by layer: %v", err)
   280  	}
   281  
   282  	if len(e.scnrs)*e.distGen != len(B) {
   283  		t.Fatalf("wanted len: %v got: %v", len(e.scnrs)*e.distGen, len(B))
   284  	}
   285  }
   286  
   287  // IndexAndRetreiveRepos confirms inserting and
   288  // selecting repositories associated with a layer works
   289  // correctly.
   290  func (e *indexE2e) IndexAndRetrieveRepos(t *testing.T) {
   291  	ctx := zlog.Test(e.ctx, t)
   292  	A := test.GenUniqueRepositories(e.repoGen)
   293  
   294  	for _, scnr := range e.scnrs {
   295  		err := e.store.IndexRepositories(ctx, A, e.manifest.Layers[0], scnr)
   296  		if err != nil {
   297  			t.Fatalf("failed to index repos: %v", err)
   298  		}
   299  	}
   300  
   301  	B, err := e.store.RepositoriesByLayer(ctx, e.manifest.Layers[0].Hash, e.scnrs)
   302  	if err != nil {
   303  		t.Fatalf("failed to retrieve repos by layer: %v", err)
   304  	}
   305  
   306  	if len(e.scnrs)*e.repoGen != len(B) {
   307  		t.Fatalf("wanted len: %v got: %v", len(e.scnrs)*e.repoGen, len(B))
   308  	}
   309  }
   310  
   311  // LayerScanned confirms the book keeping involved in marking a layer
   312  // scanned works correctly.
   313  func (e *indexE2e) LayerScanned(t *testing.T) {
   314  	ctx := zlog.Test(e.ctx, t)
   315  	for _, scnr := range e.scnrs {
   316  		err := e.store.SetLayerScanned(ctx, e.manifest.Layers[0].Hash, scnr)
   317  		if err != nil {
   318  			t.Fatalf("failed to set layer scanned: %v", err)
   319  		}
   320  
   321  		b, err := e.store.LayerScanned(ctx, e.manifest.Layers[0].Hash, scnr)
   322  		if err != nil {
   323  			t.Fatalf("failed to query if layer is scanned: %v", err)
   324  		}
   325  		if !b {
   326  			t.Fatalf("expected layer to be scanned")
   327  		}
   328  	}
   329  }
   330  
   331  // LayerScannedNotExists confirms an error is returned when attempting
   332  // to obtain if a layer was scanned by a non-existent scanner.
   333  func (e *indexE2e) LayerScannedNotExists(t *testing.T) {
   334  	ctx := zlog.Test(e.ctx, t)
   335  	scnr := mockScnr{
   336  		name:    "invalid",
   337  		kind:    "invalid",
   338  		version: "invalid",
   339  	}
   340  
   341  	_, err := e.store.LayerScanned(ctx, e.manifest.Layers[0].Hash, scnr)
   342  	if err == nil {
   343  		t.Fatalf("expected error scnr not found error condition")
   344  	}
   345  }
   346  
   347  // LayerScannedFalse confirms a false boolean is returned when attempting
   348  // to obtain if a non-exitent layer was scanned by a valid scanner
   349  func (e *indexE2e) LayerScannedFalse(t *testing.T) {
   350  	ctx := zlog.Test(e.ctx, t)
   351  
   352  	// create a layer that has not been persisted to the store
   353  	layer := &claircore.Layer{
   354  		Hash: claircore.MustParseDigest(`sha256:5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03`),
   355  	}
   356  
   357  	b, err := e.store.LayerScanned(ctx, layer.Hash, e.scnrs[0])
   358  	if err != nil {
   359  		t.Fatalf("failed to query if layer is scanned: %v", err)
   360  	}
   361  	if b {
   362  		t.Fatalf("expected layer not to be scanned")
   363  	}
   364  }
   365  
   366  // IndexReport confirms the book keeping around index reports works
   367  // correctly.
   368  func (e *indexE2e) IndexReport(t *testing.T) {
   369  	ctx := zlog.Test(e.ctx, t)
   370  
   371  	A := &claircore.IndexReport{
   372  		Hash:  e.manifest.Hash,
   373  		State: "Testing",
   374  	}
   375  
   376  	err := e.store.SetIndexReport(ctx, A)
   377  	if err != nil {
   378  		t.Fatalf("failed to set index report: %v", err)
   379  	}
   380  	B, ok, err := e.store.IndexReport(ctx, e.manifest.Hash)
   381  	if err != nil {
   382  		t.Fatalf("failed to retrieve index report: %v", err)
   383  	}
   384  	if !ok {
   385  		t.Fatalf("no index report found")
   386  	}
   387  	if !cmp.Equal(A.Hash.String(), B.Hash.String()) {
   388  		t.Fatalf("%v", cmp.Diff(A.Hash.String(), B.Hash.String()))
   389  	}
   390  	if !cmp.Equal(A.State, B.State) {
   391  		t.Fatalf("%v", cmp.Diff(A.Hash.String(), B.Hash.String()))
   392  	}
   393  
   394  	A.State = "IndexFinished"
   395  	err = e.store.SetIndexFinished(ctx, A, e.scnrs)
   396  	if err != nil {
   397  		t.Fatalf("failed to set index as finished: %v", err)
   398  	}
   399  
   400  	b, err := e.store.ManifestScanned(ctx, e.manifest.Hash, e.scnrs)
   401  	if err != nil {
   402  		t.Fatalf("failed to query if manifest was scanned: %v", err)
   403  	}
   404  	if !b {
   405  		t.Fatalf("expected manifest to be scanned")
   406  	}
   407  
   408  	B, ok, err = e.store.IndexReport(ctx, e.manifest.Hash)
   409  	if err != nil {
   410  		t.Fatalf("failed to retrieve index report: %v", err)
   411  	}
   412  	if !ok {
   413  		t.Fatalf("no index report found")
   414  	}
   415  	if !cmp.Equal(A.Hash.String(), B.Hash.String()) {
   416  		t.Fatalf("%v", cmp.Diff(A.Hash.String(), B.Hash.String()))
   417  	}
   418  	if !cmp.Equal(A.State, B.State) {
   419  		t.Fatalf("%v", cmp.Diff(A.Hash.String(), B.Hash.String()))
   420  	}
   421  }