From f9ce25f15fed48397456e47c29122cf9a43075f2 Mon Sep 17 00:00:00 2001 From: Dan Bungert Date: Thu, 16 Feb 2023 18:31:31 -0700 Subject: [PATCH] tests: patch parameterized to handle async parameterized async tests run into cpython bug gh-101486 We use parameterized.expand, which works by creating new functions and inserting those into the list of tests. It's a wonder this worked at all before for the async tests. Update the function generation to create a coroutine function, if appropriate. LP: #2007554 --- .../common/filesystem/tests/test_gaps.py | 2 +- .../filesystem/tests/test_manipulator.py | 2 +- subiquity/models/tests/test_filesystem.py | 3 +- subiquity/models/tests/test_keyboard.py | 2 +- .../controllers/tests/test_filesystem.py | 2 +- .../server/controllers/tests/test_kernel.py | 2 +- .../server/controllers/tests/test_keyboard.py | 2 +- subiquitycore/tests/parameterized.py | 75 +++++++++++++++++++ subiquitycore/tests/test_async_helpers.py | 4 +- 9 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 subiquitycore/tests/parameterized.py diff --git a/subiquity/common/filesystem/tests/test_gaps.py b/subiquity/common/filesystem/tests/test_gaps.py index b6dac5dd..0db2bbf4 100644 --- a/subiquity/common/filesystem/tests/test_gaps.py +++ b/subiquity/common/filesystem/tests/test_gaps.py @@ -17,7 +17,7 @@ from functools import partial import unittest from unittest import mock -from parameterized import parameterized +from subiquitycore.tests.parameterized import parameterized from subiquity.models.filesystem import ( Disk, diff --git a/subiquity/common/filesystem/tests/test_manipulator.py b/subiquity/common/filesystem/tests/test_manipulator.py index e84b122c..bf810eb4 100644 --- a/subiquity/common/filesystem/tests/test_manipulator.py +++ b/subiquity/common/filesystem/tests/test_manipulator.py @@ -19,7 +19,7 @@ from unittest import mock import attr -from parameterized import parameterized +from subiquitycore.tests.parameterized import parameterized from subiquity.common.filesystem.actions import ( DeviceAction, diff --git a/subiquity/models/tests/test_filesystem.py b/subiquity/models/tests/test_filesystem.py index 6278ec5e..2f4bab5a 100644 --- a/subiquity/models/tests/test_filesystem.py +++ b/subiquity/models/tests/test_filesystem.py @@ -17,7 +17,8 @@ import unittest from unittest import mock import attr -from parameterized import parameterized + +from subiquitycore.tests.parameterized import parameterized from subiquity.models.filesystem import ( ActionRenderMode, diff --git a/subiquity/models/tests/test_keyboard.py b/subiquity/models/tests/test_keyboard.py index f39bedb6..f1d482fb 100644 --- a/subiquity/models/tests/test_keyboard.py +++ b/subiquity/models/tests/test_keyboard.py @@ -13,7 +13,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . -from parameterized import parameterized +from subiquitycore.tests.parameterized import parameterized from subiquitycore.tests import SubiTestCase diff --git a/subiquity/server/controllers/tests/test_filesystem.py b/subiquity/server/controllers/tests/test_filesystem.py index c23bb11b..e8a2aabf 100644 --- a/subiquity/server/controllers/tests/test_filesystem.py +++ b/subiquity/server/controllers/tests/test_filesystem.py @@ -17,7 +17,7 @@ import copy from unittest import mock, TestCase, IsolatedAsyncioTestCase import uuid -from parameterized import parameterized +from subiquitycore.tests.parameterized import parameterized from subiquitycore.snapd import AsyncSnapd, get_fake_connection from subiquitycore.tests.mocks import make_app diff --git a/subiquity/server/controllers/tests/test_kernel.py b/subiquity/server/controllers/tests/test_kernel.py index b7ed22e0..fee277bc 100644 --- a/subiquity/server/controllers/tests/test_kernel.py +++ b/subiquity/server/controllers/tests/test_kernel.py @@ -16,7 +16,7 @@ import os import os.path -from parameterized import parameterized +from subiquitycore.tests.parameterized import parameterized from subiquity.models.kernel import KernelModel from subiquity.server.controllers.kernel import KernelController diff --git a/subiquity/server/controllers/tests/test_keyboard.py b/subiquity/server/controllers/tests/test_keyboard.py index 80df6dca..c751701f 100644 --- a/subiquity/server/controllers/tests/test_keyboard.py +++ b/subiquity/server/controllers/tests/test_keyboard.py @@ -17,10 +17,10 @@ import os import unittest from unittest.mock import Mock, patch -from parameterized import parameterized from subiquitycore.tests import SubiTestCase from subiquitycore.tests.mocks import make_app +from subiquitycore.tests.parameterized import parameterized from subiquity.models.keyboard import ( KeyboardModel, diff --git a/subiquitycore/tests/parameterized.py b/subiquitycore/tests/parameterized.py new file mode 100644 index 00000000..d7258b27 --- /dev/null +++ b/subiquitycore/tests/parameterized.py @@ -0,0 +1,75 @@ +# Portions Copyright 2023 Canonical, Ltd. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +# This is adapted from +# https://github.com/wolever/parameterized/commit/0403e891d9a6ec5fa77c0e200f31e1298fcacbc9 # noqa +# +# Copyright 2010 David Wolever . All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY DAVID WOLEVER ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +# EVENT SHALL DAVID WOLEVER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and documentation are +# those of the authors and should not be interpreted as representing official +# policies, either expressed or implied, of David Wolever. + +import inspect +from functools import wraps + +from parameterized import parameterized as _parameterized + + +# parameterized.expand uses param_as_standalone_func to create the expanded +# test functions. When the function being expanded is a coroutine function, +# the expanded one should be as well. LP: #2007554 +class parameterized(_parameterized): + @classmethod + def param_as_standalone_func(cls, p, func, name): + if inspect.iscoroutinefunction(func): + @wraps(func) + async def standalone_func(*a): + return await func(*(a + p.args), **p.kwargs) + else: + @wraps(func) + def standalone_func(*a): + return func(*(a + p.args), **p.kwargs) + + standalone_func.__name__ = name + + standalone_func.place_as = func + + try: + del standalone_func.__wrapped__ + except AttributeError: + pass + return standalone_func diff --git a/subiquitycore/tests/test_async_helpers.py b/subiquitycore/tests/test_async_helpers.py index 0dca6b24..5680be65 100644 --- a/subiquitycore/tests/test_async_helpers.py +++ b/subiquitycore/tests/test_async_helpers.py @@ -17,13 +17,13 @@ import asyncio import unittest from unittest.mock import AsyncMock -from parameterized import parameterized - from subiquitycore.async_helpers import ( SingleInstanceTask, TaskAlreadyRunningError, ) +from subiquitycore.tests.parameterized import parameterized + class TestSingleInstanceTask(unittest.IsolatedAsyncioTestCase): @parameterized.expand([(True, 2), (False, 1)])