Add Designate hacking checks to the tempest plugin

This patch adds the Designate hacking checks to also run against
the Designate tempest plugin code to maintain consistent style
checking across the Designate repositories.

Change-Id: I8f41bb8188ba8442dbf493dac39b8601f5208938
This commit is contained in:
Michael Johnson 2021-11-30 00:31:24 +00:00
parent fe4672da25
commit cc8f89b41c
14 changed files with 248 additions and 65 deletions

View File

@ -15,16 +15,16 @@ from tempest import clients
from tempest import config
from tempest.lib import auth
from designate_tempest_plugin.services.dns.v2.json.blacklists_client import \
BlacklistsClient
from designate_tempest_plugin.services.dns.v2.json.pool_client import \
PoolClient
from designate_tempest_plugin.services.dns.v2.json.recordset_client import \
RecordsetClient
from designate_tempest_plugin.services.dns.v2.json.tld_client import \
TldClient
from designate_tempest_plugin.services.dns.v2.json.zones_client import \
ZonesClient
from designate_tempest_plugin.services.dns.v2.json.blacklists_client import (
BlacklistsClient)
from designate_tempest_plugin.services.dns.v2.json.pool_client import (
PoolClient)
from designate_tempest_plugin.services.dns.v2.json.recordset_client import (
RecordsetClient)
from designate_tempest_plugin.services.dns.v2.json.tld_client import (
TldClient)
from designate_tempest_plugin.services.dns.v2.json.zones_client import (
ZonesClient)
CONF = config.CONF

View File

@ -95,8 +95,8 @@ def rand_quotas(zones=None, zone_records=None, zone_recordsets=None,
}
if CONF.dns_feature_enabled.bug_1573141_fixed:
quotas_dict['api_export_size'] = \
api_export_size or data_utils.rand_int_id(100, 999999)
quotas_dict['api_export_size'] = (
api_export_size or data_utils.rand_int_id(100, 999999))
else:
LOG.warning("Leaving `api_export_size` out of quota data due to: "
"https://bugs.launchpad.net/designate/+bug/1573141")
@ -190,8 +190,7 @@ def rand_sshfp_recordset(zone_name, algorithm_number=None,
**kwargs):
algorithm_number = algorithm_number or 2
fingerprint_type = fingerprint_type or 1
fingerprint = fingerprint or \
"123456789abcdef67890123456789abcdef67890"
fingerprint = fingerprint or "123456789abcdef67890123456789abcdef67890"
data = "%s %s %s" % (algorithm_number, fingerprint_type, fingerprint)
return rand_recordset_data('SSHFP', zone_name, records=[data], **kwargs)

View File

