Skip to content

feat(software): device lists sort and filter, type, installedBy and a real up-to-date status CU-17tkuw61fh5 - #2909

Merged
andrii-flamingo merged 4 commits into
mainfrom
feat/software-lists-api
Nov 2, 2026
Merged

andrii-flamingo merged 4 commits into
mainfrom
feat/software-lists-api

fix(software): CU-17tkuw61fh5 an organization without a name no longe…

daab8f7
Select commit
Loading
Failed to load commit list.
Flamingo / Flamingo Code Review / tests and mutation completed Oct 30, 2026 in 0s

Tests and mutation: every lane passed, 2 uncaught mutants on added lines, 1 gap

🧪 Tests and mutation

Tests per lane

Language Project Command Status Counts Time
Java (Maven) . mvn -B test -pl openframe-api-lib,openframe-api-service-core -am ✅ passed openframe-agent-key 4 · openframe-api-lib 603 · openframe-api-service-core 747 (42 skipped) · openframe-core 150 · openframe-core-crypto 8 · openframe-data-cassandra 20 · openframe-data-kafka 19 · openframe-data-loki 96 · openframe-data-mongo-sync 463 (196 skipped) · openframe-data-nats 152 (4 skipped) · openframe-data-pinot 69 · openframe-exception 4 · openframe-graphql-node 76 · openframe-graphql-relay 69 · openframe-machine-delivery 134 · openframe-notification-core 98 (22 skipped) · openframe-notification-mail 4 · openframe-presence 12 · openframe-security-core 38 · fleetmdm 51 · 0 failures 170 s

Java: 2817 тестів, 0 падінь, 264 пропущено.

Мутації на нових рядках: 60 з 62 вбито, 1 вижив (еквівалентний), 1 без покриття.

Знахідки цього етапу автор переглянув і вирішив поки лишити.

Mutation testing

This build has no PIT plugin, so each module is mutated from the command line with pit-adhoc.sh, changing nothing in the repository.

Module Classes Whole classes New lines only Time
lib FleetSoftwareMapper, SoftwareFilters, SoftwareInventoryService, SoftwareVersions 310 mutants, 245 killed (79%), 39 survived, 26 no coverage, test strength 86%, line coverage 90% 62 mutants: 60 killed, 1 survived, 1 no coverage 53 s
service-core SoftwareDataFetcher 24 mutants, 0 killed (0%), 24 no coverage, line coverage 0% none on added lines 12 s

New code, its covering tests and the result

