Skip to content

Commit 85a32c6

Browse files
Hook25bladernr
authored andcommitted
Dmi resource sane_product to avoid in duplication (bugfix) (#2046)
* Add sane_product key * Move all hardcoded consts to new sane_product * Test sane_product translator * Also test the unknown
1 parent bbc4103 commit 85a32c6

File tree

8 files changed

+109
-20
lines changed

8 files changed

+109
-20
lines changed

providers/base/units/audio/jobs.pxu

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ estimated_duration: 30.0
564564
imports: from com.canonical.plainbox import manifest
565565
requires:
566566
manifest.has_line_out == 'True'
567-
dmi.product in ['Desktop','Low Profile Desktop','Tower','Mini Tower','Space-saving','All In One','All-In-One','AIO']
567+
dmi.sane_product == "non-portable"
568568
_purpose:
569569
Check that external line out connection works correctly
570570
_steps:
@@ -585,7 +585,7 @@ estimated_duration: 120.0
585585
imports: from com.canonical.plainbox import manifest
586586
requires:
587587
manifest.has_line_in == 'True'
588-
dmi.product in ['Desktop','Low Profile Desktop','Tower','Mini Tower','Space-saving','All In One','All-In-One','AIO']
588+
dmi.sane_product == "non-portable"
589589
manifest.has_audio_playback == 'True'
590590
package.name == 'alsa-base'
591591
package.name == 'gstreamer1.0-plugins-good' or package.name == 'gstreamer0.10-plugins-good'

providers/base/units/graphics/jobs.pxu

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ id: graphics/{index}_auto_glxgears_{product_slug}
306306
flags: also-after-suspend
307307
requires:
308308
executable.name == 'glxgears'
309-
dmi.product in ['Notebook','Laptop','Portable','All In One','All-In-One','AIO','Convertible', 'Tablet', 'Detachable']
309+
dmi.sane_product == "portable"
310310
user: root
311311
command:
312312
# shellcheck disable=SC1091
@@ -327,7 +327,7 @@ id: graphics/{index}_valid_glxgears_{product_slug}
327327
flags: also-after-suspend
328328
requires:
329329
executable.name == 'glxgears'
330-
dmi.product in ['Notebook','Laptop','Portable','All In One','All-In-One','AIO','Convertible', 'Tablet', 'Detachable']
330+
dmi.sane_product == "portable"
331331
user: root
332332
command:
333333
# shellcheck disable=SC1091
@@ -356,7 +356,7 @@ id: graphics/{index}_auto_glxgears_fullscreen_{product_slug}
356356
flags: also-after-suspend
357357
requires:
358358
executable.name == 'glxgears'
359-
dmi.product in ['Notebook','Laptop','Portable','All In One','All-In-One','AIO','Convertible','Tablet', 'Detachable']
359+
dmi.sane_product == "portable"
360360
user: root
361361
command:
362362
# shellcheck disable=SC1091
@@ -377,7 +377,7 @@ id: graphics/{index}_valid_glxgears_fullscreen_{product_slug}
377377
flags: also-after-suspend
378378
requires:
379379
executable.name == 'glxgears'
380-
dmi.product in ['Notebook','Laptop','Portable','All In One','All-In-One','AIO','Convertible','Tablet', 'Detachable']
380+
dmi.sane_product == "portable"
381381
user: root
382382
command:
383383
# shellcheck disable=SC1091
@@ -405,7 +405,7 @@ flags: also-after-suspend
405405
user: root
406406
requires:
407407
executable.name == 'glxgears'
408-
dmi.product in ['Desktop','Low Profile Desktop','Tower','Mini Tower','Space-saving', 'Mini PC']
408+
dmi.sane_product == "non-portable"
409409
command:
410410
prime_offload_tester.py -c glxgears -t 30
411411
summary:
@@ -420,7 +420,7 @@ flags: also-after-suspend
420420
user: root
421421
requires:
422422
executable.name == 'glxgears'
423-
dmi.product in ['Desktop','Low Profile Desktop','Tower','Mini Tower','Space-saving', 'Mini PC']
423+
dmi.sane_product == "non-portable"
424424
command:
425425
prime_offload_tester.py -c "glxgears -fullscreen" -t 30
426426
summary:
@@ -435,7 +435,7 @@ flags: also-after-suspend
435435
user: root
436436
requires:
437437
executable.name == 'glxgears'
438-
dmi.product in ['Desktop','Low Profile Desktop','Tower','Mini Tower','Space-saving', 'Mini PC']
438+
dmi.sane_product == "non-portable"
439439
command:
440440
prime_offload_tester.py -c glxgears -t 30
441441
summary:
@@ -456,7 +456,7 @@ flags: also-after-suspend
456456
user: root
457457
requires:
458458
executable.name == 'glxgears'
459-
dmi.product in ['Desktop','Low Profile Desktop','Tower','Mini Tower','Space-saving', 'Mini PC']
459+
dmi.sane_product == "non-portable"
460460
command:
461461
prime_offload_tester.py -c "glxgears -fullscreen" -t 30
462462
summary:
@@ -673,7 +673,7 @@ plugin: shell
673673
category_id: com.canonical.plainbox::graphics
674674
id: graphics/nvlink-status-check
675675
requires:
676-
dmi.product in ['Desktop','Low Profile Desktop','Tower','Mini Tower', 'Space-saving']
676+
dmi.sane_product == "non-portable"
677677
graphics_card.driver == 'nvidia'
678678
command: nvidia_nvlink_check.sh
679679
_summary: Check NVIDIA NVLINK status

providers/base/units/monitor/jobs.pxu

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ template-resource: graphics_card
128128
template-filter: graphics_card.prime_gpu_offload == 'Off'
129129
id: monitor/{index}_multi-head_{product_slug}
130130
template-id: monitor/index_multi-head_product_slug
131-
requires: dmi.product in ['Desktop','Low Profile Desktop','Tower','Mini Tower', 'Space-saving', 'Mini PC']
131+
requires: dmi.sane_product == "non-portable"
132132
flags: also-after-suspend
133133
plugin: manual
134134
category_id: com.canonical.plainbox::monitor
@@ -146,7 +146,7 @@ _summary:
146146
Verify multi-monitor output functionality on desktop systems.
147147

148148
id: monitor/multi-head
149-
requires: dmi.product in ['Desktop','Low Profile Desktop','Tower','Mini Tower', 'Space-saving', 'Mini PC']
149+
requires: dmi.sane_product == "non-portable"
150150
flags: also-after-suspend
151151
plugin: manual
152152
category_id: com.canonical.plainbox::monitor
@@ -187,7 +187,7 @@ template-resource: graphics_card
187187
template-filter: graphics_card.prime_gpu_offload == 'Off'
188188
id: monitor/{index}_dim_brightness_{product_slug}
189189
template-id: monitor/index_dim_brightness_product_slug
190-
requires: dmi.product in ['Notebook','Laptop','Portable','All In One','All-In-One','AIO','Convertible', 'Tablet', 'Detachable']
190+
requires: dmi.sane_product == "portable"
191191
plugin: user-interact-verify
192192
category_id: com.canonical.plainbox::monitor
193193
user: root

providers/base/units/power-management/jobs.pxu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ category_id: com.canonical.plainbox::power-management
545545
id: power-management/light_sensor
546546
estimated_duration: 10.0
547547
requires:
548-
dmi.product in ['Notebook','Laptop','Portable','Convertible', 'Tablet', 'Detachable']
548+
dmi.sane_product == "portable"
549549
executable.name == 'monitor-sensor'
550550
flags: also-after-suspend
551551
command: light_sensor_test.sh

providers/base/units/stress/jobs.pxu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ plugin: manual
592592
category_id: com.canonical.plainbox::stress
593593
id: stress/wireless_hotkey
594594
estimated_duration: 60.0
595-
requires: dmi.product in ['Notebook','Laptop','Portable']
595+
requires: dmi.sane_product == "portable"
596596
_purpose:
597597
To make sure that stressing the wifi hotkey does not cause applets to disappear from the panel or the system to lock up
598598
_steps:

providers/base/units/suspend/suspend.pxu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,7 @@ category_id: com.canonical.plainbox::suspend
15311531
id: touchpad/touchpad_after_suspend
15321532
depends: suspend/suspend_advanced_auto
15331533
requires:
1534-
dmi.product in ['Notebook','Laptop','Portable']
1534+
dmi.sane_product == "portable"
15351535
xinput.device_class == 'XITouchClass' and xinput.touch_mode != 'dependent'
15361536
command: true
15371537
estimated_duration: 1.2

providers/resource/bin/dmi_resource.py

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22
#
33
# This file is part of Checkbox.
44
#
5-
# Copyright 2011 Canonical Ltd.
5+
# Copyright 2011-2025 Canonical Ltd.
66
#
77
# Checkbox is free software: you can redistribute it and/or modify
88
# it under the terms of the GNU General Public License version 3,
99
# as published by the Free Software Foundation.
10-
1110
#
1211
# Checkbox is distributed in the hope that it will be useful,
1312
# but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -27,6 +26,38 @@
2726
COMMAND = "dmidecode"
2827

2928

29+
def sane_product(og_product: str) -> str:
30+
"""
31+
Transform the product key into a usable form
32+
33+
The product key is basically free-form text. In order to make it more
34+
usable in resource expressions, which usually want to know if a device is
35+
portable (a laptop/tablet) or not, this cleans up the key to a "canonical"
36+
answer, either `non-portable` or `portable`
37+
"""
38+
cleaned = og_product.lower().replace(" ", "-")
39+
if cleaned in [
40+
"desktop",
41+
"low-profile-desktop",
42+
"tower",
43+
"mini-tower",
44+
"space-saving",
45+
"all-in-one",
46+
"aio",
47+
]:
48+
return "not-portable"
49+
elif cleaned in [
50+
"notebook",
51+
"laptop",
52+
"portable",
53+
"convertible",
54+
"tablet",
55+
"detachable",
56+
]:
57+
return "portable"
58+
return "unknown"
59+
60+
3061
class DmiResult:
3162

3263
attributes = (
@@ -45,7 +76,9 @@ def addDmiDevice(self, device):
4576
for attribute in self.attributes:
4677
value = getattr(device, attribute, None)
4778
if value is not None:
48-
print("%s: %s" % (attribute, value))
79+
print("{}: {}".format(attribute, value))
80+
if attribute == "product" and value:
81+
print("{}: {}".format("sane_product", sane_product(value)))
4982

5083
print()
5184

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/usr/bin/env python3
2+
# This file is part of Checkbox.
3+
#
4+
# Copyright 2025 Canonical Ltd.
5+
# Written by:
6+
# Massimiliano Girardi <[email protected]>
7+
#
8+
# Checkbox is free software: you can redistribute it and/or modify
9+
# it under the terms of the GNU General Public License version 3,
10+
# as published by the Free Software Foundation.
11+
#
12+
# Checkbox is distributed in the hope that it will be useful,
13+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
# GNU General Public License for more details.
16+
#
17+
# You should have received a copy of the GNU General Public License
18+
# along with Checkbox. If not, see <http://www.gnu.org/licenses/>.
19+
20+
import unittest
21+
from unittest import TestCase
22+
from unittest.mock import MagicMock
23+
24+
import dmi_resource
25+
26+
27+
class TestDmiResource(TestCase):
28+
def test_sane_product_portable(self):
29+
products = [
30+
"Notebook",
31+
"Laptop",
32+
"Portable",
33+
"Convertible",
34+
"Tablet",
35+
"Detachable",
36+
]
37+
category = set(map(dmi_resource.sane_product, products))
38+
self.assertEqual(category, {"portable"})
39+
40+
def test_sane_product_non_portable(self):
41+
products = [
42+
"Desktop",
43+
"Low Profile Desktop",
44+
"Tower",
45+
"Mini-Tower",
46+
"Space Saving",
47+
"All-in-One",
48+
"aio",
49+
]
50+
category = set(map(dmi_resource.sane_product, products))
51+
self.assertEqual(category, {"not-portable"})
52+
53+
def test_sane_product_unknown(self):
54+
products = ["strange-iot-product"]
55+
category = set(map(dmi_resource.sane_product, products))
56+
self.assertEqual(category, {"unknown"})

0 commit comments

Comments
 (0)