# Copyright © 2019-2020 Intel Corporation # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """Tests for pick's core data structures and routines.""" from unittest import mock import textwrap import typing import attr import pytest from . import core class TestCommit: @pytest.fixture def unnominated_commit(self) -> 'core.Commit': return core.Commit('abc123', 'sub: A commit', main_sha='45678') @pytest.fixture def nominated_commit(self) -> 'core.Commit': return core.Commit('abc123', 'sub: A commit', True, core.NominationType.CC, core.Resolution.UNRESOLVED) class TestToJson: def test_not_nominated(self, unnominated_commit: 'core.Commit'): c = unnominated_commit v = c.to_json() assert v == {'sha': 'abc123', 'description': 'sub: A commit', 'nominated': False, 'nomination_type': None, 'resolution': core.Resolution.UNRESOLVED.value, 'main_sha': '45678', 'because_sha': None} def test_nominated(self, nominated_commit: 'core.Commit'): c = nominated_commit v = c.to_json() assert v == {'sha': 'abc123', 'description': 'sub: A commit', 'nominated': True, 'nomination_type': core.NominationType.CC.value, 'resolution': core.Resolution.UNRESOLVED.value, 'main_sha': None, 'because_sha': None} class TestFromJson: def test_not_nominated(self, unnominated_commit: 'core.Commit'): c = unnominated_commit v = c.to_json() c2 = core.Commit.from_json(v) assert c == c2 def test_nominated(self, nominated_commit: 'core.Commit'): c = nominated_commit v = c.to_json() c2 = core.Commit.from_json(v) assert c == c2 class TestRE: """Tests for the regular expressions used to identify commits.""" class TestFixes: def test_simple(self): message = textwrap.dedent("""\ etnaviv: fix vertex buffer state emission for single stream GPUs GPUs with a single supported vertex stream must use the single state address to program the stream. Fixes: 3d09bb390a39 (etnaviv: GC7000: State changes for HALTI3..5) Signed-off-by: Lucas Stach Reviewed-by: Jonathan Marek """) m = core.IS_FIX.search(message) assert m is not None assert m.group(1) == '3d09bb390a39' class TestCC: def test_single_branch(self): """Tests commit meant for a single branch, ie, 19.1""" message = textwrap.dedent("""\ radv: fix DCC fast clear code for intensity formats This fixes a rendering issue with DiRT 4 on GFX10. Only GFX10 was affected because intensity formats are different. Cc: 19.2 Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/1923 Signed-off-by: Samuel Pitoiset Reviewed-by: Bas Nieuwenhuizen """) m = core.IS_CC.search(message) assert m is not None assert m.group(1) == '19.2' def test_multiple_branches(self): """Tests commit with more than one branch specified""" message = textwrap.dedent("""\ radeonsi: enable zerovram for Rocket League Fixes corruption on game startup. Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/1888 Cc: 19.1 19.2 Reviewed-by: Pierre-Eric Pelloux-Prayer """) m = core.IS_CC.search(message) assert m is not None assert m.group(1) == '19.1' assert m.group(2) == '19.2' def test_no_branch(self): """Tests commit with no branch specification""" message = textwrap.dedent("""\ anv/android: fix images created with external format support This fixes a case where user first creates image and then later binds it with memory created from AHW buffer. Cc: Signed-off-by: Tapani Pälli Reviewed-by: Lionel Landwerlin """) m = core.IS_CC.search(message) assert m is not None def test_quotes(self): """Tests commit with quotes around the versions""" message = textwrap.dedent("""\ anv: Always fill out the AUX table even if CCS is disabled Cc: "20.0" mesa-stable@lists.freedesktop.org Reviewed-by: Kenneth Graunke Tested-by: Marge Bot Part-of: """) m = core.IS_CC.search(message) assert m is not None assert m.group(1) == '20.0' def test_multiple_quotes(self): """Tests commit with quotes around the versions""" message = textwrap.dedent("""\ anv: Always fill out the AUX table even if CCS is disabled Cc: "20.0" "20.1" mesa-stable@lists.freedesktop.org Reviewed-by: Kenneth Graunke Tested-by: Marge Bot Part-of: """) m = core.IS_CC.search(message) assert m is not None assert m.group(1) == '20.0' assert m.group(2) == '20.1' def test_single_quotes(self): """Tests commit with quotes around the versions""" message = textwrap.dedent("""\ anv: Always fill out the AUX table even if CCS is disabled Cc: '20.0' mesa-stable@lists.freedesktop.org Reviewed-by: Kenneth Graunke Tested-by: Marge Bot Part-of: """) m = core.IS_CC.search(message) assert m is not None assert m.group(1) == '20.0' def test_multiple_single_quotes(self): """Tests commit with quotes around the versions""" message = textwrap.dedent("""\ anv: Always fill out the AUX table even if CCS is disabled Cc: '20.0' '20.1' mesa-stable@lists.freedesktop.org Reviewed-by: Kenneth Graunke Tested-by: Marge Bot Part-of: """) m = core.IS_CC.search(message) assert m is not None assert m.group(1) == '20.0' assert m.group(2) == '20.1' class TestRevert: def test_simple(self): message = textwrap.dedent("""\ Revert "radv: do not emit PKT3_CONTEXT_CONTROL with AMDGPU 3.6.0+" This reverts commit 2ca8629fa9b303e24783b76a7b3b0c2513e32fbd. This was initially ported from RadeonSI, but in the meantime it has been reverted because it might hang. Be conservative and re-introduce this packet emission. Unfortunately this doesn't fix anything known. Cc: 19.2 Signed-off-by: Samuel Pitoiset Reviewed-by: Bas Nieuwenhuizen """) m = core.IS_REVERT.search(message) assert m is not None assert m.group(1) == '2ca8629fa9b303e24783b76a7b3b0c2513e32fbd' class TestResolveNomination: @attr.s(slots=True) class FakeSubprocess: """A fake asyncio.subprocess like classe for use with mock.""" out: typing.Optional[bytes] = attr.ib(None) returncode: int = attr.ib(0) async def mock(self, *_, **__): """A dirtly little helper for mocking.""" return self async def communicate(self) -> typing.Tuple[bytes, bytes]: assert self.out is not None return self.out, b'' async def wait(self) -> int: return self.returncode @staticmethod async def return_true(*_, **__) -> bool: return True @staticmethod async def return_false(*_, **__) -> bool: return False @pytest.mark.asyncio async def test_fix_is_nominated(self): s = self.FakeSubprocess(b'Fixes: 3d09bb390a39 (etnaviv: GC7000: State changes for HALTI3..5)') c = core.Commit('abcdef1234567890', 'a commit') with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): with mock.patch('bin.pick.core.is_commit_in_branch', self.return_true): await core.resolve_nomination(c, '') assert c.nominated assert c.nomination_type is core.NominationType.FIXES @pytest.mark.asyncio async def test_fix_is_not_nominated(self): s = self.FakeSubprocess(b'Fixes: 3d09bb390a39 (etnaviv: GC7000: State changes for HALTI3..5)') c = core.Commit('abcdef1234567890', 'a commit') with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): with mock.patch('bin.pick.core.is_commit_in_branch', self.return_false): await core.resolve_nomination(c, '') assert not c.nominated assert c.nomination_type is core.NominationType.FIXES @pytest.mark.asyncio async def test_cc_is_nominated(self): s = self.FakeSubprocess(b'Cc: 16.2 ') c = core.Commit('abcdef1234567890', 'a commit') with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): await core.resolve_nomination(c, '16.2') assert c.nominated assert c.nomination_type is core.NominationType.CC @pytest.mark.asyncio async def test_cc_is_nominated2(self): s = self.FakeSubprocess(b'Cc: mesa-stable@lists.freedesktop.org') c = core.Commit('abcdef1234567890', 'a commit') with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): await core.resolve_nomination(c, '16.2') assert c.nominated assert c.nomination_type is core.NominationType.CC @pytest.mark.asyncio async def test_cc_is_not_nominated(self): s = self.FakeSubprocess(b'Cc: 16.2 ') c = core.Commit('abcdef1234567890', 'a commit') with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): await core.resolve_nomination(c, '16.1') assert not c.nominated assert c.nomination_type is None @pytest.mark.asyncio async def test_revert_is_nominated(self): s = self.FakeSubprocess(b'This reverts commit 1234567890123456789012345678901234567890.') c = core.Commit('abcdef1234567890', 'a commit') with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): with mock.patch('bin.pick.core.is_commit_in_branch', self.return_true): await core.resolve_nomination(c, '') assert c.nominated assert c.nomination_type is core.NominationType.REVERT @pytest.mark.asyncio async def test_revert_is_not_nominated(self): s = self.FakeSubprocess(b'This reverts commit 1234567890123456789012345678901234567890.') c = core.Commit('abcdef1234567890', 'a commit') with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): with mock.patch('bin.pick.core.is_commit_in_branch', self.return_false): await core.resolve_nomination(c, '') assert not c.nominated assert c.nomination_type is core.NominationType.REVERT @pytest.mark.asyncio async def test_is_fix_and_cc(self): s = self.FakeSubprocess( b'Fixes: 3d09bb390a39 (etnaviv: GC7000: State changes for HALTI3..5)\n' b'Cc: 16.1 ' ) c = core.Commit('abcdef1234567890', 'a commit') with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): with mock.patch('bin.pick.core.is_commit_in_branch', self.return_true): await core.resolve_nomination(c, '16.1') assert c.nominated assert c.nomination_type is core.NominationType.FIXES @pytest.mark.asyncio async def test_is_fix_and_revert(self): s = self.FakeSubprocess( b'Fixes: 3d09bb390a39 (etnaviv: GC7000: State changes for HALTI3..5)\n' b'This reverts commit 1234567890123456789012345678901234567890.' ) c = core.Commit('abcdef1234567890', 'a commit') with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): with mock.patch('bin.pick.core.is_commit_in_branch', self.return_true): await core.resolve_nomination(c, '16.1') assert c.nominated assert c.nomination_type is core.NominationType.FIXES @pytest.mark.asyncio async def test_is_cc_and_revert(self): s = self.FakeSubprocess( b'This reverts commit 1234567890123456789012345678901234567890.\n' b'Cc: 16.1 ' ) c = core.Commit('abcdef1234567890', 'a commit') with mock.patch('bin.pick.core.asyncio.create_subprocess_exec', s.mock): with mock.patch('bin.pick.core.is_commit_in_branch', self.return_true): await core.resolve_nomination(c, '16.1') assert c.nominated assert c.nomination_type is core.NominationType.CC class TestResolveFixes: @pytest.mark.asyncio async def test_in_new(self): """Because commit abcd is nominated, so f123 should be as well.""" c = [ core.Commit('f123', 'desc', nomination_type=core.NominationType.FIXES, because_sha='abcd'), core.Commit('abcd', 'desc', True), ] await core.resolve_fixes(c, []) assert c[1].nominated @pytest.mark.asyncio async def test_not_in_new(self): """Because commit abcd is not nominated, commit f123 shouldn't be either.""" c = [ core.Commit('f123', 'desc', nomination_type=core.NominationType.FIXES, because_sha='abcd'), core.Commit('abcd', 'desc'), ] await core.resolve_fixes(c, []) assert not c[0].nominated @pytest.mark.asyncio async def test_in_previous(self): """Because commit abcd is nominated, so f123 should be as well.""" p = [ core.Commit('abcd', 'desc', True), ] c = [ core.Commit('f123', 'desc', nomination_type=core.NominationType.FIXES, because_sha='abcd'), ] await core.resolve_fixes(c, p) assert c[0].nominated @pytest.mark.asyncio async def test_not_in_previous(self): """Because commit abcd is not nominated, commit f123 shouldn't be either.""" p = [ core.Commit('abcd', 'desc'), ] c = [ core.Commit('f123', 'desc', nomination_type=core.NominationType.FIXES, because_sha='abcd'), ] await core.resolve_fixes(c, p) assert not c[0].nominated class TestIsCommitInBranch: @pytest.mark.asyncio async def test_no(self): # Hopefully this is never true? value = await core.is_commit_in_branch('ffffffffffffffffffffffffffffff') assert not value @pytest.mark.asyncio async def test_yes(self): # This commit is from 2000, it better always be in the branch value = await core.is_commit_in_branch('88f3b89a2cb77766d2009b9868c44e03abe2dbb2') assert value class TestFullSha: @pytest.mark.asyncio async def test_basic(self): # This commit is from 2000, it better always be in the branch value = await core.full_sha('88f3b89a2cb777') assert value @pytest.mark.asyncio async def test_invalid(self): # This commit is from 2000, it better always be in the branch with pytest.raises(core.PickUIException): await core.full_sha('fffffffffffffffffffffffffffffffffff')