Skip to content

Commit ca2b990

Browse files
committed
Add unit test for FilterCandidatesByPriorityWithTarget
Signed-off-by: Teoh Suh Haw <suh.haw.teoh@intel.com>
1 parent cd60799 commit ca2b990

File tree

1 file changed

+210
-8
lines changed

1 file changed

+210
-8
lines changed

internal/ospackage/debutils/resolver_test.go

Lines changed: 210 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package debutils_test
1+
package debutils
22

33
import (
44
"fmt"
@@ -9,7 +9,6 @@ import (
99

1010
"github.com/open-edge-platform/os-image-composer/internal/config"
1111
"github.com/open-edge-platform/os-image-composer/internal/ospackage"
12-
"github.com/open-edge-platform/os-image-composer/internal/ospackage/debutils"
1312
)
1413

1514
func TestResolveDependenciesAdvanced(t *testing.T) {
@@ -70,7 +69,7 @@ func TestResolveDependenciesAdvanced(t *testing.T) {
7069

7170
for _, tc := range testCases {
7271
t.Run(tc.name, func(t *testing.T) {
73-
result, err := debutils.ResolveDependencies(tc.requested, tc.all)
72+
result, err := ResolveDependencies(tc.requested, tc.all)
7473

7574
if tc.expectError {
7675
if err == nil {
@@ -161,7 +160,7 @@ func TestGenerateDot(t *testing.T) {
161160

162161
for _, tc := range testCases {
163162
t.Run(tc.name, func(t *testing.T) {
164-
err := debutils.GenerateDot(tc.pkgs, tc.filename, tc.pkgSources)
163+
err := GenerateDot(tc.pkgs, tc.filename, tc.pkgSources)
165164
if tc.expectError {
166165
if err == nil {
167166
t.Errorf("expected error but got none")
@@ -201,7 +200,7 @@ func TestGenerateDot(t *testing.T) {
201200
// Check dependencies - each unique edge should appear exactly once
202201
seenEdges := make(map[string]bool)
203202
for _, dep := range pkg.Requires {
204-
depName := debutils.CleanDependencyName(dep)
203+
depName := CleanDependencyName(dep)
205204
if depName == "" {
206205
continue
207206
}
@@ -268,7 +267,7 @@ func TestCleanDependencyName(t *testing.T) {
268267

269268
for _, tc := range testCases {
270269
t.Run(tc.input, func(t *testing.T) {
271-
result := debutils.CleanDependencyName(tc.input)
270+
result := CleanDependencyName(tc.input)
272271
if result != tc.expected {
273272
t.Errorf("cleanDependencyName(%q) = %q, expected %q", tc.input, result, tc.expected)
274273
}
@@ -325,7 +324,7 @@ func TestCompareDebianVersions(t *testing.T) {
325324
for _, tc := range testCases {
326325
t.Run(tc.a+"_vs_"+tc.b, func(t *testing.T) {
327326
// Test the exported CompareDebianVersions function directly
328-
result, err := debutils.CompareDebianVersions(tc.a, tc.b)
327+
result, err := CompareDebianVersions(tc.a, tc.b)
329328
if err != nil {
330329
t.Errorf("CompareDebianVersions(%q, %q) returned error: %v", tc.a, tc.b, err)
331330
return
@@ -380,6 +379,209 @@ func TestCompareVersions(t *testing.T) {
380379
}
381380
}
382381

382+
func TestFilterCandidatesByPriorityWithTarget(t *testing.T) {
383+
// Mock repository configurations for testing
384+
oldRepoCfgs := RepoCfgs
385+
oldRepoCfg := RepoCfg
386+
defer func() {
387+
RepoCfgs = oldRepoCfgs
388+
RepoCfg = oldRepoCfg
389+
}()
390+
391+
// Set up test repositories with different priorities
392+
RepoCfgs = []RepoConfig{
393+
{PkgPrefix: "http://archive.ubuntu.com/ubuntu", Priority: 500}, // Default priority
394+
{PkgPrefix: "http://ppa.launchpad.net/test/ppa/ubuntu", Priority: 990}, // Preferred
395+
{PkgPrefix: "http://blocked.repo.com/ubuntu", Priority: -1}, // Blocked
396+
{PkgPrefix: "http://force.repo.com/ubuntu", Priority: 1001}, // Force install
397+
}
398+
399+
testCases := []struct {
400+
name string
401+
candidates []ospackage.PackageInfo
402+
targetName string
403+
expectedNames []string // Expected order of package names after filtering
404+
expectedCount int
405+
description string
406+
}{
407+
{
408+
name: "empty candidates",
409+
candidates: []ospackage.PackageInfo{},
410+
targetName: "test-pkg",
411+
expectedNames: []string{},
412+
expectedCount: 0,
413+
description: "should handle empty candidate list",
414+
},
415+
{
416+
name: "exact name wins over provides",
417+
candidates: []ospackage.PackageInfo{
418+
{Name: "linux-image-6.17.0-1017-oem", Version: "6.17.0-1017.18",
419+
URL: "http://archive.ubuntu.com/ubuntu/pool/main/l/linux/linux-image-6.17.0-1017-oem_6.17.0-1017.18_amd64.deb",
420+
Provides: []string{"v4l2loopback-dkms"}},
421+
{Name: "v4l2loopback-dkms", Version: "0.12.7-2ubuntu5.1",
422+
URL: "http://archive.ubuntu.com/ubuntu/pool/universe/v/v4l2loopback/v4l2loopback-dkms_0.12.7-2ubuntu5.1_all.deb"},
423+
},
424+
targetName: "v4l2loopback-dkms",
425+
expectedNames: []string{"v4l2loopback-dkms", "linux-image-6.17.0-1017-oem"},
426+
expectedCount: 2,
427+
description: "exact name match should come first despite lower version number",
428+
},
429+
{
430+
name: "blocked packages filtered out",
431+
candidates: []ospackage.PackageInfo{
432+
{Name: "good-pkg", Version: "1.0",
433+
URL: "http://archive.ubuntu.com/ubuntu/pool/main/g/good/good-pkg_1.0_amd64.deb"},
434+
{Name: "blocked-pkg", Version: "2.0",
435+
URL: "http://blocked.repo.com/ubuntu/pool/main/b/blocked/blocked-pkg_2.0_amd64.deb"},
436+
},
437+
targetName: "test-pkg",
438+
expectedNames: []string{"good-pkg"},
439+
expectedCount: 1,
440+
description: "packages from blocked repositories should be filtered out",
441+
},
442+
{
443+
name: "priority comparison for exact matches",
444+
candidates: []ospackage.PackageInfo{
445+
{Name: "pkg", Version: "1.0",
446+
URL: "http://archive.ubuntu.com/ubuntu/pool/main/p/pkg/pkg_1.0_amd64.deb"}, // Priority 500
447+
{Name: "pkg", Version: "1.0",
448+
URL: "http://ppa.launchpad.net/test/ppa/ubuntu/pool/main/p/pkg/pkg_1.0_amd64.deb"}, // Priority 990
449+
},
450+
targetName: "pkg",
451+
expectedNames: []string{"pkg", "pkg"}, // Higher priority first
452+
expectedCount: 2,
453+
description: "higher priority exact matches should come first",
454+
},
455+
{
456+
name: "version comparison for exact matches",
457+
candidates: []ospackage.PackageInfo{
458+
{Name: "pkg", Version: "1.0",
459+
URL: "http://archive.ubuntu.com/ubuntu/pool/main/p/pkg/pkg_1.0_amd64.deb"},
460+
{Name: "pkg", Version: "2.0",
461+
URL: "http://archive.ubuntu.com/ubuntu/pool/main/p/pkg/pkg_2.0_amd64.deb"},
462+
},
463+
targetName: "pkg",
464+
expectedNames: []string{"pkg", "pkg"}, // Higher version first
465+
expectedCount: 2,
466+
description: "higher version exact matches should come first when same priority",
467+
},
468+
{
469+
name: "force install priority",
470+
candidates: []ospackage.PackageInfo{
471+
{Name: "pkg", Version: "1.0",
472+
URL: "http://archive.ubuntu.com/ubuntu/pool/main/p/pkg/pkg_1.0_amd64.deb"}, // Priority 500
473+
{Name: "pkg", Version: "1.0",
474+
URL: "http://force.repo.com/ubuntu/pool/main/p/pkg/pkg_1.0_amd64.deb"}, // Priority 1001 (force)
475+
},
476+
targetName: "pkg",
477+
expectedNames: []string{"pkg", "pkg"}, // Force install first
478+
expectedCount: 2,
479+
description: "force install packages should have highest priority",
480+
},
481+
{
482+
name: "provides matches stable order",
483+
candidates: []ospackage.PackageInfo{
484+
{Name: "kernel-a", Version: "6.17.0",
485+
URL: "http://archive.ubuntu.com/ubuntu/pool/main/k/kernel-a/kernel-a_6.17.0_amd64.deb",
486+
Provides: []string{"virtual-pkg"}},
487+
{Name: "kernel-b", Version: "5.15.0",
488+
URL: "http://archive.ubuntu.com/ubuntu/pool/main/k/kernel-b/kernel-b_5.15.0_amd64.deb",
489+
Provides: []string{"virtual-pkg"}},
490+
},
491+
targetName: "virtual-pkg",
492+
expectedNames: []string{"kernel-a", "kernel-b"}, // Maintain stable order, no version comparison
493+
expectedCount: 2,
494+
description: "provides matches should maintain stable order without cross-type version comparison",
495+
},
496+
{
497+
name: "mixed exact and provides with different priorities",
498+
candidates: []ospackage.PackageInfo{
499+
{Name: "real-pkg", Version: "1.0",
500+
URL: "http://archive.ubuntu.com/ubuntu/pool/main/r/real/real-pkg_1.0_amd64.deb"}, // Priority 500
501+
{Name: "high-priority-virtual", Version: "2.0",
502+
URL: "http://ppa.launchpad.net/test/ppa/ubuntu/pool/main/h/high/high-priority-virtual_2.0_amd64.deb", // Priority 990
503+
Provides: []string{"real-pkg"}},
504+
},
505+
targetName: "real-pkg",
506+
expectedNames: []string{"real-pkg", "high-priority-virtual"}, // Exact match wins despite lower priority
507+
expectedCount: 2,
508+
description: "exact matches should win over provides matches regardless of priority",
509+
},
510+
{
511+
name: "all candidates blocked",
512+
candidates: []ospackage.PackageInfo{
513+
{Name: "blocked1", Version: "1.0",
514+
URL: "http://blocked.repo.com/ubuntu/pool/main/b/blocked1/blocked1_1.0_amd64.deb"},
515+
{Name: "blocked2", Version: "2.0",
516+
URL: "http://blocked.repo.com/ubuntu/pool/main/b/blocked2/blocked2_2.0_amd64.deb"},
517+
},
518+
targetName: "test-pkg",
519+
expectedNames: []string{},
520+
expectedCount: 0,
521+
description: "should return empty when all candidates are blocked",
522+
},
523+
{
524+
name: "real v4l2loopback-dkms scenario",
525+
candidates: []ospackage.PackageInfo{
526+
// Multiple kernel packages providing v4l2loopback-dkms (with higher versions)
527+
{Name: "linux-image-unsigned-6.17.0-1017-oem", Version: "6.17.0-1017.18",
528+
URL: "http://archive.ubuntu.com/ubuntu/pool/main/l/linux-unsigned/linux-image-unsigned-6.17.0-1017-oem_6.17.0-1017.18_amd64.deb",
529+
Provides: []string{"v4l2loopback-dkms"}},
530+
{Name: "linux-image-unsigned-6.15.0-1015-oem", Version: "6.15.0-1015.16",
531+
URL: "http://archive.ubuntu.com/ubuntu/pool/main/l/linux-unsigned/linux-image-unsigned-6.15.0-1015-oem_6.15.0-1015.16_amd64.deb",
532+
Provides: []string{"v4l2loopback-dkms"}},
533+
// Real v4l2loopback-dkms package (with lower version number)
534+
{Name: "v4l2loopback-dkms", Version: "0.12.7-2ubuntu5.1",
535+
URL: "http://archive.ubuntu.com/ubuntu/pool/universe/v/v4l2loopback/v4l2loopback-dkms_0.12.7-2ubuntu5.1_all.deb"},
536+
},
537+
targetName: "v4l2loopback-dkms",
538+
expectedNames: []string{"v4l2loopback-dkms", "linux-image-unsigned-6.17.0-1017-oem", "linux-image-unsigned-6.15.0-1015-oem"},
539+
expectedCount: 3,
540+
description: "real v4l2loopback-dkms package should be selected first despite kernel packages having higher version numbers",
541+
},
542+
}
543+
544+
for _, tc := range testCases {
545+
t.Run(tc.name, func(t *testing.T) {
546+
result := filterCandidatesByPriorityWithTarget(tc.candidates, tc.targetName)
547+
548+
if len(result) != tc.expectedCount {
549+
t.Errorf("expected %d candidates, got %d", tc.expectedCount, len(result))
550+
for i, pkg := range result {
551+
t.Logf(" result[%d]: %s (version: %s)", i, pkg.Name, pkg.Version)
552+
}
553+
}
554+
555+
// Check that the order matches expected names
556+
for i, expected := range tc.expectedNames {
557+
if i >= len(result) {
558+
t.Errorf("expected candidate %d to be %s, but result has only %d candidates", i, expected, len(result))
559+
continue
560+
}
561+
if result[i].Name != expected {
562+
t.Errorf("expected candidate %d to be %s, got %s", i, expected, result[i].Name)
563+
}
564+
}
565+
566+
// Verify no blocked packages in result
567+
for _, pkg := range result {
568+
if strings.Contains(pkg.URL, "blocked.repo.com") {
569+
t.Errorf("blocked package %s should not be in result", pkg.Name)
570+
}
571+
}
572+
573+
// For the real v4l2loopback-dkms scenario, verify the exact match comes first
574+
if tc.name == "real v4l2loopback-dkms scenario" && len(result) > 0 {
575+
if result[0].Name != "v4l2loopback-dkms" {
576+
t.Errorf("v4l2loopback-dkms should be first candidate, got %s", result[0].Name)
577+
}
578+
}
579+
580+
t.Logf("Test '%s': %s", tc.name, tc.description)
581+
})
582+
}
583+
}
584+
383585
func TestResolveTopPackageConflicts(t *testing.T) {
384586
all := []ospackage.PackageInfo{
385587
{Name: "acct", Version: "6.6.4-5+b1", URL: "pool/main/a/acct/acct_6.6.4-5+b1_amd64.deb"},
@@ -433,7 +635,7 @@ func TestResolveTopPackageConflicts(t *testing.T) {
433635

434636
for _, tc := range testCases {
435637
t.Run(tc.name, func(t *testing.T) {
436-
result, found := debutils.ResolveTopPackageConflicts(tc.want, all)
638+
result, found := ResolveTopPackageConflicts(tc.want, all)
437639

438640
if found != tc.expectFound {
439641
t.Errorf("ResolveTopPackageConflicts(%q) found=%v, expected found=%v", tc.want, found, tc.expectFound)

0 commit comments

Comments
 (0)