1# Copyright © 2019-2020 Intel Corporation 2 3# Permission is hereby granted, free of charge, to any person obtaining a copy 4# of this software and associated documentation files (the "Software"), to deal 5# in the Software without restriction, including without limitation the rights 6# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7# copies of the Software, and to permit persons to whom the Software is 8# furnished to do so, subject to the following conditions: 9 10# The above copyright notice and this permission notice shall be included in 11# all copies or substantial portions of the Software. 12 13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19# SOFTWARE. 20 21"""Tests for pick's core data structures and routines.""" 22 23from unittest import mock 24import textwrap 25import typing 26 27import attr 28import pytest 29 30from . import core 31 32 33class TestCommit: 34 35 @pytest.fixture 36 def unnominated_commit(self) -> 'core.Commit': 37 return core.Commit('abc123', 'sub: A commit', main_sha='45678') 38 39 @pytest.fixture 40 def nominated_commit(self) -> 'core.Commit': 41 return core.Commit('abc123', 'sub: A commit', True, 42 core.NominationType.CC, core.Resolution.UNRESOLVED) 43 44 class TestToJson: 45 46 def test_not_nominated(self, unnominated_commit: 'core.Commit'): 47 c = unnominated_commit 48 v = c.to_json() 49 assert v == {'sha': 'abc123', 'description': 'sub: A commit', 'nominated': False, 50 'nomination_type': None, 'resolution': core.Resolution.UNRESOLVED.value, 51 'main_sha': '45678', 'because_sha': None} 52 53 def test_nominated(self, nominated_commit: 'core.Commit'): 54 c = nominated_commit 55 v = c.to_json() 56 assert v == {'sha': 'abc123', 57 'description': 'sub: A commit', 58 'nominated': True, 59 'nomination_type': core.NominationType.CC.value, 60 'resolution': core.Resolution.UNRESOLVED.value, 61 'main_sha': None, 62 'because_sha': None} 63 64 class TestFromJson: 65 66 def test_not_nominated(self, unnominated_commit: 'core.Commit'): 67 c = unnominated_commit 68 v = c.to_json() 69 c2 = core.Commit.from_json(v) 70 assert c == c2 71 72 def test_nominated(self, nominated_commit: 'core.Commit'): 73 c = nominated_commit 74 v = c.to_json() 75 c2 = core.Commit.from_json(v) 76 assert c == c2 77 78 79class TestRE: 80 81 """Tests for the regular expressions used to identify commits.""" 82 83 class TestFixes: 84 85 def test_simple(self): 86 message = textwrap.dedent("""\ 87 etnaviv: fix vertex buffer state emission for single stream GPUs 88 89 GPUs with a single supported vertex stream must use the single state 90 address to program the stream. 91 92 Fixes: 3d09bb390a39 (etnaviv: GC7000: State changes for HALTI3..5) 93 Signed-off-by: Lucas Stach <l.stach@pengutronix.de> 94 Reviewed-by: Jonathan Marek <jonathan@marek.ca> 95 """) 96 97 m = core.IS_FIX.search(message) 98 assert m is not None 99 assert m.group(1) == '3d09bb390a39' 100 101 class TestCC: 102 103 def test_single_branch(self): 104 """Tests commit meant for a single branch, ie, 19.1""" 105 message = textwrap.dedent("""\ 106 radv: fix DCC fast clear code for intensity formats 107 108 This fixes a rendering issue with DiRT 4 on GFX10. Only GFX10 was 109 affected because intensity formats are different. 110 111 Cc: 19.2 <mesa-stable@lists.freedesktop.org> 112 Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/1923 113 Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> 114 Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl> 115 """) 116 117 m = core.IS_CC.search(message) 118 assert m is not None 119 assert m.group(1) == '19.2' 120 121 def test_multiple_branches(self): 122 """Tests commit with more than one branch specified""" 123 message = textwrap.dedent("""\ 124 radeonsi: enable zerovram for Rocket League 125 126 Fixes corruption on game startup. 127 Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/1888 128 129 Cc: 19.1 19.2 <mesa-stable@lists.freedesktop.org> 130 Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com> 131 """) 132 133 m = core.IS_CC.search(message) 134 assert m is not None 135 assert m.group(1) == '19.1' 136 assert m.group(2) == '19.2' 137 138 def test_no_branch(self): 139 """Tests commit with no branch specification""" 140 message = textwrap.dedent("""\ 141 anv/android: fix images created with external format support 142 143 This fixes a case where user first creates image and then later binds it 144 with memory created from AHW buffer. 145 146 Cc: <mesa-stable@lists.freedesktop.org> 147 Signed-off-by: Tapani Pälli <tapani.palli@intel.com> 148 Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> 149 """) 150 151 m = core.IS_CC.search(message) 152 assert m is not None 153 154 def test_quotes(self): 155 """Tests commit with quotes around the versions""" 156 message = textwrap.dedent("""\ 157 anv: Always fill out the AUX table even if CCS is disabled 158 159 Cc: "20.0" mesa-stable@lists.freedesktop.org 160 Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> 161 Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454> 162 Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454> 163 """) 164 165 m = core.IS_CC.search(message) 166 assert m is not None 167 assert m.group(1) == '20.0' 168 169 def test_multiple_quotes(self): 170 """Tests commit with quotes around the versions""" 171 message = textwrap.dedent("""\ 172 anv: Always fill out the AUX table even if CCS is disabled 173 174 Cc: "20.0" "20.1" mesa-stable@lists.freedesktop.org 175 Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> 176 Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454> 177 Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454> 178 """) 179 180 m = core.IS_CC.search(message) 181 assert m is not None 182 assert m.group(1) == '20.0' 183 assert m.group(2) == '20.1' 184 185 def test_single_quotes(self): 186 """Tests commit with quotes around the versions""" 187 message = textwrap.dedent("""\ 188 anv: Always fill out the AUX table even if CCS is disabled 189 190 Cc: '20.0' mesa-stable@lists.freedesktop.org 191 Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> 192 Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454> 193 Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454> 194 """) 195 196 m = core.IS_CC.search(message) 197 assert m is not None 198 assert m.group(1) == '20.0' 199 200 def test_multiple_single_quotes(self): 201 """Tests commit with quotes around the versions""" 202 message = textwrap.dedent("""\ 203 anv: Always fill out the AUX table even if CCS is disabled 204 205 Cc: '20.0' '20.1' mesa-stable@lists.freedesktop.org 206 Reviewed-by: Kenneth Graunke <kenneth@whitecape.org> 207 Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454> 208 Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454> 209 """) 210 211 m = core.IS_CC.search(message) 212 assert m is not None 213 assert m.group(1) == '20.0' 214 assert m.group(2) == '20.1' 215 216 class TestRevert: 217 218 def test_simple(self): 219 message = textwrap.dedent("""\ 220 Revert "radv: do not emit PKT3_CONTEXT_CONTROL with AMDGPU 3.6.0+" 221 222 This reverts commit 2ca8629fa9b303e24783b76a7b3b0c2513e32fbd. 223 224 This was initially ported from RadeonSI, but in the meantime it has 225 been reverted because it might hang. Be conservative and re-introduce 226 this packet emission. 227 228 Unfortunately this doesn't fix anything known. 229 230 Cc: 19.2 <mesa-stable@lists.freedesktop.org> 231 Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com> 232 Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl> 233 """) 234 235 m = core.IS_REVERT.search(message) 236 assert m is not None 237 assert m.group(1) == '2ca8629fa9b303e24783b76a7b3b0c2513e32fbd' 238 239 240class TestResolveNomination: 241 242 @attr.s(slots=True) 243 class FakeSubprocess: 244 245 """A fake asyncio.subprocess like classe for use with mock.""" 246 247 out: typing.Optional[bytes] = attr.ib(None) 248 returncode: int = attr.ib(0) 249 250 async def mock(self, *_, **__): 251 """A dirtly little helper for mocking.""" 252 return self 253 254 async def communicate(self) -> typing.Tuple[bytes, bytes]: 255 assert self.out is not None 256 return self.out, b'' 257 258 async def wait(self) -> int: 259 return self.returncode 260 261 @staticmethod 262 async def return_true(*_, **__) -> bool: 263 return True 264 265 @staticmethod 266 async def return_false(*_, **__) -> bool: 267 return False 268 269 @pytest.mark.asyncio 270 async def test_fix_is_nominated(self): 271 s = self.FakeSubprocess(b'Fixes: 3d09bb390a39 (etnaviv: GC7000: State changes for HALTI3..5)') 272 c = core.Commit('abcdef1234567890', 'a commit') 273 274 with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): 275 with mock.patch('bin.pick.core.is_commit_in_branch', self.return_true): 276 await core.resolve_nomination(c, '') 277 278 assert c.nominated 279 assert c.nomination_type is core.NominationType.FIXES 280 281 @pytest.mark.asyncio 282 async def test_fix_is_not_nominated(self): 283 s = self.FakeSubprocess(b'Fixes: 3d09bb390a39 (etnaviv: GC7000: State changes for HALTI3..5)') 284 c = core.Commit('abcdef1234567890', 'a commit') 285 286 with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): 287 with mock.patch('bin.pick.core.is_commit_in_branch', self.return_false): 288 await core.resolve_nomination(c, '') 289 290 assert not c.nominated 291 assert c.nomination_type is core.NominationType.FIXES 292 293 @pytest.mark.asyncio 294 async def test_cc_is_nominated(self): 295 s = self.FakeSubprocess(b'Cc: 16.2 <mesa-stable@lists.freedesktop.org>') 296 c = core.Commit('abcdef1234567890', 'a commit') 297 298 with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): 299 await core.resolve_nomination(c, '16.2') 300 301 assert c.nominated 302 assert c.nomination_type is core.NominationType.CC 303 304 @pytest.mark.asyncio 305 async def test_cc_is_nominated2(self): 306 s = self.FakeSubprocess(b'Cc: mesa-stable@lists.freedesktop.org') 307 c = core.Commit('abcdef1234567890', 'a commit') 308 309 with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): 310 await core.resolve_nomination(c, '16.2') 311 312 assert c.nominated 313 assert c.nomination_type is core.NominationType.CC 314 315 @pytest.mark.asyncio 316 async def test_cc_is_not_nominated(self): 317 s = self.FakeSubprocess(b'Cc: 16.2 <mesa-stable@lists.freedesktop.org>') 318 c = core.Commit('abcdef1234567890', 'a commit') 319 320 with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): 321 await core.resolve_nomination(c, '16.1') 322 323 assert not c.nominated 324 assert c.nomination_type is None 325 326 @pytest.mark.asyncio 327 async def test_revert_is_nominated(self): 328 s = self.FakeSubprocess(b'This reverts commit 1234567890123456789012345678901234567890.') 329 c = core.Commit('abcdef1234567890', 'a commit') 330 331 with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): 332 with mock.patch('bin.pick.core.is_commit_in_branch', self.return_true): 333 await core.resolve_nomination(c, '') 334 335 assert c.nominated 336 assert c.nomination_type is core.NominationType.REVERT 337 338 @pytest.mark.asyncio 339 async def test_revert_is_not_nominated(self): 340 s = self.FakeSubprocess(b'This reverts commit 1234567890123456789012345678901234567890.') 341 c = core.Commit('abcdef1234567890', 'a commit') 342 343 with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): 344 with mock.patch('bin.pick.core.is_commit_in_branch', self.return_false): 345 await core.resolve_nomination(c, '') 346 347 assert not c.nominated 348 assert c.nomination_type is core.NominationType.REVERT 349 350 @pytest.mark.asyncio 351 async def test_is_fix_and_cc(self): 352 s = self.FakeSubprocess( 353 b'Fixes: 3d09bb390a39 (etnaviv: GC7000: State changes for HALTI3..5)\n' 354 b'Cc: 16.1 <mesa-stable@lists.freedesktop.org>' 355 ) 356 c = core.Commit('abcdef1234567890', 'a commit') 357 358 with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): 359 with mock.patch('bin.pick.core.is_commit_in_branch', self.return_true): 360 await core.resolve_nomination(c, '16.1') 361 362 assert c.nominated 363 assert c.nomination_type is core.NominationType.FIXES 364 365 @pytest.mark.asyncio 366 async def test_is_fix_and_revert(self): 367 s = self.FakeSubprocess( 368 b'Fixes: 3d09bb390a39 (etnaviv: GC7000: State changes for HALTI3..5)\n' 369 b'This reverts commit 1234567890123456789012345678901234567890.' 370 ) 371 c = core.Commit('abcdef1234567890', 'a commit') 372 373 with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): 374 with mock.patch('bin.pick.core.is_commit_in_branch', self.return_true): 375 await core.resolve_nomination(c, '16.1') 376 377 assert c.nominated 378 assert c.nomination_type is core.NominationType.FIXES 379 380 @pytest.mark.asyncio 381 async def test_is_cc_and_revert(self): 382 s = self.FakeSubprocess( 383 b'This reverts commit 1234567890123456789012345678901234567890.\n' 384 b'Cc: 16.1 <mesa-stable@lists.freedesktop.org>' 385 ) 386 c = core.Commit('abcdef1234567890', 'a commit') 387 388 with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): 389 with mock.patch('bin.pick.core.is_commit_in_branch', self.return_true): 390 await core.resolve_nomination(c, '16.1') 391 392 assert c.nominated 393 assert c.nomination_type is core.NominationType.CC 394 395 396class TestResolveFixes: 397 398 @pytest.mark.asyncio 399 async def test_in_new(self): 400 """Because commit abcd is nominated, so f123 should be as well.""" 401 c = [ 402 core.Commit('f123', 'desc', nomination_type=core.NominationType.FIXES, because_sha='abcd'), 403 core.Commit('abcd', 'desc', True), 404 ] 405 await core.resolve_fixes(c, []) 406 assert c[1].nominated 407 408 @pytest.mark.asyncio 409 async def test_not_in_new(self): 410 """Because commit abcd is not nominated, commit f123 shouldn't be either.""" 411 c = [ 412 core.Commit('f123', 'desc', nomination_type=core.NominationType.FIXES, because_sha='abcd'), 413 core.Commit('abcd', 'desc'), 414 ] 415 await core.resolve_fixes(c, []) 416 assert not c[0].nominated 417 418 @pytest.mark.asyncio 419 async def test_in_previous(self): 420 """Because commit abcd is nominated, so f123 should be as well.""" 421 p = [ 422 core.Commit('abcd', 'desc', True), 423 ] 424 c = [ 425 core.Commit('f123', 'desc', nomination_type=core.NominationType.FIXES, because_sha='abcd'), 426 ] 427 await core.resolve_fixes(c, p) 428 assert c[0].nominated 429 430 @pytest.mark.asyncio 431 async def test_not_in_previous(self): 432 """Because commit abcd is not nominated, commit f123 shouldn't be either.""" 433 p = [ 434 core.Commit('abcd', 'desc'), 435 ] 436 c = [ 437 core.Commit('f123', 'desc', nomination_type=core.NominationType.FIXES, because_sha='abcd'), 438 ] 439 await core.resolve_fixes(c, p) 440 assert not c[0].nominated 441 442 443class TestIsCommitInBranch: 444 445 @pytest.mark.asyncio 446 async def test_no(self): 447 # Hopefully this is never true? 448 value = await core.is_commit_in_branch('ffffffffffffffffffffffffffffff') 449 assert not value 450 451 @pytest.mark.asyncio 452 async def test_yes(self): 453 # This commit is from 2000, it better always be in the branch 454 value = await core.is_commit_in_branch('88f3b89a2cb77766d2009b9868c44e03abe2dbb2') 455 assert value 456 457 458class TestFullSha: 459 460 @pytest.mark.asyncio 461 async def test_basic(self): 462 # This commit is from 2000, it better always be in the branch 463 value = await core.full_sha('88f3b89a2cb777') 464 assert value 465 466 @pytest.mark.asyncio 467 async def test_invalid(self): 468 # This commit is from 2000, it better always be in the branch 469 with pytest.raises(core.PickUIException): 470 await core.full_sha('fffffffffffffffffffffffffffffffffff') 471