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 }