New code Covering tests Result
lambda$listVulnerabilitiesForSoftware$3 in SoftwareInventoryService, line 351 SoftwareInventoryServiceTest (3), 2 more killed
lambda$listDevicesForSoftware$0 in SoftwareInventoryService, line 365 SoftwareInventoryServiceTest (3), 6 more killed
listDevicesForSoftware in SoftwareInventoryService, line 368 SoftwareInventoryServiceTest (3), 7 more killed
devicesWithAutoUpdate in SoftwareInventoryService, lines 374-375 SoftwareInventoryServiceTest (3), 11 more killed
deviceOrder in SoftwareInventoryService, lines 379-388 SoftwareInventoryServiceTest (3), 8 more killed
taggedMachines in SoftwareInventoryService, lines 393-400 SoftwareInventoryServiceTest (3), 7 more killed
lambda$taggedMachines$0 in SoftwareInventoryService, line 396 SoftwareInventoryServiceTest (1) killed
matchesDeviceFilter in SoftwareInventoryService, lines 408-417 SoftwareInventoryServiceTest (3), 6 more killed
selected in SoftwareInventoryService, line 422 SoftwareInventoryServiceTest (3), 4 more killed
listSoftwareForDevice in SoftwareInventoryService, lines 432-439 SoftwareInventoryServiceTest (3), 9 more killed
lambda$listSoftwareForDevice$0 in SoftwareInventoryService, line 434 SoftwareInventoryServiceTest (3), 7 more killed
getDeviceSoftwareFilters in SoftwareInventoryService, line 445 SoftwareInventoryServiceTest (3), 1 more killed
getSoftwareDeviceFilters in SoftwareInventoryService, line 552 SoftwareInventoryServiceTest (3), 2 more killed
lambda$getSoftwareDeviceFilters$0 in SoftwareInventoryService, line 556 SoftwareInventoryServiceTest (3), 2 more killed
lambda$organizationFacet$0 in SoftwareInventoryService, line 563 SoftwareInventoryServiceTest (3), 2 more killed
organizationFacet in SoftwareInventoryService, lines 566-572 SoftwareInventoryServiceTest (3), 2 more killed
lambda$organizationFacet$1 in SoftwareInventoryService, line 570 SoftwareInventoryServiceTest (2) killed
lambda$organizationFacet$2 in SoftwareInventoryService, line 571 none no coverage (line 571)
lambda$allDevicesForSoftware$1 in SoftwareInventoryService, line 609 SoftwareInventoryServiceTest (3), 10 more killed
installedBy in SoftwareInventoryService, line 633 SoftwareInventoryServiceTest (3), 10 more killed
latestVersion in FleetSoftwareMapper, line 37 FleetSoftwareMapperTest (2), SoftwareInventoryServiceTest (1), 20 more killed
compare in SoftwareVersions, lines 17-24 SoftwareVersionsTest (2), FleetSoftwareMapperTest (1), 9 more 8 killed. Survived: line 17: changed conditional boundary
parseSegment in SoftwareVersions, line 30 SoftwareVersionsTest (1), FleetSoftwareMapperTest (1), SoftwareInventoryServiceTest (1), 9 more killed
The covering tests by name (22 methods)
  • SoftwareInventoryService.lambda$listVulnerabilitiesForSoftware$3: SoftwareInventoryServiceTest.listVulnerabilitiesForSoftware_nullEnrichment_noNpe, SoftwareInventoryServiceTest.listVulnerabilitiesForSoftware_dedupsByCve, SoftwareInventoryServiceTest.listVulnerabilitiesForSoftware_severitiesFilter, and 2 more
  • SoftwareInventoryService.lambda$listDevicesForSoftware$0: SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, SoftwareInventoryServiceTest.listDevices_installedBy, SoftwareInventoryServiceTest.listDevices_statusFilter, and 6 more
  • SoftwareInventoryService.listDevicesForSoftware: SoftwareInventoryServiceTest.listDevices_nonNumericId_emptyNoFleet, SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, SoftwareInventoryServiceTest.listDevices_installedBy, and 7 more
  • SoftwareInventoryService.devicesWithAutoUpdate: SoftwareInventoryServiceTest.listDevices_autoUpdateFilter_beforeThePage, SoftwareInventoryServiceTest.softwareDeviceFilters_allFacets, SoftwareInventoryServiceTest.listDevices_filters, and 11 more
  • SoftwareInventoryService.deviceOrder: SoftwareInventoryServiceTest.listDevices_unknownSortField_rejectedBeforeFleet, SoftwareInventoryServiceTest.listDevices_nonNumericId_emptyNoFleet, SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, and 8 more
  • SoftwareInventoryService.taggedMachines: SoftwareInventoryServiceTest.listDevices_nonNumericId_emptyNoFleet, SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, SoftwareInventoryServiceTest.listDevices_installedBy, and 7 more
  • SoftwareInventoryService.lambda$taggedMachines$0: SoftwareInventoryServiceTest.listDevices_filters
  • SoftwareInventoryService.matchesDeviceFilter: SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, SoftwareInventoryServiceTest.listDevices_installedBy, SoftwareInventoryServiceTest.listDevices_statusFilter, and 6 more
  • SoftwareInventoryService.selected: SoftwareInventoryServiceTest.listVulnerabilitiesForSoftware_severitiesFilter, SoftwareInventoryServiceTest.listSoftwareForDevice_sourcesFilter_keepsMatchingTitlesOnly, SoftwareInventoryServiceTest.listSoftwareForDevice_minSeverityHigh_titlesBelowBandExcluded, and 4 more
  • SoftwareInventoryService.listSoftwareForDevice: SoftwareInventoryServiceTest.listSoftwareForDevice_autoUpdateFilterAndFacet, SoftwareInventoryServiceTest.listSoftwareForDevice_emptyInventory_emptyPageWithoutCatalogOrCountLookups, SoftwareInventoryServiceTest.listSoftwareForDevice_titleWithoutCves_summaryIsNull, and 9 more
  • SoftwareInventoryService.lambda$listSoftwareForDevice$0: SoftwareInventoryServiceTest.listSoftwareForDevice_titleWithoutCves_summaryIsNull, SoftwareInventoryServiceTest.listSoftwareForDevice_defaultOrder_byNameCaseInsensitive, SoftwareInventoryServiceTest.listSoftwareForDevice_pageRequested_everyFilteredRowCountedFromHostSoftwareNotPerRow, and 7 more
  • SoftwareInventoryService.getDeviceSoftwareFilters: SoftwareInventoryServiceTest.listSoftwareForDevice_autoUpdateFilterAndFacet, SoftwareInventoryServiceTest.getDeviceSoftwareFilters_emptyInventory_emptyFacets, SoftwareInventoryServiceTest.getDeviceSoftwareFilters_searchApplied_onlyMatchingTitlesCounted, and 1 more
  • SoftwareInventoryService.getSoftwareDeviceFilters: SoftwareInventoryServiceTest.softwareDeviceFilters_noOrganizationOnAnyDevice_noLookup, SoftwareInventoryServiceTest.softwareDeviceFilters_facetsByStatus, SoftwareInventoryServiceTest.softwareDeviceFilters_organizationWithoutName_labelledByItsId, and 2 more
  • SoftwareInventoryService.lambda$getSoftwareDeviceFilters$0: SoftwareInventoryServiceTest.softwareDeviceFilters_allFacets, SoftwareInventoryServiceTest.softwareDeviceFilters_noOrganizationOnAnyDevice_noLookup, SoftwareInventoryServiceTest.softwareDeviceFilters_facetsByStatus, and 2 more
  • SoftwareInventoryService.lambda$organizationFacet$0: SoftwareInventoryServiceTest.softwareDeviceFilters_noOrganizationOnAnyDevice_noLookup, SoftwareInventoryServiceTest.softwareDeviceFilters_facetsByStatus, SoftwareInventoryServiceTest.softwareDeviceFilters_organizationWithoutName_labelledByItsId, and 2 more
  • SoftwareInventoryService.organizationFacet: SoftwareInventoryServiceTest.softwareDeviceFilters_noOrganizationOnAnyDevice_noLookup, SoftwareInventoryServiceTest.softwareDeviceFilters_organizationWithoutName_labelledByItsId, SoftwareInventoryServiceTest.softwareDeviceFilters_allFacets, and 2 more
  • SoftwareInventoryService.lambda$organizationFacet$1: SoftwareInventoryServiceTest.softwareDeviceFilters_organizationWithoutName_labelledByItsId, SoftwareInventoryServiceTest.softwareDeviceFilters_allFacets
  • SoftwareInventoryService.lambda$allDevicesForSoftware$1: SoftwareInventoryServiceTest.listDevices_correlatesAndDropsUnenrolled, SoftwareInventoryServiceTest.listDevices_installedBy, SoftwareInventoryServiceTest.listDevices_statusFilter, and 10 more
  • SoftwareInventoryService.installedBy: SoftwareInventoryServiceTest.listDevices_installedBy, SoftwareInventoryServiceTest.softwareDeviceFilters_facetsByStatus, SoftwareInventoryServiceTest.softwareDeviceFilters_allFacets, and 10 more
  • FleetSoftwareMapper.latestVersion: FleetSoftwareMapperTest.toResponse_noVersions_noLatest, FleetSoftwareMapperTest.toResponse_latestVersionIsTheHighest_inNumericOrder, SoftwareInventoryServiceTest.listDevices_statusAgainstTheHighestVersion, and 20 more
  • SoftwareVersions.compare: SoftwareVersionsTest.sameVersion_isEqual, SoftwareVersionsTest.lowerComesFirst, FleetSoftwareMapperTest.toResponse_latestVersionIsTheHighest_inNumericOrder, and 9 more
  • SoftwareVersions.parseSegment: SoftwareVersionsTest.lowerComesFirst, FleetSoftwareMapperTest.toResponse_latestVersionIsTheHighest_inNumericOrder, SoftwareInventoryServiceTest.listVulnerabilitiesForSoftware_dedupsByCve, and 9 more