@ -0,0 +1,187 @@
# Copyright 2014 Hewlett-Packard Development Company, L.P.
# Copyright (c) 2012, Cloudscaling
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import re
from hacking import core
import pycodestyle
# D701: Default parameter value is a mutable type
# D702: Log messages require translation
# D703: Found use of _() without explicit import of _!
# D704: Found import of %s. This oslo library has been graduated!
# D705: timeutils.utcnow() must be used instead of datetime.%s()
# D706: Don't translate debug level logs
# D707: basestring is not Python3-compatible, use str instead.
# D708: Do not use xrange. Use range for large loops.
# D709: LOG.audit is deprecated, please use LOG.info!
# D710: LOG.warn() is not allowed. Use LOG.warning()
# D711: Don't use backslashes for line continuation.
UNDERSCORE_IMPORT_FILES = []
mutable_default_argument_check = re.compile(
r"^\s*def .+\((.+=\{\}|.+=\[\])")
string_translation = re.compile(r"[^_]*_\(\s*('|\")")
translated_log = re.compile(
r"(.)*LOG\.(audit|error|info|warn|warning|critical|exception)"
r"\(\s*_\(\s*('|\")")
underscore_import_check = re.compile(r"(.)*import _(.)*")
# We need this for cases where they have created their own _ function.
custom_underscore_check = re.compile(r"(.)*_\s*=\s*(.)*")
graduated_oslo_libraries_import_re = re.compile(
r"^\s*(?:import|from) designate\.openstack\.common\.?.*?"
r"(gettextutils|rpc)"
r".*?")
no_line_continuation_backslash_re = re.compile(r'.*(\\)\n')
@core.flake8ext
def mutable_default_arguments(physical_line, logical_line, filename):
if pycodestyle.noqa(physical_line):
return
if mutable_default_argument_check.match(logical_line):
yield (0, "D701: Default parameter value is a mutable type")
@core.flake8ext
def no_translate_debug_logs(logical_line, filename):
"""Check for 'LOG.debug(_('
As per our translation policy,
https://wiki.openstack.org/wiki/LoggingStandards#Log_Translation
we shouldn't translate debug level logs.
* This check assumes that 'LOG' is a logger.
* Use filename so we can start enforcing this in specific folders instead
of needing to do so all at once.
N319
"""
if logical_line.startswith("LOG.debug(_("):
yield(0, "D706: Don't translate debug level logs")
@core.flake8ext
def check_explicit_underscore_import(logical_line, filename):
"""Check for explicit import of the _ function
We need to ensure that any files that are using the _() function
to translate logs are explicitly importing the _ function. We
can't trust unit test to catch whether the import has been
added so we need to check for it here.
"""
# Build a list of the files that have _ imported. No further
# checking needed once it is found.
if filename in UNDERSCORE_IMPORT_FILES:
pass
elif (underscore_import_check.match(logical_line) or
custom_underscore_check.match(logical_line)):
UNDERSCORE_IMPORT_FILES.append(filename)
elif (translated_log.match(logical_line) or
string_translation.match(logical_line)):
yield(0, "D703: Found use of _() without explicit import of _!")
@core.flake8ext
def no_import_graduated_oslo_libraries(logical_line, filename):
"""Check that we don't continue to use o.c. oslo libraries after graduation
After a library graduates from oslo-incubator, as we make the switch, we
should ensure we don't continue to use the oslo-incubator versions.
In many cases, it's not possible to immediately remove the code from the
openstack/common folder due to dependency issues.
"""
# We can't modify oslo-incubator code, so ignore it here.
if "designate/openstack/common" in filename:
return
matches = graduated_oslo_libraries_import_re.match(logical_line)
if matches:
yield(0, "D704: Found import of %s. This oslo library has been "
"graduated!" % matches.group(1))
@core.flake8ext
def use_timeutils_utcnow(logical_line, filename):
# tools are OK to use the standard datetime module
if "/tools/" in filename:
return
msg = "D705: timeutils.utcnow() must be used instead of datetime.%s()"
datetime_funcs = ['now', 'utcnow']
for f in datetime_funcs:
pos = logical_line.find('datetime.%s' % f)
if pos != -1:
yield (pos, msg % f)
@core.flake8ext
def check_no_basestring(logical_line):
if re.search(r"\bbasestring\b", logical_line):
msg = ("D707: basestring is not Python3-compatible, use "
"str instead.")
yield(0, msg)
@core.flake8ext
def check_python3_xrange(logical_line):
if re.search(r"\bxrange\s*\(", logical_line):
yield(0, "D708: Do not use xrange. Use range for "
"large loops.")
@core.flake8ext
def check_no_log_audit(logical_line):
"""Ensure that we are not using LOG.audit messages
Plans are in place going forward as discussed in the following
spec (https://review.opendev.org/#/c/132552/) to take out
LOG.audit messages. Given that audit was a concept invented
for OpenStack we can enforce not using it.
"""
if "LOG.audit(" in logical_line:
yield(0, "D709: LOG.audit is deprecated, please use LOG.info!")
@core.flake8ext
def check_no_log_warn(logical_line):
"""Disallow 'LOG.warn('
D710
"""
if logical_line.startswith('LOG.warn('):
yield(0, "D710:Use LOG.warning() rather than LOG.warn()")
@core.flake8ext
def check_line_continuation_no_backslash(logical_line, tokens):
"""D711 - Don't use backslashes for line continuation.
:param logical_line: The logical line to check. Not actually used.
:param tokens: List of tokens to check.
:returns: None if the tokens don't contain any issues, otherwise a tuple
is yielded that contains the offending index in the logical
line and a message describe the check validation failure.
"""
backslash = None
for token_type, text, start, end, orig_line in tokens:
m = no_line_continuation_backslash_re.match(orig_line)
if m:
backslash = (start[0], m.start(1))
break
if backslash is not None:
msg = 'D711 Backslash line continuations not allowed'
yield backslash, msg

