summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkihiro Motoki <amotoki@gmail.com>2017-06-09 10:47:12 +0000
committerAkihiro Motoki <amotoki@gmail.com>2017-06-09 16:05:31 +0000
commitb9d0243c33dcab1408ecc0661b3fe83d6af9568a (patch)
treeab204f5854501092c104f88a7340acca3c6900ff
parent95629a337e8aa19fb283cf11a701bd8025b88346 (diff)
downloadhorizon-b9d0243c33dcab1408ecc0661b3fe83d6af9568a.tar.gz
Fix H405 (multi line docstring) warnings (openstack_dashboard)
H405: multi line docstring summary not separated with an empty line Closes-Bug: #1696996 Change-Id: Id895695663b19522d9cdc22f8b012e49680d708b
-rw-r--r--openstack_dashboard/api/base.py11
-rw-r--r--openstack_dashboard/api/cinder.py14
-rw-r--r--openstack_dashboard/api/glance.py9
-rw-r--r--openstack_dashboard/api/keystone.py5
-rw-r--r--openstack_dashboard/api/nova.py5
-rw-r--r--openstack_dashboard/api/rest/cinder.py37
-rw-r--r--openstack_dashboard/api/rest/glance.py21
-rw-r--r--openstack_dashboard/api/rest/heat.py12
-rw-r--r--openstack_dashboard/api/rest/json_encoder.py4
-rw-r--r--openstack_dashboard/api/rest/keystone.py50
-rw-r--r--openstack_dashboard/api/rest/network.py12
-rw-r--r--openstack_dashboard/api/rest/neutron.py25
-rw-r--r--openstack_dashboard/api/rest/nova.py79
-rw-r--r--openstack_dashboard/api/rest/swift.py34
-rw-r--r--openstack_dashboard/api/rest/urls.py6
-rw-r--r--openstack_dashboard/api/rest/utils.py10
-rw-r--r--openstack_dashboard/dashboards/admin/hypervisors/tests.py6
-rw-r--r--openstack_dashboard/dashboards/project/images/images/forms.py5
-rw-r--r--openstack_dashboard/dashboards/project/images/utils.py7
-rw-r--r--openstack_dashboard/dashboards/project/instances/tables.py3
-rw-r--r--openstack_dashboard/dashboards/project/instances/tests.py11
-rw-r--r--openstack_dashboard/dashboards/project/instances/utils.py8
-rw-r--r--openstack_dashboard/dashboards/project/network_topology/views.py6
-rw-r--r--openstack_dashboard/dashboards/project/security_groups/tests.py3
-rw-r--r--openstack_dashboard/dashboards/project/volumes/tables.py3
-rw-r--r--openstack_dashboard/test/integration_tests/basewebobject.py15
-rw-r--r--openstack_dashboard/test/integration_tests/decorators.py17
-rw-r--r--openstack_dashboard/test/integration_tests/helpers.py11
-rw-r--r--openstack_dashboard/test/integration_tests/pages/admin/system/metadatadefinitionspage.py1
-rw-r--r--openstack_dashboard/test/integration_tests/pages/pageobject.py1
-rw-r--r--openstack_dashboard/test/integration_tests/regions/baseregion.py16
-rw-r--r--openstack_dashboard/test/integration_tests/regions/forms.py12
-rw-r--r--openstack_dashboard/test/integration_tests/regions/menus.py5
-rw-r--r--openstack_dashboard/test/integration_tests/regions/tables.py4
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_credentials.py2
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_defaults.py1
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_flavors.py4
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_host_aggregates.py1
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_images.py81
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_instances.py20
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_login.py1
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_metadata_definitions.py3
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_networks.py1
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_router.py7
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_router_gateway.py39
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_security_groups.py9
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_stacks.py3
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_user_settings.py11
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_volume_snapshots.py77
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_volumes.py122
-rw-r--r--openstack_dashboard/test/integration_tests/tests/test_volumetypes.py23
-rw-r--r--openstack_dashboard/test/test_data/utils.py17
-rw-r--r--openstack_dashboard/usage/quotas.py1
-rw-r--r--openstack_dashboard/utils/filters.py4
-rw-r--r--tox.ini3
55 files changed, 438 insertions, 460 deletions
diff --git a/openstack_dashboard/api/base.py b/openstack_dashboard/api/base.py
index 5a1bed7f8..5bcec0cc9 100644
--- a/openstack_dashboard/api/base.py
+++ b/openstack_dashboard/api/base.py
@@ -199,8 +199,10 @@ class Quota(object):
class QuotaSet(Sequence):
- """Wrapper for client QuotaSet objects which turns the individual quotas
- into Quota objects for easier handling/iteration.
+ """Wrapper for client QuotaSet objects.
+
+ This turns the individual quotas into Quota objects
+ for easier handling/iteration.
`QuotaSet` objects support a mix of `list` and `dict` methods; you can use
the bracket notation (`qs["my_quota"] = 0`) to add new quota values, and
@@ -229,8 +231,9 @@ class QuotaSet(Sequence):
return self.items[index]
def __add__(self, other):
- """Merge another QuotaSet into this one. Existing quotas are
- not overridden.
+ """Merge another QuotaSet into this one.
+
+ Existing quotas are not overridden.
"""
if not isinstance(other, QuotaSet):
msg = "Can only add QuotaSet to QuotaSet, " \
diff --git a/openstack_dashboard/api/cinder.py b/openstack_dashboard/api/cinder.py
index f8cdefff4..43c51cbf2 100644
--- a/openstack_dashboard/api/cinder.py
+++ b/openstack_dashboard/api/cinder.py
@@ -253,7 +253,9 @@ def update_pagination(entities, page_size, marker, sort_dir):
@profiler.trace
def volume_list_paged(request, search_opts=None, marker=None, paginate=False,
sort_dir="desc"):
- """To see all volumes in the cloud as an admin you can pass in a special
+ """List volumes with pagination.
+
+ To see all volumes in the cloud as an admin you can pass in a special
search option: {'all_tenants': 1}
"""
has_more_data = False
@@ -611,8 +613,7 @@ def volume_cg_snapshot_delete(request, cg_snapshot_id):
@memoized
def volume_backup_supported(request):
- """This method will determine if cinder supports backup.
- """
+ """This method will determine if cinder supports backup."""
# TODO(lcheng) Cinder does not expose the information if cinder
# backup is configured yet. This is a workaround until that
# capability is available.
@@ -970,8 +971,7 @@ def list_extensions(cinder_api):
@memoized_with_request(list_extensions)
def extension_supported(extensions, extension_name):
- """This method will determine if Cinder supports a given extension name.
- """
+ """This method will determine if Cinder supports a given extension name."""
for extension in extensions:
if extension.name == extension_name:
return True
@@ -980,7 +980,9 @@ def extension_supported(extensions, extension_name):
@profiler.trace
def transfer_list(request, detailed=True, search_opts=None):
- """To see all volumes transfers as an admin pass in a special
+ """List volume transfers.
+
+ To see all volumes transfers as an admin pass in a special
search option: {'all_tenants': 1}
"""
c_client = cinderclient(request)
diff --git a/openstack_dashboard/api/glance.py b/openstack_dashboard/api/glance.py
index c3f6985df..1fe514e63 100644
--- a/openstack_dashboard/api/glance.py
+++ b/openstack_dashboard/api/glance.py
@@ -239,9 +239,7 @@ def image_delete(request, image_id):
@profiler.trace
def image_get(request, image_id):
- """Returns an Image object populated with metadata for image
- with supplied identifier.
- """
+ """Returns an Image object populated with metadata for a given image."""
image = glanceclient(request).images.get(image_id)
return Image(image)
@@ -525,8 +523,9 @@ class Namespace(BaseGlanceMetadefAPIResourceWrapper):
def filter_properties_target(namespaces_iter,
resource_types,
properties_target):
- """Filter metadata namespaces based on the given resource types and
- properties target.
+ """Filter metadata namespaces.
+
+ Filtering is done based ongiven resource types and a properties target.
:param namespaces_iter: Metadata namespaces iterable.
:param resource_types: List of resource type names.
diff --git a/openstack_dashboard/api/keystone.py b/openstack_dashboard/api/keystone.py
index 1ca7ffdde..7a767bf4e 100644
--- a/openstack_dashboard/api/keystone.py
+++ b/openstack_dashboard/api/keystone.py
@@ -311,8 +311,9 @@ def get_default_domain(request, get_name=True):
def get_effective_domain_id(request):
- """Gets the id of the default domain to use when creating Identity
- objects. If the requests default domain is the same as DEFAULT_DOMAIN,
+ """Gets the id of the default domain.
+
+ If the requests default domain is the same as DEFAULT_DOMAIN,
return None.
"""
default_domain = get_default_domain(request)
diff --git a/openstack_dashboard/api/nova.py b/openstack_dashboard/api/nova.py
index 137223125..4eb497344 100644
--- a/openstack_dashboard/api/nova.py
+++ b/openstack_dashboard/api/nova.py
@@ -225,8 +225,9 @@ class FlavorExtraSpec(object):
def get_auth_params_from_request(request):
- """Extracts the properties from the request object needed by the novaclient
- call below. These will be used to memoize the calls to novaclient
+ """Extracts properties needed by novaclient call from the request object.
+
+ These will be used to memoize the calls to novaclient.
"""
return (
request.user.username,
diff --git a/openstack_dashboard/api/rest/cinder.py b/openstack_dashboard/api/rest/cinder.py
index fd1e6a759..53cc3f489 100644
--- a/openstack_dashboard/api/rest/cinder.py
+++ b/openstack_dashboard/api/rest/cinder.py
@@ -11,8 +11,7 @@
# 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.
-"""API over the cinder service.
-"""
+"""API over the cinder service."""
from django.utils.translation import ugettext_lazy as _
from django.views import generic
@@ -28,14 +27,12 @@ CLIENT_KEYWORDS = {'marker', 'sort_dir', 'paginate'}
@urls.register
class Volumes(generic.View):
- """API for cinder volumes.
- """
+ """API for cinder volumes."""
url_regex = r'cinder/volumes/$'
@rest_utils.ajax()
def get(self, request):
- """Get a detailed list of volumes associated with the current user's
- project.
+ """Get a detailed list of volumes associated with the current project.
Example GET:
http://localhost/api/cinder/volumes?paginate=true&sort_dir=asc
@@ -99,8 +96,7 @@ class Volumes(generic.View):
@urls.register
class Volume(generic.View):
- """API for cinder volume.
- """
+ """API for cinder volume."""
url_regex = r'cinder/volumes/(?P<volume_id>[^/]+)/$'
@rest_utils.ajax()
@@ -118,8 +114,7 @@ class Volume(generic.View):
@urls.register
class VolumeTypes(generic.View):
- """API for volume types.
- """
+ """API for volume types."""
url_regex = r'cinder/volumetypes/$'
@rest_utils.ajax()
@@ -162,8 +157,7 @@ class VolumeMetadata(generic.View):
@urls.register
class VolumeType(generic.View):
- """API for getting a volume type.
- """
+ """API for getting a volume type."""
url_regex = r'cinder/volumetypes/(?P<volumetype_id>[^/]+)/$'
@rest_utils.ajax()
@@ -189,14 +183,12 @@ class VolumeType(generic.View):
@urls.register
class VolumeSnapshots(generic.View):
- """API for cinder volume snapshots.
- """
+ """API for cinder volume snapshots."""
url_regex = r'cinder/volumesnapshots/$'
@rest_utils.ajax()
def get(self, request):
- """Get a detailed list of volume snapshots associated with the current
- user's project.
+ """Get a list of volume snapshots associated with the current project.
The listing result is an object with property "items".
"""
@@ -277,8 +269,7 @@ class VolumeTypeMetadata(generic.View):
@urls.register
class Extensions(generic.View):
- """API for cinder extensions.
- """
+ # API for cinder extensions.
url_regex = r'cinder/extensions/$'
@rest_utils.ajax()
@@ -324,13 +315,13 @@ class TenantAbsoluteLimits(generic.View):
@urls.register
class Services(generic.View):
- """API for cinder services.
- """
+ """API for cinder services."""
url_regex = r'cinder/services/$'
@rest_utils.ajax()
def get(self, request):
"""Get a list of cinder services.
+
Will return HTTP 501 status code if the service_list extension is
not supported.
"""
@@ -352,8 +343,7 @@ class Services(generic.View):
@urls.register
class DefaultQuotaSets(generic.View):
- """API for getting default quotas for cinder
- """
+ """API for getting default quotas for cinder"""
url_regex = r'cinder/quota-sets/defaults/$'
@rest_utils.ajax()
@@ -400,8 +390,7 @@ class DefaultQuotaSets(generic.View):
@urls.register
class QuotaSets(generic.View):
- """API for setting quotas for a given project.
- """
+ """API for setting quotas for a given project."""
url_regex = r'cinder/quota-sets/(?P<project_id>[0-9a-f]+)$'
@rest_utils.ajax(data_required=True)
diff --git a/openstack_dashboard/api/rest/glance.py b/openstack_dashboard/api/rest/glance.py
index 7fe8aac8f..6c66b3c1e 100644
--- a/openstack_dashboard/api/rest/glance.py
+++ b/openstack_dashboard/api/rest/glance.py
@@ -11,8 +11,7 @@
# 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.
-"""API for the glance service.
-"""
+"""API for the glance service."""
from django import forms
from django.views.decorators.csrf import csrf_exempt
@@ -29,21 +28,18 @@ CLIENT_KEYWORDS = {'resource_type', 'marker',
@urls.register
class Version(generic.View):
- """API for active glance version.
- """
+ """API for active glance version."""
url_regex = r'glance/version/$'
@rest_utils.ajax()
def get(self, request):
- """Get active glance version.
- """
+ """Get active glance version."""
return {'version': str(api.glance.get_version())}
@urls.register
class Image(generic.View):
- """API for retrieving a single image
- """
+ """API for retrieving a single image"""
url_regex = r'glance/images/(?P<image_id>[^/]+|default)/$'
@rest_utils.ajax()
@@ -95,14 +91,12 @@ class Image(generic.View):
@urls.register
class ImageProperties(generic.View):
- """API for retrieving only a custom properties of single image.
- """
+ """API for retrieving only a custom properties of single image."""
url_regex = r'glance/images/(?P<image_id>[^/]+)/properties/'
@rest_utils.ajax()
def get(self, request, image_id):
- """Get custom properties of specific image.
- """
+ """Get custom properties of specific image."""
return api.glance.image_get(request, image_id).properties
@rest_utils.ajax(data_required=True)
@@ -123,8 +117,7 @@ class UploadObjectForm(forms.Form):
@urls.register
class Images(generic.View):
- """API for Glance images.
- """
+ """API for Glance images."""
url_regex = r'glance/images/$'
@rest_utils.ajax()
diff --git a/openstack_dashboard/api/rest/heat.py b/openstack_dashboard/api/rest/heat.py
index 19fdca4e7..df8752f1f 100644
--- a/openstack_dashboard/api/rest/heat.py
+++ b/openstack_dashboard/api/rest/heat.py
@@ -9,8 +9,7 @@
# 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.
-"""API for the heat service.
-"""
+"""API for the heat service."""
from django.views import generic
@@ -21,8 +20,7 @@ from openstack_dashboard.api.rest import utils as rest_utils
@urls.register
class Validate(generic.View):
- """API for validating a template
- """
+ """API for validating a template"""
url_regex = r'heat/validate/$'
@rest_utils.ajax(data_required=True)
@@ -40,14 +38,12 @@ class Validate(generic.View):
@urls.register
class Services(generic.View):
- """API for heat services.
- """
+ """API for heat services."""
url_regex = r'heat/services/$'
@rest_utils.ajax()
def get(self, request):
- """Get a list of heat services.
- """
+ """Get a list of heat services."""
if api.base.is_service_enabled(request, 'orchestration'):
result = api.heat.service_list(request)
return {'items': [u.to_dict() for u in result]}
diff --git a/openstack_dashboard/api/rest/json_encoder.py b/openstack_dashboard/api/rest/json_encoder.py
index 2f203514e..91f156174 100644
--- a/openstack_dashboard/api/rest/json_encoder.py
+++ b/openstack_dashboard/api/rest/json_encoder.py
@@ -25,7 +25,9 @@ class NaNJSONEncoder(json.JSONEncoder):
super(NaNJSONEncoder, self).__init__(**kwargs)
def iterencode(self, o, _one_shot=False):
- """The sole purpose of defining a custom JSONEncoder class is to
+ """JSON encoder with NaN and float inf support.
+
+ The sole purpose of defining a custom JSONEncoder class is to
override floatstr() inner function, or more specifically the
representation of NaN and +/-float('inf') values in a JSON. Although
Infinity values are not supported by JSON standard, we still can
diff --git a/openstack_dashboard/api/rest/keystone.py b/openstack_dashboard/api/rest/keystone.py
index 4e44d9d30..32df3ad41 100644
--- a/openstack_dashboard/api/rest/keystone.py
+++ b/openstack_dashboard/api/rest/keystone.py
@@ -11,8 +11,7 @@
# 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.
-"""API over the keystone service.
-"""
+"""API over the keystone service."""
from django.conf import settings
import django.http
@@ -25,21 +24,18 @@ from openstack_dashboard.api.rest import utils as rest_utils
@urls.register
class Version(generic.View):
- """API for active keystone version.
- """
+ """API for active keystone version."""
url_regex = r'keystone/version/$'
@rest_utils.ajax()
def get(self, request):
- """Get active keystone version.
- """
+ """Get active keystone version."""
return {'version': str(api.keystone.get_version())}
@urls.register
class Users(generic.View):
- """API for keystone users.
- """
+ """API for keystone users."""
url_regex = r'keystone/users/$'
client_keywords = {'project_id', 'domain_id', 'group_id'}
@@ -113,8 +109,7 @@ class Users(generic.View):
@urls.register
class User(generic.View):
- """API for a single keystone user.
- """
+ """API for a single keystone user."""
url_regex = r'keystone/users/(?P<id>[0-9a-f]+|current)$'
@rest_utils.ajax()
@@ -172,8 +167,7 @@ class User(generic.View):
@urls.register
class Roles(generic.View):
- """API over all roles.
- """
+ """API over all roles."""
url_regex = r'keystone/roles/$'
@rest_utils.ajax()
@@ -230,8 +224,7 @@ class Roles(generic.View):
@urls.register
class Role(generic.View):
- """API for a single role.
- """
+ """API for a single role."""
url_regex = r'keystone/roles/(?P<id>[0-9a-f]+|default)$'
@rest_utils.ajax()
@@ -269,8 +262,7 @@ class Role(generic.View):
@urls.register
class Domains(generic.View):
- """API over all domains.
- """
+ """API over all domains."""
url_regex = r'keystone/domains/$'
@rest_utils.ajax()
@@ -321,8 +313,7 @@ class Domains(generic.View):
@urls.register
class Domain(generic.View):
- """API over a single domains.
- """
+ """API over a single domains."""
url_regex = r'keystone/domains/(?P<id>[0-9a-f]+|default)$'
@rest_utils.ajax()
@@ -477,8 +468,7 @@ class Project(generic.View):
@rest_utils.ajax()
def get(self, request, id):
- """Get a specific project by id.
- """
+ """Get a specific project by id."""
return api.keystone.tenant_get(request, id).to_dict()
@rest_utils.ajax()
@@ -532,16 +522,13 @@ class ServiceCatalog(generic.View):
@rest_utils.ajax()
def get(self, request):
- """Return the Keystone service catalog associated with the current
- user.
- """
+ """Return the service catalog associated with the current user."""
return request.user.service_catalog
@urls.register
class UserSession(generic.View):
- """API for a single keystone user.
- """
+ """API for a single keystone user."""
url_regex = r'keystone/user-session/$'
allowed_fields = {
'available_services_regions',
@@ -561,8 +548,7 @@ class UserSession(generic.View):
@rest_utils.ajax()
def get(self, request):
- """Get the current user session.
- """
+ """Get the current user session."""
res = {k: getattr(request.user, k, None) for k in self.allowed_fields}
if getattr(settings, 'ENABLE_CLIENT_TOKEN', True):
res['token'] = request.user.token.id
@@ -571,14 +557,12 @@ class UserSession(generic.View):
@urls.register
class Services(generic.View):
- """API for keystone services.
- """
+ """API for keystone services."""
url_regex = r'keystone/services/$'
@rest_utils.ajax()
def get(self, request):
- """Get a list of keystone services.
- """
+ """Get a list of keystone services."""
region = request.user.services_region
services = []
for i, service in enumerate(request.user.service_catalog):
@@ -591,13 +575,13 @@ class Services(generic.View):
@urls.register
class Groups(generic.View):
- """API over all groups.
- """
+ """API over all groups."""
url_regex = r'keystone/groups/$'
@rest_utils.ajax()
def get(self, request):
"""Get a list of groups.
+
The listing result is an object with property "items".
"""
domain_context = request.session.get('domain_context')
diff --git a/openstack_dashboard/api/rest/network.py b/openstack_dashboard/api/rest/network.py
index 9b8754449..850dee9d0 100644
--- a/openstack_dashboard/api/rest/network.py
+++ b/openstack_dashboard/api/rest/network.py
@@ -13,8 +13,7 @@
# 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.
-"""API for the network abstraction APIs.
-"""
+"""API for the network abstraction APIs."""
from django.views import generic
@@ -49,8 +48,7 @@ class SecurityGroups(generic.View):
@urls.register
class FloatingIP(generic.View):
- """API for a single floating IP address.
- """
+ """API for a single floating IP address."""
url_regex = r'network/floatingip/$'
@rest_utils.ajax(data_required=True)
@@ -84,8 +82,7 @@ class FloatingIP(generic.View):
@urls.register
class FloatingIPs(generic.View):
- """API for floating IP addresses.
- """
+ """API for floating IP addresses."""
url_regex = r'network/floatingips/$'
@rest_utils.ajax()
@@ -104,8 +101,7 @@ class FloatingIPs(generic.View):
@urls.register
class FloatingIPPools(generic.View):
- """API for floating IP pools.
- """
+ """API for floating IP pools."""
url_regex = r'network/floatingippools/$'
@rest_utils.ajax()
diff --git a/openstack_dashboard/api/rest/neutron.py b/openstack_dashboard/api/rest/neutron.py
index 704fb8fde..63d563924 100644
--- a/openstack_dashboard/api/rest/neutron.py
+++ b/openstack_dashboard/api/rest/neutron.py
@@ -12,8 +12,7 @@
# 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.
-"""API over the neutron service.
-"""
+"""API over the neutron service."""
from django.utils.translation import ugettext_lazy as _
from django.views import generic
@@ -72,7 +71,8 @@ class Networks(generic.View):
@urls.register
class Subnets(generic.View):
- """API for Neutron SubNets
+ """API for Neutron Subnets
+
http://developer.openstack.org/api-ref-networking-v2.html#subnets
"""
url_regex = r'neutron/subnets/$'
@@ -119,6 +119,7 @@ class Subnets(generic.View):
@urls.register
class Ports(generic.View):
"""API for Neutron Ports
+
http://developer.openstack.org/api-ref-networking-v2.html#ports
"""
url_regex = r'neutron/ports/$'
@@ -138,8 +139,7 @@ class Ports(generic.View):
@urls.register
class Trunks(generic.View):
- """API for neutron Trunks
- """
+ """API for neutron Trunks"""
url_regex = r'neutron/trunks/$'
@rest_utils.ajax()
@@ -155,14 +155,12 @@ class Trunks(generic.View):
@urls.register
class Services(generic.View):
- """API for Neutron agents
- """
+ """API for Neutron agents"""
url_regex = r'neutron/agents/$'
@rest_utils.ajax()
def get(self, request):
- """Get a list of agents
- """
+ """Get a list of agents"""
if api.base.is_service_enabled(request, 'network') and \
api.neutron.is_extension_supported(request, 'agent'):
result = api.neutron.agent_list(request, **request.GET)
@@ -173,8 +171,7 @@ class Services(generic.View):
@urls.register
class Extensions(generic.View):
- """API for neutron extensions.
- """
+ """API for neutron extensions."""
url_regex = r'neutron/extensions/$'
@rest_utils.ajax()
@@ -192,8 +189,7 @@ class Extensions(generic.View):
class DefaultQuotaSets(generic.View):
- """API for getting default quotas for neutron
- """
+ """API for getting default quotas for neutron"""
url_regex = r'neutron/quota-sets/defaults/$'
@rest_utils.ajax()
@@ -218,8 +214,7 @@ class DefaultQuotaSets(generic.View):
@urls.register
class QuotasSets(generic.View):
- """API for setting quotas of a given project.
- """
+ """API for setting quotas of a given project."""
url_regex = r'neutron/quotas-sets/(?P<project_id>[0-9a-f]+)$'
@rest_utils.ajax(data_required=True)
diff --git a/openstack_dashboard/api/rest/nova.py b/openstack_dashboard/api/rest/nova.py
index 9aec4941f..d0934d009 100644
--- a/openstack_dashboard/api/rest/nova.py
+++ b/openstack_dashboard/api/rest/nova.py
@@ -11,8 +11,7 @@
# 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.
-"""API over the nova service.
-"""
+"""API over the nova service."""
from collections import OrderedDict
from django.http import HttpResponse
@@ -34,8 +33,7 @@ from openstack_dashboard.usage import quotas
@urls.register
class Snapshots(generic.View):
- """API for nova snapshots.
- """
+ """API for nova snapshots."""
url_regex = r'nova/snapshots/$'
@rest_utils.ajax(data_required=True)
@@ -50,14 +48,12 @@ class Snapshots(generic.View):
@urls.register
class Keypairs(generic.View):
- """API for nova keypairs.
- """
+ """API for nova keypairs."""
url_regex = r'nova/keypairs/$'
@rest_utils.ajax()
def get(self, request):
- """Get a list of keypairs associated with the current logged-in
- account.
+ """Get a list of keypairs associated with the current logged-in user.
The listing result is an object with property "items".
"""
@@ -130,13 +126,13 @@ class Keypair(generic.View):
@urls.register
class Services(generic.View):
- """API for nova services.
- """
+ """API for nova services."""
url_regex = r'nova/services/$'
@rest_utils.ajax()
def get(self, request):
"""Get a list of nova services.
+
Will return HTTP 501 status code if the service_list extension is
not supported.
"""
@@ -150,8 +146,7 @@ class Services(generic.View):
@urls.register
class AvailabilityZones(generic.View):
- """API for nova availability zones.
- """
+ """API for nova availability zones."""
url_regex = r'nova/availzones/$'
@rest_utils.ajax()
@@ -173,8 +168,7 @@ class AvailabilityZones(generic.View):
@urls.register
class Limits(generic.View):
- """API for nova limits.
- """
+ """API for nova limits."""
url_regex = r'nova/limits/$'
@rest_utils.ajax(json_encoder=json_encoder.NaNJSONEncoder)
@@ -199,8 +193,7 @@ class Limits(generic.View):
@urls.register
class ServerActions(generic.View):
- """API over all server actions.
- """
+ """API over all server actions."""
url_regex = r'nova/servers/(?P<server_id>[^/]+)/actions/$'
@rest_utils.ajax()
@@ -219,8 +212,7 @@ class ServerActions(generic.View):
@urls.register
class SecurityGroups(generic.View):
- """API over all server security groups.
- """
+ """API over all server security groups."""
url_regex = r'nova/servers/(?P<server_id>[^/]+)/security-groups/$'
@rest_utils.ajax()
@@ -239,8 +231,7 @@ class SecurityGroups(generic.View):
@urls.register
class Volumes(generic.View):
- """API over all server volumes.
- """
+ """API over all server volumes."""
url_regex = r'nova/servers/(?P<server_id>[^/]+)/volumes/$'
@rest_utils.ajax()
@@ -259,14 +250,12 @@ class Volumes(generic.View):
@urls.register
class RemoteConsoleInfo(generic.View):
- """API for remote console information.
- """
+ """API for remote console information."""
url_regex = r'nova/servers/(?P<server_id>[^/]+)/console-info/$'
@rest_utils.ajax()
def post(self, request, server_id):
- """Gets information about an available remote console for the given
- server.
+ """Gets information of a remote console for the given server.
Example POST:
http://localhost/api/nova/servers/abcd/console-info/
@@ -317,8 +306,7 @@ class RemoteConsoleInfo(generic.View):
@urls.register
class ConsoleOutput(generic.View):
- """API for console output.
- """
+ """API for console output."""
url_regex = r'nova/servers/(?P<server_id>[^/]+)/console-output/$'
@rest_utils.ajax()
@@ -339,8 +327,7 @@ class ConsoleOutput(generic.View):
@urls.register
class Servers(generic.View):
- """API over all servers.
- """
+ """API over all servers."""
url_regex = r'nova/servers/$'
_optional_create = [
@@ -415,8 +402,7 @@ class Servers(generic.View):
@urls.register
class Server(generic.View):
- """API for retrieving a single server
- """
+ """API for retrieving a single server"""
url_regex = r'nova/servers/(?P<server_id>[^/]+|default)$'
@rest_utils.ajax()
@@ -429,8 +415,7 @@ class Server(generic.View):
@rest_utils.ajax(data_required=True)
def post(self, request, server_id):
- """Perform a change to a server
- """
+ """Perform a change to a server"""
operation = request.DATA.get('operation', 'none')
operations = {
'stop': api.nova.server_stop,
@@ -451,8 +436,7 @@ class Server(generic.View):
@urls.register
class ServerGroups(generic.View):
- """API for nova server groups.
- """
+ """API for nova server groups."""
url_regex = r'nova/servergroups/$'
@rest_utils.ajax()
@@ -467,8 +451,7 @@ class ServerGroups(generic.View):
@urls.register
class ServerMetadata(generic.View):
- """API for server metadata.
- """
+ """API for server metadata."""
url_regex = r'nova/servers/(?P<server_id>[^/]+|default)/metadata$'
@rest_utils.ajax()
@@ -496,8 +479,7 @@ class ServerMetadata(generic.View):
@urls.register
class Extensions(generic.View):
- """API for nova extensions.
- """
+ """API for nova extensions."""
url_regex = r'nova/extensions/$'
@rest_utils.ajax()
@@ -516,8 +498,7 @@ class Extensions(generic.View):
@urls.register
class Flavors(generic.View):
- """API for nova flavors.
- """
+ """API for nova flavors."""
url_regex = r'nova/flavors/$'
@rest_utils.ajax()
@@ -580,8 +561,7 @@ class Flavors(generic.View):
@urls.register
class Flavor(generic.View):
- """API for retrieving a single flavor
- """
+ """API for retrieving a single flavor"""
url_regex = r'nova/flavors/(?P<flavor_id>[^/]+)/$'
@rest_utils.ajax()
@@ -654,8 +634,7 @@ class Flavor(generic.View):
@urls.register
class FlavorExtraSpecs(generic.View):
- """API for managing flavor extra specs
- """
+ """API for managing flavor extra specs"""
url_regex = r'nova/flavors/(?P<flavor_id>[^/]+)/extra-specs/$'
@rest_utils.ajax()
@@ -684,8 +663,7 @@ class FlavorExtraSpecs(generic.View):
@urls.register
class AggregateExtraSpecs(generic.View):
- """API for managing aggregate extra specs
- """
+ """API for managing aggregate extra specs"""
url_regex = r'nova/aggregates/(?P<aggregate_id>[^/]+)/extra-specs/$'
@rest_utils.ajax()
@@ -712,8 +690,7 @@ class AggregateExtraSpecs(generic.View):
@urls.register
class DefaultQuotaSets(generic.View):
- """API for getting default quotas for nova
- """
+ """API for getting default quotas for nova"""
url_regex = r'nova/quota-sets/defaults/$'
@rest_utils.ajax()
@@ -771,8 +748,7 @@ class DefaultQuotaSets(generic.View):
@urls.register
class EditableQuotaSets(generic.View):
- """API for editable quotas.
- """
+ """API for editable quotas."""
url_regex = r'nova/quota-sets/editable/$'
@rest_utils.ajax()
@@ -791,8 +767,7 @@ class EditableQuotaSets(generic.View):
@urls.register
class QuotaSets(generic.View):
- """API for setting quotas for a given project.
- """
+ """API for setting quotas for a given project."""
url_regex = r'nova/quota-sets/(?P<project_id>[0-9a-f]+)$'
@rest_utils.ajax(data_required=True)
diff --git a/openstack_dashboard/api/rest/swift.py b/openstack_dashboard/api/rest/swift.py
index 9419a1903..273ec7bc3 100644
--- a/openstack_dashboard/api/rest/swift.py
+++ b/openstack_dashboard/api/rest/swift.py
@@ -11,8 +11,8 @@
# 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.
-"""API for the swift service.
-"""
+"""API for the swift service."""
+
import os
from django import forms
@@ -31,22 +31,19 @@ from openstack_dashboard.api import swift
@urls.register
class Info(generic.View):
- """API for information about the Swift installation.
- """
+ """API for information about the Swift installation."""
url_regex = r'swift/info/$'
@rest_utils.ajax()
def get(self, request):
- """Get information about the Swift installation.
- """
+ """Get information about the Swift installation."""
capabilities = api.swift.swift_get_capabilities(request)
return {'info': capabilities}
@urls.register
class Containers(generic.View):
- """API for swift container listing for an account
- """
+ """API for swift container listing for an account"""
url_regex = r'swift/containers/$'
@rest_utils.ajax()
@@ -71,15 +68,13 @@ class Containers(generic.View):
@urls.register
class Container(generic.View):
- """API for swift container level information
- """
+ """API for swift container level information"""
url_regex = r'swift/containers/(?P<container>[^/]+)/metadata/$'
@rest_utils.ajax()
def get(self, request, container):
- """Get the container details
- """
+ """Get the container details"""
return api.swift.swift_get_container(request, container).to_dict()
@rest_utils.ajax()
@@ -117,8 +112,7 @@ class Container(generic.View):
@urls.register
class Objects(generic.View):
- """API for a list of swift objects
- """
+ """API for a list of swift objects"""
url_regex = r'swift/containers/(?P<container>[^/]+)/objects/$'
@rest_utils.ajax()
@@ -158,8 +152,7 @@ class UploadObjectForm(forms.Form):
@urls.register
class Object(generic.View):
- """API for a single swift object or pseudo-folder
- """
+ """API for a single swift object or pseudo-folder"""
url_regex = r'swift/containers/(?P<container>[^/]+)/object/' \
'(?P<object_name>.+)$'
@@ -219,8 +212,7 @@ class Object(generic.View):
api.swift.swift_delete_object(request, container, object_name)
def get(self, request, container, object_name):
- """Get the object contents.
- """
+ """Get the object contents."""
obj = api.swift.swift_get_object(
request,
container,
@@ -245,8 +237,7 @@ class Object(generic.View):
@urls.register
class ObjectMetadata(generic.View):
- """API for a single swift object
- """
+ """API for a single swift object"""
url_regex = r'swift/containers/(?P<container>[^/]+)/metadata/' \
'(?P<object_name>.+)$'
@@ -262,8 +253,7 @@ class ObjectMetadata(generic.View):
@urls.register
class ObjectCopy(generic.View):
- """API to copy a swift object
- """
+ """API to copy a swift object"""
url_regex = r'swift/containers/(?P<container>[^/]+)/copy/' \
'(?P<object_name>.+)$'
diff --git a/openstack_dashboard/api/rest/urls.py b/openstack_dashboard/api/rest/urls.py
index e4556ea9a..8ba246586 100644
--- a/openstack_dashboard/api/rest/urls.py
+++ b/openstack_dashboard/api/rest/urls.py
@@ -20,13 +20,13 @@ urlpatterns = []
# @register below, and the import the endpoint module in the
# rest_api/__init__.py module
def register(view):
- '''Register API views to respond to a regex pattern (url_regex on the
- view class).
+ """Register API views to respond to a regex pattern.
+ ``url_regex`` on a wrapped view class is used as the regex pattern.
The view should be a standard Django class-based view implementing an
as_view() method. The url_regex attribute of the view should be a standard
Django URL regex pattern.
- '''
+ """
p = urls.url(view.url_regex, view.as_view())
urlpatterns.append(p)
return view
diff --git a/openstack_dashboard/api/rest/utils.py b/openstack_dashboard/api/rest/utils.py
index bafce7db9..4471b5e58 100644
--- a/openstack_dashboard/api/rest/utils.py
+++ b/openstack_dashboard/api/rest/utils.py
@@ -75,7 +75,9 @@ class JSONResponse(_RestResponse):
def ajax(authenticated=True, data_required=False,
json_encoder=json.JSONEncoder):
- '''Provide a decorator to wrap a view method so that it may exist in an
+ """Decorator to allow the wrappered view to exist in an AJAX environment.
+
+ Provide a decorator to wrap a view method so that it may exist in an
entirely AJAX environment:
- data decoded from JSON as input and data coded as JSON as output
@@ -98,7 +100,7 @@ def ajax(authenticated=True, data_required=False,
Methods returning nothing (or None explicitly) will result in a 204 "NO
CONTENT" being returned to the caller.
- '''
+ """
def decorator(function, authenticated=authenticated,
data_required=data_required):
@functools.wraps(function,
@@ -173,7 +175,9 @@ def parse_filters_kwargs(request, client_keywords=None):
def post2data(func):
- """The sole purpose of this decorator is to restore original form values
+ """Decorator to restore original form values along with their types.
+
+ The sole purpose of this decorator is to restore original form values
along with their types stored on client-side under key $$originalJSON.
This in turn prevents the loss of field types when they are passed with
header 'Content-Type: multipart/form-data', which is needed to pass a
diff --git a/openstack_dashboard/dashboards/admin/hypervisors/tests.py b/openstack_dashboard/dashboards/admin/hypervisors/tests.py
index 7a3ed51bc..61cbcaa99 100644
--- a/openstack_dashboard/dashboards/admin/hypervisors/tests.py
+++ b/openstack_dashboard/dashboards/admin/hypervisors/tests.py
@@ -71,9 +71,9 @@ class HypervisorViewTest(test.BaseAdminViewTests):
'hypervisor_stats',
'service_list')})
def test_service_list_unavailable(self):
- """test that error message should be returned when
- nova.service_list isn't available
- """
+ # test that error message should be returned when
+ # nova.service_list isn't available.
+
hypervisors = self.hypervisors.list()
stats = self.hypervisors.stats
api.nova.hypervisor_list(IsA(http.HttpRequest)).AndReturn(hypervisors)
diff --git a/openstack_dashboard/dashboards/project/images/images/forms.py b/openstack_dashboard/dashboards/project/images/images/forms.py
index dd36641ad..2e2788fd8 100644
--- a/openstack_dashboard/dashboards/project/images/images/forms.py
+++ b/openstack_dashboard/dashboards/project/images/images/forms.py
@@ -45,9 +45,8 @@ class ImageURLField(forms.URLField):
def create_image_metadata(data):
- """Use the given dict of image form data to generate the metadata used for
- creating the image in glance.
- """
+ """Generate metadata dict for a new image from a given form data."""
+
# Glance does not really do anything with container_format at the
# moment. It requires it is set to the same disk_format for the three
# Amazon image types, otherwise it just treats them as 'bare.' As such
diff --git a/openstack_dashboard/dashboards/project/images/utils.py b/openstack_dashboard/dashboards/project/images/utils.py
index 9bfee8cfa..69e82a7e6 100644
--- a/openstack_dashboard/dashboards/project/images/utils.py
+++ b/openstack_dashboard/dashboards/project/images/utils.py
@@ -19,13 +19,12 @@ from openstack_dashboard.api import glance
def get_available_images(request, project_id=None, images_cache=None):
- """Returns a list of images that are public or owned by the given
- project_id. If project_id is not specified, only public images
- are returned.
+ """Returns a list of images that are public or owned by the given project.
+
+ If project_id is not specified, only public images are returned.
:param images_cache: An optional dict-like object in which to
cache public and per-project id image metadata.
-
"""
if images_cache is None:
images_cache = {}
diff --git a/openstack_dashboard/dashboards/project/instances/tables.py b/openstack_dashboard/dashboards/project/instances/tables.py
index 4ed11704b..3f52f6cc4 100644
--- a/openstack_dashboard/dashboards/project/instances/tables.py
+++ b/openstack_dashboard/dashboards/project/instances/tables.py
@@ -101,9 +101,6 @@ class DeleteInstance(policy.PolicyTargetMixin, tables.DeleteAction):
)
def allowed(self, request, instance=None):
- """Allow delete action if instance is in error state or not currently
- being deleted.
- """
error_state = False
if instance:
error_state = (instance.status == 'ERROR')
diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py
index 9c46324aa..7d1c49301 100644
--- a/openstack_dashboard/dashboards/project/instances/tests.py
+++ b/openstack_dashboard/dashboards/project/instances/tests.py
@@ -3920,9 +3920,9 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
api.network: ('servers_update_addresses',),
})
def test_index_form_action_with_pagination(self):
- """The form action on the next page should have marker
- object from the previous page last element.
- """
+ # The form action on the next page should have marker
+ # object from the previous page last element.
+
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 2)
servers = self.servers.list()[:3]
@@ -3984,9 +3984,8 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
api.glance: ('image_list_detailed',),
api.network: ('servers_update_addresses',)})
def test_delete_instance_with_pagination(self):
- """Instance should be deleted from
- the next page.
- """
+ # Instance should be deleted from the next page.
+
page_size = getattr(settings, 'API_RESULT_PAGE_SIZE', 2)
servers = self.servers.list()[:3]
server = servers[-1]
diff --git a/openstack_dashboard/dashboards/project/instances/utils.py b/openstack_dashboard/dashboards/project/instances/utils.py
index 4f73bc07e..5749d3127 100644
--- a/openstack_dashboard/dashboards/project/instances/utils.py
+++ b/openstack_dashboard/dashboards/project/instances/utils.py
@@ -35,10 +35,10 @@ def flavor_list(request):
def sort_flavor_list(request, flavors):
"""Utility method to sort a list of flavors.
- By default, returns the available flavors, sorted by RAM
- usage (ascending). Override these behaviours with a
- CREATE_INSTANCE_FLAVOR_SORT dict
- in local_settings.py.
+
+ By default, returns the available flavors, sorted by RAM usage (ascending).
+ Override these behaviours with a ``CREATE_INSTANCE_FLAVOR_SORT`` dict
+ in ``local_settings.py``.
"""
def get_key(flavor, sort_key):
try:
diff --git a/openstack_dashboard/dashboards/project/network_topology/views.py b/openstack_dashboard/dashboards/project/network_topology/views.py
index abe66205f..cbf101cda 100644
--- a/openstack_dashboard/dashboards/project/network_topology/views.py
+++ b/openstack_dashboard/dashboards/project/network_topology/views.py
@@ -85,8 +85,10 @@ console_invalid_status = {
class TranslationHelper(object):
- """Helper class to provide the translations of instances, networks,
- routers and ports from other parts of the code to the network topology
+ """Helper class to provide the translations.
+
+ This allows the network topology to access the translated strings
+ for various resources defined in other parts of the code.
"""
def __init__(self):
# turn translation tuples into dicts for easy access
diff --git a/openstack_dashboard/dashboards/project/security_groups/tests.py b/openstack_dashboard/dashboards/project/security_groups/tests.py
index 35790d398..6691f04e4 100644
--- a/openstack_dashboard/dashboards/project/security_groups/tests.py
+++ b/openstack_dashboard/dashboards/project/security_groups/tests.py
@@ -228,8 +228,7 @@ class SecurityGroupsViewTests(test.TestCase):
self._create_security_group(sec_group)
def test_create_security_groups_special_chars(self):
- """Ensure that a group name is not restricted to alphanumeric
- characters.
+ """Ensure non-alphanumeric characters can be used as a group name.
bug #1233501 Security group names cannot contain at characters
bug #1224576 Security group names cannot contain spaces
diff --git a/openstack_dashboard/dashboards/project/volumes/tables.py b/openstack_dashboard/dashboards/project/volumes/tables.py
index f4d5c475b..d4928da70 100644
--- a/openstack_dashboard/dashboards/project/volumes/tables.py
+++ b/openstack_dashboard/dashboards/project/volumes/tables.py
@@ -566,9 +566,6 @@ class DetachVolume(tables.BatchAction):
class AttachedInstanceColumn(tables.WrappingColumn):
- """Customized column class that does complex processing on the attachments
- for a volume instance.
- """
def get_raw_data(self, attachment):
request = self.table.request
return safestring.mark_safe(get_attachment_name(request, attachment))
diff --git a/openstack_dashboard/test/integration_tests/basewebobject.py b/openstack_dashboard/test/integration_tests/basewebobject.py
index 16b2de8f2..3cc13e12e 100644
--- a/openstack_dashboard/test/integration_tests/basewebobject.py
+++ b/openstack_dashboard/test/integration_tests/basewebobject.py
@@ -93,8 +93,9 @@ class BaseWebObject(unittest.TestCase):
self.driver.implicitly_wait(self.conf.selenium.implicit_wait)
def _wait_until(self, predicate, timeout=None, poll_frequency=0.5):
- """Wait until the value returned by predicate is not False or
- the timeout is elapsed.
+ """Wait until the value returned by predicate is not False.
+
+ It also returns when the timeout is elapsed.
'predicate' takes the driver as argument.
"""
if not timeout:
@@ -103,10 +104,12 @@ class BaseWebObject(unittest.TestCase):
predicate)
def _wait_till_text_present_in_element(self, element, texts, timeout=None):
- """Waiting for a text to appear in a certain element very often is
- actually waiting for a _different_ element with a different text to
- appear in place of an old element. So a way to avoid capturing stale
- element reference should be provided for this use case.
+ """Waiting for a text to appear in a certain element.
+
+ Most frequent usage is actually to wait for a _different_ element
+ with a different text to appear in place of an old element.
+ So a way to avoid capturing stale element reference should be provided
+ for this use case.
Better to wrap getting entity status cell in a lambda
to avoid problems with cell being replaced with totally different
diff --git a/openstack_dashboard/test/integration_tests/decorators.py b/openstack_dashboard/test/integration_tests/decorators.py
index a787aebf8..8748a9876 100644
--- a/openstack_dashboard/test/integration_tests/decorators.py
+++ b/openstack_dashboard/test/integration_tests/decorators.py
@@ -32,7 +32,9 @@ def _is_test_cls(cls):
def _mark_method_skipped(meth, reason):
- """Mark method as skipped by replacing the actual method with wrapper
+ """Decorate to mark method as skipped.
+
+ This marks method as skipped by replacing the actual method with wrapper
that raises the testtools.testcase.TestSkipped exception.
"""
@@ -71,8 +73,9 @@ def _get_skip_method(obj):
def services_required(*req_services):
- """Decorator for marking test's service requirements,
- if requirements are not met in the configuration file
+ """Decorator for marking test's service requirements.
+
+ If requirements are not met in the configuration file
test is marked as skipped.
Usage:
@@ -110,8 +113,9 @@ def services_required(*req_services):
def _parse_compound_config_option_value(option_name):
- """Parses the value of a given config option where option's section name is
- separated from option name by '.'.
+ """Parses the value of a given config option.
+
+ The section name of the option is separated from option name by '.'.
"""
name_parts = option_name.split('.')
name_parts.reverse()
@@ -163,8 +167,7 @@ def skip_because(**kwargs):
def attach_video(func):
- """Notify test runner to attach test video in any case
- """
+ """Notify test runner to attach test video in any case"""
@functools.wraps(func)
def wrapper(self, *args, **kwgs):
diff --git a/openstack_dashboard/test/integration_tests/helpers.py b/openstack_dashboard/test/integration_tests/helpers.py
index 117c41f02..5671cef35 100644
--- a/openstack_dashboard/test/integration_tests/helpers.py
+++ b/openstack_dashboard/test/integration_tests/helpers.py
@@ -200,8 +200,9 @@ class BaseTestCase(testtools.TestCase):
super(BaseTestCase, self).addOnException(wrapped_handler)
def _configure_log(self):
- """Configure log to capture test logs include selenium logs in order
- to attach them if test will be broken.
+ """Configure log to capture test logs include selenium logs.
+
+ This allows us to attach them if test will be broken.
"""
# clear other handlers to set target handler
ROOT_LOGGER.handlers[:] = []
@@ -276,8 +277,10 @@ class BaseTestCase(testtools.TestCase):
return rec(_log)
def zoom_out(self, times=3):
- """Zooming out prevents different elements being driven out of xvfb
- viewport (which in Selenium>=2.50.1 prevents interaction with them.
+ """Zooming out a specified element.
+
+ It prevents different elements being driven out of xvfb viewport
+ (which in Selenium>=2.50.1 prevents interaction with them).
"""
html = self.driver.find_element(by.By.TAG_NAME, 'html')
html.send_keys(keys.Keys.NULL)
diff --git a/openstack_dashboard/test/integration_tests/pages/admin/system/metadatadefinitionspage.py b/openstack_dashboard/test/integration_tests/pages/admin/system/metadatadefinitionspage.py
index 115ea6c9c..35d7f041d 100644
--- a/openstack_dashboard/test/integration_tests/pages/admin/system/metadatadefinitionspage.py
+++ b/openstack_dashboard/test/integration_tests/pages/admin/system/metadatadefinitionspage.py
@@ -61,6 +61,7 @@ class MetadatadefinitionsPage(basepage.BaseNavigationPage):
def json_load_template(self, namespace_template_name):
"""Read template for namespace creation
+
:param namespace_template_name: Path to template
:return = json data container
"""
diff --git a/openstack_dashboard/test/integration_tests/pages/pageobject.py b/openstack_dashboard/test/integration_tests/pages/pageobject.py
index 91590a1fe..26948162d 100644
--- a/openstack_dashboard/test/integration_tests/pages/pageobject.py
+++ b/openstack_dashboard/test/integration_tests/pages/pageobject.py
@@ -56,6 +56,7 @@ class PageObject(basewebobject.BaseWebObject):
def switch_window(self, window_name=None, window_index=None):
"""Switches focus between the webdriver windows.
+
Args:
- window_name: The name of the window to switch to.
- window_index: The index of the window handle to switch to.
diff --git a/openstack_dashboard/test/integration_tests/regions/baseregion.py b/openstack_dashboard/test/integration_tests/regions/baseregion.py
index 5a47280ba..26e5f21f6 100644
--- a/openstack_dashboard/test/integration_tests/regions/baseregion.py
+++ b/openstack_dashboard/test/integration_tests/regions/baseregion.py
@@ -42,15 +42,15 @@ class BaseRegion(basewebobject.BaseWebObject):
self._dynamic_properties = {}
def __getattr__(self, name):
- """It is not possible to create property bounded just to object
- and not class at runtime, therefore it is necessary to
- override __getattr__ and make fake 'properties' by storing them in
- the protected attribute _dynamic_attributes and returning result
- of the method associated with the specified attribute.
+ # It is not possible to create property bounded just to object
+ # and not class at runtime, therefore it is necessary to
+ # override __getattr__ and make fake 'properties' by storing them in
+ # the protected attribute _dynamic_attributes and returning result
+ # of the method associated with the specified attribute.
+
+ # This way the feeling of having regions accessed as 'properties'
+ # is created, which is one of the requirement of page object pattern.
- This way the feeling of having regions accessed as 'properties'
- is created, which is one of the requirement of page object pattern.
- """
try:
return self._dynamic_properties[name]
except KeyError:
diff --git a/openstack_dashboard/test/integration_tests/regions/forms.py b/openstack_dashboard/test/integration_tests/regions/forms.py
index 342e029fa..6ecc993a4 100644
--- a/openstack_dashboard/test/integration_tests/regions/forms.py
+++ b/openstack_dashboard/test/integration_tests/regions/forms.py
@@ -287,9 +287,8 @@ class BaseFormRegion(baseregion.BaseRegion):
_default_form_locator = (by.By.CSS_SELECTOR, 'div.modal-dialog')
def __init__(self, driver, conf, src_elem=None):
- """In most cases forms can be located through _default_form_locator,
- so specifying source element can be skipped.
- """
+ # In most cases forms can be located through _default_form_locator,
+ # so specifying source element can be skipped.
if src_elem is None:
# fake self.src_elem must be set up in order self._get_element work
self.src_elem = driver
@@ -449,9 +448,10 @@ class TabbedFormRegion(FormRegion):
class DateFormRegion(BaseFormRegion):
- """Form that queries data to table that is regularly below the form,
- typical example is located on Project/Compute/Overview page.
- """
+ """Form that queries data to table that is regularly below the form.
+
+ A typical example is located on Project/Compute/Overview page.
+ """
_from_field_locator = (by.By.CSS_SELECTOR, 'input#id_start')
_to_field_locator = (by.By.CSS_SELECTOR, 'input#id_end')
diff --git a/openstack_dashboard/test/integration_tests/regions/menus.py b/openstack_dashboard/test/integration_tests/regions/menus.py
index 7b500f409..214747de1 100644
--- a/openstack_dashboard/test/integration_tests/regions/menus.py
+++ b/openstack_dashboard/test/integration_tests/regions/menus.py
@@ -221,8 +221,9 @@ class DropDownMenuRegion(baseregion.BaseRegion):
class UserDropDownMenuRegion(DropDownMenuRegion):
- """Drop down menu located in the right side of the topbar,
- contains links to settings and help.
+ """Drop down menu located in the right side of the topbar.
+
+ This menu contains links to settings and help.
"""
_settings_link_locator = (by.By.CSS_SELECTOR,
'a[href*="/settings/"]')
diff --git a/openstack_dashboard/test/integration_tests/regions/tables.py b/openstack_dashboard/test/integration_tests/regions/tables.py
index 46f9948f4..9742e2a9f 100644
--- a/openstack_dashboard/test/integration_tests/regions/tables.py
+++ b/openstack_dashboard/test/integration_tests/regions/tables.py
@@ -208,6 +208,7 @@ class TableRegion(baseregion.BaseRegion):
def assert_definition(self, expected_table_definition, sorting=False):
"""Checks that actual table is expected one.
+
Items to compare: 'next' and 'prev' links, count of rows and names of
elements in list
:param expected_table_definition: expected values (dictionary)
@@ -225,8 +226,7 @@ class TableRegion(baseregion.BaseRegion):
def bind_table_action(action_name):
- """A decorator to bind table region method to an actual table action
- button.
+ """Decorator to bind table region method to an actual table action button.
Many table actions when started (by clicking a corresponding button
in UI) lead to some form showing up. To further interact with this form,
diff --git a/openstack_dashboard/test/integration_tests/tests/test_credentials.py b/openstack_dashboard/test/integration_tests/tests/test_credentials.py
index 570483f27..9c61b39b1 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_credentials.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_credentials.py
@@ -43,6 +43,7 @@ class TestDownloadRCFile(helpers.AdminTestCase):
def test_download_rc_v2_file(self):
"""This is a basic scenario test:
+
Steps:
1) Login to Horizon Dashboard as admin user
2) Navigate to Project > Compute > Access & Security > API Access tab
@@ -62,6 +63,7 @@ class TestDownloadRCFile(helpers.AdminTestCase):
@decorators.skip_because(bugs=['1584057'])
def test_download_rc_v3_file(self):
"""This is a basic scenario test:
+
Steps:
1) Login to Horizon Dashboard as admin user
2) Navigate to Project > Compute > Access & Security > API Access tab
diff --git a/openstack_dashboard/test/integration_tests/tests/test_defaults.py b/openstack_dashboard/test/integration_tests/tests/test_defaults.py
index 9d6e46174..d11a2c9e6 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_defaults.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_defaults.py
@@ -25,6 +25,7 @@ class TestDefaults(helpers.AdminTestCase):
def test_update_defaults(self):
"""Tests the Update Default Quotas functionality:
+
1) Login as Admin and go to Admin > System > Defaults
2) Updates default Quotas by adding a random number between 1 and 10
3) Verifies that the updated values are present in the
diff --git a/openstack_dashboard/test/integration_tests/tests/test_flavors.py b/openstack_dashboard/test/integration_tests/tests/test_flavors.py
index f427b0ccf..8705d8d5d 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_flavors.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_flavors.py
@@ -80,6 +80,7 @@ class TestFlavors(helpers.AdminTestCase):
def test_flavor_create(self):
"""tests the flavor creation and deletion functionalities:
+
* creates a new flavor
* verifies the flavor appears in the flavors table
* deletes the newly created flavor
@@ -89,8 +90,7 @@ class TestFlavors(helpers.AdminTestCase):
self._delete_flavor(self.FLAVOR_NAME)
def test_flavor_update_info(self):
- """Tests the flavor Edit row action functionality:
- """
+ """Tests the flavor Edit row action functionality"""
self._create_flavor(self.FLAVOR_NAME)
diff --git a/openstack_dashboard/test/integration_tests/tests/test_host_aggregates.py b/openstack_dashboard/test/integration_tests/tests/test_host_aggregates.py
index 67ae46cec..3e0b410f6 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_host_aggregates.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_host_aggregates.py
@@ -20,6 +20,7 @@ class TestHostAggregates(helpers.AdminTestCase):
def test_host_aggregate_create(self):
"""tests the host aggregate creation and deletion functionalities:
+
* creates a new host aggregate
* verifies the host aggregate appears in the host aggregates table
* deletes the newly created host aggregate
diff --git a/openstack_dashboard/test/integration_tests/tests/test_images.py b/openstack_dashboard/test/integration_tests/tests/test_images.py
index 5360a7b99..fbc295083 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_images.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_images.py
@@ -74,6 +74,7 @@ class TestImagesBasic(TestImagesLegacy):
@decorators.skip_because(bugs=['1595335'])
def test_image_create_delete(self):
"""tests the image creation and deletion functionalities:
+
* creates a new image from horizon.conf http_image
* verifies the image appears in the images table as active
* deletes the newly created image
@@ -84,6 +85,7 @@ class TestImagesBasic(TestImagesLegacy):
def test_image_create_delete_from_local_file(self):
"""tests the image creation and deletion functionalities:
+
* downloads image from horizon.conf stated in http_image
* creates the image from the downloaded file
* verifies the image appears in the images table as active
@@ -96,20 +98,21 @@ class TestImagesBasic(TestImagesLegacy):
def test_images_pagination(self):
"""This test checks images pagination
- Steps:
- 1) Login to Horizon Dashboard as horizon user
- 2) Navigate to user settings page
- 3) Change 'Items Per Page' value to 1
- 4) Go to Project -> Compute -> Images page
- 5) Check that only 'Next' link is available, only one image is
- available (and it has correct name)
- 6) Click 'Next' and check that both 'Prev' and 'Next' links are
- available, only one image is available (and it has correct name)
- 7) Click 'Next' and check that only 'Prev' link is available,
- only one image is visible (and it has correct name)
- 8) Click 'Prev' and check results (should be the same as for step6)
- 9) Click 'Prev' and check results (should be the same as for step5)
- 10) Go to user settings page and restore 'Items Per Page'
+
+ Steps:
+ 1) Login to Horizon Dashboard as horizon user
+ 2) Navigate to user settings page
+ 3) Change 'Items Per Page' value to 1
+ 4) Go to Project -> Compute -> Images page
+ 5) Check that only 'Next' link is available, only one image is
+ available (and it has correct name)
+ 6) Click 'Next' and check that both 'Prev' and 'Next' links are
+ available, only one image is available (and it has correct name)
+ 7) Click 'Next' and check that only 'Prev' link is available,
+ only one image is visible (and it has correct name)
+ 8) Click 'Prev' and check results (should be the same as for step6)
+ 9) Click 'Prev' and check results (should be the same as for step5)
+ 10) Go to user settings page and restore 'Items Per Page'
"""
default_image_list = self.CONFIG.image.images_list
items_per_page = 1
@@ -148,6 +151,7 @@ class TestImagesBasic(TestImagesLegacy):
def test_update_image_metadata(self):
"""Test update image metadata
+
* logs in as admin user
* creates image from locally downloaded file
* verifies the image appears in the images table as active
@@ -176,6 +180,7 @@ class TestImagesBasic(TestImagesLegacy):
def test_remove_protected_image(self):
"""tests that protected image is not deletable
+
* logs in as admin user
* creates image from locally downloaded file
* verifies the image appears in the images table as active
@@ -215,6 +220,7 @@ class TestImagesBasic(TestImagesLegacy):
def test_edit_image_description_and_name(self):
"""tests that image description is editable
+
* creates image from locally downloaded file
* verifies the image appears in the images table as active
* toggle edit action and adds some description
@@ -263,12 +269,13 @@ class TestImagesAdvanced(TestImagesLegacy):
"""Login as demo user"""
def test_create_volume_from_image(self):
"""This test case checks create volume from image functionality:
- Steps:
- 1. Login to Horizon Dashboard as regular user
- 2. Navigate to Project -> Compute -> Images
- 3. Create new volume from image
- 4. Check that volume is created with expected name
- 5. Check that volume status is Available
+
+ Steps:
+ 1. Login to Horizon Dashboard as regular user
+ 2. Navigate to Project -> Compute -> Images
+ 3. Create new volume from image
+ 4. Check that volume is created with expected name
+ 5. Check that volume status is Available
"""
images_page = self.images_page
source_image = self.CONFIG.image.images_list[0]
@@ -290,13 +297,14 @@ class TestImagesAdvanced(TestImagesLegacy):
def test_launch_instance_from_image(self):
"""This test case checks launch instance from image functionality:
- Steps:
- 1. Login to Horizon Dashboard as regular user
- 2. Navigate to Project -> Compute -> Images
- 3. Launch new instance from image
- 4. Check that instance is create
- 5. Check that status of newly created instance is Active
- 6. Check that image_name in correct in instances table
+
+ Steps:
+ 1. Login to Horizon Dashboard as regular user
+ 2. Navigate to Project -> Compute -> Images
+ 3. Launch new instance from image
+ 4. Check that instance is create
+ 5. Check that status of newly created instance is Active
+ 6. Check that image_name in correct in instances table
"""
images_page = self.images_page
source_image = self.CONFIG.image.images_list[0]
@@ -331,15 +339,16 @@ class TestImagesAdmin(helpers.AdminTestCase, TestImagesLegacy):
def test_filter_images(self):
"""This test checks filtering of images
- Steps:
- 1) Login to Horizon dashboard as admin user
- 2) Go to Admin -> System -> Images
- 3) Use filter by Image Name
- 4) Check that filtered table has one image only (which name is
- equal to filter value)
- 5) Check that no other images in the table
- 6) Clear filter and set nonexistent image name. Check that 0 rows
- are displayed
+
+ Steps:
+ 1) Login to Horizon dashboard as admin user
+ 2) Go to Admin -> System -> Images
+ 3) Use filter by Image Name
+ 4) Check that filtered table has one image only (which name is
+ equal to filter value)
+ 5) Check that no other images in the table
+ 6) Clear filter and set nonexistent image name. Check that 0 rows
+ are displayed
"""
images_list = self.CONFIG.image.images_list
images_page = self.images_page
diff --git a/openstack_dashboard/test/integration_tests/tests/test_instances.py b/openstack_dashboard/test/integration_tests/tests/test_instances.py
index 8fc8ee6a5..3363236b4 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_instances.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_instances.py
@@ -24,6 +24,7 @@ class TestInstances(helpers.TestCase):
def test_create_delete_instance(self):
"""tests the instance creation and deletion functionality:
+
* creates a new instance in Project > Compute > Instances page
* verifies the instance appears in the instances table as active
* deletes the newly created instance via proper page (depends on user)
@@ -49,6 +50,7 @@ class TestInstances(helpers.TestCase):
@decorators.skip_because(bugs=['1584057'])
def test_instances_pagination(self):
"""This test checks instance pagination
+
Steps:
1) Login to Horizon Dashboard as regular user
2) Navigate to user settings page
@@ -57,9 +59,9 @@ class TestInstances(helpers.TestCase):
5) Create 2 instances
6) Go to appropriate page (depends on user)
7) Check that only 'Next' link is available, only one instance is
- available (and it has correct name) on the first page
+ available (and it has correct name) on the first page
8) Click 'Next' and check that on the second page only one instance is
- available (and it has correct name), there is no 'Next' link on page
+ available (and it has correct name), there is no 'Next' link on page
9) Go to user settings page and restore 'Items Per Page'
10) Delete created instances via proper page (depends on user)
"""
@@ -110,6 +112,7 @@ class TestInstances(helpers.TestCase):
def test_instances_pagination_and_filtration(self):
"""This test checks instance pagination and filtration
+
Steps:
1) Login to Horizon Dashboard as regular user
2) Go to to user settings page
@@ -118,11 +121,11 @@ class TestInstances(helpers.TestCase):
5) Create 2 instances
6) Go to appropriate page (depends on user)
7) Check filter by Name of the first and the second instance in order
- to have one instance in the list (and it should have correct name) and
- no 'Next' link is available
+ to have one instance in the list (and it should have correct name)
+ and no 'Next' link is available
8) Check filter by common part of Name of in order to have one instance
- in the list (and it should have correct name) and 'Next' link is
- available on the first page and is not available on the second page
+ in the list (and it should have correct name) and 'Next' link is
+ available on the first page and is not available on the second page
9) Go to user settings page and restore 'Items Per Page'
10) Delete created instances via proper page (depends on user)
@@ -181,6 +184,7 @@ class TestInstances(helpers.TestCase):
def test_filter_instances(self):
"""This test checks filtering of instances by Instance Name
+
Steps:
1) Login to Horizon dashboard as regular user
2) Go to Project > Compute > Instances
@@ -188,9 +192,9 @@ class TestInstances(helpers.TestCase):
4) Go to appropriate page (depends on user)
5) Use filter by Instance Name
6) Check that filtered table has one instance only (which name is equal
- to filter value) and no other instances in the table
+ to filter value) and no other instances in the table
7) Check that filtered table has both instances (search by common part
- of instance names)
+ of instance names)
8) Set nonexistent instance name. Check that 0 rows are displayed
9) Clear filter and delete instances via proper page (depends on user)
"""
diff --git a/openstack_dashboard/test/integration_tests/tests/test_login.py b/openstack_dashboard/test/integration_tests/tests/test_login.py
index 5c242b9e0..1c37b1be2 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_login.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_login.py
@@ -16,6 +16,7 @@ from openstack_dashboard.test.integration_tests.pages import loginpage
class TestLogin(helpers.BaseTestCase):
"""This is a basic scenario test:
+
* checks that the login page is available
* logs in as a regular user
* checks that the user home page loads without error
diff --git a/openstack_dashboard/test/integration_tests/tests/test_metadata_definitions.py b/openstack_dashboard/test/integration_tests/tests/test_metadata_definitions.py
index e84746152..a72e367ec 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_metadata_definitions.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_metadata_definitions.py
@@ -31,6 +31,7 @@ class TestMetadataDefinitions(helpers.AdminTestCase):
is_public=True, is_protected=False, template_path=None,
checks=(PUBLIC, PROTECTED)):
"""Create NameSpace and run checks
+
:param namespace_name: Display name of namespace in template
:param page: Connection point
:param template_json_container: JSON container with NameSpace content
@@ -71,6 +72,7 @@ class TestMetadataDefinitions(helpers.AdminTestCase):
def namespace_delete_with_checks(self, namespace_name, page):
"""Delete NameSpace and run checks
+
:param namespace_name: Display name of namespace in template
:param page: Connection point
:return: Nothing
@@ -83,6 +85,7 @@ class TestMetadataDefinitions(helpers.AdminTestCase):
def test_namespace_create_delete(self):
"""Tests the NameSpace creation and deletion functionality:
+
* Actions:
* 1) Login to Horizon Dashboard as admin user.
* 2) Navigate to Admin -> System -> Metadata Definitions.
diff --git a/openstack_dashboard/test/integration_tests/tests/test_networks.py b/openstack_dashboard/test/integration_tests/tests/test_networks.py
index 75e6abe10..d5394ae62 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_networks.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_networks.py
@@ -23,6 +23,7 @@ class TestNetworks(helpers.TestCase):
def test_private_network_create(self):
"""tests the network creation and deletion functionalities:
+
* creates a new private network and a new subnet associated with it
* verifies the network appears in the networks table as active
* deletes the newly created network
diff --git a/openstack_dashboard/test/integration_tests/tests/test_router.py b/openstack_dashboard/test/integration_tests/tests/test_router.py
index 9dd6b981c..733f69509 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_router.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_router.py
@@ -44,6 +44,7 @@ class TestRouters(helpers.TestCase):
def test_router_create(self):
"""tests the router creation and deletion functionalities:
+
* creates a new router for public network
* verifies the router appears in the routers table as active
* deletes the newly created router
@@ -73,6 +74,7 @@ class TestRouters(helpers.TestCase):
def test_router_add_delete_interface(self):
"""Tests the router interface creation and deletion functionalities:
+
* Follows the steps to create a new router
* Clicks on the new router name from the routers table
* Moves to the Interfaces page/tab
@@ -102,8 +104,8 @@ class TestRouters(helpers.TestCase):
self._delete_router()
def test_router_delete_interface_by_row(self):
- """Tests the router interface creation and deletion by
- row action functionalities:
+ """Tests the router interface creation and deletion by row action:
+
* Follows the steps to create a new router
* Clicks on the new router name from the routers table
* Moves to the Interfaces page/tab
@@ -160,6 +162,7 @@ class TestAdminRouters(helpers.AdminTestCase):
@decorators.services_required("neutron")
def test_router_create_admin(self):
"""tests the router creation and deletion functionalities:
+
* creates a new router for public network
* verifies the router appears in the routers table as active
* edits router name
diff --git a/openstack_dashboard/test/integration_tests/tests/test_router_gateway.py b/openstack_dashboard/test/integration_tests/tests/test_router_gateway.py
index b2003d26f..676fff6c0 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_router_gateway.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_router_gateway.py
@@ -20,25 +20,26 @@ class TestRouters(helpers.TestCase):
@decorators.services_required("neutron")
def test_router_create(self):
- """This test case checks create, clear/set gateway,
- delete router functionality
- executed by non-admin user::
- Steps:
- 1. Login to Horizon Dashboard as horizon user
- 2. Navigate to Project -> Network -> Routers page
- 3. Create new router
- 4. Check that the router appears in the routers table as active
- 5. Check that no Error messages present
- 6. Clear the gateway
- 7. Check that the router is still in the routers table
- with no external network
- 8. Check that no Error messages present
- 9. Set the gateway to 'public' network
- 10. Check that no Error messages present
- 11. Check that router's external network is set to 'public'
- 12. Delete the router
- 13. Check that the router is absent in the routers table
- 14. Check that no Error messages present
+ """Checks create, clear/set gateway, delete router functionality
+
+ Executed by non-admin user.
+
+ Steps:
+ 1. Login to Horizon Dashboard as horizon user
+ 2. Navigate to Project -> Network -> Routers page
+ 3. Create new router
+ 4. Check that the router appears in the routers table as active
+ 5. Check that no Error messages present
+ 6. Clear the gateway
+ 7. Check that the router is still in the routers table
+ with no external network
+ 8. Check that no Error messages present
+ 9. Set the gateway to 'public' network
+ 10. Check that no Error messages present
+ 11. Check that router's external network is set to 'public'
+ 12. Delete the router
+ 13. Check that the router is absent in the routers table
+ 14. Check that no Error messages present
"""
routers_page = self.home_pg.go_to_network_routerspage()
diff --git a/openstack_dashboard/test/integration_tests/tests/test_security_groups.py b/openstack_dashboard/test/integration_tests/tests/test_security_groups.py
index 779c1063b..abd100f44 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_security_groups.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_security_groups.py
@@ -64,17 +64,19 @@ class TestSecuritygroup(helpers.TestCase):
def test_securitygroup_create_delete(self):
"""tests the security group creation and deletion functionalities:
+
* creates a new security group
* verifies the security group appears in the security groups table
* deletes the newly created security group
* verifies the security group does not appear in the table after
- deletion
+ deletion
"""
self._create_securitygroup()
self._delete_securitygroup()
def test_managerules_create_delete_by_row(self):
"""tests the manage rules creation and deletion functionalities:
+
* create a new security group
* verifies the security group appears in the security groups table
* creates a new rule
@@ -83,7 +85,7 @@ class TestSecuritygroup(helpers.TestCase):
* verifies the rule does not appear in the table after deletion
* deletes the newly created security group
* verifies the security group does not appear in the table after
- deletion
+ deletion
"""
self._create_securitygroup()
self._add_rule()
@@ -92,6 +94,7 @@ class TestSecuritygroup(helpers.TestCase):
def test_managerules_create_delete_by_table(self):
"""tests the manage rules creation and deletion functionalities:
+
* create a new security group
* verifies the security group appears in the security groups table
* creates a new rule
@@ -100,7 +103,7 @@ class TestSecuritygroup(helpers.TestCase):
* verifies the rule does not appear in the table after deletion
* deletes the newly created security group
* verifies the security group does not appear in the table after
- deletion
+ deletion
"""
self._create_securitygroup()
self._add_rule()
diff --git a/openstack_dashboard/test/integration_tests/tests/test_stacks.py b/openstack_dashboard/test/integration_tests/tests/test_stacks.py
index d87f0c2c8..7c9ff95ba 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_stacks.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_stacks.py
@@ -43,9 +43,10 @@ class TestStacks(helpers.AdminTestCase):
@decorators.services_required("heat")
def test_create_delete_stack(self):
"""tests the stack creation and deletion functionality
+
* creates a new stack
* verifies the stack appears in the stacks table in Create Complete
- state
+ state
* deletes the newly created stack
* verifies the stack does not appear in the table after deletion
"""
diff --git a/openstack_dashboard/test/integration_tests/tests/test_user_settings.py b/openstack_dashboard/test/integration_tests/tests/test_user_settings.py
index a4f08d628..088ac6a4d 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_user_settings.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_user_settings.py
@@ -56,9 +56,8 @@ class TestPasswordChange(helpers.TestCase):
"Failed to login with default password")
def test_password_change(self):
- """Changes the password, verifies it was indeed changed and resets to
- default password.
- """
+ # Changes the password, verifies it was indeed changed and
+ # resets to default password.
passwordchange_page = self.home_pg.go_to_settings_changepasswordpage()
try:
@@ -74,9 +73,8 @@ class TestPasswordChange(helpers.TestCase):
self._login()
def test_show_message_after_logout(self):
- """Ensure an informational message is shown on the login page after the
- user is logged out.
- """
+ # Ensure an informational message is shown on the login page
+ # after the user is logged out.
passwordchange_page = self.home_pg.go_to_settings_changepasswordpage()
try:
@@ -111,6 +109,7 @@ class TestUserSettings(helpers.TestCase):
def test_user_settings_change(self):
"""tests the user's settings options:
+
* changes the system's language
* changes the timezone
* changes the number of items per page (page size)
diff --git a/openstack_dashboard/test/integration_tests/tests/test_volume_snapshots.py b/openstack_dashboard/test/integration_tests/tests/test_volume_snapshots.py
index 12eb889de..7dea44404 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_volume_snapshots.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_volume_snapshots.py
@@ -45,16 +45,17 @@ class TestVolumeSnapshotsBasic(helpers.TestCase):
def test_create_edit_delete_volume_snapshot(self):
"""Test checks create/delete volume snapshot action
- Steps:
- 1. Login to Horizon Dashboard
- 2. Navigate to Project -> Compute -> Volumes page
- 3. Create snapshot for existed volume
- 4. Check that no ERROR appears
- 5. Check that snapshot is in the list
- 6. Check that snapshot has reference to correct volume
- 7. Edit snapshot name and description
- 8. Delete volume snapshot from proper page
- 9. Check that volume snapshot not in the list
+
+ Steps:
+ 1. Login to Horizon Dashboard
+ 2. Navigate to Project -> Compute -> Volumes page
+ 3. Create snapshot for existed volume
+ 4. Check that no ERROR appears
+ 5. Check that snapshot is in the list
+ 6. Check that snapshot has reference to correct volume
+ 7. Edit snapshot name and description
+ 8. Delete volume snapshot from proper page
+ 9. Check that volume snapshot not in the list
"""
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
volumes_snapshot_page = volumes_page.create_volume_snapshot(
@@ -90,25 +91,26 @@ class TestVolumeSnapshotsBasic(helpers.TestCase):
def test_volume_snapshots_pagination(self):
"""This test checks volumes snapshots pagination
- Steps:
- 1) Login to Horizon Dashboard
- 2) Go to Project -> Compute -> Volumes -> Volumes tab, create
- volumes and 3 snapshots
- 3) Navigate to user settings page
- 4) Change 'Items Per Page' value to 1
- 5) Go to Project -> Compute -> Volumes -> Volumes Snapshot tab
- or Admin -> System -> Volumes -> Volumes Snapshot tab
- (depends on user)
- 6) Check that only 'Next' link is available, only one snapshot is
- available (and it has correct name)
- 7) Click 'Next' and check that both 'Prev' and 'Next' links are
- available, only one snapshot is available (and it has correct name)
- 8) Click 'Next' and check that only 'Prev' link is available,
- only one snapshot is visible (and it has correct name)
- 9) Click 'Prev' and check result (should be the same as for step7)
- 10) Click 'Prev' and check result (should be the same as for step6)
- 11) Go to user settings page and restore 'Items Per Page'
- 12) Delete created snapshots and volumes
+
+ Steps:
+ 1) Login to Horizon Dashboard
+ 2) Go to Project -> Compute -> Volumes -> Volumes tab, create
+ volumes and 3 snapshots
+ 3) Navigate to user settings page
+ 4) Change 'Items Per Page' value to 1
+ 5) Go to Project -> Compute -> Volumes -> Volumes Snapshot tab
+ or Admin -> System -> Volumes -> Volumes Snapshot tab
+ (depends on user)
+ 6) Check that only 'Next' link is available, only one snapshot is
+ available (and it has correct name)
+ 7) Click 'Next' and check that both 'Prev' and 'Next' links are
+ available, only one snapshot is available (and it has correct name)
+ 8) Click 'Next' and check that only 'Prev' link is available,
+ only one snapshot is visible (and it has correct name)
+ 9) Click 'Prev' and check result (should be the same as for step7)
+ 10) Click 'Prev' and check result (should be the same as for step6)
+ 11) Go to user settings page and restore 'Items Per Page'
+ 12) Delete created snapshots and volumes
"""
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
count = 3
@@ -223,14 +225,15 @@ class TestVolumeSnapshotsAdvanced(helpers.TestCase):
def test_create_volume_from_snapshot(self):
"""Test checks possibility to create volume from snapshot
- Steps:
- 1. Login to Horizon Dashboard as regular user
- 2. Navigate to Project -> Compute -> Volumes page
- 3. Create snapshot for existed volume
- 4. Create new volume from snapshot
- 5. Check the volume is created and has 'Available' status
- 6. Delete volume snapshot
- 7. Delete volume
+
+ Steps:
+ 1. Login to Horizon Dashboard as regular user
+ 2. Navigate to Project -> Compute -> Volumes page
+ 3. Create snapshot for existed volume
+ 4. Create new volume from snapshot
+ 5. Check the volume is created and has 'Available' status
+ 6. Delete volume snapshot
+ 7. Delete volume
"""
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
volumes_snapshot_page = volumes_page.create_volume_snapshot(
diff --git a/openstack_dashboard/test/integration_tests/tests/test_volumes.py b/openstack_dashboard/test/integration_tests/tests/test_volumes.py
index ceb9c63f5..39c06305e 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_volumes.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_volumes.py
@@ -27,18 +27,19 @@ class TestVolumesBasic(helpers.TestCase):
def test_volume_create_edit_delete(self):
"""This test case checks create, edit, delete volume functionality:
- Steps:
- 1. Login to Horizon Dashboard
- 2. Navigate to Project -> Compute -> Volumes page
- 3. Create new volume
- 4. Check that the volume is in the list
- 5. Check that no Error messages present
- 6. Edit the volume
- 7. Check that the volume is still in the list
- 8. Check that no Error messages present
- 9. Delete the volume via proper page (depends on user)
- 10. Check that the volume is absent in the list
- 11. Check that no Error messages present
+
+ Steps:
+ 1. Login to Horizon Dashboard
+ 2. Navigate to Project -> Compute -> Volumes page
+ 3. Create new volume
+ 4. Check that the volume is in the list
+ 5. Check that no Error messages present
+ 6. Edit the volume
+ 7. Check that the volume is still in the list
+ 8. Check that no Error messages present
+ 9. Delete the volume via proper page (depends on user)
+ 10. Check that the volume is absent in the list
+ 11. Check that no Error messages present
"""
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
volumes_page.create_volume(self.VOLUME_NAME)
@@ -78,24 +79,25 @@ class TestVolumesBasic(helpers.TestCase):
def test_volumes_pagination(self):
"""This test checks volumes pagination
- Steps:
- 1) Login to Horizon Dashboard
- 2) Go to Project -> Compute -> Volumes -> Volumes tab and create
- three volumes
- 3) Navigate to user settings page
- 4) Change 'Items Per Page' value to 1
- 5) Go to Project -> Compute -> Volumes -> Volumes tab or
- Admin -> System -> Volumes -> Volumes tab (depends on user)
- 6) Check that only 'Next' link is available, only one volume is
- available (and it has correct name)
- 7) Click 'Next' and check that both 'Prev' and 'Next' links are
- available, only one volume is available (and it has correct name)
- 8) Click 'Next' and check that only 'Prev' link is available,
- only one volume is visible (and it has correct name)
- 9) Click 'Prev' and check result (should be the same as for step7)
- 10) Click 'Prev' and check result (should be the same as for step6)
- 11) Go to user settings page and restore 'Items Per Page'
- 12) Delete created volumes
+
+ Steps:
+ 1) Login to Horizon Dashboard
+ 2) Go to Project -> Compute -> Volumes -> Volumes tab and create
+ three volumes
+ 3) Navigate to user settings page
+ 4) Change 'Items Per Page' value to 1
+ 5) Go to Project -> Compute -> Volumes -> Volumes tab or
+ Admin -> System -> Volumes -> Volumes tab (depends on user)
+ 6) Check that only 'Next' link is available, only one volume is
+ available (and it has correct name)
+ 7) Click 'Next' and check that both 'Prev' and 'Next' links are
+ available, only one volume is available (and it has correct name)
+ 8) Click 'Next' and check that only 'Prev' link is available,
+ only one volume is visible (and it has correct name)
+ 9) Click 'Prev' and check result (should be the same as for step7)
+ 10) Click 'Prev' and check result (should be the same as for step6)
+ 11) Go to user settings page and restore 'Items Per Page'
+ 12) Delete created volumes
"""
volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
count = 3
@@ -167,15 +169,16 @@ class TestVolumesAdvanced(helpers.TestCase):
@decorators.skip_because(bugs=['1584057'])
def test_manage_volume_attachments(self):
"""This test case checks attach/detach actions for volume
- Steps:
- 1. Login to Horizon Dashboard as horizon user
- 2. Navigate to Project -> Compute -> Instances, create instance
- 3. Navigate to Project -> Compute -> Volumes, create volume
- 4. Attach volume to instance from step2
- 5. Check that volume status and link to instance
- 6. Detach volume from instance
- 7. Check volume status
- 8. Delete volume and instance
+
+ Steps:
+ 1. Login to Horizon Dashboard as horizon user
+ 2. Navigate to Project -> Compute -> Instances, create instance
+ 3. Navigate to Project -> Compute -> Volumes, create volume
+ 4. Attach volume to instance from step2
+ 5. Check that volume status and link to instance
+ 6. Detach volume from instance
+ 7. Check volume status
+ 8. Delete volume and instance
"""
instance_name = helpers.gen_random_resource_name('instance')
instances_page = self.home_pg.go_to_compute_instancespage()
@@ -251,12 +254,13 @@ class TestVolumesActions(helpers.TestCase):
def test_volume_extend(self):
"""This test case checks extend volume functionality:
- Steps:
- 1. Check current volume size
- 2. Extend volume
- 3. Check that no Error messages present
- 4. Check that the volume is still in the list
- 5. Check that the volume size is changed
+
+ Steps:
+ 1. Check current volume size
+ 2. Extend volume
+ 3. Check that no Error messages present
+ 4. Check that the volume is still in the list
+ 5. Check that the volume size is changed
"""
orig_size = self.volumes_page.get_size(self.VOLUME_NAME)
self.volumes_page.extend_volume(self.VOLUME_NAME, orig_size + 1)
@@ -272,12 +276,13 @@ class TestVolumesActions(helpers.TestCase):
@decorators.skip_because(bugs=['1584057'])
def test_volume_upload_to_image(self):
"""This test case checks upload volume to image functionality:
- Steps:
- 1. Upload volume to image with some disk format
- 2. Check that image is created
- 3. Check that no Error messages present
- 4. Delete the image
- 5. Repeat actions for all disk formats
+
+ Steps:
+ 1. Upload volume to image with some disk format
+ 2. Check that image is created
+ 3. Check that no Error messages present
+ 4. Delete the image
+ 5. Repeat actions for all disk formats
"""
self.volumes_page = self.home_pg.go_to_compute_volumes_volumespage()
all_formats = {"qcow2": u'QCOW2', "raw": u'Raw', "vdi": u'VDI',
@@ -306,13 +311,14 @@ class TestVolumesActions(helpers.TestCase):
def test_volume_launch_as_instance(self):
"""This test case checks launch volume as instance functionality:
- Steps:
- 1. Launch volume as instance
- 2. Check that instance is created
- 3. Check that no Error messages present
- 4. Check that instance status is 'active'
- 5. Check that volume status is 'in use'
- 6. Delete instance
+
+ Steps:
+ 1. Launch volume as instance
+ 2. Check that instance is created
+ 3. Check that no Error messages present
+ 4. Check that instance status is 'active'
+ 5. Check that volume status is 'in use'
+ 6. Delete instance
"""
self.volumes_page.launch_instance(self.VOLUME_NAME, self.INSTANCE_NAME)
self.assertTrue(
diff --git a/openstack_dashboard/test/integration_tests/tests/test_volumetypes.py b/openstack_dashboard/test/integration_tests/tests/test_volumetypes.py
index a73cc3553..7e03b2a3e 100644
--- a/openstack_dashboard/test/integration_tests/tests/test_volumetypes.py
+++ b/openstack_dashboard/test/integration_tests/tests/test_volumetypes.py
@@ -19,15 +19,16 @@ class TestAdminVolumeTypes(helpers.AdminTestCase):
def test_volume_type_create_delete(self):
"""This test case checks create, delete volume type:
- Steps:
- 1. Login to Horizon Dashboard as admin user
- 2. Navigate to Admin -> System -> Volumes -> Volume Types page
- 3. Create new volume type
- 4. Check that the volume type is in the list
- 5. Check that no Error messages present
- 6. Delete the volume type
- 7. Check that the volume type is absent in the list
- 8. Check that no Error messages present
+
+ Steps:
+ 1. Login to Horizon Dashboard as admin user
+ 2. Navigate to Admin -> System -> Volumes -> Volume Types page
+ 3. Create new volume type
+ 4. Check that the volume type is in the list
+ 5. Check that no Error messages present
+ 6. Delete the volume type
+ 7. Check that the volume type is absent in the list
+ 8. Check that no Error messages present
"""
volume_types_page = self.home_pg.go_to_system_volumes_volumetypespage()
@@ -55,6 +56,7 @@ class TestQoSSpec(helpers.AdminTestCase):
def test_qos_spec_create_delete(self):
"""tests the QoS Spec creation and deletion functionality
+
* creates a new QoS Spec
* verifies the QoS Spec appears in the QoS Specs table
* deletes the newly created QoS Spec
@@ -78,10 +80,11 @@ class TestQoSSpec(helpers.AdminTestCase):
def test_qos_spec_edit_consumer(self):
"""tests Edit Consumer of QoS Spec functionality
+
* creates a new QoS Spec
* verifies the QoS Spec appears in the QoS Specs table
* edit consumer of created QoS Spec (check all options - front-end,
- both, back-end)
+ both, back-end)
* verifies current consumer of the QoS Spec in the QoS Specs table
* deletes the newly created QoS Spec
* verifies the QoS Spec does not appear in the table after deletion
diff --git a/openstack_dashboard/test/test_data/utils.py b/openstack_dashboard/test/test_data/utils.py
index a73930065..4337bf0c0 100644
--- a/openstack_dashboard/test/test_data/utils.py
+++ b/openstack_dashboard/test/test_data/utils.py
@@ -43,9 +43,11 @@ def load_test_data(load_onto=None):
class TestData(object):
- """Holder object for test data. Any functions passed to the init method
- will be called with the ``TestData`` object as their only argument. They
- can then load data onto the object as desired.
+ """Holder object for test data.
+
+ Any functions passed to the init method will be called with the
+ ``TestData`` object as their only argument.
+ They can then load data onto the object as desired.
The idea is to use the instantiated object like this::
@@ -93,9 +95,7 @@ class TestDataContainer(object):
return self._objects
def filter(self, filtered=None, **kwargs):
- """Returns objects in this container whose attributes match the given
- keyword arguments.
- """
+ """Returns objects whose attributes match the given kwargs."""
if filtered is None:
filtered = self._objects
try:
@@ -111,8 +111,9 @@ class TestDataContainer(object):
return self.filter(filtered=filtered, **kwargs)
def get(self, **kwargs):
- """Returns the single object in this container whose attributes match
- the given keyword arguments. An error will be raised if the arguments
+ """Returns a single object whose attributes match the given kwargs.
+
+ An error will be raised if the arguments
provided don't return exactly one match.
"""
matches = self.filter(**kwargs)
diff --git a/openstack_dashboard/usage/quotas.py b/openstack_dashboard/usage/quotas.py
index 50a89d8a1..7db3ddb4a 100644
--- a/openstack_dashboard/usage/quotas.py
+++ b/openstack_dashboard/usage/quotas.py
@@ -396,6 +396,7 @@ def _get_tenant_volume_usages(request, usages, disabled_quotas, tenant_id):
@memoized
def tenant_quota_usages(request, tenant_id=None):
"""Get our quotas and construct our usage object.
+
If no tenant_id is provided, a the request.user.project_id
is assumed to be used
"""
diff --git a/openstack_dashboard/utils/filters.py b/openstack_dashboard/utils/filters.py
index 094524f91..bd0df4d9a 100644
--- a/openstack_dashboard/utils/filters.py
+++ b/openstack_dashboard/utils/filters.py
@@ -30,7 +30,9 @@ def get_int_or_uuid(value):
def get_display_label(choices, status):
- """This method is used in places where a resource's status or
+ """Get a display label for resource status.
+
+ This method is used in places where a resource's status or
admin state labels need to assigned before they are sent to the
view template.
"""
diff --git a/tox.ini b/tox.ini
index 517d4c3c5..b76cd7428 100644
--- a/tox.ini
+++ b/tox.ini
@@ -117,8 +117,7 @@ commands =
[flake8]
exclude = .venv,.git,.tox,dist,*lib/python*,*egg,build,panel_template,dash_template,local_settings.py,*/local/*,*/test/test_plugins/*,.ropeproject,node_modules
-# H405 multi line docstring summary not separated with an empty line
-ignore = H405
+ignore =
# Enable the following hacking rules which are disabled by default
# H203 Use assertIs(Not)None to check for None
# H904 Delay string interpolations at logging calls