What the surviving mutations leave unverified

  • SoftwareVersions.java:17: Мутант межі циклу ( на =) вижив, але він еквівалентний: на зайвій ітерації обидва сегменти дорівнюють 0, результат не змінюється. Ризику немає.
  • SoftwareInventoryService.java:571: Merge-функція (a, b) - a не виконується в тестах. organizationId має унікальний індекс, тому дублікатів не очікується і ризик малий.
  • SoftwareDataFetcher.java:71-93: SoftwareDataFetcher не покритий тестами (0 з 24 мутантів): перехід softwareDevices на SortInput і softwareVulnerabilities на SoftwareVulnerabilityFilterInput не перевірений GraphQL-запитом, лише компіляцією. Такий самий SortInput вже працює в softwareVulnerabilities, але десеріалізацію нового input-типу варто перевірити на dev.

2 mutants on lines this change added are not caught (1 survived, 1 with no test reaching them): each is annotated on its line in the Flamingo Code Review / tests and mutation check.

1 gap (not tested here):

  • Java (Maven) .: SoftwareFilterInput.java, SoftwareOnDeviceFilterInput.java, SoftwareOnDeviceFilters.java, SoftwareOnDeviceResponse.java, SoftwareVulnerabilityFilterInput.java changed but not mutation-tested (outside the mutation targets openframe-api-lib configures)