View File

@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations under
# the License.
from designate_tempest_plugin.services.dns.admin.json.quotas_client import \
QuotasClient
from designate_tempest_plugin.services.dns.admin.json.quotas_client import (
QuotasClient)
__all__ = ['QuotasClient']

View File

@ -12,35 +12,21 @@
# License for the specific language governing permissions and limitations under
# the License.
from designate_tempest_plugin.services.dns.v2.json.blacklists_client import \
BlacklistsClient
from designate_tempest_plugin.services.dns.v2.json.designate_limit_client \
import DesignateLimitClient
from designate_tempest_plugin.services.dns.v2.json.pool_client import \
PoolClient
from designate_tempest_plugin.services.dns.v2.json.ptr_client \
import PtrClient
from designate_tempest_plugin.services.dns.v2.json.quotas_client import \
QuotasClient
from designate_tempest_plugin.services.dns.v2.json.recordset_client import \
RecordsetClient
from designate_tempest_plugin.services.dns.v2.json.service_client import \
ServiceClient
from designate_tempest_plugin.services.dns.v2.json.tld_client import TldClient
from designate_tempest_plugin.services.dns.v2.json.transfer_accepts_client \
import TransferAcceptClient
from designate_tempest_plugin.services.dns.v2.json.transfer_request_client \
import TransferRequestClient
from designate_tempest_plugin.services.dns.v2.json.tsigkey_client import \
TsigkeyClient
from designate_tempest_plugin.services.dns.v2.json.zones_client import \
ZonesClient
from designate_tempest_plugin.services.dns.v2.json.zone_exports_client import \
ZoneExportsClient
from designate_tempest_plugin.services.dns.v2.json.zone_imports_client import \
ZoneImportsClient
from designate_tempest_plugin.services.dns.v2.json.api_version_client import \
ApiVersionClient
from .json.blacklists_client import BlacklistsClient
from .json.designate_limit_client import DesignateLimitClient
from .json.pool_client import PoolClient
from .json.ptr_client import PtrClient
from .json.quotas_client import QuotasClient
from .json.recordset_client import RecordsetClient
from .json.service_client import ServiceClient
from .json.tld_client import TldClient
from .json.transfer_accepts_client import TransferAcceptClient
from .json.transfer_request_client import TransferRequestClient
from .json.tsigkey_client import TsigkeyClient
from .json.zones_client import ZonesClient
from .json.zone_exports_client import ZoneExportsClient
from .json.zone_imports_client import ZoneImportsClient
from .json.api_version_client import ApiVersionClient
__all__ = ['BlacklistsClient', 'DesignateLimitClient', 'PoolClient',
'PtrClient', 'QuotasClient', 'RecordsetClient', 'ServiceClient',

View File

@ -24,8 +24,8 @@ from designate_tempest_plugin.common import waiters
from designate_tempest_plugin import data_utils as dns_data_utils
from designate_tempest_plugin.tests import base
from designate_tempest_plugin.services.dns.query.query_client \
import SingleQueryClient
from designate_tempest_plugin.services.dns.query.query_client import (
SingleQueryClient)
CONF = config.CONF
LOG = logging.getLogger(__name__)

View File

@ -15,8 +15,8 @@ from tempest import test
from tempest import config
from tempest.lib.common.utils import test_utils as utils
from designate_tempest_plugin.services.dns.query.query_client import \
QueryClient
from designate_tempest_plugin.services.dns.query.query_client import (
QueryClient)
from designate_tempest_plugin.tests import rbac_utils

View File

@ -92,8 +92,8 @@ class QuotasV2Test(base.BaseDnsV2Test):
def _reach_quota_limit(
self, limit_threshold, quota_type, zone=None):
attempt_number = 0
not_raised_msg = "Failed, expected '413 over_quota' response of " \
"type:{} wasn't received.".format(quota_type)
not_raised_msg = ("Failed, expected '413 over_quota' response of "
"type:{} wasn't received.".format(quota_type))
while attempt_number <= limit_threshold + 1:
try:
attempt_number += 1
@ -136,8 +136,8 @@ class QuotasV2Test(base.BaseDnsV2Test):
raised_err = str(e).replace(' ', '')
if not_raised_msg in str(e):
raise AssertionError(not_raised_msg)
elif "'code':413" in raised_err and \
"'type':'over_quota'" in raised_err:
elif ("'code':413" in raised_err and
"'type':'over_quota'" in raised_err):
LOG.info("OK, type':'over_quota' was raised")
break
else:
@ -309,10 +309,9 @@ class QuotasBoundary(base.BaseDnsV2Test, tempest.test.BaseTestCase):
cls.quota_client = cls.os_system_admin.dns_v2.QuotasClient()
cls.project_client = cls.os_system_admin.projects_client
cls.zone_client = cls.os_system_admin.dns_v2.ZonesClient()
cls.recordset_client = \
cls.os_system_admin.dns_v2.RecordsetClient()
cls.export_zone_client = \
cls.os_system_admin.dns_v2.ZoneExportsClient()
cls.recordset_client = cls.os_system_admin.dns_v2.RecordsetClient()
cls.export_zone_client = (
cls.os_system_admin.dns_v2.ZoneExportsClient())
else:
cls.quota_client = cls.os_admin.dns_v2.QuotasClient()
cls.project_client = cls.os_admin.projects_client

View File

@ -23,8 +23,8 @@ from designate_tempest_plugin.tests import base
from designate_tempest_plugin.common import constants as const
from designate_tempest_plugin import data_utils as dns_data_utils
from designate_tempest_plugin.common import waiters
from designate_tempest_plugin.services.dns.query.query_client \
import SingleQueryClient
from designate_tempest_plugin.services.dns.query.query_client import (
SingleQueryClient)
LOG = logging.getLogger(__name__)

View File

@ -25,8 +25,8 @@ from designate_tempest_plugin import data_utils as dns_data_utils
from designate_tempest_plugin.tests import base
from designate_tempest_plugin.common import constants as const
from designate_tempest_plugin.common import waiters
from designate_tempest_plugin.services.dns.query.query_client \
import SingleQueryClient
from designate_tempest_plugin.services.dns.query.query_client import (
SingleQueryClient)
CONF = config.CONF

View File

@ -22,8 +22,8 @@ from tempest.lib import decorators
from designate_tempest_plugin.common import constants as const
from designate_tempest_plugin.common import waiters
from designate_tempest_plugin import data_utils as dns_data_utils
from designate_tempest_plugin.tests.api.v2.test_zones_exports import \
BaseZoneExportsTest
from designate_tempest_plugin.tests.api.v2.test_zones_exports import (
BaseZoneExportsTest)
CONF = config.CONF
LOG = logging.getLogger(__name__)

View File

@ -17,8 +17,8 @@ from tempest.lib import decorators
from designate_tempest_plugin.common import constants as const
from designate_tempest_plugin.common import waiters
from designate_tempest_plugin import data_utils as dns_data_utils
from designate_tempest_plugin.tests.api.v2.test_zones_imports import \
BaseZonesImportTest
from designate_tempest_plugin.tests.api.v2.test_zones_imports import (
BaseZonesImportTest)
LOG = logging.getLogger(__name__)

12
tox.ini
View File

@ -105,3 +105,15 @@ extension =
T112 = tempest.hacking.checks:dont_import_local_tempest_into_lib
T113 = tempest.hacking.checks:dont_use_config_in_tempest_lib
T114 = tempest.hacking.checks:use_rand_uuid_instead_of_uuid4
D701 = checks:mutable_default_arguments
D703 = checks:check_explicit_underscore_import
D704 = checks:no_import_graduated_oslo_libraries
D705 = checks:use_timeutils_utcnow
D706 = checks:no_translate_debug_logs
D707 = checks:check_no_basestring
D708 = checks:check_python3_xrange
D709 = checks:check_no_log_audit
D710 = checks:check_no_log_warn
D711 = checks:check_line_continuation_no_backslash
paths = ./designate_tempest_plugin/hacking