Merge "Add code to enable single-value response for http clients"
diff --git a/HACKING.rst b/HACKING.rst
index e57b670..e920634 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -8,7 +8,8 @@
Tempest Specific Commandments
------------------------------
-- [T102] Cannot import OpenStack python clients in tempest/api tests
+- [T102] Cannot import OpenStack python clients in tempest/api &
+ tempest/scenario tests
- [T104] Scenario tests require a services decorator
- [T105] Unit tests cannot use setUpClass
- [T106] vim configuration should not be kept in source files.
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 13ee8fe..b70b446 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -467,9 +467,6 @@
# [nova.vnc]->vnc_enabled in nova.conf (boolean value)
#vnc_console = false
-# If false skip all v2 api tests with xml (boolean value)
-#xml_api_v2 = true
-
[dashboard]
@@ -632,9 +629,6 @@
# (boolean value)
#trust = true
-# If false, skip all identity api tests with xml (boolean value)
-#xml_api = false
-
[image]
@@ -810,9 +804,6 @@
# attributes ipv6_ra_mode and ipv6_address_mode (boolean value)
#ipv6_subnet_attributes = false
-# If false, skip all network api tests with xml (boolean value)
-#xml_api = false
-
[object-storage]
diff --git a/requirements.txt b/requirements.txt
index e939c5c..ce5886e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -6,7 +6,6 @@
httplib2>=0.7.5
jsonschema>=2.0.0,<3.0.0
testtools>=0.9.36,!=1.2.0
-lxml>=2.3
boto>=2.32.1
paramiko>=1.13.0
netaddr>=0.7.12
diff --git a/tempest/README.rst b/tempest/README.rst
index fb25151..d28c3f9 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -55,7 +55,8 @@
functionality. They are typically a series of steps where complicated
state requiring multiple services is set up exercised, and torn down.
-Scenario tests can and should use the OpenStack python clients.
+Scenario tests should not use the existing python clients for OpenStack,
+but should instead use the tempest implementations of clients.
:ref:`stress_field_guide`
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 2f53a0b..6a3ee44 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -38,9 +38,6 @@
def resource_setup(cls):
cls.set_network_resources()
super(BaseComputeTest, cls).resource_setup()
- if getattr(cls, '_interface', None) == 'xml' and cls._api_version == 2:
- if not CONF.compute_feature_enabled.xml_api_v2:
- raise cls.skipException('XML API is not enabled')
# TODO(andreaf) WE should care also for the alt_manager here
# but only once client lazy load in the manager is done
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 4b5f107..b13dd22 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -62,9 +62,6 @@
super(BaseNetworkTest, cls).resource_setup()
if not CONF.service_available.neutron:
raise cls.skipException("Neutron support is required")
- if getattr(cls, '_interface', None) == 'xml':
- if not CONF.network_feature_enabled.xml_api:
- raise cls.skipException('XML API is not enabled')
if cls._ip_version == 6 and not CONF.network_feature_enabled.ipv6:
raise cls.skipException("IPv6 Tests are disabled.")
diff --git a/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml b/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml
index 8690941..4f9df91 100644
--- a/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml
+++ b/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml
@@ -7,6 +7,8 @@
Default: not_yet
image:
Type: String
+ flavor:
+ Type: String
Resources:
fluffy:
Type: AWS::AutoScaling::LaunchConfiguration
@@ -16,7 +18,7 @@
- Stinky
Properties:
ImageId: {Ref: image}
- InstanceType: not_used
+ InstanceType: {Ref: flavor}
UserData:
Fn::Replace:
- variable_a: {Ref: trigger}
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
index 759cbbe..bf6c79c 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -31,13 +31,15 @@
template = cls.read_template('non_empty_stack')
image_id = (CONF.orchestration.image_ref or
cls._create_image()['id'])
+ flavor = CONF.orchestration.instance_type
# create the stack
cls.stack_identifier = cls.create_stack(
cls.stack_name,
template,
parameters={
'trigger': 'start',
- 'image': image_id
+ 'image': image_id,
+ 'flavor': flavor
})
cls.stack_id = cls.stack_identifier.split('/')[1]
cls.resource_name = 'fluffy'
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index 0cc2471..50bab56 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -22,13 +22,13 @@
QUOTA_USAGE_KEYS = ['reserved', 'limit', 'in_use']
-class VolumeQuotasAdminTestJSON(base.BaseVolumeV1AdminTest):
+class BaseVolumeQuotasAdminV2TestJSON(base.BaseVolumeAdminTest):
_interface = "json"
force_tenant_isolation = True
@classmethod
def resource_setup(cls):
- super(VolumeQuotasAdminTestJSON, cls).resource_setup()
+ super(BaseVolumeQuotasAdminV2TestJSON, cls).resource_setup()
cls.demo_tenant_id = cls.isolated_creds.get_primary_creds().tenant_id
@test.attr(type='gate')
@@ -113,3 +113,7 @@
self.quotas_client.delete_quota_set(tenant_id)
_, quota_set_new = self.quotas_client.get_quota_set(tenant_id)
self.assertEqual(volume_default, quota_set_new['volumes'])
+
+
+class VolumeQuotasAdminV1TestJSON(BaseVolumeQuotasAdminV2TestJSON):
+ _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index 0fff561..c367ebb 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -18,13 +18,13 @@
from tempest import test
-class VolumeQuotasNegativeTestJSON(base.BaseVolumeV1AdminTest):
+class BaseVolumeQuotasNegativeV2TestJSON(base.BaseVolumeAdminTest):
_interface = "json"
force_tenant_isolation = True
@classmethod
def resource_setup(cls):
- super(VolumeQuotasNegativeTestJSON, cls).resource_setup()
+ super(BaseVolumeQuotasNegativeV2TestJSON, cls).resource_setup()
demo_user = cls.isolated_creds.get_primary_creds()
cls.demo_tenant_id = demo_user.tenant_id
cls.shared_quota_set = {'gigabytes': 3, 'volumes': 1, 'snapshots': 1}
@@ -76,3 +76,7 @@
self.assertRaises(exceptions.OverLimit,
self.snapshots_client.create_snapshot,
self.volume['id'])
+
+
+class VolumeQuotasNegativeV1TestJSON(BaseVolumeQuotasNegativeV2TestJSON):
+ _api_version = 1
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 5d99123..2a52e55 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -165,8 +165,6 @@
cls.qos_specs = []
- cls.quotas_client = cls.os_adm.volume_quotas_client
-
if cls._api_version == 1:
if not CONF.volume_feature_enabled.api_v1:
msg = "Volume API v1 is disabled"
@@ -177,6 +175,7 @@
cls.hosts_client = cls.os_adm.volume_hosts_client
cls.admin_snapshots_client = cls.os_adm.snapshots_client
cls.backups_adm_client = cls.os_adm.backups_client
+ cls.quotas_client = cls.os_adm.volume_quotas_client
elif cls._api_version == 2:
if not CONF.volume_feature_enabled.api_v2:
msg = "Volume API v2 is disabled"
@@ -187,6 +186,7 @@
cls.hosts_client = cls.os_adm.volume_hosts_v2_client
cls.admin_snapshots_client = cls.os_adm.snapshots_v2_client
cls.backups_adm_client = cls.os_adm.backups_v2_client
+ cls.quotas_client = cls.os_adm.volume_quotas_v2_client
@classmethod
def resource_cleanup(cls):
diff --git a/tempest/clients.py b/tempest/clients.py
index 486eef2..5873a85 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -138,6 +138,8 @@
from tempest.services.volume.json.volumes_client import VolumesClientJSON
from tempest.services.volume.v2.json.admin.volume_hosts_client import \
VolumeHostsV2ClientJSON
+from tempest.services.volume.v2.json.admin.volume_quotas_client import \
+ VolumeQuotasV2Client
from tempest.services.volume.v2.json.admin.volume_types_client import \
VolumeTypesV2ClientJSON
from tempest.services.volume.v2.json.availability_zone_client import \
@@ -302,6 +304,7 @@
self.volume_hosts_v2_client = VolumeHostsV2ClientJSON(
self.auth_provider)
self.volume_quotas_client = VolumeQuotasClientJSON(self.auth_provider)
+ self.volume_quotas_v2_client = VolumeQuotasV2Client(self.auth_provider)
self.volumes_extension_client = VolumeExtensionClientJSON(
self.auth_provider)
self.volumes_v2_extension_client = VolumeV2ExtensionClientJSON(
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index 228e47c..1ce1e39 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -203,9 +203,8 @@
if 'overlaps with another subnet' not in str(e):
raise
else:
- e = exceptions.BuildErrorException()
- e.message = 'Available CIDR for subnet creation could not be found'
- raise e
+ message = 'Available CIDR for subnet creation could not be found'
+ raise Exception(message)
return resp_body['subnet']
def _create_router(self, router_name, tenant_id):
diff --git a/tempest/config.py b/tempest/config.py
index 616a476..b467f83 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -143,9 +143,6 @@
cfg.BoolOpt('api_v3',
default=True,
help='Is the v3 identity API enabled'),
- cfg.BoolOpt('xml_api',
- default=False,
- help='If false, skip all identity api tests with xml'),
]
compute_group = cfg.OptGroup(name='compute',
@@ -280,9 +277,6 @@
cfg.BoolOpt('api_v3',
default=False,
help="If false, skip all nova v3 tests."),
- cfg.BoolOpt('xml_api_v2',
- default=True,
- help="If false skip all v2 api tests with xml"),
cfg.BoolOpt('disk_config',
default=True,
help="If false, skip disk config tests"),
@@ -491,9 +485,6 @@
"the extended IPv6 attributes ipv6_ra_mode "
"and ipv6_address_mode"
),
- cfg.BoolOpt('xml_api',
- default=False,
- help='If false, skip all network api tests with xml')
]
messaging_group = cfg.OptGroup(name='messaging',
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 6014cff..29898a9 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -30,18 +30,18 @@
mutable_default_args = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])")
-def import_no_clients_in_api(physical_line, filename):
- """Check for client imports from tempest/api tests
+def import_no_clients_in_api_and_scenario_tests(physical_line, filename):
+ """Check for client imports from tempest/api & tempest/scenario tests
T102: Cannot import OpenStack python clients
"""
- if "tempest/api" in filename:
+ if "tempest/api" in filename or "tempest/scenario" in filename:
res = PYTHON_CLIENT_RE.match(physical_line)
if res:
return (physical_line.find(res.group(1)),
("T102: python clients import not allowed"
- " in tempest/api/* tests"))
+ " in tempest/api/* or tempest/scenario/* tests"))
def scenario_tests_need_service_tags(physical_line, filename,
@@ -117,7 +117,7 @@
def factory(register):
- register(import_no_clients_in_api)
+ register(import_no_clients_in_api_and_scenario_tests)
register(scenario_tests_need_service_tags)
register(no_setup_teardown_class_for_tests)
register(no_vi_headers)
diff --git a/tempest/scenario/README.rst b/tempest/scenario/README.rst
index 5a287d6..38e0de9 100644
--- a/tempest/scenario/README.rst
+++ b/tempest/scenario/README.rst
@@ -29,9 +29,9 @@
Scope of these tests
--------------------
-Scenario tests should use the official python client libraries for
-OpenStack, as they provide a more realistic approach in how people
-will interact with the services.
+Scenario tests should always use the Tempest implementation of the
+OpenStack API, as we want to ensure that bugs aren't hidden by the
+official clients.
Tests should be tagged with which services they exercise, as
determined by which client libraries are used directly by the test.
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index 875a1d9..1a10b79 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -12,11 +12,10 @@
# License for the specific language governing permissions and limitations
# under the License.
+import HTMLParser
import urllib
import urllib2
-from lxml import html
-
from tempest import config
from tempest.scenario import manager
from tempest import test
@@ -24,6 +23,30 @@
CONF = config.CONF
+class HorizonHTMLParser(HTMLParser.HTMLParser):
+ csrf_token = None
+ region = None
+
+ def _find_name(self, attrs, name):
+ for attrpair in attrs:
+ if attrpair[0] == 'name' and attrpair[1] == name:
+ return True
+ return False
+
+ def _find_value(self, attrs):
+ for attrpair in attrs:
+ if attrpair[0] == 'value':
+ return attrpair[1]
+ return None
+
+ def handle_starttag(self, tag, attrs):
+ if tag == 'input':
+ if self._find_name(attrs, 'csrfmiddlewaretoken'):
+ self.csrf_token = self._find_value(attrs)
+ if self._find_name(attrs, 'region'):
+ self.region = self._find_value(attrs)
+
+
class TestDashboardBasicOps(manager.ScenarioTest):
"""
@@ -49,10 +72,8 @@
response = self.opener.open(CONF.dashboard.dashboard_url).read()
# Grab the CSRF token and default region
- csrf_token = html.fromstring(response).xpath(
- '//input[@name="csrfmiddlewaretoken"]/@value')[0]
- region = html.fromstring(response).xpath(
- '//input[@name="region"]/@value')[0]
+ parser = HorizonHTMLParser()
+ parser.feed(response)
# Prepare login form request
req = urllib2.Request(CONF.dashboard.login_url)
@@ -60,8 +81,8 @@
req.add_header('Referer', CONF.dashboard.dashboard_url)
params = {'username': CONF.identity.username,
'password': CONF.identity.password,
- 'region': region,
- 'csrfmiddlewaretoken': csrf_token}
+ 'region': parser.region,
+ 'csrfmiddlewaretoken': parser.csrf_token}
self.opener.open(req, urllib.urlencode(params))
def check_home_page(self):
diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py
new file mode 100644
index 0000000..3ee71dd
--- /dev/null
+++ b/tempest/scenario/test_shelve_instance.py
@@ -0,0 +1,96 @@
+# Copyright 2014 Scality
+# All Rights Reserved.
+#
+# 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 testtools
+
+from tempest import config
+from tempest.openstack.common import log
+from tempest.scenario import manager
+from tempest import test
+
+CONF = config.CONF
+
+LOG = log.getLogger(__name__)
+
+
+class TestShelveInstance(manager.ScenarioTest):
+ """
+ This test shelves then unshelves a Nova instance
+ The following is the scenario outline:
+ * boot a instance and create a timestamp file in it
+ * shelve the instance
+ * unshelve the instance
+ * check the existence of the timestamp file in the unshelved instance
+
+ """
+
+ def _write_timestamp(self, server_or_ip):
+ ssh_client = self.get_remote_client(server_or_ip)
+ ssh_client.exec_command('date > /tmp/timestamp; sync')
+ self.timestamp = ssh_client.exec_command('cat /tmp/timestamp')
+
+ def _check_timestamp(self, server_or_ip):
+ ssh_client = self.get_remote_client(server_or_ip)
+ got_timestamp = ssh_client.exec_command('cat /tmp/timestamp')
+ self.assertEqual(self.timestamp, got_timestamp)
+
+ def _shelve_then_unshelve_server(self, server):
+ self.servers_client.shelve_server(server['id'])
+ offload_time = CONF.compute.shelved_offload_time
+ if offload_time >= 0:
+ self.servers_client.wait_for_server_status(
+ server['id'], 'SHELVED_OFFLOADED', extra_timeout=offload_time)
+ else:
+ self.servers_client.wait_for_server_status(server['id'], 'SHELVED')
+ self.servers_client.shelve_offload_server(server['id'])
+ self.servers_client.wait_for_server_status(server['id'],
+ 'SHELVED_OFFLOADED')
+ self.servers_client.unshelve_server(server['id'])
+ self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
+
+ @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+ 'Shelve is not available.')
+ @test.services('compute', 'network', 'image')
+ def test_shelve_instance(self):
+ self.keypair = self.create_keypair()
+
+ self.security_group = self._create_security_group()
+
+ create_kwargs = {
+ 'key_name': self.keypair['name'],
+ 'security_groups': [self.security_group]
+ }
+ server = self.create_server(image=CONF.compute.image_ref,
+ create_kwargs=create_kwargs)
+
+ if CONF.compute.use_floatingip_for_ssh:
+ _, floating_ip = self.floating_ips_client.create_floating_ip()
+ self.addCleanup(self.delete_wrapper,
+ self.floating_ips_client.delete_floating_ip,
+ floating_ip['id'])
+ self.floating_ips_client.associate_floating_ip_to_server(
+ floating_ip['ip'], server['id'])
+ self._write_timestamp(floating_ip['ip'])
+ else:
+ self._write_timestamp(server)
+
+ # Prevent bug #1257594 from coming back
+ # Unshelve used to boot the instance with the original image, not
+ # with the instance snapshot
+ self._shelve_then_unshelve_server(server)
+ if CONF.compute.use_floatingip_for_ssh:
+ self._check_timestamp(floating_ip['ip'])
+ else:
+ self._check_timestamp(server)
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index 309dc5b..6b27f4a 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -73,10 +73,9 @@
metadata: A dictionary of values to be used as metadata.
"""
post_body = {
- 'size': size,
- 'display_name': kwargs.get('display_name'),
- 'metadata': kwargs.get('metadata'),
+ 'size': size
}
+ post_body.update(kwargs)
post_body = json.dumps({'volume': post_body})
resp, body = self.post('os-volumes', post_body)
diff --git a/tempest/services/volume/json/admin/volume_quotas_client.py b/tempest/services/volume/json/admin/volume_quotas_client.py
index 90790e3..5b49040 100644
--- a/tempest/services/volume/json/admin/volume_quotas_client.py
+++ b/tempest/services/volume/json/admin/volume_quotas_client.py
@@ -23,7 +23,7 @@
CONF = config.CONF
-class VolumeQuotasClientJSON(rest_client.RestClient):
+class BaseVolumeQuotasClientJSON(rest_client.RestClient):
"""
Client class to send CRUD Volume Quotas API requests to a Cinder endpoint
"""
@@ -31,7 +31,7 @@
TYPE = "json"
def __init__(self, auth_provider):
- super(VolumeQuotasClientJSON, self).__init__(auth_provider)
+ super(BaseVolumeQuotasClientJSON, self).__init__(auth_provider)
self.service = CONF.volume.catalog_type
self.build_interval = CONF.volume.build_interval
@@ -85,3 +85,9 @@
"""Delete the tenant's quota set."""
resp, body = self.delete('os-quota-sets/%s' % tenant_id)
self.expected_success(200, resp.status)
+
+
+class VolumeQuotasClientJSON(BaseVolumeQuotasClientJSON):
+ """
+ Client class to send CRUD Volume Type API V1 requests to a Cinder endpoint
+ """
diff --git a/tempest/services/volume/v2/json/admin/volume_quotas_client.py b/tempest/services/volume/v2/json/admin/volume_quotas_client.py
new file mode 100644
index 0000000..64f4f33
--- /dev/null
+++ b/tempest/services/volume/v2/json/admin/volume_quotas_client.py
@@ -0,0 +1,27 @@
+# Copyright 2014 OpenStack Foundation
+# All Rights Reserved.
+#
+# 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.
+
+from tempest.services.volume.json.admin import volume_quotas_client
+
+
+class VolumeQuotasV2Client(volume_quotas_client.BaseVolumeQuotasClientJSON):
+ """
+ Client class to send CRUD Volume V2 API requests to a Cinder endpoint
+ """
+
+ def __init__(self, auth_provider):
+ super(VolumeQuotasV2Client, self).__init__(auth_provider)
+
+ self.api_version = "v2"
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index 6857461..fd01887 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -69,13 +69,18 @@
self.assertFalse(checks.no_setup_teardown_class_for_tests(
" def tearDownClass(cls):", './tempest/test.py'))
- def test_import_no_clients_in_api(self):
+ def test_import_no_clients_in_api_and_scenario_tests(self):
for client in checks.PYTHON_CLIENTS:
string = "import " + client + "client"
- self.assertTrue(checks.import_no_clients_in_api(
- string, './tempest/api/fake_test.py'))
- self.assertFalse(checks.import_no_clients_in_api(
- string, './tempest/scenario/fake_test.py'))
+ self.assertTrue(
+ checks.import_no_clients_in_api_and_scenario_tests(
+ string, './tempest/api/fake_test.py'))
+ self.assertTrue(
+ checks.import_no_clients_in_api_and_scenario_tests(
+ string, './tempest/scenario/fake_test.py'))
+ self.assertFalse(
+ checks.import_no_clients_in_api_and_scenario_tests(
+ string, './tempest/test.py'))
def test_scenario_tests_need_service_tags(self):
self.assertFalse(checks.scenario_tests_need_service_tags(