471 lines
18 KiB
Python
471 lines
18 KiB
Python
|
# 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', master_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,
|
||
|
'master_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,
|
||
|
'master_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 <l.stach@pengutronix.de>
|
||
|
Reviewed-by: Jonathan Marek <jonathan@marek.ca>
|
||
|
""")
|
||
|
|
||
|
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 <mesa-stable@lists.freedesktop.org>
|
||
|
Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/1923
|
||
|
Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
|
||
|
Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
|
||
|
""")
|
||
|
|
||
|
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 <mesa-stable@lists.freedesktop.org>
|
||
|
Reviewed-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com>
|
||
|
""")
|
||
|
|
||
|
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: <mesa-stable@lists.freedesktop.org>
|
||
|
Signed-off-by: Tapani Pälli <tapani.palli@intel.com>
|
||
|
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
|
||
|
""")
|
||
|
|
||
|
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 <kenneth@whitecape.org>
|
||
|
Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454>
|
||
|
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454>
|
||
|
""")
|
||
|
|
||
|
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 <kenneth@whitecape.org>
|
||
|
Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454>
|
||
|
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454>
|
||
|
""")
|
||
|
|
||
|
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 <kenneth@whitecape.org>
|
||
|
Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454>
|
||
|
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454>
|
||
|
""")
|
||
|
|
||
|
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 <kenneth@whitecape.org>
|
||
|
Tested-by: Marge Bot <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454>
|
||
|
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/3454>
|
||
|
""")
|
||
|
|
||
|
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 <mesa-stable@lists.freedesktop.org>
|
||
|
Signed-off-by: Samuel Pitoiset <samuel.pitoiset@gmail.com>
|
||
|
Reviewed-by: Bas Nieuwenhuizen <bas@basnieuwenhuizen.nl>
|
||
|
""")
|
||
|
|
||
|
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 <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_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 <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.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 <mesa-stable@lists.freedesktop.org>'
|
||
|
)
|
||
|
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 <mesa-stable@lists.freedesktop.org>'
|
||
|
)
|
||
|
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')
|