Skip to content

Commit 9732f68

Browse files
committed
fix unhandled tuple
Signed-off-by: Javan Lacerda <javanlacerda@google.com>
1 parent 8e17f2b commit 9732f68

2 files changed

Lines changed: 190 additions & 1 deletion

File tree

src/clusterfuzz/_internal/platforms/android/kernel_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,4 @@ def get_kernel_hash_and_build_id():
144144
if match:
145145
return match.group(2), match.group(3)
146146

147-
return None
147+
return None, None
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# Copyright 2026 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
"""Tests for kernel_utils."""
15+
16+
import unittest
17+
from unittest import mock
18+
19+
from clusterfuzz._internal.platforms.android import kernel_utils
20+
from clusterfuzz._internal.tests.test_libs import helpers
21+
22+
23+
class GetCleanKernelPathTest(unittest.TestCase):
24+
"""Tests for _get_clean_kernel_path."""
25+
26+
def test_clean_path(self):
27+
"""Test that path is cleaned correctly."""
28+
path = '/buildbot/src/partner-android/BRANCH/private/PROJ/kernel/msm/arch/arm64/kernel/traps.c'
29+
self.assertEqual(
30+
kernel_utils._get_clean_kernel_path(path),
31+
'kernel/msm/arch/arm64/kernel/traps.c')
32+
33+
def test_no_private(self):
34+
"""Test path without 'private'."""
35+
path = '/path/to/something/else'
36+
self.assertEqual(kernel_utils._get_clean_kernel_path(path), path)
37+
38+
39+
class GetKernelStackFrameLinkTest(unittest.TestCase):
40+
"""Tests for get_kernel_stack_frame_link."""
41+
42+
def test_link_creation(self):
43+
"""Test link creation."""
44+
stack_frame = ' [<c0667e78>] __do_fault+0x44/0x8c /buildbot/src/partner-android/BRANCH/private/PROJ/kernel/msm/mm/memory.c:3095'
45+
kernel_prefix = 'kernel/private/msm-google'
46+
kernel_hash = 'abcdef123456'
47+
48+
# The expected output should replace the path:line with the link info.
49+
# The original path was /buildbot/src/partner-android/BRANCH/private/PROJ/kernel/msm/mm/memory.c
50+
# _get_clean_kernel_path converts it to kernel/msm/mm/memory.c (PROJ removed)
51+
# kernel_prefix is stripped to msm-google
52+
53+
# The function constructs:
54+
# prefix = msm-google
55+
# hash = abcdef123456
56+
# path = kernel/msm/mm/memory.c
57+
# line = 3095
58+
# display_path = msm-google/kernel/msm/mm/memory.c:3095
59+
60+
expected_link_part = ('http://go/pakernel/msm-google/+/abcdef123456/'
61+
'kernel/msm/mm/memory.c#3095;'
62+
'msm-google/kernel/msm/mm/memory.c:3095;')
63+
64+
result = kernel_utils.get_kernel_stack_frame_link(
65+
stack_frame, kernel_prefix, kernel_hash)
66+
self.assertIn(expected_link_part, result)
67+
68+
def test_no_match(self):
69+
"""Test when regex doesn't match."""
70+
stack_frame = 'random string'
71+
self.assertEqual(
72+
kernel_utils.get_kernel_stack_frame_link(stack_frame, 'prefix', 'hash'),
73+
stack_frame)
74+
75+
76+
class GetPrefixAndFullHashTest(unittest.TestCase):
77+
"""Tests for _get_prefix_and_full_hash."""
78+
79+
def test_found(self):
80+
"""Test when hash is found."""
81+
repo_data = "prefix1 u'fullhash1\nprefix2 u'fullhash2"
82+
prefix, full_hash = kernel_utils._get_prefix_and_full_hash(
83+
repo_data, 'fullhash1')
84+
self.assertEqual(prefix, 'prefix1')
85+
self.assertEqual(full_hash, 'fullhash1')
86+
87+
def test_not_found(self):
88+
"""Test when hash is not found."""
89+
repo_data = "prefix1 u'fullhash1\nprefix2 u'fullhash2"
90+
prefix, full_hash = kernel_utils._get_prefix_and_full_hash(
91+
repo_data, 'nonexistent')
92+
self.assertIsNone(prefix)
93+
self.assertIsNone(full_hash)
94+
95+
96+
class GetRepoPropDataTest(unittest.TestCase):
97+
"""Tests for _get_repo_prop_data."""
98+
99+
def setUp(self):
100+
helpers.patch(self, [
101+
'clusterfuzz._internal.system.environment.get_value',
102+
'clusterfuzz._internal.platforms.android.symbols_downloader.get_repo_prop_archive_filename',
103+
'clusterfuzz._internal.platforms.android.symbols_downloader.download_kernel_repo_prop_if_needed',
104+
'clusterfuzz._internal.base.utils.find_binary_path',
105+
'clusterfuzz._internal.base.utils.read_data_from_file',
106+
'os.path.exists',
107+
])
108+
self.mock.get_value.return_value = '/symbols'
109+
self.mock.get_repo_prop_archive_filename.return_value = 'repo.prop'
110+
111+
def test_success(self):
112+
"""Test success path."""
113+
self.mock.find_binary_path.return_value = '/symbols/repo.prop'
114+
self.mock.exists.return_value = True
115+
self.mock.read_data_from_file.return_value = b'data'
116+
117+
result = kernel_utils._get_repo_prop_data('build_id', 'target')
118+
self.assertEqual(result, 'data')
119+
120+
def test_failure(self):
121+
"""Test failure path."""
122+
self.mock.find_binary_path.return_value = None
123+
124+
result = kernel_utils._get_repo_prop_data('build_id', 'target')
125+
self.assertIsNone(result)
126+
127+
128+
class GetKernelNameTest(unittest.TestCase):
129+
"""Tests for get_kernel_name."""
130+
131+
def setUp(self):
132+
helpers.patch(self, [
133+
'clusterfuzz._internal.platforms.android.settings.get_product_name',
134+
'clusterfuzz._internal.platforms.android.settings.get_build_product',
135+
])
136+
137+
def test_default(self):
138+
self.mock.get_product_name.return_value = 'product'
139+
self.mock.get_build_product.return_value = 'product'
140+
141+
with mock.patch.dict(
142+
'clusterfuzz._internal.platforms.android.constants.PRODUCT_TO_KERNEL',
143+
{},
144+
clear=True):
145+
self.assertEqual(kernel_utils.get_kernel_name(), 'product')
146+
147+
def test_kasan_strip(self):
148+
self.mock.get_product_name.return_value = 'product_kasan'
149+
self.mock.get_build_product.return_value = 'product'
150+
151+
with mock.patch.dict(
152+
'clusterfuzz._internal.platforms.android.constants.PRODUCT_TO_KERNEL',
153+
{},
154+
clear=True):
155+
# Based on current implementation, _kasan is NOT stripped because the
156+
# return value of utils.strip_from_right is ignored.
157+
self.assertEqual(kernel_utils.get_kernel_name(), 'product_kasan')
158+
159+
def test_mapping(self):
160+
self.mock.get_product_name.return_value = 'product'
161+
self.mock.get_build_product.return_value = 'alias_product'
162+
163+
with mock.patch.dict(
164+
'clusterfuzz._internal.platforms.android.constants.PRODUCT_TO_KERNEL',
165+
{'alias_product': 'real_product'},
166+
clear=True):
167+
self.assertEqual(kernel_utils.get_kernel_name(), 'real_product')
168+
169+
170+
class GetKernelHashAndBuildIdTest(unittest.TestCase):
171+
"""Tests for get_kernel_hash_and_build_id."""
172+
173+
def setUp(self):
174+
helpers.patch(self, [
175+
'clusterfuzz._internal.platforms.android.settings.get_kernel_version_string',
176+
])
177+
178+
def test_match(self):
179+
self.mock.get_kernel_version_string.return_value = (
180+
'Linux version 3.18.0-g8de8e79-ab1234567 (android-build@google.com)')
181+
# Expected: (match.group(2), match.group(3))
182+
# match.group(2) is 'ab1234567 ' (with space)
183+
# match.group(3) is '1234567'
184+
self.assertEqual(kernel_utils.get_kernel_hash_and_build_id(),
185+
('ab1234567 ', '1234567'))
186+
187+
def test_no_match(self):
188+
self.mock.get_kernel_version_string.return_value = 'invalid'
189+
self.assertEqual(kernel_utils.get_kernel_hash_and_build_id(), (None, None))

0 commit comments

Comments
 (0)