This is an automated email from the ASF dual-hosted git repository. abukor pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/kudu.git
commit 08bd36a8745d20c5aa688f5c33a05615857d40e0 Author: Marton Greber <[email protected]> AuthorDate: Mon Mar 20 11:01:14 2023 +0000 [Python] Refactor tests to use assertRaisesRegex The Python unittest.TestCase class offers the assertRaises() and assertRaisesRegex() functions to test that an exception is raised when callable is called [1]. Currently assertRaises(exception) is used in the Python client tests, to assert the type of a given error. This patch refactors usages of assertRaises() to assertRaisesRegex(exception, regex) in order to assert the error message as well. In Python3.2 assertRaisesRegexp has been renamed to assertRaisesRegex (without the trailing 'p') [2]. To be able to use assertRaisesRegex throughout the Python codebase, a compatibility class called CompatUnitTest is added. [1] https://docs.python.org/3/library/unittest.html#unittest.TestCase [2] https://docs.python.org/3.9/library/unittest.html #unittest.TestCase.assertRaisesRegex Change-Id: I41e2d69996ee0ed0f0418ae184d95239f2739efb Reviewed-on: http://gerrit.cloudera.org:8080/19633 Tested-by: Kudu Jenkins Reviewed-by: Attila Bukor <[email protected]> --- python/kudu/compat.py | 12 +++++- python/kudu/tests/test_client.py | 58 +++++++++++++++++--------- python/kudu/tests/test_scanner.py | 1 - python/kudu/tests/test_scantoken.py | 1 - python/kudu/tests/test_schema.py | 83 +++++++++++++++++++++++++------------ python/kudu/tests/util.py | 4 +- 6 files changed, 108 insertions(+), 51 deletions(-) diff --git a/python/kudu/compat.py b/python/kudu/compat.py index c3343a6cb..6f8b415ce 100644 --- a/python/kudu/compat.py +++ b/python/kudu/compat.py @@ -18,7 +18,7 @@ # flake8: noqa import itertools - +import contextlib try: import numpy as np except ImportError: @@ -97,6 +97,16 @@ else: return list(o.items()) +if sys.version_info < (3, 1): + class CompatUnitTest(unittest.TestCase): + @contextlib.contextmanager + def assertRaisesRegex(self, expected_exception, expected_regex, *args, **kwargs): + with self.assertRaisesRegexp(expected_exception, expected_regex, *args, **kwargs): + yield +else: + class CompatUnitTest(unittest.TestCase): + pass + integer_types = six.integer_types if np is not None: integer_types += (np.integer,) diff --git a/python/kudu/tests/test_client.py b/python/kudu/tests/test_client.py index ce76a87d3..44d8e4a29 100755 --- a/python/kudu/tests/test_client.py +++ b/python/kudu/tests/test_client.py @@ -16,7 +16,7 @@ # specific language governing permissions and limitations # under the License. -from kudu.compat import unittest, long +from kudu.compat import CompatUnitTest, long from kudu.tests.common import KuduTestBase from kudu.client import (Partitioning, RangePartition, @@ -32,7 +32,7 @@ import datetime from pytz import utc -class TestClient(KuduTestBase, unittest.TestCase): +class TestClient(KuduTestBase, CompatUnitTest): def setUp(self): pass @@ -102,7 +102,8 @@ class TestClient(KuduTestBase, unittest.TestCase): assert not self.client.table_exists(name) # Should raise a more meaningful exception at some point - with self.assertRaises(kudu.KuduNotFound): + error_msg = 'the table does not exist: table_name: "{0}"'.format(name) + with self.assertRaisesRegex(kudu.KuduNotFound, error_msg): self.client.delete_table(name) def test_table_nonexistent(self): @@ -476,10 +477,12 @@ class TestClient(KuduTestBase, unittest.TestCase): # inserts. In this case, at the second position it would like to get an int64 (the type # of the auto-incrementing counter), therefore we get type error. (Specifying the # auto-incremeintg counter is obviously rejected from the server side) - with self.assertRaises(TypeError): + error_msg = 'an integer is required' + with self.assertRaisesRegex(TypeError, error_msg): op = table.new_insert((1,'text')) - with self.assertRaises(TypeError): + error_msg = 'an integer is required' + with self.assertRaisesRegex(TypeError, error_msg): op = table.new_insert([1,'text']) finally: @@ -534,8 +537,10 @@ class TestClient(KuduTestBase, unittest.TestCase): self.client.new_session(flush_mode='sync') self.client.new_session(flush_mode='background') - with self.assertRaises(ValueError): - self.client.new_session(flush_mode='foo') + flush_mode = 'foo' + error_msg = 'Invalid flush mode: {0}'.format(flush_mode) + with self.assertRaisesRegex(ValueError, error_msg): + self.client.new_session(flush_mode=flush_mode) def test_session_mutation_buffer_settings(self): self.client.new_session(flush_mode=kudu.FLUSH_AUTO_BACKGROUND, @@ -553,16 +558,20 @@ class TestClient(KuduTestBase, unittest.TestCase): def test_session_mutation_buffer_errors(self): session = self.client.new_session(flush_mode=kudu.FLUSH_AUTO_BACKGROUND) - with self.assertRaises(OverflowError): + error_msg = 'can\'t convert negative value to unsigned int' + with self.assertRaisesRegex(OverflowError, error_msg): session.set_mutation_buffer_max_num(-1) - with self.assertRaises(kudu.errors.KuduInvalidArgument): + error_msg = '120: watermark must be between 0 and 100 inclusive' + with self.assertRaisesRegex(kudu.errors.KuduInvalidArgument, error_msg): session.set_mutation_buffer_flush_watermark(1.2) - with self.assertRaises(OverflowError): + error_msg = 'can\'t convert negative value to unsigned int' + with self.assertRaisesRegex(OverflowError, error_msg): session.set_mutation_buffer_flush_interval(-1) - with self.assertRaises(OverflowError): + error_msg = 'can\'t convert negative value to size_t' + with self.assertRaisesRegex(OverflowError, error_msg): session.set_mutation_buffer_space(-1) def test_connect_timeouts(self): @@ -599,11 +608,13 @@ class TestClient(KuduTestBase, unittest.TestCase): op[key[0]] = 'test' # Test incorrectly typed data - with self.assertRaises(TypeError): + error_msg = 'an integer is required' + with self.assertRaisesRegex(TypeError, error_msg): op['int_val'] = 'incorrect' # Test setting NULL in a not-null column - with self.assertRaises(kudu.errors.KuduInvalidArgument): + error_msg = 'column not nullable: key' + with self.assertRaisesRegex(kudu.errors.KuduInvalidArgument, error_msg): op['key'] = None def test_alter_table_rename(self): @@ -821,22 +832,30 @@ class TestClient(KuduTestBase, unittest.TestCase): # negatives alterer = self.client.new_table_alterer(table) alterer.drop_column(col_name) - with self.assertRaises(KuduInvalidArgument): + error_msg = 'can\'t drop column: {0}'\ + .format(Schema.get_auto_incrementing_column_name()) + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): alterer.alter() alterer = self.client.new_table_alterer(table) alterer.add_column(col_name) - with self.assertRaises(KuduInvalidArgument): + error_msg = 'can\'t add a column with reserved name: {0}'\ + .format(Schema.get_auto_incrementing_column_name()) + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): alterer.alter() alterer = self.client.new_table_alterer(table) alterer.alter_column(col_name, "new_column_name") - with self.assertRaises(KuduInvalidArgument): + error_msg = 'can\'t change name for column: {0}'\ + .format(Schema.get_auto_incrementing_column_name()) + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): alterer.alter() alterer = self.client.new_table_alterer(table) alterer.alter_column(col_name).remove_default() - with self.assertRaises(KuduInvalidArgument): + error_msg = 'can\'t change remove default for column: {0}'\ + .format(Schema.get_auto_incrementing_column_name()) + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): alterer.alter() # positives @@ -869,11 +888,12 @@ class TestClient(KuduTestBase, unittest.TestCase): def test_require_authn(self): # Kerberos is not enabled on the cluster, so requiring # authentication is expected to fail. - with self.assertRaises(kudu.KuduBadStatus): + error_msg = 'client requires authentication, but server does not have Kerberos enabled' + with self.assertRaisesRegex(kudu.KuduBadStatus, error_msg): client = kudu.connect(self.master_hosts, self.master_ports, require_authentication=True) -class TestMonoDelta(unittest.TestCase): +class TestMonoDelta(CompatUnitTest): def test_empty_ctor(self): delta = kudu.TimeDelta() diff --git a/python/kudu/tests/test_scanner.py b/python/kudu/tests/test_scanner.py index fa406252d..c4d17839b 100644 --- a/python/kudu/tests/test_scanner.py +++ b/python/kudu/tests/test_scanner.py @@ -18,7 +18,6 @@ from __future__ import division -from kudu.compat import unittest from kudu.tests.util import TestScanBase from kudu.tests.common import KuduTestBase, TimeoutError import kudu diff --git a/python/kudu/tests/test_scantoken.py b/python/kudu/tests/test_scantoken.py index 9214adb98..c69b43a66 100644 --- a/python/kudu/tests/test_scantoken.py +++ b/python/kudu/tests/test_scantoken.py @@ -16,7 +16,6 @@ # specific language governing permissions and limitations # under the License. -from kudu.compat import unittest from kudu.tests.util import TestScanBase from kudu.tests.common import KuduTestBase import kudu diff --git a/python/kudu/tests/test_schema.py b/python/kudu/tests/test_schema.py index 069201f64..cbee07b1e 100644 --- a/python/kudu/tests/test_schema.py +++ b/python/kudu/tests/test_schema.py @@ -18,13 +18,13 @@ from __future__ import division -from kudu.compat import unittest +from kudu.compat import CompatUnitTest from kudu.errors import KuduInvalidArgument import kudu from kudu.schema import Schema -class TestSchema(unittest.TestCase): +class TestSchema(CompatUnitTest): def setUp(self): self.columns = [('one', 'int32', False), @@ -59,8 +59,10 @@ class TestSchema(unittest.TestCase): assert self.schema.primary_keys() == ['one', 'two'] def test_getitem_boundschecking(self): - with self.assertRaises(IndexError): - self.schema[4] + idx = 4 + error_msg = 'Column index {0} is not in range'.format(idx) + with self.assertRaisesRegex(IndexError, error_msg): + self.schema[idx] def test_getitem_wraparound(self): # wraparound @@ -75,7 +77,8 @@ class TestSchema(unittest.TestCase): assert result.equals(expected) - with self.assertRaises(KeyError): + error_msg = 'not_found' + with self.assertRaisesRegex(KeyError, error_msg): self.schema['not_found'] def test_schema_equals(self): @@ -113,8 +116,10 @@ class TestSchema(unittest.TestCase): bar = builder.add_column('bar', 'string') bar.compression(kudu.COMPRESSION_ZLIB) - with self.assertRaises(ValueError): - bar = builder.add_column('qux', 'string', compression='unknown') + compression = 'unknown' + error_msg = 'Invalid compression type: {0}'.format(compression) + with self.assertRaisesRegex(ValueError, error_msg): + bar = builder.add_column('qux', 'string', compression=compression) builder.set_primary_keys(['key']) builder.build() @@ -136,7 +141,8 @@ class TestSchema(unittest.TestCase): bar = builder.add_column('bar', 'string') bar.encoding(kudu.ENCODING_PLAIN) - with self.assertRaises(ValueError): + error_msg = 'Invalid encoding type' + with self.assertRaisesRegex(ValueError, error_msg): builder.add_column('qux', 'string', encoding='unknown') builder.set_primary_keys(['key']) @@ -169,7 +175,8 @@ class TestSchema(unittest.TestCase): .primary_key() .nullable(False)) - with self.assertRaises(kudu.KuduInvalidArgument): + error_msg = 'no precision provided for decimal column: key' + with self.assertRaisesRegex(kudu.KuduInvalidArgument, error_msg): builder.build() def test_precision_on_non_decimal_column(self): @@ -181,7 +188,8 @@ class TestSchema(unittest.TestCase): .precision(9) .scale(2)) - with self.assertRaises(kudu.KuduInvalidArgument): + error_msg = 'precision is not valid on a 2 column: key' + with self.assertRaisesRegex(kudu.KuduInvalidArgument, error_msg): builder.build() def test_date(self): @@ -220,7 +228,8 @@ class TestSchema(unittest.TestCase): .primary_key() .nullable(False)) - with self.assertRaises(kudu.KuduInvalidArgument): + error_msg = 'no length provided for VARCHAR column: key' + with self.assertRaisesRegex(kudu.KuduInvalidArgument, error_msg): builder.build() def test_varchar_invalid_length(self): @@ -231,7 +240,8 @@ class TestSchema(unittest.TestCase): .length(0) .nullable(False)) - with self.assertRaises(kudu.KuduInvalidArgument): + error_msg = 'length must be between 1 and 65535: key' + with self.assertRaisesRegex(kudu.KuduInvalidArgument, error_msg): builder.build() def test_length_on_non_varchar_column(self): @@ -242,17 +252,20 @@ class TestSchema(unittest.TestCase): .nullable(False) .length(10)) - with self.assertRaises(kudu.KuduInvalidArgument): + error_msg = 'no precision provided for decimal column: key' + with self.assertRaisesRegex(kudu.KuduInvalidArgument, error_msg): builder.build() def test_unsupported_col_spec_methods_for_create_table(self): builder = kudu.schema_builder() builder.add_column('test', 'int64').rename('test') - with self.assertRaises(kudu.KuduNotSupported): + error_msg = 'cannot rename a column during CreateTable: test' + with self.assertRaisesRegex(kudu.KuduNotSupported, error_msg): builder.build() builder.add_column('test', 'int64').remove_default() - with self.assertRaises(kudu.KuduNotSupported): + error_msg = 'cannot rename a column during CreateTable: test' + with self.assertRaisesRegex(kudu.KuduNotSupported, error_msg): builder.build() def test_set_column_spec_pk(self): @@ -352,7 +365,8 @@ class TestSchema(unittest.TestCase): builder.add_column('key1', 'int64').nullable(False) builder.add_column('key2', 'double').nullable(False) builder.set_non_unique_primary_keys(['key2', 'key1']) - with self.assertRaises(KuduInvalidArgument): + error_msg = 'primary key columns must be listed first in the schema: key' + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): schema = builder.build() def test_set_non_unique_primary_keys_not_first(self): @@ -361,7 +375,8 @@ class TestSchema(unittest.TestCase): (builder.add_column('key', 'int64') .nullable(False)) builder.set_non_unique_primary_keys(['key']) - with self.assertRaises(KuduInvalidArgument): + error_msg = 'primary key columns must be listed first in the schema: key' + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): schema = builder.build() def test_set_non_unique_primary_keys_same_name_twice(self): @@ -370,7 +385,8 @@ class TestSchema(unittest.TestCase): .nullable(False)) builder.add_column('data1', 'double') builder.set_non_unique_primary_keys(['key', 'key']) - with self.assertRaises(KuduInvalidArgument): + error_msg = 'primary key columns must be listed first in the schema: key' + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): schema = builder.build() def test_unique_and_non_unique_primary_key_on_same_column(self): @@ -403,7 +419,8 @@ class TestSchema(unittest.TestCase): (builder.add_column('key', 'double') .nullable(False) .non_unique_primary_key()) - with self.assertRaises(KuduInvalidArgument): + error_msg = 'primary key column must be the first column' + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): builder.build() def test_unique_and_non_unique_primary_key_on_different_cols(self): @@ -414,7 +431,8 @@ class TestSchema(unittest.TestCase): (builder.add_column('key2', 'double') .nullable(False) .non_unique_primary_key()) - with self.assertRaises(KuduInvalidArgument): + error_msg = 'multiple columns specified for primary key: key1, key2' + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): builder.build() def test_non_unique_and_unique_primary_key_on_different_cols(self): @@ -425,7 +443,8 @@ class TestSchema(unittest.TestCase): (builder.add_column('key2', 'double') .nullable(False) .primary_key()) - with self.assertRaises(KuduInvalidArgument): + error_msg = 'multiple columns specified for primary key: key1, key2' + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): builder.build() def test_multiple_non_unique_primary_keys(self): @@ -436,7 +455,8 @@ class TestSchema(unittest.TestCase): (builder.add_column('key2', 'double') .nullable(False) .non_unique_primary_key()) - with self.assertRaises(KuduInvalidArgument): + error_msg = 'multiple columns specified for primary key: key1, key2' + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): builder.build() def test_non_unique_primary_key_and_set_non_unique_primary_keys(self): @@ -446,7 +466,9 @@ class TestSchema(unittest.TestCase): .non_unique_primary_key()) builder.add_column('data1', 'double') builder.set_non_unique_primary_keys(['key']) - with self.assertRaises(KuduInvalidArgument): + error_msg = ('primary key specified by both SetNonUniquePrimaryKey\(\)' + ' and on a specific column: key') + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): builder.build() def test_primary_key_and_set_non_unique_primary_keys(self): @@ -456,7 +478,9 @@ class TestSchema(unittest.TestCase): .primary_key()) builder.add_column('data1', 'double') builder.set_non_unique_primary_keys(['key']) - with self.assertRaises(KuduInvalidArgument): + error_msg = ('primary key specified by both SetNonUniquePrimaryKey\(\)' + ' and on a specific column: key') + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): builder.build() def test_primary_key_and_set_primary_keys(self): @@ -466,7 +490,9 @@ class TestSchema(unittest.TestCase): .primary_key()) builder.add_column('data1', 'double') builder.set_primary_keys(['key']) - with self.assertRaises(KuduInvalidArgument): + error_msg = ('primary key specified by both SetPrimaryKey\(\)' + ' and on a specific column: key') + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): builder.build() def test_non_unique_primary_key_and_set_primary_keys(self): @@ -476,7 +502,9 @@ class TestSchema(unittest.TestCase): .non_unique_primary_key()) builder.add_column('data1', 'double') builder.set_primary_keys(['key']) - with self.assertRaises(KuduInvalidArgument): + error_msg = ('primary key specified by both SetPrimaryKey\(\)' + ' and on a specific column: key') + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): builder.build() def test_set_non_unique_and_set_unique_primary_key(self): @@ -507,7 +535,8 @@ class TestSchema(unittest.TestCase): .nullable(False) .primary_key()) builder.add_column(Schema.get_auto_incrementing_column_name(), 'double') - with self.assertRaises(KuduInvalidArgument): + error_msg = 'auto_incrementing_id is a reserved column name' + with self.assertRaisesRegex(KuduInvalidArgument, error_msg): builder.build() def test_default_value(self): diff --git a/python/kudu/tests/util.py b/python/kudu/tests/util.py index c3c91a5ae..3f6c0c5bc 100644 --- a/python/kudu/tests/util.py +++ b/python/kudu/tests/util.py @@ -18,14 +18,14 @@ # under the License. from decimal import Decimal -from kudu.compat import unittest +from kudu.compat import CompatUnitTest from kudu.client import Partitioning from kudu.tests.common import KuduTestBase import kudu import datetime import pytz -class TestScanBase(KuduTestBase, unittest.TestCase): +class TestScanBase(KuduTestBase, CompatUnitTest): @classmethod def setUpClass(self):
