@@ -574,6 +574,92 @@ def test_deb_running_kernel_flavour(self):
574574 host .kernel = '5.14.0-503.el9'
575575 self .assertIsNone (host .get_running_kernel_flavour ())
576576
577+ def test_deb_kernel_series_extraction (self ):
578+ """Test get_deb_kernel_series helper."""
579+ host = self ._create_host ('6.8.0-51-generic' , [self .img_51 ])
580+ self .assertEqual (
581+ host .get_deb_kernel_series ('linux-image-6.8.0-51-generic' ), '6.8'
582+ )
583+ self .assertEqual (
584+ host .get_deb_kernel_series ('linux-image-6.17.0-19-generic' ), '6.17'
585+ )
586+ self .assertEqual (
587+ host .get_deb_kernel_series ('linux-modules-extra-6.1.0-28-cloud-amd64' ), '6.1'
588+ )
589+ self .assertEqual (
590+ host .get_deb_kernel_series ('linux-image-unsigned-6.8.0-51-generic' ), '6.8'
591+ )
592+ self .assertIsNone (host .get_deb_kernel_series ('not-a-kernel' ))
593+
594+ def test_deb_hwe_not_offered_to_ga_host (self ):
595+ """HWE kernels (6.17) should not be offered as updates to GA (6.8) hosts.
596+
597+ Reproduces GitHub issue: both GA and HWE kernels in the same repo
598+ (noble-updates), same priority. Without series filtering, 6.17 would
599+ be incorrectly picked as an update for a 6.8 host.
600+ """
601+ # add HWE kernel packages to the same repo/mirror
602+ hwe_img_name = PackageName .objects .create (
603+ name = 'linux-image-6.17.0-19-generic'
604+ )
605+ hwe_img = Package .objects .create (
606+ name = hwe_img_name , arch = self .pkg_arch , epoch = '' ,
607+ version = '6.17.0-19.19~24.04.2' , release = '' , packagetype = 'D'
608+ )
609+ self .mirror .packages .add (hwe_img )
610+
611+ host = self ._create_host (
612+ '6.8.0-51-generic' ,
613+ [self .img_49 , self .img_51 ],
614+ )
615+ repo_packages = Package .objects .filter (mirror = self .mirror )
616+ kernel_packages = host .packages .filter (
617+ name__name__startswith = 'linux-image-'
618+ )
619+
620+ host .find_kernel_updates (kernel_packages , repo_packages )
621+
622+ # should get GA update (6.8.0-51 → 6.8.0-53), NOT HWE (6.17)
623+ self .assertEqual (host .updates .count (), 1 )
624+ update = host .updates .first ()
625+ self .assertEqual (update .oldpackage , self .img_51 )
626+ self .assertEqual (update .newpackage , self .img_53 )
627+
628+ def test_deb_hwe_host_gets_hwe_updates (self ):
629+ """HWE host (6.17) should get HWE updates, not GA."""
630+ hwe_img_19_name = PackageName .objects .create (
631+ name = 'linux-image-6.17.0-19-generic'
632+ )
633+ hwe_img_19 = Package .objects .create (
634+ name = hwe_img_19_name , arch = self .pkg_arch , epoch = '' ,
635+ version = '6.17.0-19.19~24.04.2' , release = '' , packagetype = 'D'
636+ )
637+ hwe_img_21_name = PackageName .objects .create (
638+ name = 'linux-image-6.17.0-21-generic'
639+ )
640+ hwe_img_21 = Package .objects .create (
641+ name = hwe_img_21_name , arch = self .pkg_arch , epoch = '' ,
642+ version = '6.17.0-21.21~24.04.2' , release = '' , packagetype = 'D'
643+ )
644+ self .mirror .packages .add (hwe_img_19 , hwe_img_21 )
645+
646+ host = self ._create_host (
647+ '6.17.0-19-generic' ,
648+ [hwe_img_19 ],
649+ )
650+ repo_packages = Package .objects .filter (mirror = self .mirror )
651+ kernel_packages = host .packages .filter (
652+ name__name__startswith = 'linux-image-'
653+ )
654+
655+ host .find_kernel_updates (kernel_packages , repo_packages )
656+
657+ # should get HWE update only
658+ self .assertEqual (host .updates .count (), 1 )
659+ update = host .updates .first ()
660+ self .assertEqual (update .oldpackage , hwe_img_19 )
661+ self .assertEqual (update .newpackage , hwe_img_21 )
662+
577663
578664@override_settings (
579665 CELERY_TASK_ALWAYS_EAGER = True ,
@@ -791,8 +877,10 @@ def test_deb_backports_lower_priority_no_update(self):
791877
792878 self .assertEqual (host .updates .count (), 0 )
793879
794- def test_deb_backports_equal_priority_shows_update (self ):
795- """DEB: backports kernel with equal priority SHOULD be flagged."""
880+ def test_deb_backports_equal_priority_no_update (self ):
881+ """DEB: backports kernel with equal priority but different series
882+ should NOT be flagged — series filtering prevents cross-track updates.
883+ """
796884 host = self ._create_host (main_priority = 500 , bp_priority = 500 )
797885 repo_packages = Package .objects .filter (
798886 mirror__in = [self .main_mirror , self .bp_mirror ]
@@ -803,10 +891,10 @@ def test_deb_backports_equal_priority_shows_update(self):
803891
804892 host .find_kernel_updates (kernel_packages , repo_packages )
805893
806- self .assertEqual (host .updates .count (), 1 )
894+ self .assertEqual (host .updates .count (), 0 )
807895
808- def test_deb_priority_zero_no_filtering (self ):
809- """DEB: priority 0 (unset) means no filtering — backward compat ."""
896+ def test_deb_priority_zero_no_cross_series_update (self ):
897+ """DEB: priority 0 (unset) still respects series filtering ."""
810898 host = self ._create_host (main_priority = 0 , bp_priority = 0 )
811899 repo_packages = Package .objects .filter (
812900 mirror__in = [self .main_mirror , self .bp_mirror ]
@@ -817,10 +905,10 @@ def test_deb_priority_zero_no_filtering(self):
817905
818906 host .find_kernel_updates (kernel_packages , repo_packages )
819907
820- self .assertEqual (host .updates .count (), 1 )
908+ self .assertEqual (host .updates .count (), 0 )
821909
822- def test_deb_host_repos_only_false_no_filtering (self ):
823- """DEB: host_repos_only=False skips priority filtering entirely ."""
910+ def test_deb_host_repos_only_false_no_cross_series_update (self ):
911+ """DEB: host_repos_only=False still respects series filtering ."""
824912 host = self ._create_host (
825913 main_priority = 500 , bp_priority = 100 , host_repos_only = False ,
826914 )
@@ -833,7 +921,7 @@ def test_deb_host_repos_only_false_no_filtering(self):
833921
834922 host .find_kernel_updates (kernel_packages , repo_packages )
835923
836- self .assertEqual (host .updates .count (), 1 )
924+ self .assertEqual (host .updates .count (), 0 )
837925
838926 def test_rpm_backports_lower_priority_no_update (self ):
839927 """RPM: kernel from lower-priority repo should NOT be flagged."""
0 commit comments