github.com/anchore/syft@v1.38.2/internal/relationship/index_test.go (about) 1 package relationship 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/assert" 7 "github.com/stretchr/testify/require" 8 9 "github.com/anchore/syft/syft/artifact" 10 "github.com/anchore/syft/syft/file" 11 "github.com/anchore/syft/syft/pkg" 12 ) 13 14 func Test_Index(t *testing.T) { 15 p1 := pkg.Package{ 16 Name: "pkg-1", 17 } 18 p2 := pkg.Package{ 19 Name: "pkg-2", 20 } 21 p3 := pkg.Package{ 22 Name: "pkg-3", 23 } 24 c1 := file.Coordinates{ 25 RealPath: "/coords/1", 26 } 27 c2 := file.Coordinates{ 28 RealPath: "/coords/2", 29 } 30 31 for _, p := range []*pkg.Package{&p1, &p2, &p3} { 32 p.SetID() 33 } 34 35 r1 := artifact.Relationship{ 36 From: p1, 37 To: p2, 38 Type: artifact.DependencyOfRelationship, 39 } 40 r2 := artifact.Relationship{ 41 From: p1, 42 To: p3, 43 Type: artifact.DependencyOfRelationship, 44 } 45 r3 := artifact.Relationship{ 46 From: p1, 47 To: c1, 48 Type: artifact.ContainsRelationship, 49 } 50 r4 := artifact.Relationship{ 51 From: p2, 52 To: c2, 53 Type: artifact.ContainsRelationship, 54 } 55 r5 := artifact.Relationship{ 56 From: p3, 57 To: c2, 58 Type: artifact.ContainsRelationship, 59 } 60 61 dup := artifact.Relationship{ 62 From: p3, 63 To: c2, 64 Type: artifact.ContainsRelationship, 65 } 66 67 idx := NewIndex(r1, r2, r3, r4, r5, dup) 68 require.ElementsMatch(t, slice(r1, r2, r3, r4, r5), idx.All()) 69 70 require.ElementsMatch(t, slice(r1, r4), idx.References(p2)) 71 require.ElementsMatch(t, slice(r4), idx.References(p2, artifact.ContainsRelationship)) 72 73 require.ElementsMatch(t, slice(r1), idx.To(p2)) 74 require.ElementsMatch(t, []artifact.Relationship(nil), idx.To(p2, artifact.ContainsRelationship)) 75 76 require.ElementsMatch(t, slice(r4), idx.From(p2)) 77 require.ElementsMatch(t, slice(r4), idx.From(p2, artifact.ContainsRelationship)) 78 } 79 80 func Test_sortOrder(t *testing.T) { 81 r1 := artifact.Relationship{ 82 From: id("1"), 83 To: id("2"), 84 Type: "1", 85 } 86 r2 := artifact.Relationship{ 87 From: id("2"), 88 To: id("3"), 89 Type: "1", 90 } 91 r3 := artifact.Relationship{ 92 From: id("3"), 93 To: id("4"), 94 Type: "1", 95 } 96 r4 := artifact.Relationship{ 97 From: id("1"), 98 To: id("2"), 99 Type: "2", 100 } 101 r5 := artifact.Relationship{ 102 From: id("2"), 103 To: id("3"), 104 Type: "2", 105 } 106 dup := artifact.Relationship{ 107 From: id("2"), 108 To: id("3"), 109 Type: "2", 110 } 111 r6 := artifact.Relationship{ 112 From: id("2"), 113 To: id("3"), 114 Type: "3", 115 } 116 117 idx := NewIndex(r5, r2, r6, r4, r1, r3, dup) 118 require.EqualValues(t, slice(r1, r2, r3, r4, r5, r6), idx.All()) 119 120 require.EqualValues(t, slice(r1, r4), idx.From(id("1"))) 121 122 require.EqualValues(t, slice(r2, r5, r6), idx.To(id("3"))) 123 124 rLast := artifact.Relationship{ 125 From: id("0"), 126 To: id("3"), 127 Type: "9999", 128 } 129 130 rFirst := artifact.Relationship{ 131 From: id("0"), 132 To: id("3"), 133 Type: "1", 134 } 135 136 rMid := artifact.Relationship{ 137 From: id("0"), 138 To: id("1"), 139 Type: "2", 140 } 141 142 idx.Add(rLast, rFirst, rMid) 143 144 require.EqualValues(t, slice(rFirst, r1, r2, r3, rMid, r4, r5, r6, rLast), idx.All()) 145 146 require.EqualValues(t, slice(rFirst, r2, r5, r6, rLast), idx.To(id("3"))) 147 } 148 149 func Test_Coordinates(t *testing.T) { 150 p1 := pkg.Package{ 151 Name: "pkg-1", 152 } 153 p2 := pkg.Package{ 154 Name: "pkg-2", 155 } 156 p3 := pkg.Package{ 157 Name: "pkg-3", 158 } 159 c1 := file.Coordinates{ 160 RealPath: "/coords/1", 161 } 162 c2 := file.Coordinates{ 163 RealPath: "/coords/2", 164 } 165 c3 := file.Coordinates{ 166 RealPath: "/coords/3", 167 } 168 c4 := file.Coordinates{ 169 RealPath: "/coords/4", 170 } 171 172 for _, p := range []*pkg.Package{&p1, &p2, &p3} { 173 p.SetID() 174 } 175 176 r1 := artifact.Relationship{ 177 From: p1, 178 To: p2, 179 Type: artifact.DependencyOfRelationship, 180 } 181 r2 := artifact.Relationship{ 182 From: p1, 183 To: p3, 184 Type: artifact.DependencyOfRelationship, 185 } 186 r3 := artifact.Relationship{ 187 From: p1, 188 To: c1, 189 Type: artifact.ContainsRelationship, 190 } 191 r4 := artifact.Relationship{ 192 From: p2, 193 To: c2, 194 Type: artifact.ContainsRelationship, 195 } 196 r5 := artifact.Relationship{ 197 From: p3, 198 To: c1, 199 Type: artifact.ContainsRelationship, 200 } 201 r6 := artifact.Relationship{ 202 From: p3, 203 To: c2, 204 Type: artifact.ContainsRelationship, 205 } 206 r7 := artifact.Relationship{ 207 From: c1, 208 To: c3, 209 Type: artifact.ContainsRelationship, 210 } 211 r8 := artifact.Relationship{ 212 From: c3, 213 To: c4, 214 Type: artifact.ContainsRelationship, 215 } 216 217 idx := NewIndex(r1, r2, r3, r4, r5, r6, r7, r8) 218 219 got := idx.Coordinates(p1) 220 require.ElementsMatch(t, slice(c1), got) 221 222 got = idx.Coordinates(p3) 223 require.ElementsMatch(t, slice(c1, c2), got) 224 } 225 226 type id string 227 228 func (i id) ID() artifact.ID { 229 return artifact.ID(i) 230 } 231 232 func slice[T any](values ...T) []T { 233 return values 234 } 235 236 func TestRemove(t *testing.T) { 237 p1 := pkg.Package{Name: "pkg-1"} 238 p2 := pkg.Package{Name: "pkg-2"} 239 p3 := pkg.Package{Name: "pkg-3"} 240 c1 := file.Coordinates{RealPath: "/coords/1"} 241 c2 := file.Coordinates{RealPath: "/coords/2"} 242 c3 := file.Coordinates{RealPath: "/coords/3"} 243 c4 := file.Coordinates{RealPath: "/coords/4"} 244 245 for _, p := range []*pkg.Package{&p1, &p2, &p3} { 246 p.SetID() 247 } 248 249 r1 := artifact.Relationship{ 250 From: p1, 251 To: p2, 252 Type: artifact.DependencyOfRelationship, 253 } 254 r2 := artifact.Relationship{ 255 From: p1, 256 To: p3, 257 Type: artifact.DependencyOfRelationship, 258 } 259 r3 := artifact.Relationship{ 260 From: p1, 261 To: c1, 262 Type: artifact.ContainsRelationship, 263 } 264 r4 := artifact.Relationship{ 265 From: p2, 266 To: c2, 267 Type: artifact.ContainsRelationship, 268 } 269 r5 := artifact.Relationship{ 270 From: p3, 271 To: c1, 272 Type: artifact.ContainsRelationship, 273 } 274 r6 := artifact.Relationship{ 275 From: p3, 276 To: c2, 277 Type: artifact.ContainsRelationship, 278 } 279 r7 := artifact.Relationship{ 280 From: c1, 281 To: c3, 282 Type: artifact.ContainsRelationship, 283 } 284 r8 := artifact.Relationship{ 285 From: c3, 286 To: c4, 287 Type: artifact.ContainsRelationship, 288 } 289 290 index := NewIndex(r1, r2, r3, r4, r5, r6, r7, r8) 291 292 assert.Equal(t, 8, len(index.All())) 293 294 // removal of p1 should remove r1, r2, and r3 295 index.Remove(p1.ID()) 296 remaining := index.All() 297 298 assert.Equal(t, 5, len(remaining)) 299 assert.NotContains(t, remaining, r1) 300 assert.NotContains(t, remaining, r2) 301 assert.NotContains(t, remaining, r3) 302 303 assert.Empty(t, index.From(p1)) 304 assert.Empty(t, index.To(p1)) 305 306 // removal of c1 should remove r5 and r7 307 index.Remove(c1.ID()) 308 remaining = index.All() 309 310 // r8 remains since c3->c4 should still exist 311 assert.Equal(t, 3, len(remaining)) 312 assert.NotContains(t, remaining, r5) 313 assert.NotContains(t, remaining, r7) 314 assert.Contains(t, remaining, r8) 315 316 assert.Empty(t, index.From(c1)) 317 assert.Empty(t, index.To(c1)) 318 319 // removal of c3 should remove r8 320 index.Remove(c3.ID()) 321 remaining = index.All() 322 323 assert.Equal(t, 2, len(remaining)) 324 assert.Contains(t, remaining, r4) 325 assert.Contains(t, remaining, r6) 326 327 assert.Empty(t, index.From(c3)) 328 assert.Empty(t, index.To(c3)) 329 } 330 331 func TestReplace(t *testing.T) { 332 p1 := pkg.Package{Name: "pkg-1"} 333 p2 := pkg.Package{Name: "pkg-2"} 334 p3 := pkg.Package{Name: "pkg-3"} 335 p4 := pkg.Package{Name: "pkg-4"} 336 337 for _, p := range []*pkg.Package{&p1, &p2, &p3, &p4} { 338 p.SetID() 339 } 340 341 r1 := artifact.Relationship{ 342 From: p1, 343 To: p2, 344 Type: artifact.DependencyOfRelationship, 345 } 346 r2 := artifact.Relationship{ 347 From: p3, 348 To: p1, 349 Type: artifact.DependencyOfRelationship, 350 } 351 r3 := artifact.Relationship{ 352 From: p2, 353 To: p3, 354 Type: artifact.ContainsRelationship, 355 } 356 357 index := NewIndex(r1, r2, r3) 358 359 // replace p1 with p4 in the relationships 360 index.Replace(p1.ID(), &p4) 361 362 expectedRels := []artifact.Relationship{ 363 { 364 From: p4, // replaced 365 To: p2, 366 Type: artifact.DependencyOfRelationship, 367 }, 368 { 369 From: p3, 370 To: p4, // replaced 371 Type: artifact.DependencyOfRelationship, 372 }, 373 { 374 From: p2, 375 To: p3, 376 Type: artifact.ContainsRelationship, 377 }, 378 } 379 380 compareRelationships(t, expectedRels, index.All()) 381 } 382 383 func compareRelationships(t testing.TB, expected, actual []artifact.Relationship) { 384 assert.Equal(t, len(expected), len(actual), "number of relationships should match") 385 for _, e := range expected { 386 found := false 387 for _, a := range actual { 388 if a.From.ID() == e.From.ID() && a.To.ID() == e.To.ID() && a.Type == e.Type { 389 found = true 390 break 391 } 392 } 393 assert.True(t, found, "expected relationship not found: %+v", e) 394 } 395 } 396 397 func TestReplace_NoExistingRelations(t *testing.T) { 398 p1 := pkg.Package{Name: "pkg-1"} 399 p2 := pkg.Package{Name: "pkg-2"} 400 401 p1.SetID() 402 p2.SetID() 403 404 index := NewIndex() 405 406 index.Replace(p1.ID(), &p2) 407 408 allRels := index.All() 409 assert.Len(t, allRels, 0) 410 }