Annotations

Check warning on line 25 in openframe-api-lib/src/main/java/com/openframe/api/util/SoftwareVersions.java

See this annotation in the file changed.

@flamingo flamingo / Flamingo Code Review / tests and mutation

SoftwareVersions.compare ставить передреліз вище за реліз і помиляється на суфіксах

Перевірено запуском на форматах із тестів Fleet: 3.14.0rc1 вважається новішою за 3.14.0, 2.23.0_9 новішою за 2.23.0_13, 5.4.0-99.118 новішою за 5.4.0-105.1, а версії з префіксом (v1.2, EAP GO-243.21565.42) нижчими за 1.0. Числа після _ і - та нечислові префікси не порівнюються, нічия вирішується порівнянням рядків.

Risk: Цей результат тепер визначає latestVersion і status у softwareDevices: пристрій зі справді новою версією може показати OUTDATED, а зі старішою UP_TO_DATE. Даних це не псує, але в UI буде неправильний статус. Тести містять вигадані значення 1.2.3-beta і 20240101123456.0 і не покривають жоден із цих випадків.

Fix: Розбирати версію на числа й слова за роздільниками . _ - + пробіл і кома, передрелізні слова (a, b, rc, alpha, beta, dev, pre, eap) ставити нижче за реліз, у тест додати реальні формати.

Check notice on line 634 in openframe-api-lib/src/main/java/com/openframe/api/service/rmm/software/SoftwareInventoryService.java

See this annotation in the file changed.

@flamingo flamingo / Flamingo Code Review / tests and mutation

installedBy ніколи не повертає UNMANAGED, хоча схема це обіцяє

Для застосунків без пакетного менеджера installedBy дорівнює null. Схема описує UNMANAGED як Manually, а опис adoptSoftware пропонує filter {installedBy: [UNMANAGED]}. Такий фільтр зараз завжди дає порожній список, а поле source того ж застосунку повертає UNMANAGED.

Risk: Рішення свідоме і пояснене в коментарі, але схема розходиться з кодом. Коли зʼявиться Adopt, його вибір пристроїв не знайде жодного пристрою, поки read model не заповнить поле.

Fix: Оновити опис у схемі або врахувати це в гілці read model.

Check notice on line 19 in openframe-api-lib/src/main/java/com/openframe/api/dto/rmm/software/SoftwareFilterInput.java

See this annotation in the file changed.

@flamingo flamingo / Flamingo Code Review / tests and mutation

softwares ігнорує нове поле filter.autoUpdateStatuses

Поле читає лише deviceSoftware. Запит softwares передає в listSoftware лише vulnerable, тому фільтр за auto-update мовчки повертає весь список, хоча опис Software.autoUpdate називає його доступним.

Risk: Фасет у softwareFilters порожній, тож UI цей фільтр не запропонує. Клієнт, що передасть його напряму, отримає нефільтрований список без помилки. Те саме вже стосується sources і deviceTagIds.

Fix: Реалізувати в гілці read model (#2651).

Check notice on line 571 in openframe-api-lib/src/main/java/com/openframe/api/service/rmm/software/SoftwareInventoryService.java

See this annotation in the file changed.

@flamingo flamingo / Flamingo Code Review / tests and mutation

No test reaches this line: EmptyObjectReturnValsMutator

replaced return value with "" for com/openframe/api/service/rmm/software/SoftwareInventoryService::lambda$organizationFacet$2 (in lambda$organizationFacet$2). No test runs this line.

Check warning on line 17 in openframe-api-lib/src/main/java/com/openframe/api/util/SoftwareVersions.java

See this annotation in the file changed.

@flamingo flamingo / Flamingo Code Review / tests and mutation

Mutant survived: ConditionalsBoundaryMutator

changed conditional boundary (in compare). A test runs this line, but none fails when it changes.