From b0aca38a60882e2813924d98c61f282850125c89 Mon Sep 17 00:00:00 2001 From: Tony Breeds Date: Tue, 12 Sep 2017 16:20:49 -0600 Subject: [PATCH] Retire Packaging Deb project repos This commit is part of a series to retire the Packaging Deb project. Step 2 is to remove all content from the project repos, replacing it with a README notification where to find ongoing work, and how to recover the repo if needed at some future point (as in https://docs.openstack.org/infra/manual/drivers.html#retiring-a-project). Change-Id: I3cb50c6ca8f660389ba2af2d8e78702d806509e9 --- .coveragerc | 4 - .gitignore | 31 - .gitreview | 4 - .mailmap | 27 - .testr.conf | 9 - HACKING.rst | 403 ----- LICENSE | 176 -- README | 14 + README.rst | 268 --- REVIEWING.rst | 128 -- bindep.txt | 13 - data/tempest-plugins-registry.header | 23 - doc/source/HACKING.rst | 1 - doc/source/REVIEWING.rst | 1 - doc/source/_static/.keep | 0 doc/source/account_generator.rst | 5 - doc/source/cleanup.rst | 5 - doc/source/conf.py | 203 --- doc/source/configuration.rst | 439 ----- doc/source/field_guide/api.rst | 1 - doc/source/field_guide/index.rst | 1 - doc/source/field_guide/scenario.rst | 1 - doc/source/field_guide/unit_tests.rst | 1 - doc/source/index.rst | 86 - doc/source/library.rst | 71 - .../library/api_microversion_testing.rst | 29 - doc/source/library/auth.rst | 11 - doc/source/library/cli.rst | 18 - doc/source/library/clients.rst | 33 - doc/source/library/credential_providers.rst | 148 -- doc/source/library/decorators.rst | 13 - doc/source/library/rest_client.rst | 11 - .../service_clients/compute_clients.rst | 7 - doc/source/library/utils.rst | 11 - doc/source/microversion_testing.rst | 341 ---- doc/source/overview.rst | 1 - doc/source/plugin.rst | 346 ---- doc/source/run.rst | 7 - doc/source/sampleconf.rst | 13 - doc/source/subunit_describe_calls.rst | 5 - doc/source/test_removal.rst | 188 --- doc/source/workspace.rst | 5 - doc/source/write_tests.rst | 311 ---- etc/accounts.yaml.sample | 62 - etc/logging.conf.sample | 35 - etc/whitelist.yaml | 0 ...d-openstack-releases-b88db468695348f6.yaml | 13 - ...st-library-interface-0eb680b810139a50.yaml | 11 - ...0.0-start-using-reno-ed9518126fd0e1a3.yaml | 3 - ...sion-testing-support-2ceddd2255670932.yaml | 3 - ...microversion-support-e0b23f960f894b9b.yaml | 3 - ...d-openstack-releases-1e5d7295d939d439.yaml | 12 - ...d-openstack-releases-f10aac381d933dd1.yaml | 12 - ...work-versions-client-d90e8334e1443f5c.yaml | 4 - ....0-add-scope-to-auth-b5a82493ea89f41e.yaml | 7 - ....1.0-add-tempest-run-3d0aaf69c2ca4115.yaml | 4 - ...d-tempest-workspaces-228a2ba4690b5589.yaml | 5 - ...bunit_describe_calls-5498a37e6cd66c4b.yaml | 8 - .../12.1.0-bug-1486834-7ebca15836ae27a9.yaml | 7 - ...y-clients-as-library-e663c6132fcac6c2.yaml | 13 - ...e-clients-as-library-86d17caa26ce3961.yaml | 15 - ...ew-test-utils-module-adf34468c4d52719.yaml | 11 - ...narios-functionality-01308e6d4307f580.yaml | 11 - ...e-integrated-horizon-bb57551c1e5f5be3.yaml | 7 - ...credential-providers-3d653ac3ba1ada2b.yaml | 5 - ...0-remove-trove-tests-666522e9113549f9.yaml | 4 - ...rs-client-as-library-25a363379da351f6.yaml | 6 - ...ort-chunked-encoding-d71f53225f68edf3.yaml | 9 - ...dir-location-changes-12260255871d3a2b.yaml | 12 - ...imeout-in-restclient-ax78061900e3f3d7.yaml | 7 - ...new-identity-clients-3c3afd674a395bde.yaml | 13 - ...2.2.0-clients_module-16f3025f515bf9ec.yaml | 18 - ....0-nova_cert_default-90eb7c1e3cde624a.yaml | 8 - ...-client-registration-00b19a2dd4935ba0.yaml | 12 - ...2.2.0-remove-javelin-276f62d04f7e4a1d.yaml | 5 - ...ervice_client_config-8a1d7b4de769c633.yaml | 6 - ...e-clients-as-library-9a3444dd63c134b3.yaml | 18 - ...y-clients-as-library-5f7ndha733nwdsn9.yaml | 15 - ...clients-as-a-library-d05b6bc35e66c6ef.yaml | 16 - ...t_ipv6_addr_by_EUI64-4673f07677289cf6.yaml | 4 - ...-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml | 5 - ...rt-of-newton-support-3ebb274f300f28eb.yaml | 13 - ...cleanup-nostandalone-39df2aafb2545d35.yaml | 5 - ...e-clients-as-library-660811011be29d1a.yaml | 6 - ...bstract-class-to-lib-70ff513221f8a871.yaml | 6 - ...lient-to-tempest.lib-4d4af33f969c576f.yaml | 5 - ...-to-versions-clients-acbc78292e24b014.yaml | 6 - ....0-add-image-clients-af94564fb34ddca6.yaml | 9 - ...-client-as-a-library-d34b4fdf376984ad.yaml | 6 - ...vice-provider-client-cbba77d424a30dd3.yaml | 4 - ...-parameter-to-client-6d16c374ac4456c1.yaml | 4 - ...-nova-api-extensions-df16b02485dae203.yaml | 7 - ...er-v3-to-lib-service-be3ba0c20753b594.yaml | 7 - ...-volume-limit-client-517c17d9090f4df4.yaml | 3 - ....0-remo-stress-tests-81052b211ad95d2e.yaml | 13 - ...move-baremetal-tests-65186d9e15d5b8fb.yaml | 4 - ...move-bootable-option-024f8944c056a3e0.yaml | 6 - ...ative-test-generator-1653f4c0f86ccf75.yaml | 4 - ...-remove-sahara-tests-1532c47c7df80e3a.yaml | 4 - ...e-clients-as-library-309030c7a16e62ab.yaml | 12 - ...clients-as-a-library-d34b4fdf376984ad.yaml | 6 - ...-image-clients-tests-49dbc0a0a4281a77.yaml | 10 - ...roles-client-library-edf96408ad9ba82e.yaml | 6 - ...ge-client-as-library-a76ffdba9d8d01cb.yaml | 8 - ...rity_disabled-option-2d3d87f6bd11d03a.yaml | 8 - ...ure-enabled.reseller-84800a8232fe217f.yaml | 8 - ...bled.volume_services-dbe024ea067d5ab2.yaml | 8 - ...jsonschema-validator-2377ba131e12d3c7.yaml | 5 - ...rsion-config-options-eaee6a7d2f8390a8.yaml | 9 - ...ation-config-options-e3d1b89ce074d71c.yaml | 25 - ...nario-config-options-414e0c5442e967e9.yaml | 6 - ...twork-config-options-f9ce276231578fe6.yaml | 11 - ...Client-tempest-tests-db1df7aae4a9fd4e.yaml | 3 - ...roles-client-library-178d4a6000dec72d.yaml | 7 - ...er-to-volumes-client-ff4f7f12795003a4.yaml | 7 - ...-client-as-a-library-ed76baf25f02c3ca.yaml | 3 - ...-type-without-spaces-b2c9b91b257814f3.yaml | 9 - ...-auth-project-client-5905076d914a3943.yaml | 6 - ...-glance-api-versions-ec5fc8081fc8a0ae.yaml | 6 - ...rvers-client-library-088df48f6d81f4be.yaml | 6 - ...n-to-identity-client-944cb7396088a575.yaml | 6 - ...ion-to-volume-client-4769dd1bd4ab9c5e.yaml | 6 - ...ta-sets-detail-kwarg-74b72183295b3ce7.yaml | 6 - ...st-lib-remote-client-adbeb3f42a36910b.yaml | 11 - ...t-run-combine-option-e94c1049ba8985d5.yaml | 6 - ...ryption-types-client-f3093532a0bcf9a1.yaml | 6 - ...ge-client-as-library-78ab198a1dc1bd41.yaml | 9 - ...e-server-tags-client-8c0042a77e859af6.yaml | 8 - ...ctivate_image-config-7a282c471937bbcb.yaml | 6 - ...tra_resources-config-8c319d6dab7f7e5c.yaml | 7 - ...rsion-config-options-8370b63aea8e14cf.yaml | 10 - ...ources-prefix-option-ad490c0a30a0266b.yaml | 10 - ...nless_attr-decorator-450a1ed727494724.yaml | 5 - ...ess_config-decorator-64c32d588043ab12.yaml | 5 - ...cinder-api-v1-option-df7d5a54d93db5cf.yaml | 12 - ...te_client_parameters-cb8d069e62957f7e.yaml | 6 - ...ients-bugfix-1667354-73d2c3c8fedc08bf.yaml | 7 - .../16.0.0-mitaka-eol-88ff8355fff81b55.yaml | 13 - ...l_until_true-of-test-de9c13bc8f969921.yaml | 6 - ...-cinder-v1-api-tests-71e266b8d55d475f.yaml | 5 - ...rity_disabled-option-d0ffaeb2e7817707.yaml | 5 - ...onfig-options-part-2-5cd17b6e0e6cb8a3.yaml | 11 - ...tra_resources-option-e8c441c38eab7ddd.yaml | 8 - ...tity-reseller-option-4411c7e3951f1094.yaml | 4 - ...ra-service-available-44a642aa9c634ab4.yaml | 7 - ...bled.volume_services-c6aa142cc1021297.yaml | 5 - ...-use-keystone-v3-api-935860d30ddbb8e9.yaml | 5 - ...ume-transfers-client-e5ed3f5464c0cdc0.yaml | 18 - ...Client-tempest-tests-6351eda451b95a86.yaml | 3 - ...ature-serial-console-45583c4341e34fc9.yaml | 7 - ...client-tempest-tests-e383efabdbb9ad03.yaml | 5 - ...ing-ip-config-option-e5774bf77702ce9f.yaml | 5 - ...lumes-client-library-b2071f2954f8e8b1.yaml | 6 - ...-api-endpoint-groups-3518a90bbb731d0f.yaml | 7 - ...ilter-api-extensions-9cfd217fd2c6a61f.yaml | 6 - ...te-vol-of-vol-client-1ecde75beb62933c.yaml | 7 - ...-to-transfers-client-80169bf78cf4fa66.yaml | 5 - ...ot-ref-config-option-67efd04897335b67.yaml | 7 - ...ty-v3-list-endpoints-958a155be4e17e5b.yaml | 6 - ...-v2-list-backups-api-c088d2b4bfe90247.yaml | 6 - ...dd-save-state-option-5ea67858cbaca969.yaml | 4 - ...cs-validation-schema-b5a3c55b45aa718a.yaml | 4 - ...hosts-client-library-c60c4eb49d139480.yaml | 5 - ...-v2-snapshots-client-bd3cbab3c7f0e0b3.yaml | 6 - ...to-v2-volumes-client-47d59ecd999ca9df.yaml | 6 - ...to-v3-volumes-client-96e7b01abdb5c9c3.yaml | 10 - ...to-v3-backups-client-e8465b2b66617dc0.yaml | 10 - ...-types-tempest-tests-1298ab8cb4fe8b7b.yaml | 5 - ...groups-tempest-tests-dd7b2abfe2b48427.yaml | 6 - ...ss-client-as-library-c4c2b22c36ff807e.yaml | 8 - .../api_v2_admin_flag-dea5ca9bc2ce63bc.yaml | 7 - ...ient-in-volume-tests-92b6dd55fcaba620.yaml | 10 - ...d_global_implied_dsr-e64cfa66e6e3ded5.yaml | 5 - ...for-v3_endpoint_type-fb9e47c5ba1c719d.yaml | 6 - ...mpute-services-tests-92b6c0618972e02f.yaml | 6 - ...dentity-token-client-8aaef74b1d61090a.yaml | 6 - .../identity_client-635275d43abbb807.yaml | 5 - ...mediate-pike-release-2ce492432ff8f012.yaml | 4 - ...igrate-dynamic-creds-ecebb47528080761.yaml | 5 - ...igrate-preprov-creds-ef61a046ee1ec604.yaml | 11 - ...ttr-decorator-to-lib-a1e80c42ba9c5392.yaml | 6 - ...bug-decorator-to-lib-dbfd5c543bbb2805.yaml | 6 - ...ase_client-to-volume-1edbz0f207c3b283.yaml | 15 - .../network-tag-client-f4614029af7927f0.yaml | 8 - .../pause_teardown-45c9d60ffa889f7f.yaml | 9 - ...p-when-nullable-list-9898cd0f22180986.yaml | 6 - .../remove-heat-tests-9efb42cac3e0b306.yaml | 4 - ...r-api-v3-option-true-1b3e61e3129b7c00.yaml | 5 - ...ntity-catalog-client-f5c8589a9d7c1eb5.yaml | 5 - ...te-directory-feature-74d6d157a5a05561.yaml | 5 - ...erify_tempest_config-2bf3d817b0070064.yaml | 6 - releasenotes/source/_static/.placeholder | 0 releasenotes/source/_templates/.placeholder | 0 releasenotes/source/conf.py | 286 ---- releasenotes/source/index.rst | 22 - releasenotes/source/unreleased.rst | 5 - releasenotes/source/v10.0.0.rst | 6 - releasenotes/source/v11.0.0.rst | 6 - releasenotes/source/v12.0.0.rst | 6 - releasenotes/source/v13.0.0.rst | 6 - releasenotes/source/v14.0.0.rst | 6 - releasenotes/source/v15.0.0.rst | 6 - releasenotes/source/v16.0.0.rst | 6 - releasenotes/source/v16.1.0.rst | 6 - requirements.txt | 25 - setup.cfg | 58 - setup.py | 29 - tempest/README.rst | 55 - tempest/__init__.py | 0 tempest/api/README.rst | 53 - tempest/api/__init__.py | 0 tempest/api/compute/__init__.py | 0 tempest/api/compute/admin/__init__.py | 0 tempest/api/compute/admin/test_agents.py | 110 -- tempest/api/compute/admin/test_aggregates.py | 217 --- .../compute/admin/test_aggregates_negative.py | 180 -- .../admin/test_auto_allocate_network.py | 208 --- .../compute/admin/test_availability_zone.py | 38 - .../admin/test_availability_zone_negative.py | 35 - .../api/compute/admin/test_create_server.py | 109 -- .../api/compute/admin/test_delete_server.py | 52 - tempest/api/compute/admin/test_fixed_ips.py | 65 - .../compute/admin/test_fixed_ips_negative.py | 94 -- tempest/api/compute/admin/test_flavors.py | 225 --- .../api/compute/admin/test_flavors_access.py | 81 - .../admin/test_flavors_access_negative.py | 115 -- .../compute/admin/test_flavors_extra_specs.py | 119 -- .../test_flavors_extra_specs_negative.py | 134 -- .../compute/admin/test_floating_ips_bulk.py | 81 - tempest/api/compute/admin/test_hosts.py | 73 - .../api/compute/admin/test_hosts_negative.py | 142 -- tempest/api/compute/admin/test_hypervisor.py | 122 -- .../compute/admin/test_hypervisor_negative.py | 139 -- .../admin/test_instance_usage_audit_log.py | 57 - .../test_instance_usage_audit_log_negative.py | 50 - .../api/compute/admin/test_keypairs_v210.py | 75 - .../api/compute/admin/test_live_migration.py | 235 --- .../admin/test_live_migration_negative.py | 63 - tempest/api/compute/admin/test_migrations.py | 138 -- tempest/api/compute/admin/test_networks.py | 65 - tempest/api/compute/admin/test_quotas.py | 187 --- .../api/compute/admin/test_quotas_negative.py | 133 -- .../test_security_group_default_rules.py | 131 -- .../api/compute/admin/test_security_groups.py | 79 - .../compute/admin/test_server_diagnostics.py | 76 - .../admin/test_server_diagnostics_negative.py | 40 - tempest/api/compute/admin/test_servers.py | 210 --- .../compute/admin/test_servers_negative.py | 134 -- .../admin/test_servers_on_multinodes.py | 78 - tempest/api/compute/admin/test_services.py | 70 - .../compute/admin/test_services_negative.py | 60 - .../compute/admin/test_simple_tenant_usage.py | 91 - .../test_simple_tenant_usage_negative.py | 71 - tempest/api/compute/admin/test_volume_swap.py | 123 -- .../compute/admin/test_volumes_negative.py | 59 - .../api/compute/api_microversion_fixture.py | 31 - tempest/api/compute/base.py | 507 ------ tempest/api/compute/certificates/__init__.py | 0 .../compute/certificates/test_certificates.py | 44 - tempest/api/compute/flavors/__init__.py | 0 tempest/api/compute/flavors/test_flavors.py | 126 -- .../compute/flavors/test_flavors_negative.py | 90 - tempest/api/compute/floating_ips/__init__.py | 0 tempest/api/compute/floating_ips/base.py | 26 - .../floating_ips/test_floating_ips_actions.py | 148 -- .../test_floating_ips_actions_negative.py | 133 -- .../floating_ips/test_list_floating_ips.py | 94 -- .../test_list_floating_ips_negative.py | 51 - tempest/api/compute/images/__init__.py | 0 .../api/compute/images/test_image_metadata.py | 144 -- .../images/test_image_metadata_negative.py | 80 - tempest/api/compute/images/test_images.py | 103 -- .../compute/images/test_images_negative.py | 127 -- .../compute/images/test_images_oneserver.py | 91 - .../images/test_images_oneserver_negative.py | 135 -- .../compute/images/test_list_image_filters.py | 290 ---- .../test_list_image_filters_negative.py | 44 - .../api/compute/images/test_list_images.py | 55 - tempest/api/compute/keypairs/__init__.py | 0 tempest/api/compute/keypairs/base.py | 48 - tempest/api/compute/keypairs/test_keypairs.py | 96 -- .../keypairs/test_keypairs_negative.py | 88 - .../api/compute/keypairs/test_keypairs_v22.py | 51 - tempest/api/compute/limits/__init__.py | 0 .../compute/limits/test_absolute_limits.py | 47 - .../limits/test_absolute_limits_negative.py | 56 - .../api/compute/security_groups/__init__.py | 0 tempest/api/compute/security_groups/base.py | 38 - .../test_security_group_rules.py | 189 --- .../test_security_group_rules_negative.py | 175 -- .../security_groups/test_security_groups.py | 174 -- .../test_security_groups_negative.py | 192 --- tempest/api/compute/servers/__init__.py | 0 .../compute/servers/test_attach_interfaces.py | 281 ---- .../compute/servers/test_availability_zone.py | 32 - .../api/compute/servers/test_create_server.py | 172 -- .../servers/test_create_server_multi_nic.py | 120 -- .../api/compute/servers/test_delete_server.py | 119 -- .../compute/servers/test_device_tagging.py | 288 ---- .../api/compute/servers/test_disk_config.py | 134 -- .../compute/servers/test_instance_actions.py | 77 - .../servers/test_instance_actions_negative.py | 48 - .../servers/test_list_server_filters.py | 323 ---- .../servers/test_list_servers_negative.py | 135 -- .../compute/servers/test_multiple_create.py | 45 - .../servers/test_multiple_create_negative.py | 58 - tempest/api/compute/servers/test_novnc.py | 186 --- .../compute/servers/test_server_actions.py | 589 ------- .../compute/servers/test_server_addresses.py | 76 - .../servers/test_server_addresses_negative.py | 54 - .../api/compute/servers/test_server_group.py | 108 -- .../compute/servers/test_server_metadata.py | 114 -- .../servers/test_server_metadata_negative.py | 174 -- .../compute/servers/test_server_password.py | 39 - .../servers/test_server_personality.py | 144 -- .../api/compute/servers/test_server_rescue.py | 93 -- .../servers/test_server_rescue_negative.py | 153 -- .../api/compute/servers/test_server_tags.py | 108 -- tempest/api/compute/servers/test_servers.py | 147 -- .../compute/servers/test_servers_negative.py | 583 ------- .../servers/test_virtual_interfaces.py | 68 - .../test_virtual_interfaces_negative.py | 45 - tempest/api/compute/test_extensions.py | 55 - tempest/api/compute/test_networks.py | 37 - tempest/api/compute/test_quotas.py | 88 - tempest/api/compute/test_tenant_networks.py | 45 - tempest/api/compute/test_versions.py | 74 - tempest/api/compute/volumes/__init__.py | 0 .../api/compute/volumes/test_attach_volume.py | 251 --- .../volumes/test_attach_volume_negative.py | 43 - .../compute/volumes/test_volume_snapshots.py | 78 - .../api/compute/volumes/test_volumes_get.py | 81 - .../api/compute/volumes/test_volumes_list.py | 141 -- .../compute/volumes/test_volumes_negative.py | 110 -- tempest/api/identity/__init__.py | 23 - tempest/api/identity/admin/__init__.py | 0 tempest/api/identity/admin/v2/__init__.py | 0 .../api/identity/admin/v2/test_endpoints.py | 92 -- tempest/api/identity/admin/v2/test_roles.py | 119 -- .../identity/admin/v2/test_roles_negative.py | 256 --- .../api/identity/admin/v2/test_services.py | 104 -- .../identity/admin/v2/test_tenant_negative.py | 142 -- tempest/api/identity/admin/v2/test_tenants.py | 149 -- tempest/api/identity/admin/v2/test_tokens.py | 133 -- .../identity/admin/v2/test_tokens_negative.py | 38 - tempest/api/identity/admin/v2/test_users.py | 193 --- .../identity/admin/v2/test_users_negative.py | 268 --- tempest/api/identity/admin/v3/__init__.py | 0 .../api/identity/admin/v3/test_credentials.py | 112 -- .../admin/v3/test_default_project_id.py | 85 - .../admin/v3/test_domain_configuration.py | 184 --- tempest/api/identity/admin/v3/test_domains.py | 168 -- .../admin/v3/test_domains_negative.py | 70 - .../identity/admin/v3/test_endpoint_groups.py | 157 -- .../api/identity/admin/v3/test_endpoints.py | 182 -- .../admin/v3/test_endpoints_negative.py | 98 -- tempest/api/identity/admin/v3/test_groups.py | 137 -- .../api/identity/admin/v3/test_inherits.py | 214 --- .../identity/admin/v3/test_list_projects.py | 97 -- .../api/identity/admin/v3/test_list_users.py | 107 -- .../identity/admin/v3/test_oauth_consumers.py | 91 - .../api/identity/admin/v3/test_policies.py | 74 - .../api/identity/admin/v3/test_projects.py | 207 --- .../admin/v3/test_projects_negative.py | 80 - tempest/api/identity/admin/v3/test_regions.py | 120 -- tempest/api/identity/admin/v3/test_roles.py | 435 ----- .../api/identity/admin/v3/test_services.py | 102 -- tempest/api/identity/admin/v3/test_tokens.py | 176 -- tempest/api/identity/admin/v3/test_trusts.py | 289 ---- tempest/api/identity/admin/v3/test_users.py | 171 -- .../identity/admin/v3/test_users_negative.py | 49 - tempest/api/identity/base.py | 287 ---- tempest/api/identity/v2/__init__.py | 0 tempest/api/identity/v2/test_api_discovery.py | 57 - .../api/identity/v2/test_ec2_credentials.py | 112 -- tempest/api/identity/v2/test_extension.py | 31 - tempest/api/identity/v2/test_tenants.py | 50 - tempest/api/identity/v2/test_tokens.py | 50 - tempest/api/identity/v2/test_users.py | 104 -- tempest/api/identity/v3/__init__.py | 0 tempest/api/identity/v3/test_api_discovery.py | 71 - tempest/api/identity/v3/test_catalog.py | 41 - tempest/api/identity/v3/test_projects.py | 59 - tempest/api/identity/v3/test_tokens.py | 93 -- tempest/api/identity/v3/test_users.py | 158 -- tempest/api/image/__init__.py | 0 tempest/api/image/base.py | 211 --- tempest/api/image/v1/__init__.py | 0 tempest/api/image/v1/test_image_members.py | 59 - .../image/v1/test_image_members_negative.py | 58 - tempest/api/image/v1/test_images.py | 330 ---- tempest/api/image/v1/test_images_negative.py | 78 - tempest/api/image/v2/__init__.py | 0 tempest/api/image/v2/test_images.py | 390 ----- tempest/api/image/v2/test_images_member.py | 98 -- .../image/v2/test_images_member_negative.py | 43 - .../test_images_metadefs_namespace_objects.py | 73 - ...st_images_metadefs_namespace_properties.py | 57 - .../v2/test_images_metadefs_namespace_tags.py | 90 - .../v2/test_images_metadefs_namespaces.py | 76 - .../v2/test_images_metadefs_resource_types.py | 54 - .../image/v2/test_images_metadefs_schema.py | 81 - tempest/api/image/v2/test_images_negative.py | 112 -- tempest/api/image/v2/test_images_tags.py | 38 - .../api/image/v2/test_images_tags_negative.py | 43 - tempest/api/image/v2/test_versions.py | 29 - tempest/api/network/__init__.py | 0 tempest/api/network/admin/__init__.py | 0 .../network/admin/test_agent_management.py | 88 - .../admin/test_dhcp_agent_scheduler.py | 98 -- .../admin/test_external_network_extension.py | 134 -- .../admin/test_external_networks_negative.py | 54 - .../admin/test_floating_ips_admin_actions.py | 121 -- .../network/admin/test_l3_agent_scheduler.py | 84 - .../network/admin/test_metering_extensions.py | 168 -- .../api/network/admin/test_negative_quotas.py | 65 - tempest/api/network/admin/test_ports.py | 99 -- tempest/api/network/admin/test_quotas.py | 85 - tempest/api/network/admin/test_routers.py | 224 --- tempest/api/network/admin/test_routers_dvr.py | 120 -- .../network/admin/test_routers_negative.py | 63 - tempest/api/network/base.py | 272 --- tempest/api/network/base_security_groups.py | 51 - .../api/network/test_allowed_address_pair.py | 135 -- tempest/api/network/test_dhcp_ipv6.py | 374 ----- tempest/api/network/test_extensions.py | 70 - .../api/network/test_extra_dhcp_options.py | 100 -- tempest/api/network/test_floating_ips.py | 225 --- .../api/network/test_floating_ips_negative.py | 89 - tempest/api/network/test_networks.py | 654 -------- tempest/api/network/test_networks_negative.py | 96 -- tempest/api/network/test_ports.py | 359 ---- tempest/api/network/test_routers.py | 319 ---- tempest/api/network/test_routers_negative.py | 142 -- tempest/api/network/test_security_groups.py | 241 --- .../network/test_security_groups_negative.py | 248 --- tempest/api/network/test_service_providers.py | 29 - .../network/test_subnetpools_extensions.py | 74 - tempest/api/network/test_tags.py | 202 --- tempest/api/network/test_versions.py | 40 - tempest/api/object_storage/__init__.py | 0 tempest/api/object_storage/base.py | 145 -- .../api/object_storage/test_account_bulk.py | 155 -- .../api/object_storage/test_account_quotas.py | 115 -- .../test_account_quotas_negative.py | 94 -- .../object_storage/test_account_services.py | 368 ----- .../test_account_services_negative.py | 56 - .../api/object_storage/test_container_acl.py | 87 - .../test_container_acl_negative.py | 228 --- .../object_storage/test_container_quotas.py | 115 -- .../object_storage/test_container_services.py | 389 ----- .../test_container_services_negative.py | 177 -- .../test_container_staticweb.py | 158 -- .../api/object_storage/test_container_sync.py | 147 -- .../test_container_sync_middleware.py | 53 - .../api/object_storage/test_crossdomain.py | 56 - .../api/object_storage/test_healthcheck.py | 40 - .../api/object_storage/test_object_expiry.py | 94 -- .../object_storage/test_object_formpost.py | 127 -- .../test_object_formpost_negative.py | 143 -- .../object_storage/test_object_services.py | 1060 ------------ tempest/api/object_storage/test_object_slo.py | 177 -- .../object_storage/test_object_temp_url.py | 188 --- .../test_object_temp_url_negative.py | 110 -- .../api/object_storage/test_object_version.py | 97 -- tempest/api/volume/__init__.py | 0 tempest/api/volume/admin/__init__.py | 0 .../admin/test_backends_capabilities.py | 79 - tempest/api/volume/admin/test_group_types.py | 54 - tempest/api/volume/admin/test_groups.py | 109 -- .../api/volume/admin/test_multi_backend.py | 141 -- tempest/api/volume/admin/test_qos.py | 159 -- .../api/volume/admin/test_snapshot_manage.py | 98 -- .../volume/admin/test_snapshots_actions.py | 109 -- .../api/volume/admin/test_user_messages.py | 88 - tempest/api/volume/admin/test_volume_hosts.py | 61 - .../api/volume/admin/test_volume_manage.py | 83 - tempest/api/volume/admin/test_volume_pools.py | 39 - .../volume/admin/test_volume_quota_classes.py | 101 -- .../api/volume/admin/test_volume_quotas.py | 183 --- .../admin/test_volume_quotas_negative.py | 71 - .../test_volume_retype_with_migration.py | 109 -- .../api/volume/admin/test_volume_services.py | 92 -- .../test_volume_snapshot_quotas_negative.py | 76 - .../volume/admin/test_volume_type_access.py | 92 -- tempest/api/volume/admin/test_volume_types.py | 194 --- .../admin/test_volume_types_extra_specs.py | 79 - .../test_volume_types_extra_specs_negative.py | 137 -- .../admin/test_volume_types_negative.py | 64 - .../api/volume/admin/test_volumes_actions.py | 100 -- .../api/volume/admin/test_volumes_backup.py | 138 -- tempest/api/volume/admin/test_volumes_list.py | 66 - .../api/volume/api_microversion_fixture.py | 30 - tempest/api/volume/base.py | 341 ---- tempest/api/volume/test_availability_zone.py | 33 - tempest/api/volume/test_extensions.py | 45 - tempest/api/volume/test_image_metadata.py | 72 - tempest/api/volume/test_snapshot_metadata.py | 113 -- tempest/api/volume/test_versions.py | 29 - .../api/volume/test_volume_absolute_limits.py | 51 - .../api/volume/test_volume_delete_cascade.py | 101 -- tempest/api/volume/test_volume_metadata.py | 100 -- tempest/api/volume/test_volume_transfers.py | 100 -- tempest/api/volume/test_volumes_actions.py | 141 -- tempest/api/volume/test_volumes_backup.py | 178 -- tempest/api/volume/test_volumes_clone.py | 68 - .../api/volume/test_volumes_clone_negative.py | 44 - tempest/api/volume/test_volumes_extend.py | 55 - tempest/api/volume/test_volumes_get.py | 153 -- tempest/api/volume/test_volumes_list.py | 380 ----- tempest/api/volume/test_volumes_negative.py | 322 ---- tempest/api/volume/test_volumes_snapshots.py | 165 -- .../api/volume/test_volumes_snapshots_list.py | 160 -- .../volume/test_volumes_snapshots_negative.py | 83 - tempest/clients.py | 316 ---- tempest/cmd/__init__.py | 0 tempest/cmd/account_generator.py | 310 ---- tempest/cmd/cleanup.py | 317 ---- tempest/cmd/cleanup_service.py | 990 ----------- tempest/cmd/config-generator.tempest.conf | 5 - tempest/cmd/init.py | 183 --- tempest/cmd/list_plugins.py | 42 - tempest/cmd/main.py | 52 - tempest/cmd/run.py | 350 ---- tempest/cmd/subunit_describe_calls.py | 317 ---- tempest/cmd/verify_tempest_config.py | 428 ----- tempest/cmd/workspace.py | 262 --- tempest/common/__init__.py | 0 tempest/common/compute.py | 363 ---- tempest/common/credentials_factory.py | 314 ---- tempest/common/custom_matchers.py | 319 ---- tempest/common/identity.py | 32 - tempest/common/image.py | 65 - tempest/common/tempest_fixtures.py | 21 - tempest/common/utils/__init__.py | 38 - tempest/common/utils/linux/__init__.py | 0 tempest/common/utils/linux/remote_client.py | 157 -- tempest/common/utils/net_info.py | 25 - tempest/common/utils/net_utils.py | 73 - tempest/common/validation_resources.py | 154 -- tempest/common/waiters.py | 288 ---- tempest/config.py | 1460 ----------------- tempest/exceptions.py | 56 - tempest/hacking/__init__.py | 0 tempest/hacking/checks.py | 311 ---- tempest/hacking/ignored_list_T110.txt | 1 - tempest/lib/__init__.py | 0 tempest/lib/api_schema/__init__.py | 0 tempest/lib/api_schema/response/__init__.py | 0 .../api_schema/response/compute/__init__.py | 0 .../response/compute/v2_1/__init__.py | 0 .../response/compute/v2_1/agents.py | 82 - .../response/compute/v2_1/aggregates.py | 92 -- .../compute/v2_1/availability_zone.py | 80 - .../response/compute/v2_1/baremetal_nodes.py | 63 - .../response/compute/v2_1/certificates.py | 41 - .../response/compute/v2_1/extensions.py | 46 - .../response/compute/v2_1/fixed_ips.py | 41 - .../response/compute/v2_1/flavors.py | 103 -- .../response/compute/v2_1/flavors_access.py | 36 - .../compute/v2_1/flavors_extra_specs.py | 40 - .../response/compute/v2_1/floating_ips.py | 148 -- .../api_schema/response/compute/v2_1/hosts.py | 119 -- .../response/compute/v2_1/hypervisors.py | 195 --- .../response/compute/v2_1/images.py | 156 -- .../compute/v2_1/instance_usage_audit_logs.py | 78 - .../response/compute/v2_1/interfaces.py | 73 - .../response/compute/v2_1/keypairs.py | 106 -- .../response/compute/v2_1/limits.py | 106 -- .../response/compute/v2_1/migrations.py | 53 - .../response/compute/v2_1/parameter_types.py | 122 -- .../response/compute/v2_1/quota_classes.py | 31 - .../response/compute/v2_1/quotas.py | 183 --- .../v2_1/security_group_default_rule.py | 65 - .../response/compute/v2_1/security_groups.py | 113 -- .../response/compute/v2_1/servers.py | 596 ------- .../response/compute/v2_1/services.py | 89 - .../response/compute/v2_1/snapshots.py | 63 - .../response/compute/v2_1/tenant_networks.py | 53 - .../response/compute/v2_1/tenant_usages.py | 89 - .../response/compute/v2_1/versions.py | 112 -- .../response/compute/v2_1/volumes.py | 122 -- .../response/compute/v2_11/__init__.py | 0 .../response/compute/v2_11/services.py | 46 - .../response/compute/v2_13/__init__.py | 0 .../response/compute/v2_13/servers.py | 34 - .../response/compute/v2_16/__init__.py | 0 .../response/compute/v2_16/servers.py | 160 -- .../response/compute/v2_19/__init__.py | 0 .../response/compute/v2_19/servers.py | 52 - .../response/compute/v2_2/__init__.py | 0 .../response/compute/v2_2/keypairs.py | 41 - .../response/compute/v2_23/__init__.py | 0 .../response/compute/v2_23/migrations.py | 62 - .../response/compute/v2_26/__init__.py | 0 .../response/compute/v2_26/servers.py | 81 - .../response/compute/v2_3/__init__.py | 0 .../response/compute/v2_3/servers.py | 166 -- .../response/compute/v2_47/__init__.py | 0 .../response/compute/v2_47/servers.py | 39 - .../response/compute/v2_48/__init__.py | 0 .../response/compute/v2_48/servers.py | 115 -- .../response/compute/v2_6/__init__.py | 0 .../response/compute/v2_6/servers.py | 48 - .../response/compute/v2_9/__init__.py | 0 .../response/compute/v2_9/servers.py | 31 - .../api_schema/response/volume/__init__.py | 0 .../api_schema/response/volume/versions.py | 60 - tempest/lib/auth.py | 851 ---------- tempest/lib/base.py | 68 - tempest/lib/cli/__init__.py | 0 tempest/lib/cli/base.py | 416 ----- tempest/lib/cli/output_parser.py | 171 -- tempest/lib/cmd/__init__.py | 0 tempest/lib/cmd/check_uuid.py | 362 ---- tempest/lib/cmd/skip_tracker.py | 168 -- tempest/lib/common/__init__.py | 0 tempest/lib/common/api_version_request.py | 159 -- tempest/lib/common/api_version_utils.py | 122 -- tempest/lib/common/cred_client.py | 212 --- tempest/lib/common/cred_provider.py | 107 -- tempest/lib/common/dynamic_creds.py | 477 ------ tempest/lib/common/fixed_network.py | 127 -- tempest/lib/common/http.py | 61 - tempest/lib/common/jsonschema_validator.py | 39 - tempest/lib/common/preprov_creds.py | 374 ----- tempest/lib/common/rest_client.py | 976 ----------- tempest/lib/common/ssh.py | 219 --- tempest/lib/common/utils/__init__.py | 0 tempest/lib/common/utils/data_utils.py | 214 --- tempest/lib/common/utils/linux/__init__.py | 0 .../lib/common/utils/linux/remote_client.py | 126 -- tempest/lib/common/utils/misc.py | 37 - tempest/lib/common/utils/test_utils.py | 107 -- tempest/lib/decorators.py | 124 -- tempest/lib/exceptions.py | 275 ---- tempest/lib/services/__init__.py | 0 tempest/lib/services/clients.py | 466 ------ tempest/lib/services/compute/__init__.py | 77 - tempest/lib/services/compute/agents_client.py | 76 - .../lib/services/compute/aggregates_client.py | 126 -- .../compute/availability_zone_client.py | 36 - .../compute/baremetal_nodes_client.py | 52 - .../services/compute/base_compute_client.py | 91 - .../services/compute/certificates_client.py | 38 - .../lib/services/compute/extensions_client.py | 35 - .../lib/services/compute/fixed_ips_client.py | 42 - .../lib/services/compute/flavors_client.py | 230 --- .../compute/floating_ip_pools_client.py | 35 - .../compute/floating_ips_bulk_client.py | 51 - .../services/compute/floating_ips_client.py | 120 -- tempest/lib/services/compute/hosts_client.py | 104 -- .../lib/services/compute/hypervisor_client.py | 73 - tempest/lib/services/compute/images_client.py | 150 -- .../instance_usage_audit_log_client.py | 39 - .../lib/services/compute/interfaces_client.py | 57 - .../lib/services/compute/keypairs_client.py | 89 - tempest/lib/services/compute/limits_client.py | 29 - .../lib/services/compute/migrations_client.py | 46 - .../lib/services/compute/networks_client.py | 34 - .../services/compute/quota_classes_client.py | 49 - tempest/lib/services/compute/quotas_client.py | 85 - .../security_group_default_rules_client.py | 65 - .../compute/security_group_rules_client.py | 45 - .../compute/security_groups_client.py | 107 -- .../services/compute/server_groups_client.py | 67 - .../lib/services/compute/servers_client.py | 864 ---------- .../lib/services/compute/services_client.py | 102 -- .../lib/services/compute/snapshots_client.py | 84 - .../compute/tenant_networks_client.py | 35 - .../services/compute/tenant_usages_client.py | 56 - .../lib/services/compute/versions_client.py | 55 - .../lib/services/compute/volumes_client.py | 94 -- tempest/lib/services/identity/__init__.py | 18 - tempest/lib/services/identity/v2/__init__.py | 24 - .../services/identity/v2/endpoints_client.py | 49 - .../services/identity/v2/identity_client.py | 69 - .../lib/services/identity/v2/roles_client.py | 109 -- .../services/identity/v2/services_client.py | 65 - .../services/identity/v2/tenants_client.py | 103 -- .../lib/services/identity/v2/token_client.py | 140 -- .../lib/services/identity/v2/users_client.py | 158 -- tempest/lib/services/identity/v3/__init__.py | 54 - .../services/identity/v3/catalog_client.py | 30 - .../identity/v3/credentials_client.py | 91 - .../v3/domain_configuration_client.py | 188 --- .../services/identity/v3/domains_client.py | 84 - .../identity/v3/endpoint_filter_client.py | 68 - .../identity/v3/endpoint_groups_client.py | 78 - .../services/identity/v3/endpoints_client.py | 81 - .../lib/services/identity/v3/groups_client.py | 115 -- .../services/identity/v3/identity_client.py | 59 - .../identity/v3/inherited_roles_client.py | 151 -- .../identity/v3/oauth_consumers_client.py | 95 -- .../identity/v3/oauth_token_client.py | 236 --- .../services/identity/v3/policies_client.py | 75 - .../services/identity/v3/projects_client.py | 75 - .../services/identity/v3/regions_client.py | 83 - .../identity/v3/role_assignments_client.py | 48 - .../lib/services/identity/v3/roles_client.py | 241 --- .../services/identity/v3/services_client.py | 82 - .../lib/services/identity/v3/token_client.py | 199 --- .../lib/services/identity/v3/trusts_client.py | 85 - .../lib/services/identity/v3/users_client.py | 120 -- .../services/identity/v3/versions_client.py | 38 - tempest/lib/services/image/__init__.py | 18 - tempest/lib/services/image/v1/__init__.py | 19 - .../services/image/v1/image_members_client.py | 66 - .../lib/services/image/v1/images_client.py | 155 -- tempest/lib/services/image/v2/__init__.py | 33 - .../services/image/v2/image_members_client.py | 84 - .../lib/services/image/v2/images_client.py | 189 --- .../image/v2/namespace_objects_client.py | 91 - .../image/v2/namespace_properties_client.py | 91 - .../image/v2/namespace_tags_client.py | 125 -- .../services/image/v2/namespaces_client.py | 91 - .../image/v2/resource_types_client.py | 75 - .../lib/services/image/v2/schemas_client.py | 29 - .../lib/services/image/v2/versions_client.py | 38 - tempest/lib/services/network/__init__.py | 42 - tempest/lib/services/network/agents_client.py | 68 - tempest/lib/services/network/base.py | 85 - .../lib/services/network/extensions_client.py | 24 - .../services/network/floating_ips_client.py | 65 - .../network/metering_label_rules_client.py | 33 - .../network/metering_labels_client.py | 57 - .../lib/services/network/networks_client.py | 76 - tempest/lib/services/network/ports_client.py | 86 - tempest/lib/services/network/quotas_client.py | 37 - .../lib/services/network/routers_client.py | 86 - .../network/security_group_rules_client.py | 51 - .../network/security_groups_client.py | 68 - .../network/service_providers_client.py | 21 - .../services/network/subnetpools_client.py | 64 - .../lib/services/network/subnets_client.py | 72 - tempest/lib/services/network/tags_client.py | 84 - .../lib/services/network/versions_client.py | 46 - tempest/lib/services/volume/__init__.py | 19 - tempest/lib/services/volume/base_client.py | 45 - tempest/lib/services/volume/v1/__init__.py | 33 - .../volume/v1/availability_zone_client.py | 28 - .../lib/services/volume/v1/backups_client.py | 104 -- .../volume/v1/encryption_types_client.py | 68 - .../services/volume/v1/extensions_client.py | 29 - .../lib/services/volume/v1/hosts_client.py | 35 - .../lib/services/volume/v1/limits_client.py | 32 - tempest/lib/services/volume/v1/qos_client.py | 131 -- .../lib/services/volume/v1/quotas_client.py | 62 - .../lib/services/volume/v1/services_client.py | 33 - .../services/volume/v1/snapshots_client.py | 186 --- .../lib/services/volume/v1/types_client.py | 165 -- .../lib/services/volume/v1/volumes_client.py | 301 ---- tempest/lib/services/volume/v2/__init__.py | 46 - .../volume/v2/availability_zone_client.py | 28 - .../lib/services/volume/v2/backups_client.py | 114 -- .../services/volume/v2/capabilities_client.py | 35 - .../volume/v2/encryption_types_client.py | 83 - .../services/volume/v2/extensions_client.py | 30 - .../lib/services/volume/v2/hosts_client.py | 48 - .../lib/services/volume/v2/limits_client.py | 32 - tempest/lib/services/volume/v2/qos_client.py | 133 -- .../volume/v2/quota_classes_client.py | 49 - .../lib/services/volume/v2/quotas_client.py | 64 - .../volume/v2/scheduler_stats_client.py | 37 - .../lib/services/volume/v2/services_client.py | 34 - .../volume/v2/snapshot_manage_client.py | 33 - .../services/volume/v2/snapshots_client.py | 208 --- .../services/volume/v2/transfers_client.py | 83 - .../lib/services/volume/v2/types_client.py | 205 --- .../volume/v2/volume_manage_client.py | 37 - .../lib/services/volume/v2/volumes_client.py | 396 ----- tempest/lib/services/volume/v3/__init__.py | 24 - .../lib/services/volume/v3/backups_client.py | 37 - tempest/lib/services/volume/v3/base_client.py | 23 - .../services/volume/v3/group_types_client.py | 77 - .../lib/services/volume/v3/groups_client.py | 97 -- .../lib/services/volume/v3/messages_client.py | 60 - .../lib/services/volume/v3/versions_client.py | 48 - .../lib/services/volume/v3/volumes_client.py | 40 - tempest/manager.py | 62 - ...lue-to-retype-volume-a401aa619aaa2457.yaml | 5 - tempest/scenario/README.rst | 49 - tempest/scenario/__init__.py | 0 tempest/scenario/manager.py | 1375 ---------------- tempest/scenario/test_aggregates_basic_ops.py | 125 -- .../scenario/test_encrypted_cinder_volumes.py | 73 - tempest/scenario/test_minimum_basic.py | 173 -- .../test_network_advanced_server_ops.py | 251 --- tempest/scenario/test_network_basic_ops.py | 857 ---------- tempest/scenario/test_network_v6.py | 258 --- .../scenario/test_object_storage_basic_ops.py | 69 - .../test_security_groups_basic_ops.py | 658 -------- tempest/scenario/test_server_advanced_ops.py | 84 - tempest/scenario/test_server_basic_ops.py | 151 -- tempest/scenario/test_server_multinode.py | 87 - tempest/scenario/test_shelve_instance.py | 91 - tempest/scenario/test_snapshot_pattern.py | 75 - tempest/scenario/test_stamp_pattern.py | 130 -- tempest/scenario/test_volume_boot_pattern.py | 236 --- .../scenario/test_volume_migrate_attached.py | 127 -- tempest/services/__init__.py | 0 tempest/services/object_storage/__init__.py | 24 - .../services/object_storage/account_client.py | 99 -- .../object_storage/bulk_middleware_client.py | 62 - .../object_storage/capabilities_client.py | 31 - .../object_storage/container_client.py | 150 -- .../services/object_storage/object_client.py | 231 --- tempest/services/orchestration/__init__.py | 18 - .../services/orchestration/json/__init__.py | 0 .../json/orchestration_client.py | 413 ----- tempest/test.py | 680 -------- tempest/test_discover/__init__.py | 0 tempest/test_discover/plugins.py | 225 --- tempest/test_discover/test_discover.py | 54 - tempest/tests/README.rst | 27 - tempest/tests/__init__.py | 0 tempest/tests/api/__init__.py | 0 tempest/tests/api/compute/__init__.py | 0 tempest/tests/api/compute/test_base.py | 173 -- tempest/tests/base.py | 49 - tempest/tests/cmd/__init__.py | 0 .../tests/cmd/sample_streams/calls.subunit | Bin 7267 -> 0 bytes tempest/tests/cmd/test_account_generator.py | 332 ---- tempest/tests/cmd/test_list_plugins.py | 24 - tempest/tests/cmd/test_run.py | 154 -- .../tests/cmd/test_subunit_describe_calls.py | 206 --- tempest/tests/cmd/test_tempest_init.py | 154 -- .../tests/cmd/test_verify_tempest_config.py | 431 ----- tempest/tests/cmd/test_workspace.py | 142 -- tempest/tests/common/__init__.py | 0 tempest/tests/common/test_admin_available.py | 120 -- tempest/tests/common/test_alt_available.py | 81 - tempest/tests/common/test_compute.py | 106 -- tempest/tests/common/test_custom_matchers.py | 102 -- tempest/tests/common/test_image.py | 61 - tempest/tests/common/test_waiters.py | 73 - tempest/tests/common/utils/__init__.py | 0 tempest/tests/common/utils/linux/__init__.py | 0 .../common/utils/linux/test_remote_client.py | 214 --- tempest/tests/common/utils/test_net_utils.py | 33 - tempest/tests/fake_config.py | 106 -- tempest/tests/fake_tempest_plugin.py | 67 - tempest/tests/files/__init__.py | 0 tempest/tests/files/failing-tests | 23 - tempest/tests/files/passing-tests | 23 - tempest/tests/files/setup.cfg | 20 - tempest/tests/files/testr-conf | 5 - tempest/tests/lib/__init__.py | 0 tempest/tests/lib/cli/__init__.py | 0 tempest/tests/lib/cli/test_command_failed.py | 30 - tempest/tests/lib/cli/test_execute.py | 93 -- tempest/tests/lib/cli/test_output_parser.py | 177 -- tempest/tests/lib/common/__init__.py | 0 .../lib/common/test_api_version_request.py | 146 -- .../lib/common/test_api_version_utils.py | 114 -- tempest/tests/lib/common/test_cred_client.py | 77 - .../tests/lib/common/test_dynamic_creds.py | 667 -------- .../lib/common/test_jsonschema_validator.py | 83 - .../tests/lib/common/test_preprov_creds.py | 487 ------ tempest/tests/lib/common/test_rest_client.py | 1158 ------------- tempest/tests/lib/common/utils/__init__.py | 0 .../tests/lib/common/utils/linux/__init__.py | 0 .../common/utils/linux/test_remote_client.py | 67 - .../tests/lib/common/utils/test_data_utils.py | 182 -- tempest/tests/lib/common/utils/test_misc.py | 52 - .../tests/lib/common/utils/test_test_utils.py | 103 -- tempest/tests/lib/fake_auth_provider.py | 38 - tempest/tests/lib/fake_credentials.py | 74 - tempest/tests/lib/fake_http.py | 77 - tempest/tests/lib/fake_identity.py | 240 --- tempest/tests/lib/services/__init__.py | 0 tempest/tests/lib/services/base.py | 77 - .../tests/lib/services/compute/__init__.py | 0 .../services/compute/test_agents_client.py | 103 -- .../compute/test_aggregates_client.py | 192 --- .../compute/test_availability_zone_client.py | 51 - .../compute/test_baremetal_nodes_client.py | 74 - .../compute/test_base_compute_client.py | 206 --- .../compute/test_certificates_client.py | 64 - .../compute/test_extensions_client.py | 65 - .../services/compute/test_fixedIPs_client.py | 58 - .../services/compute/test_flavors_client.py | 255 --- .../compute/test_floating_ip_pools_client.py | 46 - .../compute/test_floating_ips_bulk_client.py | 88 - .../compute/test_floating_ips_client.py | 113 -- .../lib/services/compute/test_hosts_client.py | 147 -- .../compute/test_hypervisor_client.py | 167 -- .../services/compute/test_images_client.py | 264 --- .../test_instance_usage_audit_log_client.py | 73 - .../compute/test_interfaces_client.py | 98 -- .../services/compute/test_keypairs_client.py | 94 -- .../services/compute/test_limits_client.py | 66 - .../compute/test_migrations_client.py | 52 - .../services/compute/test_networks_client.py | 94 -- .../compute/test_quota_classes_client.py | 71 - .../services/compute/test_quotas_client.py | 146 -- ...est_security_group_default_rules_client.py | 88 - .../test_security_group_rules_client.py | 66 - .../compute/test_security_groups_client.py | 113 -- .../compute/test_server_groups_client.py | 101 -- .../services/compute/test_servers_client.py | 1076 ------------ .../services/compute/test_services_client.py | 146 -- .../services/compute/test_snapshots_client.py | 103 -- .../compute/test_tenant_networks_client.py | 63 - .../compute/test_tenant_usages_client.py | 79 - .../services/compute/test_versions_client.py | 136 -- .../services/compute/test_volumes_client.py | 114 -- .../tests/lib/services/identity/__init__.py | 0 .../lib/services/identity/v2/__init__.py | 0 .../identity/v2/test_endpoints_client.py | 99 -- .../identity/v2/test_identity_client.py | 230 --- .../services/identity/v2/test_roles_client.py | 141 -- .../identity/v2/test_services_client.py | 97 -- .../identity/v2/test_tenants_client.py | 131 -- .../services/identity/v2/test_token_client.py | 104 -- .../services/identity/v2/test_users_client.py | 243 --- .../lib/services/identity/v3/__init__.py | 0 .../identity/v3/test_catalog_client.py | 86 - .../identity/v3/test_credentials_client.py | 179 -- .../v3/test_domain_configuration_client.py | 217 --- .../identity/v3/test_domains_client.py | 138 -- .../v3/test_endpoint_filter_client.py | 165 -- .../v3/test_endpoint_groups_client.py | 162 -- .../identity/v3/test_endpoints_client.py | 115 -- .../identity/v3/test_groups_client.py | 213 --- .../identity/v3/test_identity_client.py | 124 -- .../v3/test_inherited_roles_client.py | 220 --- .../v3/test_oauth_consumers_client.py | 160 -- .../identity/v3/test_oauth_token_client.py | 215 --- .../identity/v3/test_policies_client.py | 152 -- .../identity/v3/test_projects_client.py | 178 -- .../identity/v3/test_regions_client.py | 125 -- .../v3/test_role_assignments_client.py | 206 --- .../services/identity/v3/test_roles_client.py | 508 ------ .../identity/v3/test_services_client.py | 156 -- .../services/identity/v3/test_token_client.py | 153 -- .../identity/v3/test_trusts_client.py | 150 -- .../services/identity/v3/test_users_client.py | 205 --- .../identity/v3/test_versions_client.py | 70 - tempest/tests/lib/services/image/__init__.py | 0 .../tests/lib/services/image/v1/__init__.py | 0 .../image/v1/test_image_members_client.py | 84 - .../tests/lib/services/image/v2/__init__.py | 0 .../image/v2/test_image_members_client.py | 90 - .../services/image/v2/test_images_client.py | 111 -- .../image/v2/test_namespace_object_client.py | 210 --- .../v2/test_namespace_properties_client.py | 191 --- .../image/v2/test_namespace_tags_client.py | 126 -- .../image/v2/test_namespaces_client.py | 93 -- .../image/v2/test_resource_types_client.py | 69 - .../services/image/v2/test_schemas_client.py | 96 -- .../services/image/v2/test_versions_client.py | 94 -- .../tests/lib/services/network/__init__.py | 0 .../network/test_base_network_client.py | 96 -- .../network/test_extensions_client.py | 201 --- .../network/test_floating_ips_client.py | 145 -- .../test_metering_label_rules_client.py | 110 -- .../network/test_metering_labels_client.py | 107 -- .../lib/services/network/test_ports_client.py | 198 --- .../services/network/test_quotas_client.py | 99 -- .../services/network/test_routers_client.py | 109 -- .../test_security_group_rules_client.py | 138 -- .../network/test_security_groups_client.py | 174 -- .../network/test_service_providers_client.py | 37 - .../network/test_subnetpools_client.py | 163 -- .../services/network/test_subnets_client.py | 250 --- .../lib/services/network/test_tags_client.py | 123 -- .../services/network/test_versions_client.py | 74 - tempest/tests/lib/services/test_clients.py | 370 ----- tempest/tests/lib/services/volume/__init__.py | 0 .../tests/lib/services/volume/v1/__init__.py | 0 .../volume/v1/test_encryption_types_client.py | 86 - .../services/volume/v1/test_quotas_client.py | 96 -- .../volume/v1/test_snapshots_client.py | 200 --- .../tests/lib/services/volume/v2/__init__.py | 0 .../services/volume/v2/test_backups_client.py | 117 -- .../volume/v2/test_capabilities_client.py | 77 - .../volume/v2/test_encryption_types_client.py | 86 - .../volume/v2/test_extensions_client.py | 70 - .../services/volume/v2/test_hosts_client.py | 97 -- .../services/volume/v2/test_limits_client.py | 59 - .../volume/v2/test_quota_classes_client.py | 71 - .../services/volume/v2/test_quotas_client.py | 86 - .../volume/v2/test_scheduler_stats_client.py | 83 - .../volume/v2/test_snapshot_manage_client.py | 83 - .../volume/v2/test_snapshots_client.py | 222 --- .../volume/v2/test_transfers_client.py | 158 -- .../volume/v2/test_volume_manage_client.py | 111 -- .../services/volume/v2/test_volumes_client.py | 95 -- .../tests/lib/services/volume/v3/__init__.py | 0 .../services/volume/v3/test_backups_client.py | 50 - .../volume/v3/test_group_types_client.py | 124 -- .../services/volume/v3/test_groups_client.py | 136 -- .../volume/v3/test_user_messages_client.py | 92 -- .../volume/v3/test_versions_client.py | 91 - .../services/volume/v3/test_volumes_client.py | 48 - tempest/tests/lib/test_auth.py | 915 ----------- tempest/tests/lib/test_base.py | 64 - tempest/tests/lib/test_credentials.py | 182 -- tempest/tests/lib/test_decorators.py | 184 --- tempest/tests/lib/test_ssh.py | 305 ---- tempest/tests/lib/test_tempest_lib.py | 26 - tempest/tests/services/__init__.py | 0 .../tests/services/object_storage/__init__.py | 0 .../test_bulk_middleware_client.py | 66 - .../test_capabilities_client.py | 54 - .../object_storage/test_object_client.py | 108 -- tempest/tests/test_base_test.py | 110 -- tempest/tests/test_config.py | 89 - tempest/tests/test_decorators.py | 265 --- tempest/tests/test_hacking.py | 182 -- tempest/tests/test_list_tests.py | 46 - tempest/tests/test_microversions.py | 153 -- tempest/tests/test_tempest_plugin.py | 79 - tempest/tests/utils.py | 29 - tempest/version.py | 18 - test-requirements.txt | 12 - tools/check_logs.py | 196 --- tools/find_stack_traces.py | 160 -- tools/generate-tempest-plugins-list.py | 89 - tools/generate-tempest-plugins-list.sh | 66 - tools/skip_tracker.py | 29 - tools/tempest-plugin-sanity.sh | 122 -- tools/tox_install.sh | 30 - tools/with_venv.sh | 6 - tox.ini | 193 --- 1026 files changed, 14 insertions(+), 104060 deletions(-) delete mode 100644 .coveragerc delete mode 100644 .gitignore delete mode 100644 .gitreview delete mode 100644 .mailmap delete mode 100644 .testr.conf delete mode 100644 HACKING.rst delete mode 100644 LICENSE create mode 100644 README delete mode 100644 README.rst delete mode 100644 REVIEWING.rst delete mode 100644 bindep.txt delete mode 100644 data/tempest-plugins-registry.header delete mode 120000 doc/source/HACKING.rst delete mode 120000 doc/source/REVIEWING.rst delete mode 100644 doc/source/_static/.keep delete mode 100644 doc/source/account_generator.rst delete mode 100644 doc/source/cleanup.rst delete mode 100644 doc/source/conf.py delete mode 100644 doc/source/configuration.rst delete mode 120000 doc/source/field_guide/api.rst delete mode 120000 doc/source/field_guide/index.rst delete mode 120000 doc/source/field_guide/scenario.rst delete mode 120000 doc/source/field_guide/unit_tests.rst delete mode 100644 doc/source/index.rst delete mode 100644 doc/source/library.rst delete mode 100644 doc/source/library/api_microversion_testing.rst delete mode 100644 doc/source/library/auth.rst delete mode 100644 doc/source/library/cli.rst delete mode 100644 doc/source/library/clients.rst delete mode 100644 doc/source/library/credential_providers.rst delete mode 100644 doc/source/library/decorators.rst delete mode 100644 doc/source/library/rest_client.rst delete mode 100644 doc/source/library/service_clients/compute_clients.rst delete mode 100644 doc/source/library/utils.rst delete mode 100644 doc/source/microversion_testing.rst delete mode 120000 doc/source/overview.rst delete mode 100644 doc/source/plugin.rst delete mode 100644 doc/source/run.rst delete mode 100644 doc/source/sampleconf.rst delete mode 100644 doc/source/subunit_describe_calls.rst delete mode 100644 doc/source/test_removal.rst delete mode 100644 doc/source/workspace.rst delete mode 100644 doc/source/write_tests.rst delete mode 100644 etc/accounts.yaml.sample delete mode 100644 etc/logging.conf.sample delete mode 100644 etc/whitelist.yaml delete mode 100644 releasenotes/notes/10/10.0-supported-openstack-releases-b88db468695348f6.yaml delete mode 100644 releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml delete mode 100644 releasenotes/notes/10/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml delete mode 100644 releasenotes/notes/11/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml delete mode 100644 releasenotes/notes/11/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml delete mode 100644 releasenotes/notes/11/11.0.0-supported-openstack-releases-1e5d7295d939d439.yaml delete mode 100644 releasenotes/notes/12/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml delete mode 100644 releasenotes/notes/12/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml delete mode 100644 releasenotes/notes/12/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml delete mode 100644 releasenotes/notes/12/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml delete mode 100644 releasenotes/notes/12/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml delete mode 100644 releasenotes/notes/12/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml delete mode 100644 releasenotes/notes/12/12.1.0-bug-1486834-7ebca15836ae27a9.yaml delete mode 100644 releasenotes/notes/12/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml delete mode 100644 releasenotes/notes/12/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml delete mode 100644 releasenotes/notes/12/12.1.0-new-test-utils-module-adf34468c4d52719.yaml delete mode 100644 releasenotes/notes/12/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml delete mode 100644 releasenotes/notes/12/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml delete mode 100644 releasenotes/notes/12/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml delete mode 100644 releasenotes/notes/12/12.1.0-remove-trove-tests-666522e9113549f9.yaml delete mode 100644 releasenotes/notes/12/12.1.0-routers-client-as-library-25a363379da351f6.yaml delete mode 100644 releasenotes/notes/12/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml delete mode 100644 releasenotes/notes/12/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml delete mode 100644 releasenotes/notes/12/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml delete mode 100644 releasenotes/notes/12/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml delete mode 100644 releasenotes/notes/12/12.2.0-clients_module-16f3025f515bf9ec.yaml delete mode 100644 releasenotes/notes/12/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml delete mode 100644 releasenotes/notes/12/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml delete mode 100644 releasenotes/notes/12/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml delete mode 100644 releasenotes/notes/12/12.2.0-service_client_config-8a1d7b4de769c633.yaml delete mode 100644 releasenotes/notes/12/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml delete mode 100644 releasenotes/notes/13/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml delete mode 100644 releasenotes/notes/13/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml delete mode 100644 releasenotes/notes/13/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml delete mode 100644 releasenotes/notes/13/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml delete mode 100644 releasenotes/notes/13/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml delete mode 100644 releasenotes/notes/13/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml delete mode 100644 releasenotes/notes/13/13.0.0-volume-clients-as-library-660811011be29d1a.yaml delete mode 100644 releasenotes/notes/14/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml delete mode 100644 releasenotes/notes/14/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml delete mode 100644 releasenotes/notes/14/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml delete mode 100644 releasenotes/notes/14/14.0.0-add-image-clients-af94564fb34ddca6.yaml delete mode 100644 releasenotes/notes/14/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml delete mode 100644 releasenotes/notes/14/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml delete mode 100644 releasenotes/notes/14/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml delete mode 100644 releasenotes/notes/14/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml delete mode 100644 releasenotes/notes/14/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml delete mode 100644 releasenotes/notes/14/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml delete mode 100644 releasenotes/notes/14/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml delete mode 100644 releasenotes/notes/14/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml delete mode 100644 releasenotes/notes/14/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml delete mode 100644 releasenotes/notes/14/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml delete mode 100644 releasenotes/notes/14/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml delete mode 100644 releasenotes/notes/14/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml delete mode 100644 releasenotes/notes/15/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml delete mode 100644 releasenotes/notes/15/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml delete mode 100644 releasenotes/notes/15/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml delete mode 100644 releasenotes/notes/15/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml delete mode 100644 releasenotes/notes/15/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml delete mode 100644 releasenotes/notes/15/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml delete mode 100644 releasenotes/notes/15/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml delete mode 100644 releasenotes/notes/15/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml delete mode 100644 releasenotes/notes/15/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml delete mode 100644 releasenotes/notes/15/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml delete mode 100644 releasenotes/notes/15/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml delete mode 100644 releasenotes/notes/15/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-cascade-parameter-to-volumes-client-ff4f7f12795003a4.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-content-type-without-spaces-b2c9b91b257814f3.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-list-auth-project-client-5905076d914a3943.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-list-version-to-identity-client-944cb7396088a575.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-tempest-lib-remote-client-adbeb3f42a36910b.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-tempest-run-combine-option-e94c1049ba8985d5.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml delete mode 100644 releasenotes/notes/16/16.0.0-add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml delete mode 100644 releasenotes/notes/16/16.0.0-create-server-tags-client-8c0042a77e859af6.yaml delete mode 100644 releasenotes/notes/16/16.0.0-deprecate-deactivate_image-config-7a282c471937bbcb.yaml delete mode 100644 releasenotes/notes/16/16.0.0-deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml delete mode 100644 releasenotes/notes/16/16.0.0-deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml delete mode 100644 releasenotes/notes/16/16.0.0-deprecate-resources-prefix-option-ad490c0a30a0266b.yaml delete mode 100644 releasenotes/notes/16/16.0.0-deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml delete mode 100644 releasenotes/notes/16/16.0.0-deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml delete mode 100644 releasenotes/notes/16/16.0.0-deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml delete mode 100644 releasenotes/notes/16/16.0.0-dreprecate_client_parameters-cb8d069e62957f7e.yaml delete mode 100644 releasenotes/notes/16/16.0.0-fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml delete mode 100644 releasenotes/notes/16/16.0.0-mitaka-eol-88ff8355fff81b55.yaml delete mode 100644 releasenotes/notes/16/16.0.0-remove-call_until_true-of-test-de9c13bc8f969921.yaml delete mode 100644 releasenotes/notes/16/16.0.0-remove-cinder-v1-api-tests-71e266b8d55d475f.yaml delete mode 100644 releasenotes/notes/16/16.0.0-remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml delete mode 100644 releasenotes/notes/16/16.0.0-remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml delete mode 100644 releasenotes/notes/16/16.0.0-remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml delete mode 100644 releasenotes/notes/16/16.0.0-remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml delete mode 100644 releasenotes/notes/16/16.0.0-remove-sahara-service-available-44a642aa9c634ab4.yaml delete mode 100644 releasenotes/notes/16/16.0.0-remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml delete mode 100644 releasenotes/notes/16/16.0.0-use-keystone-v3-api-935860d30ddbb8e9.yaml delete mode 100644 releasenotes/notes/16/16.0.0-volume-transfers-client-e5ed3f5464c0cdc0.yaml delete mode 100644 releasenotes/notes/add-OAUTH-Token-Client-tempest-tests-6351eda451b95a86.yaml delete mode 100644 releasenotes/notes/add-compute-feature-serial-console-45583c4341e34fc9.yaml delete mode 100644 releasenotes/notes/add-domain-configuration-client-tempest-tests-e383efabdbb9ad03.yaml delete mode 100644 releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml delete mode 100644 releasenotes/notes/add-force-detach-volume-to-volumes-client-library-b2071f2954f8e8b1.yaml delete mode 100644 releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml delete mode 100644 releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-extensions-9cfd217fd2c6a61f.yaml delete mode 100644 releasenotes/notes/add-kwargs-to-delete-vol-of-vol-client-1ecde75beb62933c.yaml delete mode 100644 releasenotes/notes/add-list-volume-transfers-with-detail-to-transfers-client-80169bf78cf4fa66.yaml delete mode 100644 releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml delete mode 100644 releasenotes/notes/add-params-to-identity-v3-list-endpoints-958a155be4e17e5b.yaml delete mode 100644 releasenotes/notes/add-params-to-v2-list-backups-api-c088d2b4bfe90247.yaml delete mode 100644 releasenotes/notes/add-save-state-option-5ea67858cbaca969.yaml delete mode 100644 releasenotes/notes/add-server-diagnostics-validation-schema-b5a3c55b45aa718a.yaml delete mode 100644 releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml delete mode 100644 releasenotes/notes/add-show-snapshot-metadata-item-api-to-v2-snapshots-client-bd3cbab3c7f0e0b3.yaml delete mode 100644 releasenotes/notes/add-show-volume-metadata-item-api-to-v2-volumes-client-47d59ecd999ca9df.yaml delete mode 100644 releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml delete mode 100644 releasenotes/notes/add-update-backup-api-to-v3-backups-client-e8465b2b66617dc0.yaml delete mode 100644 releasenotes/notes/add-volume-group-types-tempest-tests-1298ab8cb4fe8b7b.yaml delete mode 100644 releasenotes/notes/add-volume-groups-tempest-tests-dd7b2abfe2b48427.yaml delete mode 100644 releasenotes/notes/add-volume-quota-class-client-as-library-c4c2b22c36ff807e.yaml delete mode 100644 releasenotes/notes/api_v2_admin_flag-dea5ca9bc2ce63bc.yaml delete mode 100644 releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml delete mode 100644 releasenotes/notes/deprecate-config-forbid_global_implied_dsr-e64cfa66e6e3ded5.yaml delete mode 100644 releasenotes/notes/deprecate-default-value-for-v3_endpoint_type-fb9e47c5ba1c719d.yaml delete mode 100644 releasenotes/notes/extra-compute-services-tests-92b6c0618972e02f.yaml delete mode 100644 releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml delete mode 100644 releasenotes/notes/identity_client-635275d43abbb807.yaml delete mode 100644 releasenotes/notes/intermediate-pike-release-2ce492432ff8f012.yaml delete mode 100644 releasenotes/notes/migrate-dynamic-creds-ecebb47528080761.yaml delete mode 100644 releasenotes/notes/migrate-preprov-creds-ef61a046ee1ec604.yaml delete mode 100644 releasenotes/notes/move-attr-decorator-to-lib-a1e80c42ba9c5392.yaml delete mode 100644 releasenotes/notes/move-related_bug-decorator-to-lib-dbfd5c543bbb2805.yaml delete mode 100644 releasenotes/notes/move-volume-v3-base_client-to-volume-1edbz0f207c3b283.yaml delete mode 100644 releasenotes/notes/network-tag-client-f4614029af7927f0.yaml delete mode 100644 releasenotes/notes/pause_teardown-45c9d60ffa889f7f.yaml delete mode 100644 releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml delete mode 100644 releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml delete mode 100644 releasenotes/notes/set-cinder-api-v3-option-true-1b3e61e3129b7c00.yaml delete mode 100644 releasenotes/notes/tempest-identity-catalog-client-f5c8589a9d7c1eb5.yaml delete mode 100644 releasenotes/notes/tempest-workspace-delete-directory-feature-74d6d157a5a05561.yaml delete mode 100644 releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml delete mode 100644 releasenotes/source/_static/.placeholder delete mode 100644 releasenotes/source/_templates/.placeholder delete mode 100644 releasenotes/source/conf.py delete mode 100644 releasenotes/source/index.rst delete mode 100644 releasenotes/source/unreleased.rst delete mode 100644 releasenotes/source/v10.0.0.rst delete mode 100644 releasenotes/source/v11.0.0.rst delete mode 100644 releasenotes/source/v12.0.0.rst delete mode 100644 releasenotes/source/v13.0.0.rst delete mode 100644 releasenotes/source/v14.0.0.rst delete mode 100644 releasenotes/source/v15.0.0.rst delete mode 100644 releasenotes/source/v16.0.0.rst delete mode 100644 releasenotes/source/v16.1.0.rst delete mode 100644 requirements.txt delete mode 100644 setup.cfg delete mode 100644 setup.py delete mode 100644 tempest/README.rst delete mode 100644 tempest/__init__.py delete mode 100644 tempest/api/README.rst delete mode 100644 tempest/api/__init__.py delete mode 100644 tempest/api/compute/__init__.py delete mode 100644 tempest/api/compute/admin/__init__.py delete mode 100644 tempest/api/compute/admin/test_agents.py delete mode 100644 tempest/api/compute/admin/test_aggregates.py delete mode 100644 tempest/api/compute/admin/test_aggregates_negative.py delete mode 100644 tempest/api/compute/admin/test_auto_allocate_network.py delete mode 100644 tempest/api/compute/admin/test_availability_zone.py delete mode 100644 tempest/api/compute/admin/test_availability_zone_negative.py delete mode 100644 tempest/api/compute/admin/test_create_server.py delete mode 100644 tempest/api/compute/admin/test_delete_server.py delete mode 100644 tempest/api/compute/admin/test_fixed_ips.py delete mode 100644 tempest/api/compute/admin/test_fixed_ips_negative.py delete mode 100644 tempest/api/compute/admin/test_flavors.py delete mode 100644 tempest/api/compute/admin/test_flavors_access.py delete mode 100644 tempest/api/compute/admin/test_flavors_access_negative.py delete mode 100644 tempest/api/compute/admin/test_flavors_extra_specs.py delete mode 100644 tempest/api/compute/admin/test_flavors_extra_specs_negative.py delete mode 100644 tempest/api/compute/admin/test_floating_ips_bulk.py delete mode 100644 tempest/api/compute/admin/test_hosts.py delete mode 100644 tempest/api/compute/admin/test_hosts_negative.py delete mode 100644 tempest/api/compute/admin/test_hypervisor.py delete mode 100644 tempest/api/compute/admin/test_hypervisor_negative.py delete mode 100644 tempest/api/compute/admin/test_instance_usage_audit_log.py delete mode 100644 tempest/api/compute/admin/test_instance_usage_audit_log_negative.py delete mode 100644 tempest/api/compute/admin/test_keypairs_v210.py delete mode 100644 tempest/api/compute/admin/test_live_migration.py delete mode 100644 tempest/api/compute/admin/test_live_migration_negative.py delete mode 100644 tempest/api/compute/admin/test_migrations.py delete mode 100644 tempest/api/compute/admin/test_networks.py delete mode 100644 tempest/api/compute/admin/test_quotas.py delete mode 100644 tempest/api/compute/admin/test_quotas_negative.py delete mode 100644 tempest/api/compute/admin/test_security_group_default_rules.py delete mode 100644 tempest/api/compute/admin/test_security_groups.py delete mode 100644 tempest/api/compute/admin/test_server_diagnostics.py delete mode 100644 tempest/api/compute/admin/test_server_diagnostics_negative.py delete mode 100644 tempest/api/compute/admin/test_servers.py delete mode 100644 tempest/api/compute/admin/test_servers_negative.py delete mode 100644 tempest/api/compute/admin/test_servers_on_multinodes.py delete mode 100644 tempest/api/compute/admin/test_services.py delete mode 100644 tempest/api/compute/admin/test_services_negative.py delete mode 100644 tempest/api/compute/admin/test_simple_tenant_usage.py delete mode 100644 tempest/api/compute/admin/test_simple_tenant_usage_negative.py delete mode 100644 tempest/api/compute/admin/test_volume_swap.py delete mode 100644 tempest/api/compute/admin/test_volumes_negative.py delete mode 100644 tempest/api/compute/api_microversion_fixture.py delete mode 100644 tempest/api/compute/base.py delete mode 100644 tempest/api/compute/certificates/__init__.py delete mode 100644 tempest/api/compute/certificates/test_certificates.py delete mode 100644 tempest/api/compute/flavors/__init__.py delete mode 100644 tempest/api/compute/flavors/test_flavors.py delete mode 100644 tempest/api/compute/flavors/test_flavors_negative.py delete mode 100644 tempest/api/compute/floating_ips/__init__.py delete mode 100644 tempest/api/compute/floating_ips/base.py delete mode 100644 tempest/api/compute/floating_ips/test_floating_ips_actions.py delete mode 100644 tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py delete mode 100644 tempest/api/compute/floating_ips/test_list_floating_ips.py delete mode 100644 tempest/api/compute/floating_ips/test_list_floating_ips_negative.py delete mode 100644 tempest/api/compute/images/__init__.py delete mode 100644 tempest/api/compute/images/test_image_metadata.py delete mode 100644 tempest/api/compute/images/test_image_metadata_negative.py delete mode 100644 tempest/api/compute/images/test_images.py delete mode 100644 tempest/api/compute/images/test_images_negative.py delete mode 100644 tempest/api/compute/images/test_images_oneserver.py delete mode 100644 tempest/api/compute/images/test_images_oneserver_negative.py delete mode 100644 tempest/api/compute/images/test_list_image_filters.py delete mode 100644 tempest/api/compute/images/test_list_image_filters_negative.py delete mode 100644 tempest/api/compute/images/test_list_images.py delete mode 100644 tempest/api/compute/keypairs/__init__.py delete mode 100644 tempest/api/compute/keypairs/base.py delete mode 100644 tempest/api/compute/keypairs/test_keypairs.py delete mode 100644 tempest/api/compute/keypairs/test_keypairs_negative.py delete mode 100644 tempest/api/compute/keypairs/test_keypairs_v22.py delete mode 100644 tempest/api/compute/limits/__init__.py delete mode 100644 tempest/api/compute/limits/test_absolute_limits.py delete mode 100644 tempest/api/compute/limits/test_absolute_limits_negative.py delete mode 100644 tempest/api/compute/security_groups/__init__.py delete mode 100644 tempest/api/compute/security_groups/base.py delete mode 100644 tempest/api/compute/security_groups/test_security_group_rules.py delete mode 100644 tempest/api/compute/security_groups/test_security_group_rules_negative.py delete mode 100644 tempest/api/compute/security_groups/test_security_groups.py delete mode 100644 tempest/api/compute/security_groups/test_security_groups_negative.py delete mode 100644 tempest/api/compute/servers/__init__.py delete mode 100644 tempest/api/compute/servers/test_attach_interfaces.py delete mode 100644 tempest/api/compute/servers/test_availability_zone.py delete mode 100644 tempest/api/compute/servers/test_create_server.py delete mode 100644 tempest/api/compute/servers/test_create_server_multi_nic.py delete mode 100644 tempest/api/compute/servers/test_delete_server.py delete mode 100644 tempest/api/compute/servers/test_device_tagging.py delete mode 100644 tempest/api/compute/servers/test_disk_config.py delete mode 100644 tempest/api/compute/servers/test_instance_actions.py delete mode 100644 tempest/api/compute/servers/test_instance_actions_negative.py delete mode 100644 tempest/api/compute/servers/test_list_server_filters.py delete mode 100644 tempest/api/compute/servers/test_list_servers_negative.py delete mode 100644 tempest/api/compute/servers/test_multiple_create.py delete mode 100644 tempest/api/compute/servers/test_multiple_create_negative.py delete mode 100644 tempest/api/compute/servers/test_novnc.py delete mode 100644 tempest/api/compute/servers/test_server_actions.py delete mode 100644 tempest/api/compute/servers/test_server_addresses.py delete mode 100644 tempest/api/compute/servers/test_server_addresses_negative.py delete mode 100644 tempest/api/compute/servers/test_server_group.py delete mode 100644 tempest/api/compute/servers/test_server_metadata.py delete mode 100644 tempest/api/compute/servers/test_server_metadata_negative.py delete mode 100644 tempest/api/compute/servers/test_server_password.py delete mode 100644 tempest/api/compute/servers/test_server_personality.py delete mode 100644 tempest/api/compute/servers/test_server_rescue.py delete mode 100644 tempest/api/compute/servers/test_server_rescue_negative.py delete mode 100644 tempest/api/compute/servers/test_server_tags.py delete mode 100644 tempest/api/compute/servers/test_servers.py delete mode 100644 tempest/api/compute/servers/test_servers_negative.py delete mode 100644 tempest/api/compute/servers/test_virtual_interfaces.py delete mode 100644 tempest/api/compute/servers/test_virtual_interfaces_negative.py delete mode 100644 tempest/api/compute/test_extensions.py delete mode 100644 tempest/api/compute/test_networks.py delete mode 100644 tempest/api/compute/test_quotas.py delete mode 100644 tempest/api/compute/test_tenant_networks.py delete mode 100644 tempest/api/compute/test_versions.py delete mode 100644 tempest/api/compute/volumes/__init__.py delete mode 100644 tempest/api/compute/volumes/test_attach_volume.py delete mode 100644 tempest/api/compute/volumes/test_attach_volume_negative.py delete mode 100644 tempest/api/compute/volumes/test_volume_snapshots.py delete mode 100644 tempest/api/compute/volumes/test_volumes_get.py delete mode 100644 tempest/api/compute/volumes/test_volumes_list.py delete mode 100644 tempest/api/compute/volumes/test_volumes_negative.py delete mode 100644 tempest/api/identity/__init__.py delete mode 100644 tempest/api/identity/admin/__init__.py delete mode 100644 tempest/api/identity/admin/v2/__init__.py delete mode 100644 tempest/api/identity/admin/v2/test_endpoints.py delete mode 100644 tempest/api/identity/admin/v2/test_roles.py delete mode 100644 tempest/api/identity/admin/v2/test_roles_negative.py delete mode 100644 tempest/api/identity/admin/v2/test_services.py delete mode 100644 tempest/api/identity/admin/v2/test_tenant_negative.py delete mode 100644 tempest/api/identity/admin/v2/test_tenants.py delete mode 100644 tempest/api/identity/admin/v2/test_tokens.py delete mode 100644 tempest/api/identity/admin/v2/test_tokens_negative.py delete mode 100644 tempest/api/identity/admin/v2/test_users.py delete mode 100644 tempest/api/identity/admin/v2/test_users_negative.py delete mode 100644 tempest/api/identity/admin/v3/__init__.py delete mode 100644 tempest/api/identity/admin/v3/test_credentials.py delete mode 100644 tempest/api/identity/admin/v3/test_default_project_id.py delete mode 100644 tempest/api/identity/admin/v3/test_domain_configuration.py delete mode 100644 tempest/api/identity/admin/v3/test_domains.py delete mode 100644 tempest/api/identity/admin/v3/test_domains_negative.py delete mode 100644 tempest/api/identity/admin/v3/test_endpoint_groups.py delete mode 100644 tempest/api/identity/admin/v3/test_endpoints.py delete mode 100644 tempest/api/identity/admin/v3/test_endpoints_negative.py delete mode 100644 tempest/api/identity/admin/v3/test_groups.py delete mode 100644 tempest/api/identity/admin/v3/test_inherits.py delete mode 100644 tempest/api/identity/admin/v3/test_list_projects.py delete mode 100644 tempest/api/identity/admin/v3/test_list_users.py delete mode 100644 tempest/api/identity/admin/v3/test_oauth_consumers.py delete mode 100644 tempest/api/identity/admin/v3/test_policies.py delete mode 100644 tempest/api/identity/admin/v3/test_projects.py delete mode 100644 tempest/api/identity/admin/v3/test_projects_negative.py delete mode 100644 tempest/api/identity/admin/v3/test_regions.py delete mode 100644 tempest/api/identity/admin/v3/test_roles.py delete mode 100644 tempest/api/identity/admin/v3/test_services.py delete mode 100644 tempest/api/identity/admin/v3/test_tokens.py delete mode 100644 tempest/api/identity/admin/v3/test_trusts.py delete mode 100644 tempest/api/identity/admin/v3/test_users.py delete mode 100644 tempest/api/identity/admin/v3/test_users_negative.py delete mode 100644 tempest/api/identity/base.py delete mode 100644 tempest/api/identity/v2/__init__.py delete mode 100644 tempest/api/identity/v2/test_api_discovery.py delete mode 100644 tempest/api/identity/v2/test_ec2_credentials.py delete mode 100644 tempest/api/identity/v2/test_extension.py delete mode 100644 tempest/api/identity/v2/test_tenants.py delete mode 100644 tempest/api/identity/v2/test_tokens.py delete mode 100644 tempest/api/identity/v2/test_users.py delete mode 100644 tempest/api/identity/v3/__init__.py delete mode 100644 tempest/api/identity/v3/test_api_discovery.py delete mode 100755 tempest/api/identity/v3/test_catalog.py delete mode 100644 tempest/api/identity/v3/test_projects.py delete mode 100644 tempest/api/identity/v3/test_tokens.py delete mode 100644 tempest/api/identity/v3/test_users.py delete mode 100644 tempest/api/image/__init__.py delete mode 100644 tempest/api/image/base.py delete mode 100644 tempest/api/image/v1/__init__.py delete mode 100644 tempest/api/image/v1/test_image_members.py delete mode 100644 tempest/api/image/v1/test_image_members_negative.py delete mode 100644 tempest/api/image/v1/test_images.py delete mode 100644 tempest/api/image/v1/test_images_negative.py delete mode 100644 tempest/api/image/v2/__init__.py delete mode 100644 tempest/api/image/v2/test_images.py delete mode 100644 tempest/api/image/v2/test_images_member.py delete mode 100644 tempest/api/image/v2/test_images_member_negative.py delete mode 100644 tempest/api/image/v2/test_images_metadefs_namespace_objects.py delete mode 100644 tempest/api/image/v2/test_images_metadefs_namespace_properties.py delete mode 100644 tempest/api/image/v2/test_images_metadefs_namespace_tags.py delete mode 100644 tempest/api/image/v2/test_images_metadefs_namespaces.py delete mode 100644 tempest/api/image/v2/test_images_metadefs_resource_types.py delete mode 100644 tempest/api/image/v2/test_images_metadefs_schema.py delete mode 100644 tempest/api/image/v2/test_images_negative.py delete mode 100644 tempest/api/image/v2/test_images_tags.py delete mode 100644 tempest/api/image/v2/test_images_tags_negative.py delete mode 100644 tempest/api/image/v2/test_versions.py delete mode 100644 tempest/api/network/__init__.py delete mode 100644 tempest/api/network/admin/__init__.py delete mode 100644 tempest/api/network/admin/test_agent_management.py delete mode 100644 tempest/api/network/admin/test_dhcp_agent_scheduler.py delete mode 100644 tempest/api/network/admin/test_external_network_extension.py delete mode 100644 tempest/api/network/admin/test_external_networks_negative.py delete mode 100644 tempest/api/network/admin/test_floating_ips_admin_actions.py delete mode 100644 tempest/api/network/admin/test_l3_agent_scheduler.py delete mode 100644 tempest/api/network/admin/test_metering_extensions.py delete mode 100644 tempest/api/network/admin/test_negative_quotas.py delete mode 100644 tempest/api/network/admin/test_ports.py delete mode 100644 tempest/api/network/admin/test_quotas.py delete mode 100644 tempest/api/network/admin/test_routers.py delete mode 100644 tempest/api/network/admin/test_routers_dvr.py delete mode 100644 tempest/api/network/admin/test_routers_negative.py delete mode 100644 tempest/api/network/base.py delete mode 100644 tempest/api/network/base_security_groups.py delete mode 100644 tempest/api/network/test_allowed_address_pair.py delete mode 100644 tempest/api/network/test_dhcp_ipv6.py delete mode 100644 tempest/api/network/test_extensions.py delete mode 100644 tempest/api/network/test_extra_dhcp_options.py delete mode 100644 tempest/api/network/test_floating_ips.py delete mode 100644 tempest/api/network/test_floating_ips_negative.py delete mode 100644 tempest/api/network/test_networks.py delete mode 100644 tempest/api/network/test_networks_negative.py delete mode 100644 tempest/api/network/test_ports.py delete mode 100644 tempest/api/network/test_routers.py delete mode 100644 tempest/api/network/test_routers_negative.py delete mode 100644 tempest/api/network/test_security_groups.py delete mode 100644 tempest/api/network/test_security_groups_negative.py delete mode 100644 tempest/api/network/test_service_providers.py delete mode 100644 tempest/api/network/test_subnetpools_extensions.py delete mode 100644 tempest/api/network/test_tags.py delete mode 100644 tempest/api/network/test_versions.py delete mode 100644 tempest/api/object_storage/__init__.py delete mode 100644 tempest/api/object_storage/base.py delete mode 100644 tempest/api/object_storage/test_account_bulk.py delete mode 100644 tempest/api/object_storage/test_account_quotas.py delete mode 100644 tempest/api/object_storage/test_account_quotas_negative.py delete mode 100644 tempest/api/object_storage/test_account_services.py delete mode 100644 tempest/api/object_storage/test_account_services_negative.py delete mode 100644 tempest/api/object_storage/test_container_acl.py delete mode 100644 tempest/api/object_storage/test_container_acl_negative.py delete mode 100644 tempest/api/object_storage/test_container_quotas.py delete mode 100644 tempest/api/object_storage/test_container_services.py delete mode 100644 tempest/api/object_storage/test_container_services_negative.py delete mode 100644 tempest/api/object_storage/test_container_staticweb.py delete mode 100644 tempest/api/object_storage/test_container_sync.py delete mode 100644 tempest/api/object_storage/test_container_sync_middleware.py delete mode 100644 tempest/api/object_storage/test_crossdomain.py delete mode 100644 tempest/api/object_storage/test_healthcheck.py delete mode 100644 tempest/api/object_storage/test_object_expiry.py delete mode 100644 tempest/api/object_storage/test_object_formpost.py delete mode 100644 tempest/api/object_storage/test_object_formpost_negative.py delete mode 100644 tempest/api/object_storage/test_object_services.py delete mode 100644 tempest/api/object_storage/test_object_slo.py delete mode 100644 tempest/api/object_storage/test_object_temp_url.py delete mode 100644 tempest/api/object_storage/test_object_temp_url_negative.py delete mode 100644 tempest/api/object_storage/test_object_version.py delete mode 100644 tempest/api/volume/__init__.py delete mode 100644 tempest/api/volume/admin/__init__.py delete mode 100644 tempest/api/volume/admin/test_backends_capabilities.py delete mode 100644 tempest/api/volume/admin/test_group_types.py delete mode 100644 tempest/api/volume/admin/test_groups.py delete mode 100644 tempest/api/volume/admin/test_multi_backend.py delete mode 100644 tempest/api/volume/admin/test_qos.py delete mode 100644 tempest/api/volume/admin/test_snapshot_manage.py delete mode 100644 tempest/api/volume/admin/test_snapshots_actions.py delete mode 100755 tempest/api/volume/admin/test_user_messages.py delete mode 100644 tempest/api/volume/admin/test_volume_hosts.py delete mode 100644 tempest/api/volume/admin/test_volume_manage.py delete mode 100644 tempest/api/volume/admin/test_volume_pools.py delete mode 100644 tempest/api/volume/admin/test_volume_quota_classes.py delete mode 100644 tempest/api/volume/admin/test_volume_quotas.py delete mode 100644 tempest/api/volume/admin/test_volume_quotas_negative.py delete mode 100644 tempest/api/volume/admin/test_volume_retype_with_migration.py delete mode 100644 tempest/api/volume/admin/test_volume_services.py delete mode 100644 tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py delete mode 100644 tempest/api/volume/admin/test_volume_type_access.py delete mode 100644 tempest/api/volume/admin/test_volume_types.py delete mode 100644 tempest/api/volume/admin/test_volume_types_extra_specs.py delete mode 100644 tempest/api/volume/admin/test_volume_types_extra_specs_negative.py delete mode 100644 tempest/api/volume/admin/test_volume_types_negative.py delete mode 100644 tempest/api/volume/admin/test_volumes_actions.py delete mode 100644 tempest/api/volume/admin/test_volumes_backup.py delete mode 100644 tempest/api/volume/admin/test_volumes_list.py delete mode 100644 tempest/api/volume/api_microversion_fixture.py delete mode 100644 tempest/api/volume/base.py delete mode 100644 tempest/api/volume/test_availability_zone.py delete mode 100644 tempest/api/volume/test_extensions.py delete mode 100644 tempest/api/volume/test_image_metadata.py delete mode 100644 tempest/api/volume/test_snapshot_metadata.py delete mode 100644 tempest/api/volume/test_versions.py delete mode 100644 tempest/api/volume/test_volume_absolute_limits.py delete mode 100644 tempest/api/volume/test_volume_delete_cascade.py delete mode 100644 tempest/api/volume/test_volume_metadata.py delete mode 100644 tempest/api/volume/test_volume_transfers.py delete mode 100644 tempest/api/volume/test_volumes_actions.py delete mode 100644 tempest/api/volume/test_volumes_backup.py delete mode 100644 tempest/api/volume/test_volumes_clone.py delete mode 100644 tempest/api/volume/test_volumes_clone_negative.py delete mode 100644 tempest/api/volume/test_volumes_extend.py delete mode 100644 tempest/api/volume/test_volumes_get.py delete mode 100644 tempest/api/volume/test_volumes_list.py delete mode 100644 tempest/api/volume/test_volumes_negative.py delete mode 100644 tempest/api/volume/test_volumes_snapshots.py delete mode 100644 tempest/api/volume/test_volumes_snapshots_list.py delete mode 100644 tempest/api/volume/test_volumes_snapshots_negative.py delete mode 100644 tempest/clients.py delete mode 100644 tempest/cmd/__init__.py delete mode 100755 tempest/cmd/account_generator.py delete mode 100644 tempest/cmd/cleanup.py delete mode 100644 tempest/cmd/cleanup_service.py delete mode 100644 tempest/cmd/config-generator.tempest.conf delete mode 100644 tempest/cmd/init.py delete mode 100644 tempest/cmd/list_plugins.py delete mode 100644 tempest/cmd/main.py delete mode 100644 tempest/cmd/run.py delete mode 100644 tempest/cmd/subunit_describe_calls.py delete mode 100644 tempest/cmd/verify_tempest_config.py delete mode 100644 tempest/cmd/workspace.py delete mode 100644 tempest/common/__init__.py delete mode 100644 tempest/common/compute.py delete mode 100644 tempest/common/credentials_factory.py delete mode 100644 tempest/common/custom_matchers.py delete mode 100644 tempest/common/identity.py delete mode 100644 tempest/common/image.py delete mode 100644 tempest/common/tempest_fixtures.py delete mode 100644 tempest/common/utils/__init__.py delete mode 100644 tempest/common/utils/linux/__init__.py delete mode 100644 tempest/common/utils/linux/remote_client.py delete mode 100644 tempest/common/utils/net_info.py delete mode 100644 tempest/common/utils/net_utils.py delete mode 100644 tempest/common/validation_resources.py delete mode 100644 tempest/common/waiters.py delete mode 100644 tempest/config.py delete mode 100644 tempest/exceptions.py delete mode 100644 tempest/hacking/__init__.py delete mode 100644 tempest/hacking/checks.py delete mode 100644 tempest/hacking/ignored_list_T110.txt delete mode 100644 tempest/lib/__init__.py delete mode 100644 tempest/lib/api_schema/__init__.py delete mode 100644 tempest/lib/api_schema/response/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/agents.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/aggregates.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/availability_zone.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/baremetal_nodes.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/certificates.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/extensions.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/fixed_ips.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/flavors.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/flavors_access.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/flavors_extra_specs.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/floating_ips.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/hosts.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/hypervisors.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/images.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/instance_usage_audit_logs.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/interfaces.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/keypairs.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/limits.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/migrations.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/parameter_types.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/quota_classes.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/quotas.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/security_group_default_rule.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/security_groups.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/servers.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/services.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/snapshots.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/tenant_networks.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/versions.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_1/volumes.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_11/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_11/services.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_13/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_13/servers.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_16/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_16/servers.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_19/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_19/servers.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_2/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_2/keypairs.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_23/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_23/migrations.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_26/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_26/servers.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_3/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_3/servers.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_47/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_47/servers.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_48/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_48/servers.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_6/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_6/servers.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_9/__init__.py delete mode 100644 tempest/lib/api_schema/response/compute/v2_9/servers.py delete mode 100644 tempest/lib/api_schema/response/volume/__init__.py delete mode 100644 tempest/lib/api_schema/response/volume/versions.py delete mode 100644 tempest/lib/auth.py delete mode 100644 tempest/lib/base.py delete mode 100644 tempest/lib/cli/__init__.py delete mode 100644 tempest/lib/cli/base.py delete mode 100644 tempest/lib/cli/output_parser.py delete mode 100644 tempest/lib/cmd/__init__.py delete mode 100755 tempest/lib/cmd/check_uuid.py delete mode 100755 tempest/lib/cmd/skip_tracker.py delete mode 100644 tempest/lib/common/__init__.py delete mode 100644 tempest/lib/common/api_version_request.py delete mode 100644 tempest/lib/common/api_version_utils.py delete mode 100644 tempest/lib/common/cred_client.py delete mode 100644 tempest/lib/common/cred_provider.py delete mode 100644 tempest/lib/common/dynamic_creds.py delete mode 100644 tempest/lib/common/fixed_network.py delete mode 100644 tempest/lib/common/http.py delete mode 100644 tempest/lib/common/jsonschema_validator.py delete mode 100644 tempest/lib/common/preprov_creds.py delete mode 100644 tempest/lib/common/rest_client.py delete mode 100644 tempest/lib/common/ssh.py delete mode 100644 tempest/lib/common/utils/__init__.py delete mode 100644 tempest/lib/common/utils/data_utils.py delete mode 100644 tempest/lib/common/utils/linux/__init__.py delete mode 100644 tempest/lib/common/utils/linux/remote_client.py delete mode 100644 tempest/lib/common/utils/misc.py delete mode 100644 tempest/lib/common/utils/test_utils.py delete mode 100644 tempest/lib/decorators.py delete mode 100644 tempest/lib/exceptions.py delete mode 100644 tempest/lib/services/__init__.py delete mode 100644 tempest/lib/services/clients.py delete mode 100644 tempest/lib/services/compute/__init__.py delete mode 100644 tempest/lib/services/compute/agents_client.py delete mode 100644 tempest/lib/services/compute/aggregates_client.py delete mode 100644 tempest/lib/services/compute/availability_zone_client.py delete mode 100644 tempest/lib/services/compute/baremetal_nodes_client.py delete mode 100644 tempest/lib/services/compute/base_compute_client.py delete mode 100644 tempest/lib/services/compute/certificates_client.py delete mode 100644 tempest/lib/services/compute/extensions_client.py delete mode 100644 tempest/lib/services/compute/fixed_ips_client.py delete mode 100644 tempest/lib/services/compute/flavors_client.py delete mode 100644 tempest/lib/services/compute/floating_ip_pools_client.py delete mode 100644 tempest/lib/services/compute/floating_ips_bulk_client.py delete mode 100644 tempest/lib/services/compute/floating_ips_client.py delete mode 100644 tempest/lib/services/compute/hosts_client.py delete mode 100644 tempest/lib/services/compute/hypervisor_client.py delete mode 100644 tempest/lib/services/compute/images_client.py delete mode 100644 tempest/lib/services/compute/instance_usage_audit_log_client.py delete mode 100644 tempest/lib/services/compute/interfaces_client.py delete mode 100644 tempest/lib/services/compute/keypairs_client.py delete mode 100644 tempest/lib/services/compute/limits_client.py delete mode 100644 tempest/lib/services/compute/migrations_client.py delete mode 100644 tempest/lib/services/compute/networks_client.py delete mode 100644 tempest/lib/services/compute/quota_classes_client.py delete mode 100644 tempest/lib/services/compute/quotas_client.py delete mode 100644 tempest/lib/services/compute/security_group_default_rules_client.py delete mode 100644 tempest/lib/services/compute/security_group_rules_client.py delete mode 100644 tempest/lib/services/compute/security_groups_client.py delete mode 100644 tempest/lib/services/compute/server_groups_client.py delete mode 100644 tempest/lib/services/compute/servers_client.py delete mode 100644 tempest/lib/services/compute/services_client.py delete mode 100644 tempest/lib/services/compute/snapshots_client.py delete mode 100644 tempest/lib/services/compute/tenant_networks_client.py delete mode 100644 tempest/lib/services/compute/tenant_usages_client.py delete mode 100644 tempest/lib/services/compute/versions_client.py delete mode 100644 tempest/lib/services/compute/volumes_client.py delete mode 100644 tempest/lib/services/identity/__init__.py delete mode 100644 tempest/lib/services/identity/v2/__init__.py delete mode 100644 tempest/lib/services/identity/v2/endpoints_client.py delete mode 100644 tempest/lib/services/identity/v2/identity_client.py delete mode 100644 tempest/lib/services/identity/v2/roles_client.py delete mode 100644 tempest/lib/services/identity/v2/services_client.py delete mode 100644 tempest/lib/services/identity/v2/tenants_client.py delete mode 100644 tempest/lib/services/identity/v2/token_client.py delete mode 100644 tempest/lib/services/identity/v2/users_client.py delete mode 100644 tempest/lib/services/identity/v3/__init__.py delete mode 100644 tempest/lib/services/identity/v3/catalog_client.py delete mode 100644 tempest/lib/services/identity/v3/credentials_client.py delete mode 100644 tempest/lib/services/identity/v3/domain_configuration_client.py delete mode 100644 tempest/lib/services/identity/v3/domains_client.py delete mode 100644 tempest/lib/services/identity/v3/endpoint_filter_client.py delete mode 100644 tempest/lib/services/identity/v3/endpoint_groups_client.py delete mode 100644 tempest/lib/services/identity/v3/endpoints_client.py delete mode 100644 tempest/lib/services/identity/v3/groups_client.py delete mode 100644 tempest/lib/services/identity/v3/identity_client.py delete mode 100644 tempest/lib/services/identity/v3/inherited_roles_client.py delete mode 100644 tempest/lib/services/identity/v3/oauth_consumers_client.py delete mode 100644 tempest/lib/services/identity/v3/oauth_token_client.py delete mode 100644 tempest/lib/services/identity/v3/policies_client.py delete mode 100644 tempest/lib/services/identity/v3/projects_client.py delete mode 100644 tempest/lib/services/identity/v3/regions_client.py delete mode 100644 tempest/lib/services/identity/v3/role_assignments_client.py delete mode 100644 tempest/lib/services/identity/v3/roles_client.py delete mode 100644 tempest/lib/services/identity/v3/services_client.py delete mode 100644 tempest/lib/services/identity/v3/token_client.py delete mode 100644 tempest/lib/services/identity/v3/trusts_client.py delete mode 100644 tempest/lib/services/identity/v3/users_client.py delete mode 100644 tempest/lib/services/identity/v3/versions_client.py delete mode 100644 tempest/lib/services/image/__init__.py delete mode 100644 tempest/lib/services/image/v1/__init__.py delete mode 100644 tempest/lib/services/image/v1/image_members_client.py delete mode 100644 tempest/lib/services/image/v1/images_client.py delete mode 100644 tempest/lib/services/image/v2/__init__.py delete mode 100644 tempest/lib/services/image/v2/image_members_client.py delete mode 100644 tempest/lib/services/image/v2/images_client.py delete mode 100644 tempest/lib/services/image/v2/namespace_objects_client.py delete mode 100644 tempest/lib/services/image/v2/namespace_properties_client.py delete mode 100644 tempest/lib/services/image/v2/namespace_tags_client.py delete mode 100644 tempest/lib/services/image/v2/namespaces_client.py delete mode 100644 tempest/lib/services/image/v2/resource_types_client.py delete mode 100644 tempest/lib/services/image/v2/schemas_client.py delete mode 100644 tempest/lib/services/image/v2/versions_client.py delete mode 100644 tempest/lib/services/network/__init__.py delete mode 100644 tempest/lib/services/network/agents_client.py delete mode 100644 tempest/lib/services/network/base.py delete mode 100644 tempest/lib/services/network/extensions_client.py delete mode 100644 tempest/lib/services/network/floating_ips_client.py delete mode 100644 tempest/lib/services/network/metering_label_rules_client.py delete mode 100644 tempest/lib/services/network/metering_labels_client.py delete mode 100644 tempest/lib/services/network/networks_client.py delete mode 100644 tempest/lib/services/network/ports_client.py delete mode 100644 tempest/lib/services/network/quotas_client.py delete mode 100644 tempest/lib/services/network/routers_client.py delete mode 100644 tempest/lib/services/network/security_group_rules_client.py delete mode 100644 tempest/lib/services/network/security_groups_client.py delete mode 100644 tempest/lib/services/network/service_providers_client.py delete mode 100644 tempest/lib/services/network/subnetpools_client.py delete mode 100644 tempest/lib/services/network/subnets_client.py delete mode 100644 tempest/lib/services/network/tags_client.py delete mode 100644 tempest/lib/services/network/versions_client.py delete mode 100644 tempest/lib/services/volume/__init__.py delete mode 100644 tempest/lib/services/volume/base_client.py delete mode 100644 tempest/lib/services/volume/v1/__init__.py delete mode 100644 tempest/lib/services/volume/v1/availability_zone_client.py delete mode 100644 tempest/lib/services/volume/v1/backups_client.py delete mode 100755 tempest/lib/services/volume/v1/encryption_types_client.py delete mode 100644 tempest/lib/services/volume/v1/extensions_client.py delete mode 100644 tempest/lib/services/volume/v1/hosts_client.py delete mode 100644 tempest/lib/services/volume/v1/limits_client.py delete mode 100644 tempest/lib/services/volume/v1/qos_client.py delete mode 100644 tempest/lib/services/volume/v1/quotas_client.py delete mode 100644 tempest/lib/services/volume/v1/services_client.py delete mode 100644 tempest/lib/services/volume/v1/snapshots_client.py delete mode 100644 tempest/lib/services/volume/v1/types_client.py delete mode 100644 tempest/lib/services/volume/v1/volumes_client.py delete mode 100644 tempest/lib/services/volume/v2/__init__.py delete mode 100644 tempest/lib/services/volume/v2/availability_zone_client.py delete mode 100644 tempest/lib/services/volume/v2/backups_client.py delete mode 100644 tempest/lib/services/volume/v2/capabilities_client.py delete mode 100755 tempest/lib/services/volume/v2/encryption_types_client.py delete mode 100644 tempest/lib/services/volume/v2/extensions_client.py delete mode 100644 tempest/lib/services/volume/v2/hosts_client.py delete mode 100644 tempest/lib/services/volume/v2/limits_client.py delete mode 100644 tempest/lib/services/volume/v2/qos_client.py delete mode 100644 tempest/lib/services/volume/v2/quota_classes_client.py delete mode 100644 tempest/lib/services/volume/v2/quotas_client.py delete mode 100644 tempest/lib/services/volume/v2/scheduler_stats_client.py delete mode 100644 tempest/lib/services/volume/v2/services_client.py delete mode 100644 tempest/lib/services/volume/v2/snapshot_manage_client.py delete mode 100644 tempest/lib/services/volume/v2/snapshots_client.py delete mode 100644 tempest/lib/services/volume/v2/transfers_client.py delete mode 100644 tempest/lib/services/volume/v2/types_client.py delete mode 100644 tempest/lib/services/volume/v2/volume_manage_client.py delete mode 100644 tempest/lib/services/volume/v2/volumes_client.py delete mode 100644 tempest/lib/services/volume/v3/__init__.py delete mode 100644 tempest/lib/services/volume/v3/backups_client.py delete mode 100644 tempest/lib/services/volume/v3/base_client.py delete mode 100644 tempest/lib/services/volume/v3/group_types_client.py delete mode 100644 tempest/lib/services/volume/v3/groups_client.py delete mode 100644 tempest/lib/services/volume/v3/messages_client.py delete mode 100644 tempest/lib/services/volume/v3/versions_client.py delete mode 100644 tempest/lib/services/volume/v3/volumes_client.py delete mode 100644 tempest/manager.py delete mode 100644 tempest/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml delete mode 100644 tempest/scenario/README.rst delete mode 100644 tempest/scenario/__init__.py delete mode 100644 tempest/scenario/manager.py delete mode 100644 tempest/scenario/test_aggregates_basic_ops.py delete mode 100644 tempest/scenario/test_encrypted_cinder_volumes.py delete mode 100644 tempest/scenario/test_minimum_basic.py delete mode 100644 tempest/scenario/test_network_advanced_server_ops.py delete mode 100644 tempest/scenario/test_network_basic_ops.py delete mode 100644 tempest/scenario/test_network_v6.py delete mode 100644 tempest/scenario/test_object_storage_basic_ops.py delete mode 100644 tempest/scenario/test_security_groups_basic_ops.py delete mode 100644 tempest/scenario/test_server_advanced_ops.py delete mode 100644 tempest/scenario/test_server_basic_ops.py delete mode 100644 tempest/scenario/test_server_multinode.py delete mode 100644 tempest/scenario/test_shelve_instance.py delete mode 100644 tempest/scenario/test_snapshot_pattern.py delete mode 100644 tempest/scenario/test_stamp_pattern.py delete mode 100644 tempest/scenario/test_volume_boot_pattern.py delete mode 100644 tempest/scenario/test_volume_migrate_attached.py delete mode 100644 tempest/services/__init__.py delete mode 100644 tempest/services/object_storage/__init__.py delete mode 100644 tempest/services/object_storage/account_client.py delete mode 100644 tempest/services/object_storage/bulk_middleware_client.py delete mode 100644 tempest/services/object_storage/capabilities_client.py delete mode 100644 tempest/services/object_storage/container_client.py delete mode 100644 tempest/services/object_storage/object_client.py delete mode 100644 tempest/services/orchestration/__init__.py delete mode 100644 tempest/services/orchestration/json/__init__.py delete mode 100644 tempest/services/orchestration/json/orchestration_client.py delete mode 100644 tempest/test.py delete mode 100644 tempest/test_discover/__init__.py delete mode 100644 tempest/test_discover/plugins.py delete mode 100644 tempest/test_discover/test_discover.py delete mode 100644 tempest/tests/README.rst delete mode 100644 tempest/tests/__init__.py delete mode 100644 tempest/tests/api/__init__.py delete mode 100644 tempest/tests/api/compute/__init__.py delete mode 100644 tempest/tests/api/compute/test_base.py delete mode 100644 tempest/tests/base.py delete mode 100644 tempest/tests/cmd/__init__.py delete mode 100644 tempest/tests/cmd/sample_streams/calls.subunit delete mode 100644 tempest/tests/cmd/test_account_generator.py delete mode 100644 tempest/tests/cmd/test_list_plugins.py delete mode 100644 tempest/tests/cmd/test_run.py delete mode 100644 tempest/tests/cmd/test_subunit_describe_calls.py delete mode 100644 tempest/tests/cmd/test_tempest_init.py delete mode 100644 tempest/tests/cmd/test_verify_tempest_config.py delete mode 100644 tempest/tests/cmd/test_workspace.py delete mode 100644 tempest/tests/common/__init__.py delete mode 100644 tempest/tests/common/test_admin_available.py delete mode 100644 tempest/tests/common/test_alt_available.py delete mode 100644 tempest/tests/common/test_compute.py delete mode 100644 tempest/tests/common/test_custom_matchers.py delete mode 100644 tempest/tests/common/test_image.py delete mode 100644 tempest/tests/common/test_waiters.py delete mode 100644 tempest/tests/common/utils/__init__.py delete mode 100644 tempest/tests/common/utils/linux/__init__.py delete mode 100644 tempest/tests/common/utils/linux/test_remote_client.py delete mode 100644 tempest/tests/common/utils/test_net_utils.py delete mode 100644 tempest/tests/fake_config.py delete mode 100644 tempest/tests/fake_tempest_plugin.py delete mode 100644 tempest/tests/files/__init__.py delete mode 100644 tempest/tests/files/failing-tests delete mode 100644 tempest/tests/files/passing-tests delete mode 100644 tempest/tests/files/setup.cfg delete mode 100644 tempest/tests/files/testr-conf delete mode 100644 tempest/tests/lib/__init__.py delete mode 100644 tempest/tests/lib/cli/__init__.py delete mode 100644 tempest/tests/lib/cli/test_command_failed.py delete mode 100644 tempest/tests/lib/cli/test_execute.py delete mode 100644 tempest/tests/lib/cli/test_output_parser.py delete mode 100644 tempest/tests/lib/common/__init__.py delete mode 100644 tempest/tests/lib/common/test_api_version_request.py delete mode 100644 tempest/tests/lib/common/test_api_version_utils.py delete mode 100644 tempest/tests/lib/common/test_cred_client.py delete mode 100644 tempest/tests/lib/common/test_dynamic_creds.py delete mode 100644 tempest/tests/lib/common/test_jsonschema_validator.py delete mode 100644 tempest/tests/lib/common/test_preprov_creds.py delete mode 100644 tempest/tests/lib/common/test_rest_client.py delete mode 100644 tempest/tests/lib/common/utils/__init__.py delete mode 100644 tempest/tests/lib/common/utils/linux/__init__.py delete mode 100644 tempest/tests/lib/common/utils/linux/test_remote_client.py delete mode 100644 tempest/tests/lib/common/utils/test_data_utils.py delete mode 100644 tempest/tests/lib/common/utils/test_misc.py delete mode 100644 tempest/tests/lib/common/utils/test_test_utils.py delete mode 100644 tempest/tests/lib/fake_auth_provider.py delete mode 100644 tempest/tests/lib/fake_credentials.py delete mode 100644 tempest/tests/lib/fake_http.py delete mode 100644 tempest/tests/lib/fake_identity.py delete mode 100644 tempest/tests/lib/services/__init__.py delete mode 100644 tempest/tests/lib/services/base.py delete mode 100644 tempest/tests/lib/services/compute/__init__.py delete mode 100644 tempest/tests/lib/services/compute/test_agents_client.py delete mode 100644 tempest/tests/lib/services/compute/test_aggregates_client.py delete mode 100644 tempest/tests/lib/services/compute/test_availability_zone_client.py delete mode 100644 tempest/tests/lib/services/compute/test_baremetal_nodes_client.py delete mode 100644 tempest/tests/lib/services/compute/test_base_compute_client.py delete mode 100644 tempest/tests/lib/services/compute/test_certificates_client.py delete mode 100644 tempest/tests/lib/services/compute/test_extensions_client.py delete mode 100644 tempest/tests/lib/services/compute/test_fixedIPs_client.py delete mode 100644 tempest/tests/lib/services/compute/test_flavors_client.py delete mode 100644 tempest/tests/lib/services/compute/test_floating_ip_pools_client.py delete mode 100644 tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py delete mode 100644 tempest/tests/lib/services/compute/test_floating_ips_client.py delete mode 100644 tempest/tests/lib/services/compute/test_hosts_client.py delete mode 100644 tempest/tests/lib/services/compute/test_hypervisor_client.py delete mode 100644 tempest/tests/lib/services/compute/test_images_client.py delete mode 100644 tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py delete mode 100644 tempest/tests/lib/services/compute/test_interfaces_client.py delete mode 100644 tempest/tests/lib/services/compute/test_keypairs_client.py delete mode 100644 tempest/tests/lib/services/compute/test_limits_client.py delete mode 100644 tempest/tests/lib/services/compute/test_migrations_client.py delete mode 100644 tempest/tests/lib/services/compute/test_networks_client.py delete mode 100644 tempest/tests/lib/services/compute/test_quota_classes_client.py delete mode 100644 tempest/tests/lib/services/compute/test_quotas_client.py delete mode 100644 tempest/tests/lib/services/compute/test_security_group_default_rules_client.py delete mode 100644 tempest/tests/lib/services/compute/test_security_group_rules_client.py delete mode 100644 tempest/tests/lib/services/compute/test_security_groups_client.py delete mode 100644 tempest/tests/lib/services/compute/test_server_groups_client.py delete mode 100644 tempest/tests/lib/services/compute/test_servers_client.py delete mode 100644 tempest/tests/lib/services/compute/test_services_client.py delete mode 100644 tempest/tests/lib/services/compute/test_snapshots_client.py delete mode 100644 tempest/tests/lib/services/compute/test_tenant_networks_client.py delete mode 100644 tempest/tests/lib/services/compute/test_tenant_usages_client.py delete mode 100644 tempest/tests/lib/services/compute/test_versions_client.py delete mode 100644 tempest/tests/lib/services/compute/test_volumes_client.py delete mode 100644 tempest/tests/lib/services/identity/__init__.py delete mode 100644 tempest/tests/lib/services/identity/v2/__init__.py delete mode 100644 tempest/tests/lib/services/identity/v2/test_endpoints_client.py delete mode 100644 tempest/tests/lib/services/identity/v2/test_identity_client.py delete mode 100644 tempest/tests/lib/services/identity/v2/test_roles_client.py delete mode 100644 tempest/tests/lib/services/identity/v2/test_services_client.py delete mode 100644 tempest/tests/lib/services/identity/v2/test_tenants_client.py delete mode 100644 tempest/tests/lib/services/identity/v2/test_token_client.py delete mode 100644 tempest/tests/lib/services/identity/v2/test_users_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/__init__.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_catalog_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_credentials_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_domain_configuration_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_domains_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_endpoints_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_groups_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_identity_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_inherited_roles_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_oauth_consumers_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_oauth_token_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_policies_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_projects_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_regions_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_role_assignments_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_roles_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_services_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_token_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_trusts_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_users_client.py delete mode 100644 tempest/tests/lib/services/identity/v3/test_versions_client.py delete mode 100644 tempest/tests/lib/services/image/__init__.py delete mode 100644 tempest/tests/lib/services/image/v1/__init__.py delete mode 100644 tempest/tests/lib/services/image/v1/test_image_members_client.py delete mode 100644 tempest/tests/lib/services/image/v2/__init__.py delete mode 100644 tempest/tests/lib/services/image/v2/test_image_members_client.py delete mode 100644 tempest/tests/lib/services/image/v2/test_images_client.py delete mode 100644 tempest/tests/lib/services/image/v2/test_namespace_object_client.py delete mode 100644 tempest/tests/lib/services/image/v2/test_namespace_properties_client.py delete mode 100644 tempest/tests/lib/services/image/v2/test_namespace_tags_client.py delete mode 100644 tempest/tests/lib/services/image/v2/test_namespaces_client.py delete mode 100644 tempest/tests/lib/services/image/v2/test_resource_types_client.py delete mode 100644 tempest/tests/lib/services/image/v2/test_schemas_client.py delete mode 100644 tempest/tests/lib/services/image/v2/test_versions_client.py delete mode 100644 tempest/tests/lib/services/network/__init__.py delete mode 100644 tempest/tests/lib/services/network/test_base_network_client.py delete mode 100644 tempest/tests/lib/services/network/test_extensions_client.py delete mode 100644 tempest/tests/lib/services/network/test_floating_ips_client.py delete mode 100644 tempest/tests/lib/services/network/test_metering_label_rules_client.py delete mode 100644 tempest/tests/lib/services/network/test_metering_labels_client.py delete mode 100644 tempest/tests/lib/services/network/test_ports_client.py delete mode 100644 tempest/tests/lib/services/network/test_quotas_client.py delete mode 100644 tempest/tests/lib/services/network/test_routers_client.py delete mode 100644 tempest/tests/lib/services/network/test_security_group_rules_client.py delete mode 100644 tempest/tests/lib/services/network/test_security_groups_client.py delete mode 100644 tempest/tests/lib/services/network/test_service_providers_client.py delete mode 100644 tempest/tests/lib/services/network/test_subnetpools_client.py delete mode 100644 tempest/tests/lib/services/network/test_subnets_client.py delete mode 100644 tempest/tests/lib/services/network/test_tags_client.py delete mode 100644 tempest/tests/lib/services/network/test_versions_client.py delete mode 100644 tempest/tests/lib/services/test_clients.py delete mode 100644 tempest/tests/lib/services/volume/__init__.py delete mode 100644 tempest/tests/lib/services/volume/v1/__init__.py delete mode 100644 tempest/tests/lib/services/volume/v1/test_encryption_types_client.py delete mode 100644 tempest/tests/lib/services/volume/v1/test_quotas_client.py delete mode 100644 tempest/tests/lib/services/volume/v1/test_snapshots_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/__init__.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_backups_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_capabilities_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_encryption_types_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_extensions_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_hosts_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_limits_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_quota_classes_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_quotas_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_scheduler_stats_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_snapshots_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_transfers_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_volume_manage_client.py delete mode 100644 tempest/tests/lib/services/volume/v2/test_volumes_client.py delete mode 100644 tempest/tests/lib/services/volume/v3/__init__.py delete mode 100644 tempest/tests/lib/services/volume/v3/test_backups_client.py delete mode 100644 tempest/tests/lib/services/volume/v3/test_group_types_client.py delete mode 100644 tempest/tests/lib/services/volume/v3/test_groups_client.py delete mode 100644 tempest/tests/lib/services/volume/v3/test_user_messages_client.py delete mode 100644 tempest/tests/lib/services/volume/v3/test_versions_client.py delete mode 100644 tempest/tests/lib/services/volume/v3/test_volumes_client.py delete mode 100644 tempest/tests/lib/test_auth.py delete mode 100644 tempest/tests/lib/test_base.py delete mode 100644 tempest/tests/lib/test_credentials.py delete mode 100644 tempest/tests/lib/test_decorators.py delete mode 100644 tempest/tests/lib/test_ssh.py delete mode 100644 tempest/tests/lib/test_tempest_lib.py delete mode 100644 tempest/tests/services/__init__.py delete mode 100644 tempest/tests/services/object_storage/__init__.py delete mode 100644 tempest/tests/services/object_storage/test_bulk_middleware_client.py delete mode 100644 tempest/tests/services/object_storage/test_capabilities_client.py delete mode 100644 tempest/tests/services/object_storage/test_object_client.py delete mode 100644 tempest/tests/test_base_test.py delete mode 100644 tempest/tests/test_config.py delete mode 100644 tempest/tests/test_decorators.py delete mode 100644 tempest/tests/test_hacking.py delete mode 100644 tempest/tests/test_list_tests.py delete mode 100644 tempest/tests/test_microversions.py delete mode 100644 tempest/tests/test_tempest_plugin.py delete mode 100644 tempest/tests/utils.py delete mode 100644 tempest/version.py delete mode 100644 test-requirements.txt delete mode 100755 tools/check_logs.py delete mode 100755 tools/find_stack_traces.py delete mode 100644 tools/generate-tempest-plugins-list.py delete mode 100755 tools/generate-tempest-plugins-list.sh delete mode 100755 tools/skip_tracker.py delete mode 100644 tools/tempest-plugin-sanity.sh delete mode 100755 tools/tox_install.sh delete mode 100755 tools/with_venv.sh delete mode 100644 tox.ini diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 449e62c2d..000000000 --- a/.coveragerc +++ /dev/null @@ -1,4 +0,0 @@ -[run] -branch = True -source = tempest -omit = tempest/tests/*,tempest/scenario/test_*.py,tempest/api/* diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 287db4cf5..000000000 --- a/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -AUTHORS -ChangeLog -*.pyc -__pycache__/ -etc/accounts.yaml -etc/tempest.conf -etc/tempest.conf.sample -etc/logging.conf -include/swift_objects/swift_small -include/swift_objects/swift_medium -include/swift_objects/swift_large -*.log -*.swp -*.swo -*.egg* -.tox -.venv -dist -build -.testrepository -.idea -.project -.pydevproject -.coverage* -!.coveragerc -cover/ -doc/source/_static/tempest.conf.sample -doc/source/plugin-registry.rst - -# Files created by releasenotes build -releasenotes/build diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 84b5114f5..000000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/tempest.git diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 3ea6ab0d5..000000000 --- a/.mailmap +++ /dev/null @@ -1,27 +0,0 @@ - - - -Adam Gandelman -Andrea Frittoli -Andrea Frittoli -Daryl Walleck -David Kranz David Kranz -Ghanshyam -Ghanshyam -Jay Pipes -Joe Gordon -Ken'ichi Ohmichi -Ken'ichi Ohmichi -Marc Koderer -Masayuki Igawa -Masayuki Igawa -Masayuki Igawa -Matthew Treinish -Nayna Patel -ravikumar-venkatesan -ravikumar-venkatesan -Rohit Karajgi -Sean Dague -Sean Dague -Yuiko Takada -Zhi Kun Liu diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index 95a4fb4d2..000000000 --- a/.testr.conf +++ /dev/null @@ -1,9 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-500} \ - OS_TEST_LOCK_PATH=${OS_TEST_LOCK_PATH:-${TMPDIR:-'/tmp'}} \ - ${PYTHON:-python} -m subunit.run discover -t ${OS_TOP_LEVEL:-./} ${OS_TEST_PATH:-./tempest/test_discover} $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list -group_regex=([^\.]*\.)* diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index e5f45ac1b..000000000 --- a/HACKING.rst +++ /dev/null @@ -1,403 +0,0 @@ -Tempest Coding Guide -==================== - -- Step 1: Read the OpenStack Style Commandments - https://docs.openstack.org/hacking/latest/ -- Step 2: Read on - -Tempest Specific Commandments ------------------------------- - -- [T102] Cannot import OpenStack python clients in tempest/api & - tempest/scenario tests -- [T104] Scenario tests require a services decorator -- [T105] Tests cannot use setUpClass/tearDownClass -- [T106] vim configuration should not be kept in source files. -- [T107] Check that a service tag isn't in the module path -- [T108] Check no hyphen at the end of rand_name() argument -- [T109] Cannot use testtools.skip decorator; instead use - decorators.skip_because from tempest.lib -- [T110] Check that service client names of GET should be consistent -- [T111] Check that service client names of DELETE should be consistent -- [T112] Check that tempest.lib should not import local tempest code -- [T113] Check that tests use data_utils.rand_uuid() instead of uuid.uuid4() -- [T114] Check that tempest.lib does not use tempest config -- [T115] Check that admin tests should exist under admin path -- [N322] Method's default argument shouldn't be mutable - -Test Data/Configuration ------------------------ -- Assume nothing about existing test data -- Tests should be self contained (provide their own data) -- Clean up test data at the completion of each test -- Use configuration files for values that will vary by environment - - -Exception Handling ------------------- -According to the ``The Zen of Python`` the -``Errors should never pass silently.`` -Tempest usually runs in special environment (jenkins gate jobs), in every -error or failure situation we should provide as much error related -information as possible, because we usually do not have the chance to -investigate the situation after the issue happened. - -In every test case the abnormal situations must be very verbosely explained, -by the exception and the log. - -In most cases the very first issue is the most important information. - -Try to avoid using ``try`` blocks in the test cases, as both the ``except`` -and ``finally`` blocks could replace the original exception, -when the additional operations leads to another exception. - -Just letting an exception to propagate, is not a bad idea in a test case, -at all. - -Try to avoid using any exception handling construct which can hide the errors -origin. - -If you really need to use a ``try`` block, please ensure the original -exception at least logged. When the exception is logged you usually need -to ``raise`` the same or a different exception anyway. - -Use of ``self.addCleanup`` is often a good way to avoid having to catch -exceptions and still ensure resources are correctly cleaned up if the -test fails part way through. - -Use the ``self.assert*`` methods provided by the unit test framework. -This signals the failures early on. - -Avoid using the ``self.fail`` alone, its stack trace will signal -the ``self.fail`` line as the origin of the error. - -Avoid constructing complex boolean expressions for assertion. -The ``self.assertTrue`` or ``self.assertFalse`` without a ``msg`` argument, -will just tell you the single boolean value, and you will not know anything -about the values used in the formula, the ``msg`` argument might be good enough -for providing more information. - -Most other assert method can include more information by default. -For example ``self.assertIn`` can include the whole set. - -It is recommended to use testtools `matcher`_ for the more tricky assertions. -You can implement your own specific `matcher`_ as well. - -.. _matcher: http://testtools.readthedocs.org/en/latest/for-test-authors.html#matchers - -If the test case fails you can see the related logs and the information -carried by the exception (exception class, backtrack and exception info). -This and the service logs are your only guide to finding the root cause of flaky -issues. - -Test cases are independent --------------------------- -Every ``test_method`` must be callable individually and MUST NOT depends on, -any other ``test_method`` or ``test_method`` ordering. - -Test cases MAY depend on commonly initialized resources/facilities, like -credentials management, testresources and so on. These facilities, MUST be able -to work even if just one ``test_method`` is selected for execution. - -Service Tagging ---------------- -Service tagging is used to specify which services are exercised by a particular -test method. You specify the services with the ``tempest.test.services`` -decorator. For example: - -@services('compute', 'image') - -Valid service tag names are the same as the list of directories in tempest.api -that have tests. - -For scenario tests having a service tag is required. For the API tests service -tags are only needed if the test method makes an API call (either directly or -indirectly through another service) that differs from the parent directory -name. For example, any test that make an API call to a service other than Nova -in ``tempest.api.compute`` would require a service tag for those services, -however they do not need to be tagged as ``compute``. - -Test fixtures and resources ---------------------------- -Test level resources should be cleaned-up after the test execution. Clean-up -is best scheduled using `addCleanup` which ensures that the resource cleanup -code is always invoked, and in reverse order with respect to the creation -order. - -Test class level resources should be defined in the `resource_setup` method of -the test class, except for any credential obtained from the credentials -provider, which should be set-up in the `setup_credentials` method. - -The test base class `BaseTestCase` defines Tempest framework for class level -fixtures. `setUpClass` and `tearDownClass` are defined here and cannot be -overwritten by subclasses (enforced via hacking rule T105). - -Set-up is split in a series of steps (setup stages), which can be overwritten -by test classes. Set-up stages are: - -- `skip_checks` -- `setup_credentials` -- `setup_clients` -- `resource_setup` - -Tear-down is also split in a series of steps (teardown stages), which are -stacked for execution only if the corresponding setup stage had been -reached during the setup phase. Tear-down stages are: - -- `clear_credentials` (defined in the base test class) -- `resource_cleanup` - -Skipping Tests --------------- -Skipping tests should be based on configuration only. If that is not possible, -it is likely that either a configuration flag is missing, or the test should -fail rather than be skipped. -Using discovery for skipping tests is generally discouraged. - -When running a test that requires a certain "feature" in the target -cloud, if that feature is missing we should fail, because either the test -configuration is invalid, or the cloud is broken and the expected "feature" is -not there even if the cloud was configured with it. - -Negative Tests --------------- -Error handling is an important aspect of API design and usage. Negative -tests are a way to ensure that an application can gracefully handle -invalid or unexpected input. However, as a black box integration test -suite, Tempest is not suitable for handling all negative test cases, as -the wide variety and complexity of negative tests can lead to long test -runs and knowledge of internal implementation details. The bulk of -negative testing should be handled with project function tests. -All negative tests should be based on `API-WG guideline`_ . Such negative -tests can block any changes from accurate failure code to invalid one. - -.. _API-WG guideline: http://specs.openstack.org/openstack/api-wg/guidelines/http.html#failure-code-clarifications - -If facing some gray area which is not clarified on the above guideline, propose -a new guideline to the API-WG. With a proposal to the API-WG we will be able to -build a consensus across all OpenStack projects and improve the quality and -consistency of all the APIs. - -In addition, we have some guidelines for additional negative tests. - -- About BadRequest(HTTP400) case: We can add a single negative tests of - BadRequest for each resource and method(POST, PUT). - Please don't implement more negative tests on the same combination of - resource and method even if API request parameters are different from - the existing test. -- About NotFound(HTTP404) case: We can add a single negative tests of - NotFound for each resource and method(GET, PUT, DELETE, HEAD). - Please don't implement more negative tests on the same combination - of resource and method. - -The above guidelines don't cover all cases and we will grow these guidelines -organically over time. Patches outside of the above guidelines are left up to -the reviewers' discretion and if we face some conflicts between reviewers, we -will expand the guideline based on our discussion and experience. - -Test skips because of Known Bugs --------------------------------- -If a test is broken because of a bug it is appropriate to skip the test until -bug has been fixed. You should use the ``skip_because`` decorator so that -Tempest's skip tracking tool can watch the bug status. - -Example:: - - @skip_because(bug="980688") - def test_this_and_that(self): - ... - -Guidelines ----------- -- Do not submit changesets with only testcases which are skipped as - they will not be merged. -- Consistently check the status code of responses in testcases. The - earlier a problem is detected the easier it is to debug, especially - where there is complicated setup required. - -Parallel Test Execution ------------------------ -Tempest by default runs its tests in parallel this creates the possibility for -interesting interactions between tests which can cause unexpected failures. -Dynamic credentials provides protection from most of the potential race -conditions between tests outside the same class. But there are still a few of -things to watch out for to try to avoid issues when running your tests in -parallel. - -- Resources outside of a project scope still have the potential to conflict. This - is a larger concern for the admin tests since most resources and actions that - require admin privileges are outside of projects. - -- Races between methods in the same class are not a problem because - parallelization in Tempest is at the test class level, but if there is a json - and xml version of the same test class there could still be a race between - methods. - -- The rand_name() function from tempest.lib.common.utils.data_utils should be - used anywhere a resource is created with a name. Static naming should be - avoided to prevent resource conflicts. - -- If the execution of a set of tests is required to be serialized then locking - can be used to perform this. See usage of ``LockFixture`` for examples of - using locking. - -Sample Configuration File -------------------------- -The sample config file is autogenerated using a script. If any changes are made -to the config variables in tempest/config.py then the sample config file must be -regenerated. This can be done running:: - - tox -e genconfig - -Unit Tests ----------- -Unit tests are a separate class of tests in Tempest. They verify Tempest -itself, and thus have a different set of guidelines around them: - -1. They can not require anything running externally. All you should need to - run the unit tests is the git tree, python and the dependencies installed. - This includes running services, a config file, etc. - -2. The unit tests cannot use setUpClass, instead fixtures and testresources - should be used for shared state between tests. - - -.. _TestDocumentation: - -Test Documentation ------------------- -For tests being added we need to require inline documentation in the form of -docstrings to explain what is being tested. In API tests for a new API a class -level docstring should be added to an API reference doc. If one doesn't exist -a TODO comment should be put indicating that the reference needs to be added. -For individual API test cases a method level docstring should be used to -explain the functionality being tested if the test name isn't descriptive -enough. For example:: - - def test_get_role_by_id(self): - """Get a role by its id.""" - -the docstring there is superfluous and shouldn't be added. but for a method -like:: - - def test_volume_backup_create_get_detailed_list_restore_delete(self): - pass - -a docstring would be useful because while the test title is fairly descriptive -the operations being performed are complex enough that a bit more explanation -will help people figure out the intent of the test. - -For scenario tests a class level docstring describing the steps in the scenario -is required. If there is more than one test case in the class individual -docstrings for the workflow in each test methods can be used instead. A good -example of this would be:: - - class TestVolumeBootPattern(manager.ScenarioTest): - """ - This test case attempts to reproduce the following steps: - - * Create in Cinder some bootable volume importing a Glance image - * Boot an instance from the bootable volume - * Write content to the volume - * Delete an instance and Boot a new instance from the volume - * Check written content in the instance - * Create a volume snapshot while the instance is running - * Boot an additional instance from the new snapshot based volume - * Check written content in the instance booted from snapshot - """ - -Test Identification with Idempotent ID --------------------------------------- - -Every function that provides a test must have an ``idempotent_id`` decorator -that is a unique ``uuid-4`` instance. This ID is used to complement the fully -qualified test name and track test functionality through refactoring. The -format of the metadata looks like:: - - @decorators.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997') - def test_list_servers_with_detail(self): - # The created server should be in the detailed list of all servers - ... - -Tempest.lib includes a ``check-uuid`` tool that will test for the existence -and uniqueness of idempotent_id metadata for every test. If you have -Tempest installed you run the tool against Tempest by calling from the -Tempest repo:: - - check-uuid - -It can be invoked against any test suite by passing a package name:: - - check-uuid --package - -Tests without an ``idempotent_id`` can be automatically fixed by running -the command with the ``--fix`` flag, which will modify the source package -by inserting randomly generated uuids for every test that does not have -one:: - - check-uuid --fix - -The ``check-uuid`` tool is used as part of the Tempest gate job -to ensure that all tests have an ``idempotent_id`` decorator. - -Branchless Tempest Considerations ---------------------------------- - -Starting with the OpenStack Icehouse release Tempest no longer has any stable -branches. This is to better ensure API consistency between releases because -the API behavior should not change between releases. This means that the stable -branches are also gated by the Tempest master branch, which also means that -proposed commits to Tempest must work against both the master and all the -currently supported stable branches of the projects. As such there are a few -special considerations that have to be accounted for when pushing new changes -to Tempest. - -1. New Tests for new features -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When adding tests for new features that were not in previous releases of the -projects the new test has to be properly skipped with a feature flag. Whether -this is just as simple as using the @test.requires_ext() decorator to check -if the required extension (or discoverable optional API) is enabled or adding -a new config option to the appropriate section. If there isn't a method of -selecting the new **feature** from the config file then there won't be a -mechanism to disable the test with older stable releases and the new test won't -be able to merge. - -2. Bug fix on core project needing Tempest changes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When trying to land a bug fix which changes a tested API you'll have to use the -following procedure:: - - 1. Propose change to the project, get a +2 on the change even with failing - 2. Propose skip on Tempest which will only be approved after the - corresponding change in the project has a +2 on change - 3. Land project change in master and all open stable branches (if required) - 4. Land changed test in Tempest - -Otherwise the bug fix won't be able to land in the project. - -Handily, `Zuul’s cross-repository dependencies -`_. -can be leveraged to do without step 2 and to have steps 3 and 4 happen -"atomically". To do that, make the patch written in step 1 to depend (refer to -Zuul's documentation above) on the patch written in step 4. The commit message -for the Tempest change should have a link to the Gerrit review that justifies -that change. - -3. New Tests for existing features -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If a test is being added for a feature that exists in all the current releases -of the projects then the only concern is that the API behavior is the same -across all the versions of the project being tested. If the behavior is not -consistent the test will not be able to merge. - -API Stability -------------- - -For new tests being added to Tempest the assumption is that the API being -tested is considered stable and adheres to the OpenStack API stability -guidelines. If an API is still considered experimental or in development then -it should not be tested by Tempest until it is considered stable. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 68c771a09..000000000 --- a/LICENSE +++ /dev/null @@ -1,176 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - diff --git a/README b/README new file mode 100644 index 000000000..8fcd2b2f8 --- /dev/null +++ b/README @@ -0,0 +1,14 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +For ongoing work on maintaining OpenStack packages in the Debian +distribution, please see the Debian OpenStack packaging team at +https://wiki.debian.org/OpenStack/. + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/README.rst b/README.rst deleted file mode 100644 index 2e13fec5a..000000000 --- a/README.rst +++ /dev/null @@ -1,268 +0,0 @@ -======================== -Team and repository tags -======================== - -.. image:: http://governance.openstack.org/badges/tempest.svg - :target: http://governance.openstack.org/reference/tags/index.html - -.. Change things from this point on - -Tempest - The OpenStack Integration Test Suite -============================================== - -The documentation for Tempest is officially hosted at: -https://docs.openstack.org/tempest/latest/ - -This is a set of integration tests to be run against a live OpenStack -cluster. Tempest has batteries of tests for OpenStack API validation, -Scenarios, and other specific tests useful in validating an OpenStack -deployment. - -Design Principles ------------------ -Tempest Design Principles that we strive to live by. - -- Tempest should be able to run against any OpenStack cloud, be it a - one node DevStack install, a 20 node LXC cloud, or a 1000 node KVM - cloud. -- Tempest should be explicit in testing features. It is easy to auto - discover features of a cloud incorrectly, and give people an - incorrect assessment of their cloud. Explicit is always better. -- Tempest uses OpenStack public interfaces. Tests in Tempest should - only touch public OpenStack APIs. -- Tempest should not touch private or implementation specific - interfaces. This means not directly going to the database, not - directly hitting the hypervisors, not testing extensions not - included in the OpenStack base. If there are some features of - OpenStack that are not verifiable through standard interfaces, this - should be considered a possible enhancement. -- Tempest strives for complete coverage of the OpenStack API and - common scenarios that demonstrate a working cloud. -- Tempest drives load in an OpenStack cloud. By including a broad - array of API and scenario tests Tempest can be reused in whole or in - parts as load generation for an OpenStack cloud. -- Tempest should attempt to clean up after itself, whenever possible - we should tear down resources when done. -- Tempest should be self-testing. - -Quickstart ----------- - -To run Tempest, you first need to create a configuration file that will tell -Tempest where to find the various OpenStack services and other testing behavior -switches. Where the configuration file lives and how you interact with it -depends on how you'll be running Tempest. There are 2 methods of using Tempest. -The first, which is a newer and recommended workflow treats Tempest as a system -installed program. The second older method is to run Tempest assuming your -working dir is the actually Tempest source repo, and there are a number of -assumptions related to that. For this section we'll only cover the newer method -as it is simpler, and quicker to work with. - -#. You first need to install Tempest. This is done with pip after you check out - the Tempest repo:: - - $ git clone http://git.openstack.org/openstack/tempest - $ pip install tempest/ - - This can be done within a venv, but the assumption for this guide is that - the Tempest CLI entry point will be in your shell's PATH. - -#. Installing Tempest may create a ``/etc/tempest dir``, however if one isn't - created you can create one or use ``~/.tempest/etc`` or ``~/.config/tempest`` in - place of ``/etc/tempest``. If none of these dirs are created Tempest will create - ``~/.tempest/etc`` when it's needed. The contents of this dir will always - automatically be copied to all ``etc/`` dirs in local workspaces as an initial - setup step. So if there is any common configuration you'd like to be shared - between local Tempest workspaces it's recommended that you pre-populate it - before running ``tempest init``. - -#. Setup a local Tempest workspace. This is done by using the tempest init - command:: - - $ tempest init cloud-01 - - which also works the same as:: - - $ mkdir cloud-01 && cd cloud-01 && tempest init - - This will create a new directory for running a single Tempest configuration. - If you'd like to run Tempest against multiple OpenStack deployments the idea - is that you'll create a new working directory for each to maintain separate - configuration files and local artifact storage for each. - -#. Then ``cd`` into the newly created working dir and also modify the local - config files located in the ``etc/`` subdir created by the ``tempest init`` - command. Tempest is expecting a ``tempest.conf`` file in etc/ so if only a - sample exists you must rename or copy it to tempest.conf before making - any changes to it otherwise Tempest will not know how to load it. For - details on configuring Tempest refer to the :ref:`tempest-configuration`. - -#. Once the configuration is done you're now ready to run Tempest. This can - be done using the :ref:`tempest_run` command. This can be done by either - running:: - - $ tempest run - - from the Tempest workspace directory. Or you can use the ``--workspace`` - argument to run in the workspace you created regardless of your current - working directory. For example:: - - $ tempest run --workspace cloud-01 - - There is also the option to use testr directly, or any `testr`_ based test - runner, like `ostestr`_. For example, from the workspace dir run:: - - $ ostestr --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' - - will run the same set of tests as the default gate jobs. - -.. _testr: https://testrepository.readthedocs.org/en/latest/MANUAL.html -.. _ostestr: https://docs.openstack.org/os-testr/latest/ - -Library -------- -Tempest exposes a library interface. This interface is a stable interface and -should be backwards compatible (including backwards compatibility with the -old tempest-lib package, with the exception of the import). If you plan to -directly consume Tempest in your project you should only import code from the -Tempest library interface, other pieces of Tempest do not have the same -stable interface and there are no guarantees on the Python API unless otherwise -stated. - -For more details refer to the library documentation here: :ref:`library` - -Release Versioning ------------------- -`Tempest Release Notes `_ -shows what changes have been released on each version. - -Tempest's released versions are broken into 2 sets of information. Depending on -how you intend to consume Tempest you might need - -The version is a set of 3 numbers: - -X.Y.Z - -While this is almost `semver`_ like, the way versioning is handled is slightly -different: - -X is used to represent the supported OpenStack releases for Tempest tests -in-tree, and to signify major feature changes to Tempest. It's a monotonically -increasing integer where each version either indicates a new supported OpenStack -release, the drop of support for an OpenStack release (which will coincide with -the upstream stable branch going EOL), or a major feature lands (or is removed) -from Tempest. - -Y.Z is used to represent library interface changes. This is treated the same -way as minor and patch versions from `semver`_ but only for the library -interface. When Y is incremented we've added functionality to the library -interface and when Z is incremented it's a bug fix release for the library. -Also note that both Y and Z are reset to 0 at each increment of X. - -.. _semver: http://semver.org/ - -Configuration -------------- - -Detailed configuration of Tempest is beyond the scope of this -document see :ref:`tempest-configuration` for more details on configuring -Tempest. The ``etc/tempest.conf.sample`` attempts to be a self-documenting -version of the configuration. - -You can generate a new sample tempest.conf file, run the following -command from the top level of the Tempest directory:: - - $ tox -e genconfig - -The most important pieces that are needed are the user ids, OpenStack -endpoints, and basic flavors and images needed to run tests. - -Unit Tests ----------- - -Tempest also has a set of unit tests which test the Tempest code itself. These -tests can be run by specifying the test discovery path:: - - $ OS_TEST_PATH=./tempest/tests testr run --parallel - -By setting OS_TEST_PATH to ./tempest/tests it specifies that test discover -should only be run on the unit test directory. The default value of OS_TEST_PATH -is OS_TEST_PATH=./tempest/test_discover which will only run test discover on the -Tempest suite. - -Alternatively, there are the py27 and py35 tox jobs which will run the unit -tests with the corresponding version of python. - -Python 2.6 ----------- - -Starting in the Kilo release the OpenStack services dropped all support for -python 2.6. This change has been mirrored in Tempest, starting after the -tempest-2 tag. This means that proposed changes to Tempest which only fix -python 2.6 compatibility will be rejected, and moving forward more features not -present in python 2.6 will be used. If you're running your OpenStack services -on an earlier release with python 2.6 you can easily run Tempest against it -from a remote system running python 2.7. (or deploy a cloud guest in your cloud -that has python 2.7) - -Python 3.x ----------- - -Starting during the Pike cycle Tempest has a gating CI job that runs Tempest -with Python 3. Any Tempest release after 15.0.0 should fully support running -under Python 3 as well as Python 2.7. - -Legacy run method ------------------ - -The legacy method of running Tempest is to just treat the Tempest source code -as a python unittest repository and run directly from the source repo. When -running in this way you still start with a Tempest config file and the steps -are basically the same except that it expects you know where the Tempest code -lives on your system and requires a bit more manual interaction to get Tempest -running. For example, when running Tempest this way things like a lock file -directory do not get generated automatically and the burden is on the user to -create and configure that. - -To start you need to create a configuration file. The easiest way to create a -configuration file is to generate a sample in the ``etc/`` directory :: - - $ cd $TEMPEST_ROOT_DIR - $ oslo-config-generator --config-file \ - tempest/cmd/config-generator.tempest.conf \ - --output-file etc/tempest.conf - -After that, open up the ``etc/tempest.conf`` file and edit the -configuration variables to match valid data in your environment. -This includes your Keystone endpoint, a valid user and credentials, -and reference data to be used in testing. - -.. note:: - - If you have a running DevStack environment, Tempest will be - automatically configured and placed in ``/opt/stack/tempest``. It - will have a configuration file already set up to work with your - DevStack installation. - -Tempest is not tied to any single test runner, but `testr`_ is the most commonly -used tool. Also, the nosetests test runner is **not** recommended to run Tempest. - -After setting up your configuration file, you can execute the set of Tempest -tests by using ``testr`` :: - - $ testr run --parallel - -To run one single test serially :: - - $ testr run tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_reboot_non_existent_server - -Tox also contains several existing job configurations. For example:: - - $ tox -e full - -which will run the same set of tests as the OpenStack gate. (it's exactly how -the gate invokes Tempest) Or:: - - $ tox -e smoke - -to run the tests tagged as smoke. diff --git a/REVIEWING.rst b/REVIEWING.rst deleted file mode 100644 index 7d28320b4..000000000 --- a/REVIEWING.rst +++ /dev/null @@ -1,128 +0,0 @@ -Reviewing Tempest Code -====================== - -To start read the `OpenStack Common Review Checklist -`_ - - -Ensuring code is executed -------------------------- - -For any new or change to a test it has to be verified in the gate. This means -that the first thing to check with any change is that a gate job actually runs -it. Tests which aren't executed either because of configuration or skips should -not be accepted. - -If a new test is added that depends on a new config option (like a feature -flag), the commit message must reference a change in DevStack or DevStack-Gate -that enables the execution of this newly introduced test. This reference could -either be a `Cross-Repository Dependency `_ or a simple link -to a Gerrit review. - - -Execution time --------------- -While checking in the job logs that a new test is actually executed, also -pay attention to the execution time of that test. Keep in mind that each test -is going to be executed hundreds of time each day, because Tempest tests -run in many OpenStack projects. It's worth considering how important/critical -the feature under test is with how costly the new test is. - - -Unit Tests ----------- - -For any change that adds new functionality to either common functionality or an -out-of-band tool unit tests are required. This is to ensure we don't introduce -future regressions and to test conditions which we may not hit in the gate runs. -Tests, and service clients aren't required to have unit tests since they should -be self verifying by running them in the gate. - - -API Stability -------------- -Tests should only be added for a published stable APIs. If a patch contains -tests for an API which hasn't been marked as stable or for an API that which -doesn't conform to the `API stability guidelines -`_ then it -should not be approved. - - -Reject Copy and Paste Test Code -------------------------------- -When creating new tests that are similar to existing tests it is tempting to -simply copy the code and make a few modifications. This increases code size and -the maintenance burden. Such changes should not be approved if it is easy to -abstract the duplicated code into a function or method. - - -Tests overlap -------------- -When a new test is being proposed, question whether this feature is not already -tested with Tempest. Tempest has more than 1200 tests, spread amongst many -directories, so it's easy to introduce test duplication. For example, testing -volume attachment to a server could be a compute test or a volume test, depending -on how you see it. So one must look carefully in the entire code base for possible -overlap. As a rule of thumb, the older a feature is, the more likely it's -already tested. - - -Being explicit --------------- -When tests are being added that depend on a configurable feature or extension, -polling the API to discover that it is enabled should not be done. This will -just result in bugs being masked because the test can be skipped automatically. -Instead the config file should be used to determine whether a test should be -skipped or not. Do not approve changes that depend on an API call to determine -whether to skip or not. - - -Configuration Options ---------------------- -With the introduction of the Tempest external test plugin interface we needed -to provide a stable contract for Tempest's configuration options. This means -we can no longer simply remove a configuration option when it's no longer used. -Patches proposed that remove options without a deprecation cycle should not -be approved. Similarly when changing default values with configuration we need -to similarly be careful that we don't break existing functionality. Also, when -adding options, just as before, we need to weigh the benefit of adding an -additional option against the complexity and maintenance overhead having it -costs. - - -Test Documentation ------------------- -When a new test is being added refer to the :ref:`TestDocumentation` section in -hacking to see if the requirements are being met. With the exception of a class -level docstring linking to the API ref doc in the API tests and a docstring for -scenario tests this is up to the reviewers discretion whether a docstring is -required or not. - -Release Notes -------------- -Release notes are how we indicate to users and other consumers of Tempest what -has changed in a given release. Since Tempest 10.0.0 we've been using `reno`_ -to manage and build the release notes. There are certain types of changes that -require release notes and we should not approve them without including a release -note. These include but aren't limited to, any addition, deprecation or removal -from the lib interface, any change to configuration options (including -deprecation), CLI additions or deprecations, major feature additions, and -anything backwards incompatible or would require a user to take note or do -something extra. - -.. _reno: https://docs.openstack.org/reno/latest/ - -Deprecated Code ---------------- -Sometimes we have some bugs in deprecated code. Basically, we leave it. Because -we don't need to maintain it. However, if the bug is critical, we might need to -fix it. When it will happen, we will deal with it on a case-by-case basis. - -When to approve ---------------- - * Every patch needs two +2s before being approved. - * Its ok to hold off on an approval until a subject matter expert reviews it - * If a patch has already been approved but requires a trivial rebase to merge, - you do not have to wait for a second +2, since the patch has already had - two +2s. diff --git a/bindep.txt b/bindep.txt deleted file mode 100644 index 8914adecf..000000000 --- a/bindep.txt +++ /dev/null @@ -1,13 +0,0 @@ -# This file contains runtime (non-python) dependencies -# More info at: http://docs.openstack.org/infra/bindep/readme.html - -libffi-dev [platform:dpkg] -libffi-devel [platform:rpm] -gcc [platform:rpm] -gcc [platform:dpkg] -python-dev [platform:dpkg] -python-devel [platform:rpm] -python3-dev [platform:dpkg] -python3-devel [platform:rpm] -openssl-devel [platform:rpm] -libssl-dev [platform:dpkg] diff --git a/data/tempest-plugins-registry.header b/data/tempest-plugins-registry.header deleted file mode 100644 index 9821e8e70..000000000 --- a/data/tempest-plugins-registry.header +++ /dev/null @@ -1,23 +0,0 @@ -.. - Note to patch submitters: this file is covered by a periodic proposal - job. You should edit the files data/tempest-plugins-registry.footer - and data/tempest-plugins-registry.header instead of this one. - -========================== - Tempest Plugin Registry -========================== - -Since we've created the external plugin mechanism, it's gotten used by -a lot of projects. The following is a list of plugins that currently -exist. - -Detected Plugins -================ - -The following are plugins that a script has found in the openstack/ -namespace, which includes but is not limited to official OpenStack -projects. - -+----------------------------+-------------------------------------------------------------------------+ -|Plugin Name |URL | -+----------------------------+-------------------------------------------------------------------------+ diff --git a/doc/source/HACKING.rst b/doc/source/HACKING.rst deleted file mode 120000 index a2f06b723..000000000 --- a/doc/source/HACKING.rst +++ /dev/null @@ -1 +0,0 @@ -../../HACKING.rst \ No newline at end of file diff --git a/doc/source/REVIEWING.rst b/doc/source/REVIEWING.rst deleted file mode 120000 index 841e042c5..000000000 --- a/doc/source/REVIEWING.rst +++ /dev/null @@ -1 +0,0 @@ -../../REVIEWING.rst \ No newline at end of file diff --git a/doc/source/_static/.keep b/doc/source/_static/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/source/account_generator.rst b/doc/source/account_generator.rst deleted file mode 100644 index 032a20dbc..000000000 --- a/doc/source/account_generator.rst +++ /dev/null @@ -1,5 +0,0 @@ --------------------------------------- -Tempest Test-Account Generator Utility --------------------------------------- - -.. automodule:: tempest.cmd.account_generator diff --git a/doc/source/cleanup.rst b/doc/source/cleanup.rst deleted file mode 100644 index acd016c3f..000000000 --- a/doc/source/cleanup.rst +++ /dev/null @@ -1,5 +0,0 @@ --------------------------------- -Post Tempest Run Cleanup Utility --------------------------------- - -.. automodule:: tempest.cmd.cleanup \ No newline at end of file diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index 201d3877b..000000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,203 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Tempest documentation build configuration file, created by -# sphinx-quickstart on Tue May 21 17:43:32 2013. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os -import subprocess -import warnings - -import openstackdocstheme - -# Build the plugin registry -def build_plugin_registry(app): - root_dir = os.path.dirname( - os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - subprocess.call(['tools/generate-tempest-plugins-list.sh'], cwd=root_dir) - -def setup(app): - if os.getenv('GENERATE_TEMPEST_PLUGIN_LIST', 'true').lower() == 'true': - app.connect('builder-inited', build_plugin_registry) - - - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.todo', - 'sphinx.ext.viewcode', - 'openstackdocstheme', - 'oslo_config.sphinxconfiggen', - ] - -config_generator_config_file = '../../tempest/cmd/config-generator.tempest.conf' -sample_config_basename = '_static/tempest' - -todo_include_todos = True - -# openstackdocstheme options -repository_name = 'openstack/tempest' -bug_project = 'tempest' -bug_tag = '' - -# Must set this variable to include year, month, day, hours, and minutes. -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Tempest' -copyright = u'2013, OpenStack QA Team' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = False - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -modindex_common_prefix = ['tempest.'] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -html_use_smartypants = False - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -html_domain_indices = False - -# If false, no index is generated. -html_use_index = False - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# A list of warning types to suppress arbitrary warning messages. -suppress_warnings = ['image.nonlocal_uri'] diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst deleted file mode 100644 index 8f2865ad5..000000000 --- a/doc/source/configuration.rst +++ /dev/null @@ -1,439 +0,0 @@ -.. _tempest-configuration: - -Tempest Configuration Guide -=========================== - -This guide is a starting point for configuring Tempest. It aims to elaborate -on and explain some of the mandatory and common configuration settings and how -they are used in conjunction. The source of truth on each option is the sample -config file which explains the purpose of each individual option. You can see -the sample config file here: :ref:`tempest-sampleconf` - -.. _tempest_cred_provider_conf: - -Test Credentials ----------------- - -Tempest allows for configuring a set of admin credentials in the ``auth`` -section, via the following parameters: - - #. ``admin_username`` - #. ``admin_password`` - #. ``admin_project_name`` - #. ``admin_domain_name`` - -Admin credentials are not mandatory to run Tempest, but when provided they -can be used to: - -- Run tests for admin APIs -- Generate test credentials on the fly (see `Dynamic Credentials`_) - -When Keystone uses a policy that requires domain scoped tokens for admin -actions, the flag ``admin_domain_scope`` must be set to ``True``. -The admin user configured, if any, must have a role assigned to the domain to -be usable. - -Tempest allows for configuring pre-provisioned test credentials as well. -This can be done using the accounts.yaml file (see -`Pre-Provisioned Credentials`_). This file is used to specify an arbitrary -number of users available to run tests with. -You can specify the location of the file in the ``auth`` section in the -tempest.conf file. To see the specific format used in the file please refer to -the ``accounts.yaml.sample`` file included in Tempest. - -Keystone Connection Info -^^^^^^^^^^^^^^^^^^^^^^^^ -In order for Tempest to be able to talk to your OpenStack deployment you need -to provide it with information about how it communicates with keystone. -This involves configuring the following options in the ``identity`` section: - - - ``auth_version`` - - ``uri`` - - ``uri_v3`` - -The ``auth_version`` option is used to tell Tempest whether it should be using -Keystone's v2 or v3 api for communicating with Keystone. The two uri options are -used to tell Tempest the url of the keystone endpoint. The ``uri`` option is -used for Keystone v2 request and ``uri_v3`` is used for Keystone v3. You want to -ensure that which ever version you set for ``auth_version`` has its uri option -defined. - -Credential Provider Mechanisms -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Tempest currently has two different internal methods for providing authentication -to tests: dynamic credentials and pre-provisioned credentials. -Depending on which one is in use the configuration of Tempest is slightly different. - -Dynamic Credentials -""""""""""""""""""" -Dynamic Credentials (formerly known as Tenant isolation) was originally created -to enable running Tempest in parallel. For each test class it creates a unique -set of user credentials to use for the tests in the class. It can create up to -three sets of username, password, and project names for a primary user, -an admin user, and an alternate user. To enable and use dynamic credentials you -only need to configure two things: - - #. A set of admin credentials with permissions to create users and - projects. This is specified in the ``auth`` section with the - ``admin_username``, ``admin_project_name``, ``admin_domain_name`` and - ``admin_password`` options - #. To enable dynamic credentials in the ``auth`` section with the - ``use_dynamic_credentials`` option. - -This is also currently the default credential provider enabled by Tempest, due -to its common use and ease of configuration. - -It is worth pointing out that depending on your cloud configuration you might -need to assign a role to each of the users created by Tempest's dynamic -credentials. This can be set using the ``tempest_roles`` option. It takes in a -list of role names each of which will be assigned to each of the users created -by dynamic credentials. This option will not have any effect when Tempest is not -configured to use dynamic credentials. - -When the ``admin_domain_scope`` option is set to ``True``, provisioned admin -accounts will be assigned a role on domain configured in -``default_credentials_domain_name``. This will make the accounts provisioned -usable in a cloud where domain scoped tokens are required by Keystone for -admin operations. Note that the initial pre-provision admin accounts, -configured in tempest.conf, must have a role on the same domain as well, for -Dynamic Credentials to work. - - -Pre-Provisioned Credentials -""""""""""""""""""""""""""" - -For a long time using dynamic credentials was the only method available if you -wanted to enable parallel execution of Tempest tests. However, this was -insufficient for certain use cases because of the admin credentials requirement -to create the credential sets on demand. To get around that the accounts.yaml -file was introduced and with that a new internal credential provider to enable -using the list of credentials instead of creating them on demand. With locking -test accounts each test class will reserve a set of credentials from the -accounts.yaml before executing any of its tests so that each class is isolated -like with dynamic credentials. - -To enable and use locking test accounts you need do a few things: - - #. Create an accounts.yaml file which contains the set of pre-existing - credentials to use for testing. To make sure you don't have a credentials - starvation issue when running in parallel make sure you have at least two - times the number of worker processes you are using to execute Tempest - available in the file. (If running serially the worker count is 1.) - - You can check the accounts.yaml.sample file packaged in Tempest for the yaml - format. - #. Provide Tempest with the location of your accounts.yaml file with the - ``test_accounts_file`` option in the ``auth`` section - - *NOTE: Be sure to use a full path for the file; otherwise Tempest will - likely not find it.* - - #. Set ``use_dynamic_credentials = False`` in the ``auth`` group - -It is worth pointing out that each set of credentials in the accounts.yaml -should have a unique project. This is required to provide proper isolation -to the tests using the credentials, and failure to do this will likely cause -unexpected failures in some tests. Also, ensure that these projects and users -used do not have any pre-existing resources created. Tempest assumes all -tenants it's using are empty and may sporadically fail if there are unexpected -resources present. - -When the Keystone in the target cloud requires domain scoped tokens to -perform admin actions, all pre-provisioned admin users must have a role -assigned on the domain where test accounts a provisioned. -The option ``admin_domain_scope`` is used to tell Tempest that domain scoped -tokens shall be used. ``default_credentials_domain_name`` is the domain where -test accounts are expected to be provisioned if no domain is specified. - -Note that if credentials are pre-provisioned via ``tempest account-generator`` -the role on the domain will be assigned automatically for you, as long as -``admin_domain_scope`` as ``default_credentials_domain_name`` are configured -properly in tempest.conf. - -Pre-Provisioned Credentials are also known as accounts.yaml or accounts file. - -Compute -------- - -Flavors -^^^^^^^ -For Tempest to be able to create servers you need to specify flavors that it -can use to boot the servers with. There are two options in the Tempest config -for doing this: - - #. ``flavor_ref`` - #. ``flavor_ref_alt`` - -Both of these options are in the ``compute`` section of the config file and take -in the flavor id (not the name) from Nova. The ``flavor_ref`` option is what -will be used for booting almost all of the guests; ``flavor_ref_alt`` is only -used in tests where two different-sized servers are required (for example, a -resize test). - -Using a smaller flavor is generally recommended. When larger flavors are used, -the extra time required to bring up servers will likely affect total run time -and probably require tweaking timeout values to ensure tests have ample time to -finish. - -Images -^^^^^^ -Just like with flavors, Tempest needs to know which images to use for booting -servers. There are two options in the compute section just like with flavors: - - #. ``image_ref`` - #. ``image_ref_alt`` - -Both options are expecting an image id (not name) from Nova. The ``image_ref`` -option is what will be used for booting the majority of servers in Tempest. -``image_ref_alt`` is used for tests that require two images such as rebuild. If -two images are not available you can set both options to the same image id and -those tests will be skipped. - -There are also options in the ``scenario`` section for images: - - #. ``img_file`` - #. ``img_dir`` - #. ``aki_img_file`` - #. ``ari_img_file`` - #. ``ami_img_file`` - #. ``img_container_format`` - #. ``img_disk_format`` - -However, unlike the other image options, these are used for a very small subset -of scenario tests which are uploading an image. These options are used to tell -Tempest where an image file is located and describe its metadata for when it is -uploaded. - -The behavior of these options is a bit convoluted (which will likely be fixed in -future versions). You first need to specify ``img_dir``, which is the directory -in which Tempest will look for the image files. First it will check if the -filename set for ``img_file`` could be found in ``img_dir``. If it is found then -the ``img_container_format`` and ``img_disk_format`` options are used to upload -that image to glance. However, if it is not found, Tempest will look for the -three uec image file name options as a fallback. If neither is found, the tests -requiring an image to upload will fail. - -It is worth pointing out that using `cirros`_ is a very good choice for running -Tempest. It's what is used for upstream testing, they boot quickly and have a -small footprint. - -.. _cirros: https://launchpad.net/cirros - -Networking ----------- -OpenStack has a myriad of different networking configurations possible and -depending on which of the two network backends, nova-network or Neutron, you are -using things can vary drastically. Due to this complexity Tempest has to provide -a certain level of flexibility in its configuration to ensure it will work -against any cloud. This ends up causing a large number of permutations in -Tempest's config around network configuration. - - -Enabling Remote Access to Created Servers -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. _tempest_conf_network_allocation: - -Network Creation/Usage for Servers -"""""""""""""""""""""""""""""""""" -When Tempest creates servers for testing, some tests require being able to -connect those servers. Depending on the configuration of the cloud, the methods -for doing this can be different. In certain configurations it is required to -specify a single network with server create calls. Accordingly, Tempest provides -a few different methods for providing this information in configuration to try -and ensure that regardless of the cloud's configuration it'll still be able to -run. This section covers the different methods of configuring Tempest to provide -a network when creating servers. - -Fixed Network Name -'''''''''''''''''' -This is the simplest method of specifying how networks should be used. You can -just specify a single network name/label to use for all server creations. The -limitation with this is that all projects and users must be able to see -that network name/label if they are to perform a network list and be able to use -it. - -If no network name is assigned in the config file and none of the below -alternatives are used, then Tempest will not specify a network on server -creations, which depending on the cloud configuration might prevent them from -booting. - -To set a fixed network name simply: - - #. Set the ``fixed_network_name`` option in the ``compute`` group - -In the case that the configured fixed network name can not be found by a user -network list call, it will be treated like one was not provided except that a -warning will be logged stating that it couldn't be found. - - -Accounts File -''''''''''''' -If you are using an accounts file to provide credentials for running Tempest -then you can leverage it to also specify which network should be used with -server creations on a per project and user pair basis. This provides -the necessary flexibility to work with more intricate networking configurations -by enabling the user to specify exactly which network to use for which -projects. You can refer to the accounts.yaml.sample file included in -the Tempest repo for the syntax around specifying networks in the file. - -However, specifying a network is not required when using an accounts file. If -one is not specified you can use a fixed network name to specify the network to -use when creating servers just as without an accounts file. However, any network -specified in the accounts file will take precedence over the fixed network name -provided. If no network is provided in the accounts file and a fixed network -name is not set then no network will be included in create server requests. - -If a fixed network is provided and the accounts.yaml file also contains networks -this has the benefit of enabling a couple more tests which require a static -network to perform operations like server lists with a network filter. If a -fixed network name is not provided these tests are skipped. Additionally, if a -fixed network name is provided it will serve as a fallback in case of a -misconfiguration or a missing network in the accounts file. - - -With Dynamic Credentials -'''''''''''''''''''''''' -With dynamic credentials enabled and using nova-network, your only option for -configuration is to either set a fixed network name or not. However, in most -cases it shouldn't matter because nova-network should have no problem booting a -server with multiple networks. If this is not the case for your cloud then using -an accounts file is recommended because it provides the necessary flexibility to -describe your configuration. Dynamic credentials is not able to dynamically -allocate things as necessary if Neutron is not enabled. - -With Neutron and dynamic credentials enabled there should not be any additional -configuration necessary to enable Tempest to create servers with working -networking, assuming you have properly configured the ``network`` section to -work for your cloud. Tempest will dynamically create the Neutron resources -necessary to enable using servers with that network. Also, just as with the -accounts file, if you specify a fixed network name while using Neutron and -dynamic credentials it will enable running tests which require a static network -and it will additionally be used as a fallback for server creation. However, -unlike accounts.yaml this should never be triggered. - -However, there is an option ``create_isolated_networks`` to disable dynamic -credentials's automatic provisioning of network resources. If this option is set -to ``False`` you will have to either rely on there only being a single/default -network available for the server creation, or use ``fixed_network_name`` to -inform Tempest which network to use. - -SSH Connection Configuration -"""""""""""""""""""""""""""" -There are also several different ways to actually establish a connection and -authenticate/login on the server. After a server is booted with a provided -network there are still details needed to know how to actually connect to -the server. The ``validation`` group gathers all the options regarding -connecting to and remotely accessing the created servers. - -To enable remote access to servers, there are 3 options at a minimum that are used: - - #. ``run_validation`` - #. ``connect_method`` - #. ``auth_method`` - -The ``run_validation`` is used to enable or disable ssh connectivity for -all tests (with the exception of scenario tests which do not have a flag for -enabling or disabling ssh) To enable ssh connectivity this needs be set to ``True``. - -The ``connect_method`` option is used to tell Tempest what kind of IP to use for -establishing a connection to the server. Two methods are available: ``fixed`` -and ``floating``, the later being set by default. If this is set to floating -Tempest will create a floating ip for the server before attempted to connect -to it. The IP for the floating ip is what is used for the connection. - -For the ``auth_method`` option there is currently, only one valid option, -``keypair``. With this set to ``keypair`` Tempest will create an ssh keypair -and use that for authenticating against the created server. - -Configuring Available Services ------------------------------- -OpenStack is really a constellation of several different projects which -are running together to create a cloud. However which projects you're running -is not set in stone, and which services are running is up to the deployer. -Tempest however needs to know which services are available so it can figure -out which tests it is able to run and certain setup steps which differ based -on the available services. - -The ``service_available`` section of the config file is used to set which -services are available. It contains a boolean option for each service (except -for Keystone which is a hard requirement) set it to ``True`` if the service is -available or ``False`` if it is not. - -Service Catalog -^^^^^^^^^^^^^^^ -Each project which has its own REST API contains an entry in the service -catalog. Like most things in OpenStack this is also completely configurable. -However, for Tempest to be able to figure out which endpoints should get REST -API calls for each service, it needs to know how that project is defined in the -service catalog. There are three options for each service section to accomplish -this: - - #. ``catalog_type`` - #. ``endpoint_type`` - #. ``region`` - -Setting ``catalog_type`` and ``endpoint_type`` should normally give Tempest -enough information to determine which endpoint it should pull from the service -catalog to use for talking to that particular service. However, if your cloud -has multiple regions available and you need to specify a particular one to use a -service you can set the ``region`` option in that service's section. - -It should also be noted that the default values for these options are set -to what DevStack uses (which is a de facto standard for service catalog -entries). So often nothing actually needs to be set on these options to enable -communication to a particular service. It is only if you are either not using -the same ``catalog_type`` as DevStack or you want Tempest to talk to a different -endpoint type instead of ``publicURL`` for a service that these need to be -changed. - -.. note:: - - Tempest does not serve all kinds of fancy URLs in the service catalog. The - service catalog should be in a standard format (which is going to be - standardized at the Keystone level). - Tempest expects URLs in the Service catalog in the following format: - - * ``http://example.com:1234/`` - - Examples: - - * Good - ``http://example.com:1234/v2.0`` - * Wouldn’t work - ``http://example.com:1234/xyz/v2.0/`` - (adding prefix/suffix around version etc) - -Service Feature Configuration ------------------------------ - -OpenStack provides its deployers a myriad of different configuration options to -enable anyone deploying it to create a cloud tailor-made for any individual use -case. It provides options for several different backend types, databases, -message queues, etc. However, the downside to this configurability is that -certain operations and features aren't supported depending on the configuration. -These features may or may not be discoverable from the API so the burden is -often on the user to figure out what is supported by the cloud they're talking -to. Besides the obvious interoperability issues with this it also leaves -Tempest in an interesting situation trying to figure out which tests are -expected to work. However, Tempest tests do not rely on dynamic API discovery -for a feature (assuming one exists). Instead Tempest has to be explicitly -configured as to which optional features are enabled. This is in order to -prevent bugs in the discovery mechanisms from masking failures. - -The service ``feature-enabled`` config sections are how Tempest addresses the -optional feature question. Each service that has tests for optional features -contains one of these sections. The only options in it are boolean options -with the name of a feature which is used. If it is set to false any test which -depends on that functionality will be skipped. For a complete list of all these -options refer to the sample config file. - - -API Extensions -^^^^^^^^^^^^^^ -The service feature-enabled sections often contain an ``api-extensions`` option -(or in the case of Swift a ``discoverable_apis`` option). This is used to tell -Tempest which api extensions (or configurable middleware) is used in your -deployment. It has two valid config states: either it contains a single value -``all`` (which is the default) which means that every api extension is assumed -to be enabled, or it is set to a list of each individual extension that is -enabled for that service. diff --git a/doc/source/field_guide/api.rst b/doc/source/field_guide/api.rst deleted file mode 120000 index ce0f6b722..000000000 --- a/doc/source/field_guide/api.rst +++ /dev/null @@ -1 +0,0 @@ -../../../tempest/api/README.rst \ No newline at end of file diff --git a/doc/source/field_guide/index.rst b/doc/source/field_guide/index.rst deleted file mode 120000 index 6f24b575c..000000000 --- a/doc/source/field_guide/index.rst +++ /dev/null @@ -1 +0,0 @@ -../../../tempest/README.rst \ No newline at end of file diff --git a/doc/source/field_guide/scenario.rst b/doc/source/field_guide/scenario.rst deleted file mode 120000 index 19ce39e2e..000000000 --- a/doc/source/field_guide/scenario.rst +++ /dev/null @@ -1 +0,0 @@ -../../../tempest/scenario/README.rst \ No newline at end of file diff --git a/doc/source/field_guide/unit_tests.rst b/doc/source/field_guide/unit_tests.rst deleted file mode 120000 index 67a8b2035..000000000 --- a/doc/source/field_guide/unit_tests.rst +++ /dev/null @@ -1 +0,0 @@ -../../../tempest/tests/README.rst \ No newline at end of file diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index f5628507d..000000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,86 +0,0 @@ -======================= -Tempest Testing Project -======================= - -Overview -======== - -.. toctree:: - :maxdepth: 2 - - overview - -Field Guides -============ -Tempest contains tests of many different types, the field guides -attempt to explain these in a way that makes it easy to understand -where your test contributions should go. - -.. toctree:: - :maxdepth: 1 - - field_guide/index - field_guide/api - field_guide/scenario - field_guide/unit_tests - -Users Guide -=========== - -Tempest Configuration Guide ---------------------------- - -.. toctree:: - :maxdepth: 2 - - configuration - sampleconf - -Command Documentation ---------------------- - -.. toctree:: - :maxdepth: 1 - - account_generator - cleanup - subunit_describe_calls - workspace - run - -Developers Guide -================ - -Development ------------ - -.. toctree:: - :maxdepth: 2 - - HACKING - REVIEWING - microversion_testing - test_removal - write_tests - -Plugins -------- - -.. toctree:: - :maxdepth: 2 - - plugin - plugin-registry - -Library -------- - -.. toctree:: - :maxdepth: 2 - - library - -Indices and tables -================== - -* :ref:`search` diff --git a/doc/source/library.rst b/doc/source/library.rst deleted file mode 100644 index a461a0fc0..000000000 --- a/doc/source/library.rst +++ /dev/null @@ -1,71 +0,0 @@ -.. _library: - -Tempest Library Documentation -============================= - -Tempest provides a stable library interface that provides external tools or -test suites an interface for reusing pieces of tempest code. Any public -interface that lives in tempest/lib in the tempest repo is treated as a stable -public interface and it should be safe to external consume that. Every effort -goes into maintaining backwards compatibility with any change. -The library is self contained and doesn't have any dependency on -other tempest internals outside of lib (including no usage of tempest -configuration). - -Stability ---------- -Any code that lives in tempest/lib will be treated as a stable interface. -This means that any public interface under the tempest/lib directory is -expected to be a stable interface suitable for public consumption. However, for -any interfaces outside of tempest/lib in the tempest tree (unless otherwise -noted) or any private interfaces the same stability guarantees don't apply. - -Adding Interfaces -''''''''''''''''' -When adding an interface to tempest/lib we have to make sure there are no -dependencies on any pieces of tempest outside of tempest/lib. This means if -for example there is a dependency on the configuration file we need remove that. -The other aspect when adding an interface is to make sure it's really an -interface ready for external consumption and something we want to commit to -supporting. - -Making changes -'''''''''''''' -When making changes to tempest/lib you have to be conscious of the effect of -any changes on external consumers. If your proposed changeset will change the -default behaviour of any interface, or make something which previously worked -not after your change, then it is not acceptable. Every effort needs to go into -preserving backwards compatibility in changes. - -Reviewing -''''''''' -When reviewing a proposed change to tempest/lib code we need to be careful to -ensure that we don't break backwards compatibility. For patches that change -existing interfaces we have to be careful to make sure we don't break any -external consumers. Some common red flags are: - - * a change to an existing API requires a change outside the library directory - where the interface is being consumed - * a unit test has to be significantly changed to make the proposed change pass - -Testing -''''''' -When adding a new interface to the library we need to at a minimum have unit -test coverage. A proposed change to add an interface to tempest/lib that -doesn't have unit tests shouldn't be accepted. Ideally these unit tests will -provide sufficient coverage to ensure a stable interface moving forward. - -Current Library APIs --------------------- - -.. toctree:: - :maxdepth: 2 - - library/cli - library/decorators - library/rest_client - library/utils - library/api_microversion_testing - library/auth - library/clients - library/credential_providers diff --git a/doc/source/library/api_microversion_testing.rst b/doc/source/library/api_microversion_testing.rst deleted file mode 100644 index 8be924d0a..000000000 --- a/doc/source/library/api_microversion_testing.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _api_microversion_testing: - -API Microversion Testing Support in Tempest -=========================================== - ---------------------------------------------- -Framework to support API Microversion testing ---------------------------------------------- - -Many of the OpenStack components have implemented API microversions. -It is important to test those microversions in Tempest or external plugins. -Tempest now provides stable interfaces to support to test the API microversions. -Based on the microversion range coming from the combination of both configuration -and each test case, APIs request will be made with selected microversion. - -This document explains the interfaces needed for microversion testing. - - -The api_version_request module -"""""""""""""""""""""""""""""" - -.. automodule:: tempest.lib.common.api_version_request - :members: - -The api_version_utils module -"""""""""""""""""""""""""""" - -.. automodule:: tempest.lib.common.api_version_utils - :members: diff --git a/doc/source/library/auth.rst b/doc/source/library/auth.rst deleted file mode 100644 index e1d92edb4..000000000 --- a/doc/source/library/auth.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. _auth: - -Authentication Framework Usage -============================== - ---------------- -The auth module ---------------- - -.. automodule:: tempest.lib.auth - :members: diff --git a/doc/source/library/cli.rst b/doc/source/library/cli.rst deleted file mode 100644 index 6bd78810d..000000000 --- a/doc/source/library/cli.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. _cli: - -CLI Testing Framework Usage -=========================== - -------------------- -The cli.base module -------------------- - -.. automodule:: tempest.lib.cli.base - :members: - ----------------------------- -The cli.output_parser module ----------------------------- - -.. automodule:: tempest.lib.cli.output_parser - :members: diff --git a/doc/source/library/clients.rst b/doc/source/library/clients.rst deleted file mode 100644 index 0f4ba4c1a..000000000 --- a/doc/source/library/clients.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. _clients: - -Service Clients Usage -===================== - -Tests make requests against APIs using service clients. Service clients are -specializations of the ``RestClient`` class. The service clients that cover the -APIs exposed by a service should be grouped in a service clients module. -A service clients module is python module where all service clients are -defined. If major API versions are available, submodules should be defined, -one for each version. - -The ``ClientsFactory`` class helps initializing all clients of a specific -service client module from a set of shared parameters. - -The ``ServiceClients`` class provides a convenient way to get access to all -available service clients initialized with a provided set of credentials. - ------------------------------ -The clients management module ------------------------------ - -.. automodule:: tempest.lib.services.clients - :members: - ------------------------------- -Compute service client modules ------------------------------- - -.. toctree:: - :maxdepth: 2 - - service_clients/compute_clients diff --git a/doc/source/library/credential_providers.rst b/doc/source/library/credential_providers.rst deleted file mode 100644 index 7e831cc9a..000000000 --- a/doc/source/library/credential_providers.rst +++ /dev/null @@ -1,148 +0,0 @@ -.. _cred_providers: - -Credential Providers -==================== - -These library interfaces are used to deal with allocating credentials on demand -either dynamically by calling keystone to allocate new credentials, or from -a list of preprovisioned credentials. These 2 modules are implementations of -the same abstract credential providers class and can be used interchangably. -However, each implementation has some additional parameters that are used to -influence the behavior of the modules. The API reference at the bottom of this -doc shows the interface definitions for both modules, however that may be a bit -opaque. You can see some examples of how to leverage this interface below. - -Initialization Example ----------------------- -This example is from Tempest itself (from tempest/common/credentials_factory.py -just modified slightly) and is how it initializes the credential provider based -on config:: - - from tempest import config - from tempest.lib.common import dynamic_creds - from tempest.lib.common import preprov_creds - - CONF = config.CONF - - def get_credentials_provider(name, network_resources=None, - force_tenant_isolation=False, - identity_version=None): - # If a test requires a new account to work, it can have it via forcing - # dynamic credentials. A new account will be produced only for that test. - # In case admin credentials are not available for the account creation, - # the test should be skipped else it would fail. - identity_version = identity_version or CONF.identity.auth_version - if CONF.auth.use_dynamic_credentials or force_tenant_isolation: - admin_creds = get_configured_admin_credentials( - fill_in=True, identity_version=identity_version) - return dynamic_creds.DynamicCredentialProvider( - name=name, - network_resources=network_resources, - identity_version=identity_version, - admin_creds=admin_creds, - identity_admin_domain_scope=CONF.identity.admin_domain_scope, - identity_admin_role=CONF.identity.admin_role, - extra_roles=CONF.auth.tempest_roles, - neutron_available=CONF.service_available.neutron, - project_network_cidr=CONF.network.project_network_cidr, - project_network_mask_bits=CONF.network.project_network_mask_bits, - public_network_id=CONF.network.public_network_id, - create_networks=(CONF.auth.create_isolated_networks and not - CONF.network.shared_physical_network), - resource_prefix=CONF.resources_prefix, - credentials_domain=CONF.auth.default_credentials_domain_name, - admin_role=CONF.identity.admin_role, - identity_uri=CONF.identity.uri_v3, - identity_admin_endpoint_type=CONF.identity.v3_endpoint_type) - else: - if CONF.auth.test_accounts_file: - # Most params are not relevant for pre-created accounts - return preprov_creds.PreProvisionedCredentialProvider( - name=name, identity_version=identity_version, - accounts_lock_dir=lockutils.get_lock_path(CONF), - test_accounts_file=CONF.auth.test_accounts_file, - object_storage_operator_role=CONF.object_storage.operator_role, - object_storage_reseller_admin_role=reseller_admin_role, - credentials_domain=CONF.auth.default_credentials_domain_name, - admin_role=CONF.identity.admin_role, - identity_uri=CONF.identity.uri_v3, - identity_admin_endpoint_type=CONF.identity.v3_endpoint_type) - else: - raise exceptions.InvalidConfiguration( - 'A valid credential provider is needed') - -This function just returns an initialized credential provider class based on the -config file. The consumer of this function treats the output as the same -regardless of whether it's a dynamic or preprovisioned provider object. - -Dealing with Credentials ------------------------- - -Once you have a credential provider object created the access patterns for -allocating and removing credentials are the same across both the dynamic -and preprovisioned credentials. These are defined in the abstract -CredentialProvider class. At a high level the credentials provider enables -you to get 3 basic types of credentials at once (per object): a primary, alt, -and admin. You're also able to allocate a credential by role. These credentials -are tracked by the provider object and delete must manually be called otherwise -the created resources will not be deleted (or returned to the pool in the case -of preprovisioned creds) - -Examples -'''''''' - -Continuing from the example above, to allocate credentials by the 3 basic types -you can do the following:: - - provider = get_credentials_provider('my_tests') - primary_creds = provider.get_primary_creds() - alt_creds = provider.get_alt_creds() - admin_creds = provider.get_admin_creds() - # Make sure to delete the credentials when you're finished - provider.clear_creds() - -To create and interact with credentials by role you can do the following:: - - provider = get_credentials_provider('my_tests') - my_role_creds = provider.get_creds_by_role({'roles': ['my_role']}) - # provider.clear_creds() will clear all creds including those allocated by - # role - provider.clear_creds() - -When multiple roles are specified a set of creds with all the roles assigned -will be allocated:: - - provider = get_credentials_provider('my_tests') - my_role_creds = provider.get_creds_by_role({'roles': ['my_role', - 'my_other_role']}) - # provider.clear_creds() will clear all creds including those allocated by - # role - provider.clear_creds() - -If you need multiple sets of credentials with the same roles you can also do -this by leveraging the ``force_new`` kwarg:: - - provider = get_credentials_provider('my_tests') - my_role_creds = provider.get_creds_by_role({'roles': ['my_role']}) - my_role_other_creds = provider.get_creds_by_role({'roles': ['my_role']}, - force_new=True) - # provider.clear_creds() will clear all creds including those allocated by - # role - provider.clear_creds() - -API Reference -============= - ------------------------------- -The dynamic credentials module ------------------------------- - -.. automodule:: tempest.lib.common.dynamic_creds - :members: - --------------------------------------- -The pre-provisioned credentials module --------------------------------------- - -.. automodule:: tempest.lib.common.preprov_creds - :members: diff --git a/doc/source/library/decorators.rst b/doc/source/library/decorators.rst deleted file mode 100644 index a1739678e..000000000 --- a/doc/source/library/decorators.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _decorators: - -Decorators Usage Guide -====================== - ---------------------- -The decorators module ---------------------- - -.. automodule:: tempest.lib.decorators - :members: - - diff --git a/doc/source/library/rest_client.rst b/doc/source/library/rest_client.rst deleted file mode 100644 index 3045694f5..000000000 --- a/doc/source/library/rest_client.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. _rest_client: - -Rest Client Usage -================= - ----------------------- -The rest_client module ----------------------- - -.. automodule:: tempest.lib.common.rest_client - :members: diff --git a/doc/source/library/service_clients/compute_clients.rst b/doc/source/library/service_clients/compute_clients.rst deleted file mode 100644 index 4ca55d418..000000000 --- a/doc/source/library/service_clients/compute_clients.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _servers_client: - -Compute Client Usage -==================== - -.. automodule:: tempest.lib.services.compute.servers_client - :members: diff --git a/doc/source/library/utils.rst b/doc/source/library/utils.rst deleted file mode 100644 index bc2f79b06..000000000 --- a/doc/source/library/utils.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. _utils: - -Utils Usage -=========== - ---------------- -The misc module ---------------- - -.. automodule:: tempest.lib.common.utils.misc - :members: diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst deleted file mode 100644 index 60f4f365a..000000000 --- a/doc/source/microversion_testing.rst +++ /dev/null @@ -1,341 +0,0 @@ -================================= -Microversion Testing With Tempest -================================= - -Many OpenStack Services provide their APIs with `microversion`_ -support and want to test them in Tempest. - -.. _microversion: http://specs.openstack.org/openstack/api-wg/guidelines/microversion_specification.html - -This document covers how to test microversions for each project and -whether tests should live in Tempest or on project side. - -Tempest Scope For Microversion Testing -"""""""""""""""""""""""""""""""""""""" -APIs microversions for any OpenStack service grow rapidly and -testing each and every microversion in Tempest is not feasible and -efficient way. -Also not every API microversion changes the complete system behavior -and many of them only change the API or DB layer to accept and return more -data on API. - -Tempest is an integration test suite, but not all API microversion testing fall under this category. -As a result, Tempest mainly covers integration test cases for microversions, Other testing coverage -for microversion should be hosted on project side as functional tests or via Tempest plugin as per -project guidelines. - -.. note:: Integration tests are those tests which involve more than one service to - verify the expected behavior by single or combination of API requests. - If a test is just to verify the API behavior as success and failure cases - or verify its expected response object, then it does not fall under integration - tests. - -Tempest will cover only integration testing of applicable microversions with -below exceptions: - - #. Test covers a feature which is important for interoperability. This covers tests requirement - from Defcore. - #. Test needed to fill Schema gaps. - Tempest validates API responses with defined JSON schema. API responses can be different on - each microversion and the JSON schemas need to be defined separately for the microversion. - While implementing new integration tests for a specific microversion, there - may be a gap in the JSON schemas (caused by previous microversions) implemented - in Tempest. - Filling that gap while implementing the new integration test cases is not efficient due to - many reasons: - - * Hard to review - * Sync between multiple integration tests patches which try to fill the same schema gap at same - time - * Might delay the microversion change on project side where project team wants Tempest - tests to verify the results. - - Tempest will allow to fill the schema gaps at the end of each cycle, or more - often if required. - Schema gap can be filled with testing those with a minimal set of tests. Those - tests might not be integration tests and might be already covered on project - side also. - This exception is needed because: - - * Allow to create microversion response schema in Tempest at the same time that projects are - implementing their API microversions. This will make implementation easier for adding - required tests before a new microversion change can be merged in the corresponding project - and hence accelerate the development of microversions. - * New schema must be verified by at least one test case which exercises such schema. - - For example: - If any projects implemented 4 API microversion say- v2.3, v2.4, v2.5, v2.6 - Assume microversion v2.3, v2.4, v2.6 change the API Response which means Tempest - needs to add JSON schema for v2.3, v2.4, v2.6. - In that case if only 1 or 2 tests can verify all new schemas then we do not need - separate tests for each new schemas. In worst case, we have to add 3 separate tests. - #. Test covers service behavior at large scale with involvement of more deep layer like hypervisor - etc not just API/DB layer. This type of tests will be added case by case basis and - with project team consultation about why it cannot be covered on project side and worth to test - in Tempest. - -Project Scope For Microversion Testing -"""""""""""""""""""""""""""""""""""""" -All microversions testing which are not covered under Tempest as per above section, should be -tested on project side as functional tests or as Tempest plugin as per project decision. - - -Configuration options for Microversion -"""""""""""""""""""""""""""""""""""""" - -* Add configuration options for specifying test target Microversions. - We need to specify test target Microversions because the supported - Microversions may be different between OpenStack clouds. For operating - multiple Microversion tests in a single Tempest operation, configuration - options should represent the range of test target Microversions. - New configuration options are: - - * min_microversion - * max_microversion - - Those should be defined under respective section of each service. - For example: - - .. code-block:: ini - - [compute] - min_microversion = None - max_microversion = latest - - -How To Implement Microversion Tests -""""""""""""""""""""""""""""""""""" - -Tempest provides stable interfaces to test API Microversion. -For Details, see: `API Microversion testing Framework`_ -This document explains how to implement Microversion tests using those -interfaces. - -.. _API Microversion testing Framework: https://docs.openstack.org/tempest/latest/library/api_microversion_testing.html - - -Step1: Add skip logic based on configured Microversion range -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Add logic to skip the tests based on Tests class and configured Microversion -range. -api_version_utils.check_skip_with_microversion function can be used -to automatically skip the tests which do not fall under configured -Microversion range. -For example: - -.. code-block:: python - - class BaseTestCase1(api_version_utils.BaseMicroversionTest): - - [..] - @classmethod - def skip_checks(cls): - super(BaseTestCase1, cls).skip_checks() - api_version_utils.check_skip_with_microversion(cls.min_microversion, - cls.max_microversion, - CONF.compute.min_microversion, - CONF.compute.max_microversion) - -Skip logic can be added in tests base class or any specific test class depends on -tests class structure. - -Step2: Selected API request microversion -'''''''''''''''''''''''''''''''''''''''' - -Select appropriate Microversion which needs to be used -to send with API request. -api_version_utils.select_request_microversion function can be used -to select the appropriate Microversion which will be used for API request. -For example: - -.. code-block:: python - - @classmethod - def resource_setup(cls): - super(BaseTestCase1, cls).resource_setup() - cls.request_microversion = ( - api_version_utils.select_request_microversion( - cls.min_microversion, - CONF.compute.min_microversion)) - - -Step3: Set Microversion on Service Clients -'''''''''''''''''''''''''''''''''''''''''' - -Microversion selected by Test Class in previous step needs to be set on -service clients so that APIs can be requested with selected Microversion. - -Microversion can be defined as global variable on service clients which -can be set using fixture. -Also Microversion header name needs to be defined on service clients which -should be constant because it is not supposed to be changed by project -as per API contract. -For example: - -.. code-block:: python - - COMPUTE_MICROVERSION = None - - class BaseClient1(rest_client.RestClient): - api_microversion_header_name = 'X-OpenStack-Nova-API-Version' - -Now test class can set the selected Microversion on required service clients -using fixture which can take care of resetting the same once tests is completed. -For example: - -.. code-block:: python - - def setUp(self): - super(BaseTestCase1, self).setUp() - self.useFixture(api_microversion_fixture.APIMicroversionFixture( - self.request_microversion)) - -Service clients needs to add set Microversion in API request header which -can be done by overriding the get_headers() method of rest_client. -For example: - -.. code-block:: python - - COMPUTE_MICROVERSION = None - - class BaseClient1(rest_client.RestClient): - api_microversion_header_name = 'X-OpenStack-Nova-API-Version' - - def get_headers(self): - headers = super(BaseClient1, self).get_headers() - if COMPUTE_MICROVERSION: - headers[self.api_microversion_header_name] = COMPUTE_MICROVERSION - return headers - - -Step4: Separate Test classes for each Microversion -'''''''''''''''''''''''''''''''''''''''''''''''''' - -This is last step to implement Microversion test class. - -For any Microversion tests, basically we need to implement a -separate test class. In addition, each test class defines its -Microversion range with class variable like min_microversion -and max_microversion. Tests will be valid for that defined range. -If that range is out of configured Microversion range then, test -will be skipped. - -.. note:: Microversion testing is supported at test class level not at - individual test case level. - -For example: - -Below test is applicable for Microversion from 2.2 till 2.9: - -.. code-block:: python - - class BaseTestCase1(api_version_utils.BaseMicroversionTest, - tempest.test.BaseTestCase): - - [..] - - - class Test1(BaseTestCase1): - min_microversion = '2.2' - max_microversion = '2.9' - - [..] - -Below test is applicable for Microversion from 2.10 till latest: - -.. code-block:: python - - class Test2(BaseTestCase1): - min_microversion = '2.10' - max_microversion = 'latest' - - [..] - - -Notes about Compute Microversion Tests -"""""""""""""""""""""""""""""""""""""" - -Some of the compute Microversion tests have been already implemented -with the Microversion testing framework. So for further tests only -step 4 is needed. - -Along with that JSON response schema might need versioning if needed. - -Compute service clients strictly validate the response against defined JSON -schema and does not allow additional elements in response. -So if that Microversion changed the API response then schema needs to be versioned. -New JSON schema file needs to be defined with new response attributes and service -client methods will select the schema based on requested microversion. - -If Microversion tests are implemented randomly meaning not -in sequence order(v2.20 tests added and previous Microversion tests are not yet added) -then, still schema might need to be version for older Microversion if they changed -the response. -This is because Nova Microversion includes all the previous Microversions behavior. - -For Example: - Implementing the v2.20 Microversion tests before v2.9 and 2.19- - v2.20 API request will respond as latest behavior of Nova till v2.20, - and in v2.9 and 2.19, server response has been changed so response schema needs - to be versioned accordingly. - -That can be done by using the get_schema method in below module: - -The base_compute_client module -'''''''''''''''''''''''''''''' - -.. automodule:: tempest.lib.services.compute.base_compute_client - :members: - - -Microversion tests implemented in Tempest -""""""""""""""""""""""""""""""""""""""""" - -* Compute - - * `2.1`_ - - .. _2.1: https://docs.openstack.org/nova/latest/api_microversion_history.html#id1 - - * `2.2`_ - - .. _2.2: http://docs.openstack.org/nova/latest/api_microversion_history.html#id2 - - * `2.10`_ - - .. _2.10: http://docs.openstack.org/nova/latest/api_microversion_history.html#id9 - - * `2.20`_ - - .. _2.20: http://docs.openstack.org/nova/latest/api_microversion_history.html#id18 - - * `2.25`_ - - .. _2.25: http://docs.openstack.org/nova/latest/api_microversion_history.html#maximum-in-mitaka - - * `2.32`_ - - .. _2.32: http://docs.openstack.org/nova/latest/api_microversion_history.html#id29 - - * `2.37`_ - - .. _2.37: http://docs.openstack.org/nova/latest/api_microversion_history.html#id34 - - * `2.42`_ - - .. _2.42: http://docs.openstack.org/nova/latest/api_microversion_history.html#maximum-in-ocata - - * `2.47`_ - - .. _2.47: http://docs.openstack.org/nova/latest/api_microversion_history.html#id42 - - * `2.48`_ - - .. _2.48: http://docs.openstack.org/nova/latest/api_microversion_history.html#id43 - -* Volume - - * `3.3`_ - - .. _3.3: https://docs.openstack.org/cinder/latest/devref/api_microversion_history.html#id4 diff --git a/doc/source/overview.rst b/doc/source/overview.rst deleted file mode 120000 index c768ff7d9..000000000 --- a/doc/source/overview.rst +++ /dev/null @@ -1 +0,0 @@ -../../README.rst \ No newline at end of file diff --git a/doc/source/plugin.rst b/doc/source/plugin.rst deleted file mode 100644 index b3af92f16..000000000 --- a/doc/source/plugin.rst +++ /dev/null @@ -1,346 +0,0 @@ -.. _tempest_plugin: - -============================= -Tempest Test Plugin Interface -============================= - -Tempest has an external test plugin interface which enables anyone to integrate -an external test suite as part of a tempest run. This will let any project -leverage being run with the rest of the tempest suite while not requiring the -tests live in the tempest tree. - -Creating a plugin -================= - -Creating a plugin is fairly straightforward and doesn't require much additional -effort on top of creating a test suite using tempest.lib. One thing to note with -doing this is that the interfaces exposed by tempest are not considered stable -(with the exception of configuration variables which ever effort goes into -ensuring backwards compatibility). You should not need to import anything from -tempest itself except where explicitly noted. - -Stable Tempest APIs plugins may use ------------------------------------ - -As noted above, several tempest APIs are acceptable to use from plugins, while -others are not. A list of stable APIs available to plugins is provided below: - -* tempest.lib.* -* tempest.config -* tempest.test_discover.plugins - -If there is an interface from tempest that you need to rely on in your plugin -which is not listed above, it likely needs to be migrated to tempest.lib. In -that situation, file a bug, push a migration patch, etc. to expedite providing -the interface in a reliable manner. - -Plugin Cookiecutter -------------------- - -In order to create the basic structure with base classes and test directories -you can use the tempest-plugin-cookiecutter project:: - - > pip install -U cookiecutter && cookiecutter https://git.openstack.org/openstack/tempest-plugin-cookiecutter - - Cloning into 'tempest-plugin-cookiecutter'... - remote: Counting objects: 17, done. - remote: Compressing objects: 100% (13/13), done. - remote: Total 17 (delta 1), reused 14 (delta 1) - Unpacking objects: 100% (17/17), done. - Checking connectivity... done. - project (default is "sample")? foo - testclass (default is "SampleTempestPlugin")? FooTempestPlugin - -This would create a folder called ``foo_tempest_plugin/`` with all necessary -basic classes. You only need to move/create your test in -``foo_tempest_plugin/tests``. - -Entry Point ------------ - -Once you've created your plugin class you need to add an entry point to your -project to enable tempest to find the plugin. The entry point must be added -to the "tempest.test_plugins" namespace. - -If you are using pbr this is fairly straightforward, in the setup.cfg just add -something like the following: - -.. code-block:: ini - - [entry_points] - tempest.test_plugins = - plugin_name = module.path:PluginClass - -Standalone Plugin vs In-repo Plugin ------------------------------------ - -Since all that's required for a plugin to be detected by tempest is a valid -setuptools entry point in the proper namespace there is no difference from the -tempest perspective on either creating a separate python package to -house the plugin or adding the code to an existing python project. However, -there are tradeoffs to consider when deciding which approach to take when -creating a new plugin. - -If you create a separate python project for your plugin this makes a lot of -things much easier. Firstly it makes packaging and versioning much simpler, you -can easily decouple the requirements for the plugin from the requirements for -the other project. It lets you version the plugin independently and maintain a -single version of the test code across project release boundaries (see the -`Branchless Tempest Spec`_ for more details on this). It also greatly -simplifies the install time story for external users. Instead of having to -install the right version of a project in the same python namespace as tempest -they simply need to pip install the plugin in that namespace. It also means -that users don't have to worry about inadvertently installing a tempest plugin -when they install another package. - -.. _Branchless Tempest Spec: http://specs.openstack.org/openstack/qa-specs/specs/tempest/implemented/branchless-tempest.html - -The sole advantage to integrating a plugin into an existing python project is -that it enables you to land code changes at the same time you land test changes -in the plugin. This reduces some of the burden on contributors by not having -to land 2 changes to add a new API feature and then test it and doing it as a -single combined commit. - - -Plugin Class -============ - -To provide tempest with all the required information it needs to be able to run -your plugin you need to create a plugin class which tempest will load and call -to get information when it needs. To simplify creating this tempest provides an -abstract class that should be used as the parent for your plugin. To use this -you would do something like the following: - -.. code-block:: python - - from tempest.test_discover import plugins - - class MyPlugin(plugins.TempestPlugin): - -Then you need to ensure you locally define all of the mandatory methods in the -abstract class, you can refer to the api doc below for a reference of what that -entails. - -Abstract Plugin Class ---------------------- - -.. autoclass:: tempest.test_discover.plugins.TempestPlugin - :members: - -Plugin Structure -================ -While there are no hard and fast rules for the structure a plugin, there are -basically no constraints on what the plugin looks like as long as the 2 steps -above are done. However, there are some recommended patterns to follow to make -it easy for people to contribute and work with your plugin. For example, if you -create a directory structure with something like:: - - plugin_dir/ - config.py - plugin.py - tests/ - api/ - scenario/ - services/ - client.py - -That will mirror what people expect from tempest. The file - -* **config.py**: contains any plugin specific configuration variables -* **plugin.py**: contains the plugin class used for the entry point -* **tests**: the directory where test discovery will be run, all tests should - be under this dir -* **services**: where the plugin specific service clients are - -Additionally, when you're creating the plugin you likely want to follow all -of the tempest developer and reviewer documentation to ensure that the tests -being added in the plugin act and behave like the rest of tempest. - -Dealing with configuration options ----------------------------------- - -Historically Tempest didn't provide external guarantees on its configuration -options. However, with the introduction of the plugin interface this is no -longer the case. An external plugin can rely on using any configuration option -coming from Tempest, there will be at least a full deprecation cycle for any -option before it's removed. However, just the options provided by Tempest -may not be sufficient for the plugin. If you need to add any plugin specific -configuration options you should use the ``register_opts`` and -``get_opt_lists`` methods to pass them to Tempest when the plugin is loaded. -When adding configuration options the ``register_opts`` method gets passed the -CONF object from tempest. This enables the plugin to add options to both -existing sections and also create new configuration sections for new options. - -Service Clients ---------------- - -If a plugin defines a service client, it is beneficial for it to implement the -``get_service_clients`` method in the plugin class. All service clients which -are exposed via this interface will be automatically configured and be -available in any instance of the service clients class, defined in -``tempest.lib.services.clients.ServiceClients``. In case multiple plugins are -installed, all service clients from all plugins will be registered, making it -easy to write tests which rely on multiple APIs whose service clients are in -different plugins. - -Example implementation of ``get_service_clients``: - -.. code-block:: python - - def get_service_clients(self): - # Example implementation with two service clients - my_service1_config = config.service_client_config('my_service') - params_my_service1 = { - 'name': 'my_service_v1', - 'service_version': 'my_service.v1', - 'module_path': 'plugin_tempest_tests.services.my_service.v1', - 'client_names': ['API1Client', 'API2Client'], - } - params_my_service1.update(my_service_config) - my_service2_config = config.service_client_config('my_service') - params_my_service2 = { - 'name': 'my_service_v2', - 'service_version': 'my_service.v2', - 'module_path': 'plugin_tempest_tests.services.my_service.v2', - 'client_names': ['API1Client', 'API2Client'], - } - params_my_service2.update(my_service2_config) - return [params_my_service1, params_my_service2] - -Parameters: - -* **name**: Name of the attribute used to access the ``ClientsFactory`` from - the ``ServiceClients`` instance. See example below. -* **service_version**: Tempest enforces a single implementation for each - service client. Available service clients are held in a ``ClientsRegistry`` - singleton, and registered with ``service_version``, which means that - ``service_version`` must be unique and it should represent the service API - and version implemented by the service client. -* **module_path**: Relative to the service client module, from the root of the - plugin. -* **client_names**: Name of the classes that implement service clients in the - service clients module. - -Example usage of the service clients in tests: - -.. code-block:: python - - # my_creds is instance of tempest.lib.auth.Credentials - # identity_uri is v2 or v3 depending on the configuration - from tempest.lib.services import clients - - my_clients = clients.ServiceClients(my_creds, identity_uri) - my_service1_api1_client = my_clients.my_service_v1.API1Client() - my_service2_api1_client = my_clients.my_service_v2.API1Client(my_args='any') - -Automatic configuration and registration of service clients imposes some extra -constraints on the structure of the configuration options exposed by the -plugin. - -First ``service_version`` should be in the format `service_config[.version]`. -The `.version` part is optional, and should only be used if there are multiple -versions of the same API available. The `service_config` must match the name of -a configuration options group defined by the plugin. Different versions of one -API must share the same configuration group. - -Second the configuration options group `service_config` must contain the -following options: - -* `catalog_type`: corresponds to `service` in the catalog -* `endpoint_type` - -The following options will be honoured if defined, but they are not mandatory, -as they do not necessarily apply to all service clients. - -* `region`: default to identity.region -* `build_timeout` : default to compute.build_timeout -* `build_interval`: default to compute.build_interval - -Third the service client classes should inherit from ``RestClient``, should -accept generic keyword arguments, and should pass those arguments to the -``__init__`` method of ``RestClient``. Extra arguments can be added. For -instance: - -.. code-block:: python - - class MyAPIClient(rest_client.RestClient): - - def __init__(self, auth_provider, service, region, - my_arg, my_arg2=True, **kwargs): - super(MyAPIClient, self).__init__( - auth_provider, service, region, **kwargs) - self.my_arg = my_arg - self.my_args2 = my_arg - -Finally the service client should be structured in a python module, so that all -service client classes are importable from it. Each major API version should -have its own module. - -The following folder and module structure is recommended for a single major -API version:: - - plugin_dir/ - services/ - __init__.py - client_api_1.py - client_api_2.py - -The content of __init__.py module should be: - -.. code-block:: python - - from client_api_1.py import API1Client - from client_api_2.py import API2Client - - __all__ = ['API1Client', 'API2Client'] - -The following folder and module structure is recommended for multiple major -API version:: - - plugin_dir/ - services/ - v1/ - __init__.py - client_api_1.py - client_api_2.py - v2/ - __init__.py - client_api_1.py - client_api_2.py - -The content each of __init__.py module under vN should be: - -.. code-block:: python - - from client_api_1.py import API1Client - from client_api_2.py import API2Client - - __all__ = ['API1Client', 'API2Client'] - -Using Plugins -============= - -Tempest will automatically discover any installed plugins when it is run. So by -just installing the python packages which contain your plugin you'll be using -them with tempest, nothing else is really required. - -However, you should take care when installing plugins. By their very nature -there are no guarantees when running tempest with plugins enabled about the -quality of the plugin. Additionally, while there is no limitation on running -with multiple plugins it's worth noting that poorly written plugins might not -properly isolate their tests which could cause unexpected cross interactions -between plugins. - -Notes for using plugins with virtualenvs ----------------------------------------- - -When using a tempest inside a virtualenv (like when running under tox) you have -to ensure that the package that contains your plugin is either installed in the -venv too or that you have system site-packages enabled. The virtualenv will -isolate the tempest install from the rest of your system so just installing the -plugin package on your system and then running tempest inside a venv will not -work. - -Tempest also exposes a tox job, all-plugin, which will setup a tox virtualenv -with system site-packages enabled. This will let you leverage tox without -requiring to manually install plugins in the tox venv before running tests. diff --git a/doc/source/run.rst b/doc/source/run.rst deleted file mode 100644 index ce7f03ef9..000000000 --- a/doc/source/run.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _tempest_run: - ------------ -Tempest Run ------------ - -.. automodule:: tempest.cmd.run diff --git a/doc/source/sampleconf.rst b/doc/source/sampleconf.rst deleted file mode 100644 index c2901400d..000000000 --- a/doc/source/sampleconf.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _tempest-sampleconf: - -Sample Configuration File -========================== - -The following is a sample Tempest configuration for adaptation and use. It is -auto-generated from Tempest when this documentation is built, so -if you are having issues with an option, please compare your version of -Tempest with the version of this documentation. - -The sample configuration can also be viewed in `file form <_static/tempest.conf.sample>`_. - -.. literalinclude:: _static/tempest.conf.sample diff --git a/doc/source/subunit_describe_calls.rst b/doc/source/subunit_describe_calls.rst deleted file mode 100644 index 2bda50c23..000000000 --- a/doc/source/subunit_describe_calls.rst +++ /dev/null @@ -1,5 +0,0 @@ ------------------------------- -Subunit Describe Calls Utility ------------------------------- - -.. automodule:: tempest.cmd.subunit_describe_calls diff --git a/doc/source/test_removal.rst b/doc/source/test_removal.rst deleted file mode 100644 index 07c3046b0..000000000 --- a/doc/source/test_removal.rst +++ /dev/null @@ -1,188 +0,0 @@ -Tempest Test Removal Procedure -============================== - -Historically tempest was the only way of doing functional testing and -integration testing in OpenStack. This was mostly only an artifact of tempest -being the only proven pattern for doing this, not an artifact of a design -decision. However, moving forward as functional testing is being spun up in -each individual project we really only want tempest to be the integration test -suite it was intended to be; testing the high level interactions between -projects through REST API requests. In this model there are probably existing -tests that aren't the best fit living in tempest. However, since tempest is -largely still the only gating test suite in this space we can't carelessly rip -out everything from the tree. This document outlines the procedure which was -developed to ensure we minimize the risk for removing something of value from -the tempest tree. - -This procedure might seem overly conservative and slow paced, but this is by -design to try and ensure we don't remove something that is actually providing -value. Having potential duplication between testing is not a big deal -especially compared to the alternative of removing something which is actually -providing value and is actively catching bugs, or blocking incorrect patches -from landing. - -Proposing a test removal ------------------------- - -3 prong rule for removal -^^^^^^^^^^^^^^^^^^^^^^^^ - -In the proposal etherpad we'll be looking for answers to 3 questions - - #. The tests proposed for removal must have equiv. coverage in a different - project's test suite (whether this is another gating test project, or an in - tree functional test suite). For API tests preferably the other project will - have a similar source of friction in place to prevent breaking api changes - so that we don't regress and let breaking api changes slip through the - gate. - #. The test proposed for removal has a failure rate < 0.50% in the gate over - the past release (the value and interval will likely be adjusted in the - future) - - .. _`prong #3`: - #. There must not be an external user/consumer of tempest - that depends on the test proposed for removal - -The answers to 1 and 2 are easy to verify. For 1 just provide a link to the new -test location. If you are linking to the tempest removal patch please also put -a Depends-On in the commit message for the commit which moved the test into -another repo. - -For prong 2 you can use OpenStack-Health: - -Using OpenStack-Health -"""""""""""""""""""""" - -Go to: http://status.openstack.org/openstack-health and then navigate to a per -test page for six months. You'll end up with a page that will graph the success -and failure rates on the bottom graph. For example, something like `this URL`_. - -.. _this URL: http://status.openstack.org/openstack-health/#/test/tempest.scenario.test_volume_boot_pattern.TestVolumeBootPatternV2.test_volume_boot_pattern?groupKey=project&resolutionKey=day&duration=P6M - -The Old Way using subunit2sql directly -"""""""""""""""""""""""""""""""""""""" - -SELECT * from tests where test_id like "%test_id%"; -(where $test_id is the full test_id, but truncated to the class because of -setUpClass or tearDownClass failures) - -You can access the infra mysql subunit2sql db w/ read-only permissions with: - - * hostname: logstash.openstack.org - * username: query - * password: query - * db_name: subunit2sql - -For example if you were trying to remove the test with the id: -tempest.api.compute.admin.test_flavors_negative.FlavorsAdminNegativeTestJSON.test_get_flavor_details_for_deleted_flavor -you would run the following: - - #. run: "mysql -u query -p -h logstash.openstack.org subunit2sql" to connect - to the subunit2sql db - #. run the query: MySQL [subunit2sql]> select * from tests where test_id like - "tempest.api.compute.admin.test_flavors_negative.FlavorsAdminNegativeTestJSON%"; - which will return a table of all the tests in the class (but it will also - catch failures in setUpClass and tearDownClass) - #. paste the output table with numbers and the mysql command you ran to - generate it into the etherpad. - -Eventually a cli interface will be created to make that a bit more friendly. -Also a dashboard is in the works so we don't need to manually run the command. - -The intent of the 2nd prong is to verify that moving the test into a project -specific testing is preventing bugs (assuming the tempest tests were catching -issues) from bubbling up a layer into tempest jobs. If we're seeing failure -rates above a certain threshold in the gate checks that means the functional -testing isn't really being effective in catching that bug (and therefore -blocking it from landing) and having the testing run in tempest still has -value. - -However for the 3rd prong verification is a bit more subjective. The original -intent of this prong was mostly for refstack/defcore and also for things that -running on the stable branches. We don't want to remove any tests if that -would break our api consistency checking between releases, or something that -defcore/refstack is depending on being in tempest. It's worth pointing out -that if a test is used in defcore as part of interop testing then it will -probably have continuing value being in tempest as part of the -integration/integrated tests in general. This is one area where some overlap -is expected between testing in projects and tempest, which is not a bad thing. - -Discussing the 3rd prong -"""""""""""""""""""""""" - -There are 2 approaches to addressing the 3rd prong. Either it can be raised -during a qa meeting during the tempest discussion. Please put it on the agenda -well ahead of the scheduled meeting. Since the meeting time will be well known -ahead of time anyone who depends on the tests will have ample time beforehand -to outline any concerns on the before the meeting. To give ample time for -people to respond to removal proposals please add things to the agenda by the -Monday before the meeting. - -The other option is to raise the removal on the openstack-dev mailing list. -(for example see: http://lists.openstack.org/pipermail/openstack-dev/2016-February/086218.html ) -This will raise the issue to the wider community and attract at least the same -(most likely more) attention than discussing it during the irc meeting. The -only downside is that it might take more time to get a response, given the -nature of ML. - -Exceptions to this procedure ----------------------------- - -For the most part all tempest test removals have to go through this procedure -there are a couple of exceptions though: - - #. The class of testing has been decided to be outside the scope of tempest. - #. A revert for a patch which added a broken test, or testing which didn't - actually run in the gate (basically any revert for something which - shouldn't have been added) - #. Tests that would become out of scope as a consequence of an API change, - as described in `API Compatibility`_. - Such tests cannot live in Tempest because of the branchless nature of - Tempest. Such test must still honor `prong #3`_. - -For the first exception type the only types of testing in tree which have been -declared out of scope at this point are: - - * The CLI tests (which should be completely removed at this point) - * Neutron Adv. Services testing (which should be completely removed at this - point) - * XML API Tests (which should be completely removed at this point) - * EC2 API/boto tests (which should be completely removed at this point) - -For tests that fit into this category the only criteria for removal is that -there is equivalent testing elsewhere. - -Tempest Scope -^^^^^^^^^^^^^ - -Starting in the liberty cycle tempest has defined a set of projects which -are defined as in scope for direct testing in tempest. As of today that list -is: - - * Keystone - * Nova - * Glance - * Cinder - * Neutron - * Swift - -anything that lives in tempest which doesn't test one of these projects can be -removed assuming there is equivalent testing elsewhere. Preferably using the -`tempest plugin mechanism`_ -to maintain continuity after migrating the tests out of tempest. - -.. _tempest plugin mechanism: https://docs.openstack.org/tempest/latest/plugin.html - -API Compatibility -""""""""""""""""" - -If an API introduces a non-discoverable, backward incompatible change, and -such change is not backported to all versions supported by Tempest, tests for -that API cannot live in Tempest anymore. -This is because tests would not be able to know or control which API response -to expect, and thus would not be able to enforce a specific behavior. - -If a test exists in Tempest that would meet this criteria as consequence of a -change, the test must be removed according to the procedure discussed into -this document. The API change should not be merged until all conditions -required for test removal can be met. diff --git a/doc/source/workspace.rst b/doc/source/workspace.rst deleted file mode 100644 index 41325b228..000000000 --- a/doc/source/workspace.rst +++ /dev/null @@ -1,5 +0,0 @@ ------------------ -Tempest Workspace ------------------ - -.. automodule:: tempest.cmd.workspace diff --git a/doc/source/write_tests.rst b/doc/source/write_tests.rst deleted file mode 100644 index aec55e94c..000000000 --- a/doc/source/write_tests.rst +++ /dev/null @@ -1,311 +0,0 @@ -.. _tempest_test_writing: - -Tempest Test Writing Guide -########################## - -This guide serves as a starting point for developers working on writing new -Tempest tests. At a high level tests in Tempest are just tests that conform to -the standard python `unit test`_ framework. But there are several aspects of -that are unique to Tempest and its role as an integration test suite running -against a real cloud. - -.. _unit test: https://docs.python.org/3.6/library/unittest.html - -.. note:: This guide is for writing tests in the Tempest repository. While many - parts of this guide are also applicable to Tempest plugins, not all - the APIs mentioned are considered stable or recommended for use in - plugins. Please refer to :ref:`tempest_plugin` for details about - writing plugins - - -Adding a New TestCase -===================== - -The base unit of testing in Tempest is the `TestCase`_ (also called the test -class). Each TestCase contains test methods which are the individual tests that -will be executed by the test runner. But, the TestCase is the smallest self -contained unit for tests from the Tempest perspective. It's also the level at -which Tempest is parallel safe. In other words, multiple TestCases can be -executed in parallel, but individual test methods in the same TestCase can not. -Also, all test methods within a TestCase are assumed to be executed serially. As -such you can use the test case to store variables that are shared between -methods. - -.. _TestCase: https://docs.python.org/3.6/library/unittest.html#unittest.TestCase - -In standard unittest the lifecycle of a TestCase can be described in the -following phases: - - #. setUpClass - #. setUp - #. Test Execution - #. tearDown - #. doCleanups - #. tearDownClass - -setUpClass ----------- - -The setUpClass phase is the first phase executed by the test runner and is used -to perform any setup required for all the test methods to be executed. In -Tempest this is a very important step and will automatically do the necessary -setup for interacting with the configured cloud. - -To accomplish this you do **not** define a setUpClass function, instead there -are a number of predefined phases to setUpClass that are used. The phases are: - - * skip_checks - * setup_credentials - * setup_clients - * resource_setup - -which is executed in that order. An example of a TestCase which defines all -of these would be:: - - from tempest import config - from tempest import test - - CONF = config.CONF - - - class TestExampleCase(test.BaseTestCase): - - @classmethod - def skip_checks(cls): - """This section is used to evaluate config early and skip all test - methods based on these checks - """ - super(TestExampleCase, cls).skip_checks() - if not CONF.section.foo - cls.skip('A helpful message') - - @classmethod - def setup_credentials(cls): - """This section is used to do any manual credential allocation and also - in the case of dynamic credentials to override the default network - resource creation/auto allocation - """ - # This call is used to tell the credential allocator to not create any - # network resources for this test case. It also enables selective - # creation of other neutron resources. NOTE: it must go before the - # super call - cls.set_network_resources() - super(TestExampleCase, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - """This section is used to setup client aliases from the manager object - or to initialize any additional clients. Except in a few very - specific situations you should not need to use this. - """ - super(TestExampleCase, cls).setup_clients() - cls.servers_client = cls.os_primary.servers_client - - @classmethod - def resource_setup(cls): - """This section is used to create any resources or objects which are - going to be used and shared by **all** test methods in the - TestCase. Note then anything created in this section must also be - destroyed in the corresponding resource_cleanup() method (which will - be run during tearDownClass()) - """ - super(TestExampleCase, cls).resource_setup() - cls.shared_server = cls.servers_client.create_server(...) - -.. _credentials: - -Allocating Credentials -'''''''''''''''''''''' - -Since Tempest tests are all about testing a running cloud, every test will need -credentials to be able to make API requests against the cloud. Since this is -critical to operation and, when running in parallel, easy to make a mistake, -the base TestCase class will automatically allocate a regular user for each -TestCase during the setup_credentials() phase. During this process it will also -initialize a client manager object using those credentials, which will be your -entry point into interacting with the cloud. For more details on how credentials -are allocated the :ref:`tempest_cred_provider_conf` section of the Tempest -Configuration Guide provides more details on the operation of this. - -There are some cases when you need more than a single set of credentials, or -credentials with a more specialized set of roles. To accomplish this you have -to set a class variable ``credentials`` on the TestCase directly. For example:: - - from tempest import test - - class TestExampleAdmin(test.BaseTestCase): - - credentials = ['primary', 'admin'] - - @classmethod - def skip_checks(cls): - ... - -In this example the ``TestExampleAdmin`` TestCase will allocate 2 sets of -credentials, one regular user and one admin user. The corresponding manager -objects will be set as class variables ``cls.os_primary`` and ``cls.os_admin`` -respectively. You can also allocate a second user by putting **'alt'** in the -list too. A set of alt credentials are the same as primary but can be used -for tests cases that need a second user/project. - -You can also specify credentials with specific roles assigned. This is useful -for cases where there are specific RBAC requirements hard coded into an API. -The canonical example of this are swift tests which often want to test swift's -concepts of operator and reseller_admin. An actual example from Tempest on how -to do this is:: - - class PublicObjectTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - @classmethod - def setup_credentials(cls): - super(PublicObjectTest, cls).setup_credentials() - ... - -In this case the manager objects will be set to ``cls.os_roles_operator`` and -``cls.os_roles_operator_alt`` respectively. - - -There is no limit to how many credentials you can allocate in this manner, -however in almost every case you should **not** need more than 3 sets of -credentials per test case. - -To figure out the mapping of manager objects set on the TestCase and the -requested credentials you can reference: - -+-------------------+---------------------+ -| Credentials Entry | Manager Variable | -+===================+=====================+ -| primary | cls.os_primary | -+-------------------+---------------------+ -| admin | cls.os_admin | -+-------------------+---------------------+ -| alt | cls.os_alt | -+-------------------+---------------------+ -| [$label, $role] | cls.os_roles_$label | -+-------------------+---------------------+ - -By default cls.os_primary is available since it is allocated in the base Tempest test -class (located in tempest/test.py). If your TestCase inherits from a different -direct parent class (it'll still inherit from the BaseTestCase, just not -directly) be sure to check if that class overrides allocated credentials. - -Dealing with Network Allocation -''''''''''''''''''''''''''''''' - -When Neutron is enabled and a testing requires networking this isn't normally -automatically setup when a tenant is created. Since Tempest needs isolated -tenants to function properly it also needs to handle network allocation. By -default the base test class will allocate a network, subnet, and router -automatically (this depends on the configured credential provider, for more -details see: :ref:`tempest_conf_network_allocation`). However, there are -situations where you do no need all of these resources allocated (or your -TestCase inherits from a class that overrides the default in tempest/test.py). -There is a class level mechanism to override this allocation and specify which -resources you need. To do this you need to call `cls.set_network_resources()` -in the `setup_credentials()` method before the `super()`. For example:: - - from tempest import test - - - class TestExampleCase(test.BaseTestCase): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=False) - super(TestExampleCase, cls).setup_credentials() - -There are 2 quirks with the usage here. First for the set_network_resources -function to work properly it **must be called before super()**. This is so -that children classes' settings are always used instead of a parent classes'. -The other quirk here is that if you do not want to allocate any network -resources for your test class simply call `set_network_resources()` without -any arguments. For example:: - - from tempest import test - - - class TestExampleCase(test.BaseTestCase): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(TestExampleCase, cls).setup_credentials() - -This will not allocate any networking resources. This is because by default all -the arguments default to False. - -It's also worth pointing out that it is common for base test classes for -different services (and scenario tests) to override this setting. When -inheriting from classes other than the base TestCase in tempest/test.py it is -worth checking the immediate parent for what is set to determine if your -class needs to override that setting. - -Interacting with Credentials and Clients -======================================== - -Once you have your basic TestCase setup you'll want to start writing tests. To -do that you need to interact with an OpenStack deployment. This section will -cover how credentials and clients are used inside of Tempest tests. - - -Manager Objects ---------------- - -The primary interface with which you interact with both credentials and -API clients is the client manager object. These objects are created -automatically by the base test class as part of credential setup (for more -details see the previous :ref:`credentials` section). Each manager object is -initialized with a set of credentials and has each client object already setup -to use that set of credentials for making all the API requests. Each client is -accessible as a top level attribute on the manager object. So to start making -API requests you just access the client's method for making that call and the -credentials are already setup for you. For example if you wanted to make an API -call to create a server in Nova:: - - from tempest import test - - - class TestExampleCase(test.BaseTestCase): - def test_example_create_server(self): - self.os_primary.servers_client.create_server(...) - -is all you need to do. As described previously, in the above example the -``self.os_primary`` is created automatically because the base test class sets the -``credentials`` attribute to allocate a primary credential set and initializes -the client manager as ``self.os_primary``. This same access pattern can be used -for all of the clients in Tempest. - -Credentials Objects -------------------- - -In certain cases you need direct access to the credentials (the most common -use case would be an API request that takes a user or project id in the request -body). If you're in a situation where you need to access this you'll need to -access the ``credentials`` object which is allocated from the configured -credential provider in the base test class. This is accessible from the manager -object via the manager's ``credentials`` attribute. For example:: - - from tempest import test - - - class TestExampleCase(test.BaseTestCase): - def test_example_create_server(self): - credentials = self.os_primary.credentials - -The credentials object provides access to all of the credential information you -would need to make API requests. For example, building off the previous -example:: - - from tempest import test - - - class TestExampleCase(test.BaseTestCase): - def test_example_create_server(self): - credentials = self.os_primary.credentials - username = credentials.username - user_id = credentials.user_id - password = credentials.password - tenant_id = credentials.tenant_id diff --git a/etc/accounts.yaml.sample b/etc/accounts.yaml.sample deleted file mode 100644 index 3dbed79e9..000000000 --- a/etc/accounts.yaml.sample +++ /dev/null @@ -1,62 +0,0 @@ -# The number of accounts required can be estimated as CONCURRENCY x 2 -# It is expected that each user provided here will be in a different tenant. -# This is required to provide isolation between test for running in parallel -# -# Valid fields for credentials are defined in the descendants of -# lib.auth.Credentials - see KeystoneV[2|3]Credentials.ATTRIBUTES -# -# The fields in KeystoneV3Credentials behave as follows: -# -# tenant_[id|name] also sets project_[id|name]. -# -# project_[id|name] also sets tenant_[id|name]. -# -# Providing distinct values for both tenant_[id|name] and project_[id|name] -# will result in an InvalidCredentials exception. -# -# The value of project_domain_[id|name] is used for user_domain_[id|name] if -# the latter is not specified. -# -# The value of user_domain_[id|name] is used for project_domain_[id|name] if -# the latter is not specified. -# -# The value of domain_[id|name] is used for project_domain_[id|name] if not -# specified and user_domain_[id|name] if not specified. - -- username: 'user_1' - tenant_name: 'test_tenant_1' - password: 'test_password' - -- username: 'user_2' - tenant_name: 'test_tenant_2' - password: 'test_password' - -# To specify which roles a user has list them under the roles field -- username: 'multi_role_user' - tenant_name: 'test_tenant_42' - password: 'test_password' - roles: - - 'fun_role' - - 'not_an_admin' - - 'an_admin' - -# To specify a user has a role specified in the config file you can use the -# type field to specify it, valid values are admin, operator, and reseller_admin -- username: 'swift_pseudo_admin_user_1' - tenant_name: 'admin_tenant_1' - password: 'test_password' - types: - - 'reseller_admin' - - 'operator' - -# Networks can be specified to tell tempest which network it should use when -# creating servers with an account - -- username: 'admin_user_1' - tenant_name: 'admin_tenant_1' - password: 'test_password' - types: - - 'admin' - resources: - network: 'public' - router: 'admin_tenant_1-router' diff --git a/etc/logging.conf.sample b/etc/logging.conf.sample deleted file mode 100644 index c131b07fa..000000000 --- a/etc/logging.conf.sample +++ /dev/null @@ -1,35 +0,0 @@ -[loggers] -keys=root - -[handlers] -keys=file,devel,syslog - -[formatters] -keys=simple,tests - -[logger_root] -level=DEBUG -handlers=file - -[handler_file] -class=FileHandler -level=DEBUG -args=('tempest.log', 'w+') -formatter=tests - -[handler_syslog] -class=handlers.SysLogHandler -level=ERROR -args = ('/dev/log', handlers.SysLogHandler.LOG_USER) - -[handler_devel] -class=StreamHandler -level=DEBUG -args=(sys.stdout,) -formatter=simple - -[formatter_tests] -class = oslo_log.formatters.ContextFormatter - -[formatter_simple] -format=%(asctime)s.%(msecs)03d %(process)d %(levelname)s: %(message)s diff --git a/etc/whitelist.yaml b/etc/whitelist.yaml deleted file mode 100644 index e69de29bb..000000000 diff --git a/releasenotes/notes/10/10.0-supported-openstack-releases-b88db468695348f6.yaml b/releasenotes/notes/10/10.0-supported-openstack-releases-b88db468695348f6.yaml deleted file mode 100644 index 217c2f6b6..000000000 --- a/releasenotes/notes/10/10.0-supported-openstack-releases-b88db468695348f6.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -other: - - OpenStack Releases Supported at this time are the same as in the - previous release 9, - **Kilo** and - **Liberty**. - - - The release under current development as of this tag is Mitaka, - meaning that every Tempest commit is also tested against master during - the Mitaka cycle. However, this does not necessarily mean that using - Tempest as of this tag will work against a Mitaka (or future releases) - cloud. diff --git a/releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml b/releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml deleted file mode 100644 index c1edd6316..000000000 --- a/releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -prelude: | - This release includes the addition of the stable library interface for - tempest. This behaves just as tempest-lib did prior to this, but instead - it lives directly in the tempest project. For more information refer to - the `library docs`_. - - .. _library docs: https://docs.openstack.org/tempest/latest/library.html#current-library-apis - -features: - - Tempest library interface diff --git a/releasenotes/notes/10/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml b/releasenotes/notes/10/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml deleted file mode 100644 index 0bc9af58a..000000000 --- a/releasenotes/notes/10/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -other: - - Start using reno for managing release notes. diff --git a/releasenotes/notes/11/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml b/releasenotes/notes/11/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml deleted file mode 100644 index e98671a52..000000000 --- a/releasenotes/notes/11/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Tempest library interface addition(API Microversion testing interfaces). \ No newline at end of file diff --git a/releasenotes/notes/11/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml b/releasenotes/notes/11/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml deleted file mode 100644 index de1b35ee1..000000000 --- a/releasenotes/notes/11/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Compute Microversion testing support in Service Clients. diff --git a/releasenotes/notes/11/11.0.0-supported-openstack-releases-1e5d7295d939d439.yaml b/releasenotes/notes/11/11.0.0-supported-openstack-releases-1e5d7295d939d439.yaml deleted file mode 100644 index 09ff15d14..000000000 --- a/releasenotes/notes/11/11.0.0-supported-openstack-releases-1e5d7295d939d439.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -prelude: > - This release is marking the start of Mitaka release support in tempest -other: - - OpenStack Releases Supported at this time are **Kilo**, **Liberty**, - **Mitaka** - - The release under current development as of this tag is Newton, - meaning that every Tempest commit is also tested against master during - the Newton cycle. However, this does not necessarily mean that using - Tempest as of this tag will work against a Newton (or future releases) - cloud. diff --git a/releasenotes/notes/12/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml b/releasenotes/notes/12/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml deleted file mode 100644 index 9baf0352a..000000000 --- a/releasenotes/notes/12/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -prelude: > - This release is marking the end of Kilo release support in Tempest -other: - - OpenStack Releases Supported after this release are **Liberty** - and **Mitaka** - - The release under current development as of this tag is Newton, - meaning that every Tempest commit is also tested against master during - the Newton cycle. However, this does not necessarily mean that using - Tempest as of this tag will work against a Newton (or future releases) - cloud. diff --git a/releasenotes/notes/12/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml b/releasenotes/notes/12/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml deleted file mode 100644 index 07e3151ff..000000000 --- a/releasenotes/notes/12/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Adds a network version client for querying - Neutron's API version discovery URL ("GET /"). diff --git a/releasenotes/notes/12/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml b/releasenotes/notes/12/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml deleted file mode 100644 index 297279f99..000000000 --- a/releasenotes/notes/12/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - Tempest library auth interface now supports scope. Scope allows to control - the scope of tokens requested via the identity API. Identity V2 supports - unscoped and project scoped tokens, but only the latter are implemented. - Identity V3 supports unscoped, project and domain scoped token, all three - are available. \ No newline at end of file diff --git a/releasenotes/notes/12/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml b/releasenotes/notes/12/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml deleted file mode 100644 index 429bf52a5..000000000 --- a/releasenotes/notes/12/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Adds the tempest run command to the unified tempest CLI. This new command - is used for running tempest tests. diff --git a/releasenotes/notes/12/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml b/releasenotes/notes/12/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml deleted file mode 100644 index 9a1cef6e1..000000000 --- a/releasenotes/notes/12/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Adds tempest workspaces command and WorkspaceManager. - This is used to have a centralized repository for managing - different tempest configurations. diff --git a/releasenotes/notes/12/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml b/releasenotes/notes/12/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml deleted file mode 100644 index 092014e61..000000000 --- a/releasenotes/notes/12/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Adds subunit-describe-calls. A parser for subunit streams to determine what - REST API calls are made inside of a test and in what order they are called. - - * Input can be piped in or a file can be specified - * Output is shortened for stdout, the output file has more information diff --git a/releasenotes/notes/12/12.1.0-bug-1486834-7ebca15836ae27a9.yaml b/releasenotes/notes/12/12.1.0-bug-1486834-7ebca15836ae27a9.yaml deleted file mode 100644 index b2190f368..000000000 --- a/releasenotes/notes/12/12.1.0-bug-1486834-7ebca15836ae27a9.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - Tempest library auth interface now supports - filtering with catalog name. Note that filtering by - name is only successful if a known service type is - provided. diff --git a/releasenotes/notes/12/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml b/releasenotes/notes/12/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml deleted file mode 100644 index f9173a007..000000000 --- a/releasenotes/notes/12/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -features: - - | - Define identity service clients as libraries - The following identity service clients are defined as library interface, - so the other projects can use these modules as stable libraries without - any maintenance changes. - - * endpoints_client(v2) - * roles_client(v2) - * services_client(v2) - * tenants_client(v2) - * users_client(v2) diff --git a/releasenotes/notes/12/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml b/releasenotes/notes/12/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml deleted file mode 100644 index 1fa4dddc1..000000000 --- a/releasenotes/notes/12/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -features: - - | - Define image service clients as libraries - The following image service clients are defined as library interface, - so the other projects can use these modules as stable libraries - without any maintenance changes. - - * image_members_client(v1) - * images_client(v1) - * image_members_client(v2) - * images_client(v2) - * namespaces_client(v2) - * resource_types_client(v2) - * schemas_client(v2) diff --git a/releasenotes/notes/12/12.1.0-new-test-utils-module-adf34468c4d52719.yaml b/releasenotes/notes/12/12.1.0-new-test-utils-module-adf34468c4d52719.yaml deleted file mode 100644 index 55df2b386..000000000 --- a/releasenotes/notes/12/12.1.0-new-test-utils-module-adf34468c4d52719.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -features: - - A new `test_utils` module has been added to tempest.lib.common.utils. It - should hold any common utility functions that help writing Tempest tests. - - A new utility function called `call_and_ignore_notfound_exc` has been - added to the `test_utils` module. That function call another function - passed as parameter and ignore the NotFound exception if it raised. -deprecations: - - tempest.lib.common.utils.misc.find_test_caller has been moved into the - tempest.lib.common.utils.test_utils module. Calling the find_test_caller - function with its old location is deprecated. diff --git a/releasenotes/notes/12/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml b/releasenotes/notes/12/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml deleted file mode 100644 index 4ee883f60..000000000 --- a/releasenotes/notes/12/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -upgrade: - - The input scenarios functionality no longer exists in tempest. This caused - a large number of issues for limited benefit and was only used by a single - test, test_server_basic_ops. If you were using this functionality you'll - now have to do it manually with a script and/or tempest workspaces -deprecations: - - All the options in the input-scenario group are now deprecated. These were - only used in tree by the now removed input scenarios functionality in - test_server_basic_ops. They were only deprecated because there could be - external consumers via plugins. They will be removed during the Ocata cycle. diff --git a/releasenotes/notes/12/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml b/releasenotes/notes/12/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml deleted file mode 100644 index 294f6d9a5..000000000 --- a/releasenotes/notes/12/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -upgrade: - - The integrated dashboard scenario test has been - removed and is now in a separate tempest plugin - tempest-horizon. The removed test coverage can be - used by installing tempest-horizon on the server - where you run tempest. diff --git a/releasenotes/notes/12/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml b/releasenotes/notes/12/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml deleted file mode 100644 index 89b3f4133..000000000 --- a/releasenotes/notes/12/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - The deprecated legacy credential provider has been removed. The only way to - configure credentials in tempest now is to use the dynamic or preprovisioned - credential providers diff --git a/releasenotes/notes/12/12.1.0-remove-trove-tests-666522e9113549f9.yaml b/releasenotes/notes/12/12.1.0-remove-trove-tests-666522e9113549f9.yaml deleted file mode 100644 index 7a1fc367f..000000000 --- a/releasenotes/notes/12/12.1.0-remove-trove-tests-666522e9113549f9.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - All tests for the Trove project have been removed from tempest. They now - live as a tempest plugin in the trove project. diff --git a/releasenotes/notes/12/12.1.0-routers-client-as-library-25a363379da351f6.yaml b/releasenotes/notes/12/12.1.0-routers-client-as-library-25a363379da351f6.yaml deleted file mode 100644 index 35cf2c487..000000000 --- a/releasenotes/notes/12/12.1.0-routers-client-as-library-25a363379da351f6.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - Define routers_client as stable library interface. - The routers_client module is defined as library interface, - so the other projects can use the module as stable library - without any maintenance changes. diff --git a/releasenotes/notes/12/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml b/releasenotes/notes/12/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml deleted file mode 100644 index eb45523fe..000000000 --- a/releasenotes/notes/12/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -features: - - The RestClient (in tempest.lib.common.rest_client) now supports POSTing - and PUTing data with chunked transfer encoding. Just pass an `iterable` - object as the `body` argument and set the `chunked` argument to `True`. - - A new generator called `chunkify` is added in - tempest.lib.common.utils.data_utils that yields fixed-size chunks (slices) - from a Python sequence. - diff --git a/releasenotes/notes/12/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml b/releasenotes/notes/12/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml deleted file mode 100644 index eeda92169..000000000 --- a/releasenotes/notes/12/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -upgrade: - - The location on disk that the *tempest init* command looks for has changed. - Previously it would attempt to use python packaging's data files to guess - where setuptools/distutils were installing data files, which was incredibly - unreliable and depended on how you installed tempest and which versions of - setuptools, distutils, and python you had installed. Instead, now it will - use either /etc/tempest, $XDG_CONFIG_PATH/.config/tempest, or - ~/.tempest/etc (attempted in that order). If none of these exist it will - create an empty ~/.tempest/etc directory. If you were relying on the - previous behavior and none of these directories were being used you will - need to move the files to live in one of these directories. diff --git a/releasenotes/notes/12/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml b/releasenotes/notes/12/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml deleted file mode 100644 index a360f8ed5..000000000 --- a/releasenotes/notes/12/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - RestClient now supports setting timeout in urllib3.poolmanager. - Clients will use CONF.service_clients.http_timeout for timeout - value to wait for http request to response. - - KeystoneAuthProvider will accept http_timeout and will use it in - get_credentials. diff --git a/releasenotes/notes/12/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml b/releasenotes/notes/12/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml deleted file mode 100644 index 3ec8b5678..000000000 --- a/releasenotes/notes/12/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -features: - - | - Define identity service clients as libraries. - The following identity service clients are defined as library interface, - so the other projects can use these modules as stable libraries without - any maintenance changes. - - * endpoints_client(v3) - * policies_client (v3) - * regions_client(v3) - * services_client(v3) - * projects_client(v3) diff --git a/releasenotes/notes/12/12.2.0-clients_module-16f3025f515bf9ec.yaml b/releasenotes/notes/12/12.2.0-clients_module-16f3025f515bf9ec.yaml deleted file mode 100644 index d07448aa9..000000000 --- a/releasenotes/notes/12/12.2.0-clients_module-16f3025f515bf9ec.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -features: - - The Tempest plugin interface contains a new optional method, which allows - plugins to declare and automatically register any service client defined - in the plugin. - - tempest.lib exposes a new stable interface, the clients module and - ServiceClients class, which provides a convenient way for plugin tests to - access service clients defined in Tempest as well as service clients - defined in all loaded plugins. - The new ServiceClients class only exposes for now the service clients - which are in tempest.lib, i.e. compute, network and image. The remaining - service clients (identity, volume and object-storage) will be added in - future updates. -deprecations: - - The new clients module provides a stable alternative to tempest classes - manager.Manager and clients.Manager. manager.Manager only exists now - to smoothen the transition of plugins to the new interface, but it will - be removed shortly without further notice. diff --git a/releasenotes/notes/12/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml b/releasenotes/notes/12/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml deleted file mode 100644 index cfe97c5de..000000000 --- a/releasenotes/notes/12/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -upgrade: - - - The ``nova_cert`` option default is changed to ``False``. The nova - certification management APIs were a hold over from ec2, and are - not used by any other parts of nova. They are deprecated for - removal in nova after the newton release. This makes false a more - sensible default going forward. \ No newline at end of file diff --git a/releasenotes/notes/12/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml b/releasenotes/notes/12/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml deleted file mode 100644 index 64f729ac2..000000000 --- a/releasenotes/notes/12/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -features: - - A new optional interface `TempestPlugin.get_service_clients` - is available to plugins. It allows them to declare - any service client they implement. For now this is used by - tempest only, for auto-registration of service clients - in the new class `ServiceClients`. - - A new singleton class `clients.ClientsRegistry` is - available. It holds the service clients registration data - from all plugins. It is used by `ServiceClients` for - auto-registration of the service clients implemented - in plugins. diff --git a/releasenotes/notes/12/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml b/releasenotes/notes/12/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml deleted file mode 100644 index 8e893b8dc..000000000 --- a/releasenotes/notes/12/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - The previously deprecated Javelin utility has been removed from Tempest. - As an alternative Ansible can be used to construct similar yaml workflows - to what Javelin used to provide. diff --git a/releasenotes/notes/12/12.2.0-service_client_config-8a1d7b4de769c633.yaml b/releasenotes/notes/12/12.2.0-service_client_config-8a1d7b4de769c633.yaml deleted file mode 100644 index 3e43f9a88..000000000 --- a/releasenotes/notes/12/12.2.0-service_client_config-8a1d7b4de769c633.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - A new helper method `service_client_config` has been added - to the stable module config.py that returns extracts from - configuration into a dictionary the configuration settings - relevant for the initisialisation of a service client. diff --git a/releasenotes/notes/12/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml b/releasenotes/notes/12/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml deleted file mode 100644 index cf504ad08..000000000 --- a/releasenotes/notes/12/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -features: - - | - Define volume service clients as libraries - The following volume service clients are defined as library interface, - so the other projects can use these modules as stable libraries - without any maintenance changes. - - * availability_zone_client(v1) - * availability_zone_client(v2) - * extensions_client(v1) - * extensions_client(v2) - * hosts_client(v1) - * hosts_client(v2) - * quotas_client(v1) - * quotas_client(v2) - * services_client(v1) - * services_client(v2) diff --git a/releasenotes/notes/13/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml b/releasenotes/notes/13/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml deleted file mode 100644 index 9e828f69b..000000000 --- a/releasenotes/notes/13/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -features: - - | - Define identity service clients as libraries. - Add new service clients to the library interface so the other projects can use these modules as stable libraries without - any maintenance changes. - - * identity_client(v2) - * groups_client(v3) - * trusts_client(v3) - * users_client(v3) - * identity_client(v3) - * roles_client(v3) - * inherited_roles_client(v3) - * credentials_client(v3) diff --git a/releasenotes/notes/13/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml b/releasenotes/notes/13/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml deleted file mode 100644 index 9cfce0df0..000000000 --- a/releasenotes/notes/13/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -features: - - | - Define volume service clients as libraries. - The following volume service clients are defined as library interface, - so the other projects can use these modules as stable libraries without - any maintenance changes. - - * backups_client - * encryption_types_client (v1) - * encryption_types_client (v2) - * qos_clients (v1) - * qos_clients (v2) - * snapshots_client (v1) - * snapshots_client (v2) - diff --git a/releasenotes/notes/13/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml b/releasenotes/notes/13/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml deleted file mode 100644 index 0884cfa91..000000000 --- a/releasenotes/notes/13/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -deprecations: - - Oslo.utils provides same method get_ipv6_addr_by_EUI64, - so deprecate it in Newton and remove it in Ocata. diff --git a/releasenotes/notes/13/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml b/releasenotes/notes/13/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml deleted file mode 100644 index 52c04afc1..000000000 --- a/releasenotes/notes/13/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -deprecations: - - The ``call_until_true`` function is moved from the ``tempest.test`` module - to the ``tempest.lib.common.utils.test_utils`` module. Backward - compatibility is preserved until Ocata. diff --git a/releasenotes/notes/13/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml b/releasenotes/notes/13/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml deleted file mode 100644 index b9b6fb581..000000000 --- a/releasenotes/notes/13/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -prelude: > - This release is marking the start of Newton release support in Tempest -other: - - | - OpenStack releases supported at this time are **Liberty**, **Mitaka**, - and **Newton**. - - The release under current development as of this tag is Ocata, - meaning that every Tempest commit is also tested against master during - the Ocata cycle. However, this does not necessarily mean that using - Tempest as of this tag will work against a Ocata (or future releases) - cloud. diff --git a/releasenotes/notes/13/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml b/releasenotes/notes/13/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml deleted file mode 100644 index 813e47f8a..000000000 --- a/releasenotes/notes/13/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - the already deprecated tempest-cleanup standalone command has been - removed. The corresponding functionalities can be accessed through - the unified `tempest` command (`tempest cleanup`). diff --git a/releasenotes/notes/13/13.0.0-volume-clients-as-library-660811011be29d1a.yaml b/releasenotes/notes/13/13.0.0-volume-clients-as-library-660811011be29d1a.yaml deleted file mode 100644 index 9e9eff66d..000000000 --- a/releasenotes/notes/13/13.0.0-volume-clients-as-library-660811011be29d1a.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Define the v1 and v2 types_client clients for the volume service as - library interfaces, allowing other projects to use these modules as - stable libraries without maintenance changes. diff --git a/releasenotes/notes/14/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml b/releasenotes/notes/14/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml deleted file mode 100644 index 6f7a41188..000000000 --- a/releasenotes/notes/14/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - The cred_provider abstract class which serves as the basis for both - of tempest's cred providers, pre-provisioned credentials and dynamic - credentials, is now a library interface. This provides the common signature - required for building a credential provider. diff --git a/releasenotes/notes/14/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml b/releasenotes/notes/14/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml deleted file mode 100644 index 432a6b155..000000000 --- a/releasenotes/notes/14/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - The cred_client module was added to tempest.lib. This module provides a - wrapper to the keystone services client which provides a uniform - interface that abstracts out the differences between keystone api versions. diff --git a/releasenotes/notes/14/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml b/releasenotes/notes/14/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml deleted file mode 100644 index 57bf47c56..000000000 --- a/releasenotes/notes/14/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -upgrade: - - Add an error translation to list_versions() of versions_client of both - compute and network. This can affect users who are expecting that these - clients return error status code instead of the exception. It is needed - to change the code for handling the exception like the other clients code. diff --git a/releasenotes/notes/14/14.0.0-add-image-clients-af94564fb34ddca6.yaml b/releasenotes/notes/14/14.0.0-add-image-clients-af94564fb34ddca6.yaml deleted file mode 100644 index 7e40fd4d6..000000000 --- a/releasenotes/notes/14/14.0.0-add-image-clients-af94564fb34ddca6.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -features: - - | - As in the [doc]: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html, - there are some apis are not included, add them. - - * namespace_properties_client(v2) - diff --git a/releasenotes/notes/14/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml b/releasenotes/notes/14/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml deleted file mode 100644 index a1edcc5c3..000000000 --- a/releasenotes/notes/14/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - Define the identity service role_assignments_client as a library. - Add role_assignments_client to the library interface so the other - projects can use this module as a stable library without any - maintenance changes. diff --git a/releasenotes/notes/14/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml b/releasenotes/notes/14/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml deleted file mode 100644 index b504c789a..000000000 --- a/releasenotes/notes/14/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - A Neutron Service Providers client is added to deal with resources - of the '/service-providers' route. diff --git a/releasenotes/notes/14/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml b/releasenotes/notes/14/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml deleted file mode 100644 index b2ad1995a..000000000 --- a/releasenotes/notes/14/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - A new optional parameter `port` for ssh client (`tempest.lib.common.ssh.Client`) - to specify destination port for a host. The default value is 22. diff --git a/releasenotes/notes/14/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml b/releasenotes/notes/14/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml deleted file mode 100644 index c2d9a9bc9..000000000 --- a/releasenotes/notes/14/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -deprecations: - - The *api_extensions* config option in the *compute-feature-enabled* group is - now deprecated. This option will be removed from tempest when all the - OpenStack releases supported by tempest no longer support the API extensions - mechanism. This was removed from Nova during the Newton cycle, so this will - be removed at the Mitaka EOL. diff --git a/releasenotes/notes/14/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml b/releasenotes/notes/14/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml deleted file mode 100644 index 9223ba566..000000000 --- a/releasenotes/notes/14/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml +++ /dev/null @@ -1,7 +0,0 @@ -features: - - | - Define the Volume v3 service clients as library interfaces, - allowing other projects to use these modules as stable - libraries without maintenance changes. - - * messages_client(v3) diff --git a/releasenotes/notes/14/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml b/releasenotes/notes/14/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml deleted file mode 100644 index 033e14788..000000000 --- a/releasenotes/notes/14/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - The volume_limits client was added to tempest.lib. diff --git a/releasenotes/notes/14/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml b/releasenotes/notes/14/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml deleted file mode 100644 index 389b29f76..000000000 --- a/releasenotes/notes/14/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -prelude: > - This release is marking the end of Liberty release support in Tempest -upgrade: - - The Stress tests framework and all the stress tests have been removed. -other: - - | - OpenStack releases supported at this time are **Mitaka** and **Newton**. - - The release under current development as of this tag is Ocata, meaning that - every Tempest commit is also tested against master during the Ocata cycle. - However, this does not necessarily mean that using Tempest as of this tag - will work against a Ocata (or future releases) cloud. diff --git a/releasenotes/notes/14/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml b/releasenotes/notes/14/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml deleted file mode 100644 index ca2635e16..000000000 --- a/releasenotes/notes/14/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - All tests for the Ironic project have been removed from Tempest. Those - exist as a Tempest plugin in the Ironic project. diff --git a/releasenotes/notes/14/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml b/releasenotes/notes/14/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml deleted file mode 100644 index e6e53aff2..000000000 --- a/releasenotes/notes/14/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -deprecations: - - The *bootable* config option in the *volume_feature_enabled* group is - removed because the corresponding feature os-set_bootable has been - implemented 2.5 years ago and all OpenStack versions which are supported - by Tempest should support the feature. diff --git a/releasenotes/notes/14/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml b/releasenotes/notes/14/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml deleted file mode 100644 index a734d1555..000000000 --- a/releasenotes/notes/14/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - The Negative Tests Generator has been removed (it was not used by any - Tempest tests). diff --git a/releasenotes/notes/14/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml b/releasenotes/notes/14/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml deleted file mode 100644 index b541cf902..000000000 --- a/releasenotes/notes/14/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - All tests for the Sahara project have been removed from Tempest. They now - live as a Tempest plugin in the ``openstack/sahara-tests`` repository. diff --git a/releasenotes/notes/14/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml b/releasenotes/notes/14/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml deleted file mode 100644 index 6babd93f5..000000000 --- a/releasenotes/notes/14/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -features: - - | - Define volume service clients as libraries. - The following volume service clients are defined as library interface, - so the other projects can use these modules as stable libraries without - any maintenance changes. - - * volumes_client(v1) - * volumes_client(v2) - * capabilities_client(v2) - * scheduler_stats_client(v2) diff --git a/releasenotes/notes/15/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml b/releasenotes/notes/15/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml deleted file mode 100644 index 1af193948..000000000 --- a/releasenotes/notes/15/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - Define the identity v3 service client domains_client as a library. - Add domains_client to the library interface so the other - projects can use this module as a stable library without any - maintenance changes. diff --git a/releasenotes/notes/15/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml b/releasenotes/notes/15/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml deleted file mode 100644 index eaab1f0b8..000000000 --- a/releasenotes/notes/15/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -features: - - | - As in the [doc]: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html, - there are some apis are not included, add them. - - * namespace_objects_client(v2) - * namespace_tags_client(v2) - diff --git a/releasenotes/notes/15/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml b/releasenotes/notes/15/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml deleted file mode 100644 index 9116ef8b3..000000000 --- a/releasenotes/notes/15/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add the implied roles feature API to the roles_client library. This - feature enables the possibility to create inferences rules between - roles (a role being implied by another role). diff --git a/releasenotes/notes/15/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml b/releasenotes/notes/15/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml deleted file mode 100644 index 9a4e6b195..000000000 --- a/releasenotes/notes/15/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Define v2 snapshot_manage_client client for the volume service as - library interfaces, allowing other projects to use this module as - stable libraries without maintenance changes. - - * snapshot_manage_client(v2) diff --git a/releasenotes/notes/15/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml b/releasenotes/notes/15/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml deleted file mode 100644 index 4acdc6d2b..000000000 --- a/releasenotes/notes/15/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -upgrade: - - The default value for the ``allow_port_security_disabled`` option in the - ``compute-feature-enabled`` section has been changed from ``False`` - to ``True``. -deprecations: - - The ``allow_port_security_disabled`` option in the - ``compute-feature-enabled`` section is now deprecated. diff --git a/releasenotes/notes/15/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml b/releasenotes/notes/15/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml deleted file mode 100644 index c0a06d16a..000000000 --- a/releasenotes/notes/15/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -upgrade: - - The default value for the ``reseller`` option in the - ``identity-feature-enabled`` section has been changed from ``False`` - to ``True``. -deprecations: - - The ``reseller`` option in the ``identity-feature-enabled`` section is now - deprecated. diff --git a/releasenotes/notes/15/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml b/releasenotes/notes/15/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml deleted file mode 100644 index c80f159d3..000000000 --- a/releasenotes/notes/15/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -upgrade: - - The default value for the ``volume_services`` option in the - ``volume_feature_enabled`` section has been changed from ``False`` - to ``True``. -deprecations: - - The ``volume_services`` option in the ``volume_feature_enabled`` section - is now deprecated. diff --git a/releasenotes/notes/15/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml b/releasenotes/notes/15/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml deleted file mode 100644 index 8817ed438..000000000 --- a/releasenotes/notes/15/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Added customized JSON schema format checker for 'date-time' format. - Compute response schema will be validated against customized format - checker. diff --git a/releasenotes/notes/15/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml deleted file mode 100644 index b1c0c6230..000000000 --- a/releasenotes/notes/15/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -upgrade: - - The deprecated compute microversion config options from - 'compute-feature-enabled' group have been removed. Those config options - are available under 'compute' group to configure the min and max - microversion for compute service. - - * CONF.compute.min_microversion - * CONF.compute.max_microversion diff --git a/releasenotes/notes/15/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml deleted file mode 100644 index 104bf2792..000000000 --- a/releasenotes/notes/15/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -prelude: > - This release is marking the start of Ocata release support in Tempest -upgrade: - - | - Below deprecated config options from compute group have been removed. - Corresponding config options already been available in validation group. - - - ``compute.use_floatingip_for_ssh`` (available as ``validation.connect_method``) - - ``compute.ssh_auth_method`` (available as ``validation.auth_method``) - - ``compute.image_ssh_password`` (available as ``validation.image_ssh_password``) - - ``compute.ssh_shell_prologue`` (available as ``validation.ssh_shell_prologue``) - - ``compute.ping_size `` (available as ``validation.ping_size``) - - ``compute.ping_count `` (available as ``validation.ping_count``) - - ``compute.floating_ip_range `` (available as ``validation.floating_ip_range``) -other: - - | - OpenStack releases supported at this time are **Mitaka**, **Newton**, - and **Ocata**. - - The release under current development as of this tag is Pike, - meaning that every Tempest commit is also tested against master during - the Pike cycle. However, this does not necessarily mean that using - Tempest as of this tag will work against a Pike (or future releases) - cloud. diff --git a/releasenotes/notes/15/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml deleted file mode 100644 index 371c0614a..000000000 --- a/releasenotes/notes/15/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -upgrade: - - The deprecated input-scenario config options and group - have been removed. - The input scenarios functionality already being removed from tempest - and from this release, their corresponding config options too. diff --git a/releasenotes/notes/15/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml deleted file mode 100644 index e445fb3ff..000000000 --- a/releasenotes/notes/15/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -upgrade: - - | - Below deprecated network config options have been removed. - Those config options already been renamed to below meaningful names. - - - ``tenant_network_cidr`` (removed) -> ``project_network_cidr`` - - ``tenant_network_mask_bits`` (removed) -> ``project_network_mask_bits`` - - ``tenant_network_v6_cidr`` (removed) -> ``project_network_v6_cidr`` - - ``tenant_network_v6_mask_bits`` (removed) -> ``project_network_v6_mask_bits`` - - ``tenant_networks_reachable`` (removed) -> ``project_networks_reachable`` diff --git a/releasenotes/notes/16/16.0.0-add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml b/releasenotes/notes/16/16.0.0-add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml deleted file mode 100644 index 6b4566605..000000000 --- a/releasenotes/notes/16/16.0.0-add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Add a new client to handle the OAUTH consumers feature from the identity API. diff --git a/releasenotes/notes/16/16.0.0-add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml b/releasenotes/notes/16/16.0.0-add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml deleted file mode 100644 index 01136c6af..000000000 --- a/releasenotes/notes/16/16.0.0-add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - Add missing API call, list all role inference rules, - to the roles_client library. This feature enables the - possibility of listing all role inference rules in the - system. diff --git a/releasenotes/notes/16/16.0.0-add-cascade-parameter-to-volumes-client-ff4f7f12795003a4.yaml b/releasenotes/notes/16/16.0.0-add-cascade-parameter-to-volumes-client-ff4f7f12795003a4.yaml deleted file mode 100644 index 6801858f8..000000000 --- a/releasenotes/notes/16/16.0.0-add-cascade-parameter-to-volumes-client-ff4f7f12795003a4.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - Add cascade parameter to volumes_client. - This option provides the ability to delete a volume and have Cinder - handle deletion of snapshots associated with that volume by passing - an additional argument to volume delete, "cascade=True". diff --git a/releasenotes/notes/16/16.0.0-add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml b/releasenotes/notes/16/16.0.0-add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml deleted file mode 100644 index 848a21bca..000000000 --- a/releasenotes/notes/16/16.0.0-add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Define the compute server evacuate client method in the servers_client library. diff --git a/releasenotes/notes/16/16.0.0-add-content-type-without-spaces-b2c9b91b257814f3.yaml b/releasenotes/notes/16/16.0.0-add-content-type-without-spaces-b2c9b91b257814f3.yaml deleted file mode 100644 index 0075a361e..000000000 --- a/releasenotes/notes/16/16.0.0-add-content-type-without-spaces-b2c9b91b257814f3.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -upgrade: - - The ``JSON_ENC`` and ``TXT_ENC`` option in the ``_error_checker`` - section have been added with additional content-type which are - defined in RFC7231 but missing in the currnt rest_client.py file. - The lack of these additional content-type will cause defcore test - to fail for OpenStack public cloud which uses tomcat module in the - api gateway. The additions are ``application/json;charset=utf-8``, - ``text/html;charset=utf-8``,``text/plain;charset=utf-8`` \ No newline at end of file diff --git a/releasenotes/notes/16/16.0.0-add-list-auth-project-client-5905076d914a3943.yaml b/releasenotes/notes/16/16.0.0-add-list-auth-project-client-5905076d914a3943.yaml deleted file mode 100644 index 471f8f0c0..000000000 --- a/releasenotes/notes/16/16.0.0-add-list-auth-project-client-5905076d914a3943.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add the list auth projects API to the identity client library. This feature - enables the possibility to list projects that are available to be scoped - to based on the X-Auth-Token provided in the request. diff --git a/releasenotes/notes/16/16.0.0-add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml b/releasenotes/notes/16/16.0.0-add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml deleted file mode 100644 index acc7a4187..000000000 --- a/releasenotes/notes/16/16.0.0-add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add versions_client module for image service. - This new module provides list_versions() method which shows API versions - from Image service. diff --git a/releasenotes/notes/16/16.0.0-add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml b/releasenotes/notes/16/16.0.0-add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml deleted file mode 100644 index 67f954107..000000000 --- a/releasenotes/notes/16/16.0.0-add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add the list security groups by server API to the servers_client - library. This feature enables the possibility to list security - groups for a server instance. diff --git a/releasenotes/notes/16/16.0.0-add-list-version-to-identity-client-944cb7396088a575.yaml b/releasenotes/notes/16/16.0.0-add-list-version-to-identity-client-944cb7396088a575.yaml deleted file mode 100644 index dd66ff5b6..000000000 --- a/releasenotes/notes/16/16.0.0-add-list-version-to-identity-client-944cb7396088a575.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add versions_client module for identity service. - This new module provides list_versions() method which shows API versions - from Identity service. diff --git a/releasenotes/notes/16/16.0.0-add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml b/releasenotes/notes/16/16.0.0-add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml deleted file mode 100644 index 233cc287e..000000000 --- a/releasenotes/notes/16/16.0.0-add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add versions_client module for volume service. - This new module provides list_versions() method which shows API versions - from Volume service. diff --git a/releasenotes/notes/16/16.0.0-add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml b/releasenotes/notes/16/16.0.0-add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml deleted file mode 100644 index 06f4fcd05..000000000 --- a/releasenotes/notes/16/16.0.0-add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Interface show_quota_set of compute quotas_client has been extended to include the - argument "detail", which allows for detailed quota set information for a project to be - retrieved, if set to True. diff --git a/releasenotes/notes/16/16.0.0-add-tempest-lib-remote-client-adbeb3f42a36910b.yaml b/releasenotes/notes/16/16.0.0-add-tempest-lib-remote-client-adbeb3f42a36910b.yaml deleted file mode 100644 index 1b8cda2b8..000000000 --- a/releasenotes/notes/16/16.0.0-add-tempest-lib-remote-client-adbeb3f42a36910b.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -features: - - | - Add remote_client under tempest.lib. - This remote_client under tempest.lib is defined as stable - interface, and now this module provides the following - essential methods. - - - exec_command - - validate_authentication - - ping_host diff --git a/releasenotes/notes/16/16.0.0-add-tempest-run-combine-option-e94c1049ba8985d5.yaml b/releasenotes/notes/16/16.0.0-add-tempest-run-combine-option-e94c1049ba8985d5.yaml deleted file mode 100644 index 73900ca60..000000000 --- a/releasenotes/notes/16/16.0.0-add-tempest-run-combine-option-e94c1049ba8985d5.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Adds a new cli option to tempest run, --combine, which is used to indicate - you want the subunit stream output combined with the previous run's in - the testr repository diff --git a/releasenotes/notes/16/16.0.0-add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml b/releasenotes/notes/16/16.0.0-add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml deleted file mode 100644 index c95e77c90..000000000 --- a/releasenotes/notes/16/16.0.0-add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add update encryption type API to the v2 encryption_types_client library. - This feature enables the possibility to update an encryption type for an - existing volume type. diff --git a/releasenotes/notes/16/16.0.0-add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml b/releasenotes/notes/16/16.0.0-add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml deleted file mode 100644 index 34530501b..000000000 --- a/releasenotes/notes/16/16.0.0-add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -features: - - | - Add the unmanage volume API service method in v2 volumes_client library. - Define v2 volume_manage_client client for the volume service as library - interfaces, allowing other projects to use this module as stable libraries - without maintenance changes. - - * volume_manage_client(v2) diff --git a/releasenotes/notes/16/16.0.0-create-server-tags-client-8c0042a77e859af6.yaml b/releasenotes/notes/16/16.0.0-create-server-tags-client-8c0042a77e859af6.yaml deleted file mode 100644 index 992797189..000000000 --- a/releasenotes/notes/16/16.0.0-create-server-tags-client-8c0042a77e859af6.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Add server tags APIs to the servers_client library. - This feature enables the possibility of upating, deleting - and checking existence of a tag on a server, as well - as updating and deleting all tags on a server. - diff --git a/releasenotes/notes/16/16.0.0-deprecate-deactivate_image-config-7a282c471937bbcb.yaml b/releasenotes/notes/16/16.0.0-deprecate-deactivate_image-config-7a282c471937bbcb.yaml deleted file mode 100644 index 69c6bb6b4..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-deactivate_image-config-7a282c471937bbcb.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -deprecations: - - | - The ``deactivate_image`` configuration switch from the ``config`` module - is deprecated. It was added to support the older-than-kilo releases - which we don't support anymore. diff --git a/releasenotes/notes/16/16.0.0-deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml b/releasenotes/notes/16/16.0.0-deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml deleted file mode 100644 index c3e43ee77..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -deprecations: - - | - The ``dvr_extra_resources`` configuration switch from the ``config`` module - is deprecated. It was added to support the Liberty Release which we don't - support anymore. - diff --git a/releasenotes/notes/16/16.0.0-deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml b/releasenotes/notes/16/16.0.0-deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml deleted file mode 100644 index 788bc9590..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -deprecations: - - | - Glance v1 APIs are deprecated and v2 are current. - Tempest should tests only v2 APIs. - Below API version selection config options - for glance have been deprecated and will be removed in future. - - * CONF.image_feature_enabled.api_v2 - * CONF.image_feature_enabled.api_v1 diff --git a/releasenotes/notes/16/16.0.0-deprecate-resources-prefix-option-ad490c0a30a0266b.yaml b/releasenotes/notes/16/16.0.0-deprecate-resources-prefix-option-ad490c0a30a0266b.yaml deleted file mode 100644 index f6792086b..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-resources-prefix-option-ad490c0a30a0266b.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -upgrade: - - The default value of rand_name()'s prefix argument is changed - to 'tempest' from None to identify resources are created by - Tempest. -deprecations: - - The resources_prefix is marked as deprecated because it is - enough to set 'tempest' as the prefix on rand_name() to - ideintify resources which are created by Tempest and no - projects set this option on OpenStack dev community. diff --git a/releasenotes/notes/16/16.0.0-deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml b/releasenotes/notes/16/16.0.0-deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml deleted file mode 100644 index 4d8b94157..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -deprecations: - - The ``skip_unless_attr`` decorator in lib/decorators.py has been deprecated, - please use the standard ``testtools.skipUnless`` and ``testtools.skipIf`` - decorators. diff --git a/releasenotes/notes/16/16.0.0-deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml b/releasenotes/notes/16/16.0.0-deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml deleted file mode 100644 index 6285ea6a2..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -deprecations: - - The ``skip_unless_config`` and ``skip_if_config`` decorators in the - ``config`` module have been deprecated and will be removed in the Queens - dev cycle. Use the ``testtools.skipUnless`` (or a variation of) instead. diff --git a/releasenotes/notes/16/16.0.0-deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml b/releasenotes/notes/16/16.0.0-deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml deleted file mode 100644 index 0660d9c1c..000000000 --- a/releasenotes/notes/16/16.0.0-deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -deprecations: - - | - Volume v1 API is deprecated and the v3 are CURRENT. - Tempest doesn't need to test the v1 API as the default. - The volume config option 'api_v1' has been marked as - deprecated. -upgrade: - - | - The volume config option 'api_v1' default is changed to - ``False`` because the volume v1 API has been deprecated - since Juno release. diff --git a/releasenotes/notes/16/16.0.0-dreprecate_client_parameters-cb8d069e62957f7e.yaml b/releasenotes/notes/16/16.0.0-dreprecate_client_parameters-cb8d069e62957f7e.yaml deleted file mode 100644 index 4081f6a4f..000000000 --- a/releasenotes/notes/16/16.0.0-dreprecate_client_parameters-cb8d069e62957f7e.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -deprecations: - - | - Deprecate the client_parameters argument in - `tempest.lib.services.clients.ServiceClients`. The parameter is actually - not honoured already - see https://bugs.launchpad.net/tempest/+bug/1680915 diff --git a/releasenotes/notes/16/16.0.0-fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml b/releasenotes/notes/16/16.0.0-fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml deleted file mode 100644 index 6d3157648..000000000 --- a/releasenotes/notes/16/16.0.0-fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -fixes: - - | - Fix below volume v2 service clients to make v2 API call: Bug#1667354 - - - SchedulerStatsClient - - CapabilitiesClient diff --git a/releasenotes/notes/16/16.0.0-mitaka-eol-88ff8355fff81b55.yaml b/releasenotes/notes/16/16.0.0-mitaka-eol-88ff8355fff81b55.yaml deleted file mode 100644 index 24ec51274..000000000 --- a/releasenotes/notes/16/16.0.0-mitaka-eol-88ff8355fff81b55.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -prelude: > - This release indicates end of support for Mitaka in Tempest. -other: - - | - OpenStack Releases Supported after this release are **Newton** - and **Ocata** - - The release under current development as of this tag is Pike, - meaning that every Tempest commit is also tested against master branch - during the Pike cycle. However, this does not necessarily mean that - using Tempest as of this tag will work against Pike (or future - releases) cloud. diff --git a/releasenotes/notes/16/16.0.0-remove-call_until_true-of-test-de9c13bc8f969921.yaml b/releasenotes/notes/16/16.0.0-remove-call_until_true-of-test-de9c13bc8f969921.yaml deleted file mode 100644 index 56708211c..000000000 --- a/releasenotes/notes/16/16.0.0-remove-call_until_true-of-test-de9c13bc8f969921.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -upgrade: - - The *call_until_true* of *test* module is removed because it was marked - as deprecated and Tempest provides it from *test_utils* as a stable - interface instead. Please switch to use *test_utils.call_until_true* if - necessary. diff --git a/releasenotes/notes/16/16.0.0-remove-cinder-v1-api-tests-71e266b8d55d475f.yaml b/releasenotes/notes/16/16.0.0-remove-cinder-v1-api-tests-71e266b8d55d475f.yaml deleted file mode 100644 index 710ad9ee3..000000000 --- a/releasenotes/notes/16/16.0.0-remove-cinder-v1-api-tests-71e266b8d55d475f.yaml +++ /dev/null @@ -1,5 +0,0 @@ -upgrade: - - Remove Cinder v1 API tests. - Cinder v1 API has been deprecated since Juno release, and Juno is - not supported by current Tempest. Then Cinder v1 API tests are - removed from Tempest. diff --git a/releasenotes/notes/16/16.0.0-remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml deleted file mode 100644 index 9d7102fe0..000000000 --- a/releasenotes/notes/16/16.0.0-remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - | - The deprecated config option 'allow_port_security_disabled' from compute_feature_enabled - group has been removed. diff --git a/releasenotes/notes/16/16.0.0-remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml deleted file mode 100644 index b4e4dd105..000000000 --- a/releasenotes/notes/16/16.0.0-remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -upgrade: - - | - Below deprecated config options from compute group have been removed. - Corresponding config options already been available in validation group. - - - ``compute.image_ssh_user`` (available as ``validation.image_ssh_user``) - - ``compute.ssh_user`` (available as ``validation.image_ssh_user``) - - ``scenario.ssh_user`` (available as ``validation.image_ssh_user``) - - ``compute.network_for_ssh`` (available as ``validation.network_for_ssh``) - - ``compute.ping_timeout `` (available as ``validation.ping_timeout``) diff --git a/releasenotes/notes/16/16.0.0-remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml deleted file mode 100644 index 889e86275..000000000 --- a/releasenotes/notes/16/16.0.0-remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -upgrade: - - | - The deprecated config option 'dvr_extra_resources' from network group has been removed. - This option was for extra resources which were provisioned to bind a router to Neutron - L3 agent. The extra resources need to be provisioned in Liberty release or older, - and are not required since Mitaka release. Current Tempest doesn't support Liberty, so - this option has been removed from Tempest. diff --git a/releasenotes/notes/16/16.0.0-remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml deleted file mode 100644 index 8085694f8..000000000 --- a/releasenotes/notes/16/16.0.0-remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - | - The deprecated config option 'reseller' from identity_feature_enabled group has been removed. diff --git a/releasenotes/notes/16/16.0.0-remove-sahara-service-available-44a642aa9c634ab4.yaml b/releasenotes/notes/16/16.0.0-remove-sahara-service-available-44a642aa9c634ab4.yaml deleted file mode 100644 index c0dc7d71a..000000000 --- a/releasenotes/notes/16/16.0.0-remove-sahara-service-available-44a642aa9c634ab4.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -fixes: - - | - The 'sahara' config option in the 'service-available' group has been moved to the sahara plugin - (openstack/sahara-tests) along with tests and service client during the Ocata timeframe. - A 'sahara' config option was left over on Tempest side, and it's removed now. - As long as the sahara plugin is installed, this change as no impact on users of sahara tests. diff --git a/releasenotes/notes/16/16.0.0-remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml b/releasenotes/notes/16/16.0.0-remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml deleted file mode 100644 index fc15995a3..000000000 --- a/releasenotes/notes/16/16.0.0-remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - | - The deprecated ``volume_services`` option in the ``volume_feature_enabled`` - section has now been removed. diff --git a/releasenotes/notes/16/16.0.0-use-keystone-v3-api-935860d30ddbb8e9.yaml b/releasenotes/notes/16/16.0.0-use-keystone-v3-api-935860d30ddbb8e9.yaml deleted file mode 100644 index dd6e92457..000000000 --- a/releasenotes/notes/16/16.0.0-use-keystone-v3-api-935860d30ddbb8e9.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - Tempest now defaults to using Keystone v3 API for the - authentication, because Keystone v3 API is CURRENT and - the v2 API is deprecated. diff --git a/releasenotes/notes/16/16.0.0-volume-transfers-client-e5ed3f5464c0cdc0.yaml b/releasenotes/notes/16/16.0.0-volume-transfers-client-e5ed3f5464c0cdc0.yaml deleted file mode 100644 index e5e479bf9..000000000 --- a/releasenotes/notes/16/16.0.0-volume-transfers-client-e5ed3f5464c0cdc0.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -features: - - | - Define volume transfers service clients as libraries. - The following volume transfers service clients are defined as library interface. - - * transfers_client(v2) -deprecations: - - | - Deprecate volume v2 transfers resource methods from volumes_client(v2) libraries. - Same methods are available in new transfers service client: transfers_client(v2) - The following methods of volume v2 volumes_clients have been deprecated: - - * create_volume_transfer (v2.volumes_client) - * show_volume_transfer (v2.volumes_client) - * list_volume_transfers (v2.volumes_client) - * delete_volume_transfer (v2.volumes_client) - * accept_volume_transfer (v2.volumes_client) diff --git a/releasenotes/notes/add-OAUTH-Token-Client-tempest-tests-6351eda451b95a86.yaml b/releasenotes/notes/add-OAUTH-Token-Client-tempest-tests-6351eda451b95a86.yaml deleted file mode 100644 index 9115f03a2..000000000 --- a/releasenotes/notes/add-OAUTH-Token-Client-tempest-tests-6351eda451b95a86.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Add a new client to handle the OAUTH token feature from the identity API. diff --git a/releasenotes/notes/add-compute-feature-serial-console-45583c4341e34fc9.yaml b/releasenotes/notes/add-compute-feature-serial-console-45583c4341e34fc9.yaml deleted file mode 100644 index 18fd5adfa..000000000 --- a/releasenotes/notes/add-compute-feature-serial-console-45583c4341e34fc9.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - A new boolean config option ``serial_console`` is added to the section - ``compute-feature-enabled``. If enabled, tests, which validate the - behavior of Nova's *serial console* feature (an alternative to VNC, - RDP, SPICE) can be executed. diff --git a/releasenotes/notes/add-domain-configuration-client-tempest-tests-e383efabdbb9ad03.yaml b/releasenotes/notes/add-domain-configuration-client-tempest-tests-e383efabdbb9ad03.yaml deleted file mode 100644 index 565368180..000000000 --- a/releasenotes/notes/add-domain-configuration-client-tempest-tests-e383efabdbb9ad03.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Add a new client to handle the domain configuration feature from the - identity v3 API. diff --git a/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml b/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml deleted file mode 100644 index 8221d7882..000000000 --- a/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - A new config option in the network-feature-enabled section, floating_ips, - to specify whether floating ips are available in the cloud under test. By - default this is set to True. diff --git a/releasenotes/notes/add-force-detach-volume-to-volumes-client-library-b2071f2954f8e8b1.yaml b/releasenotes/notes/add-force-detach-volume-to-volumes-client-library-b2071f2954f8e8b1.yaml deleted file mode 100644 index a0156a05f..000000000 --- a/releasenotes/notes/add-force-detach-volume-to-volumes-client-library-b2071f2954f8e8b1.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add force detach volume feature API to v2 volumes_client library. - This feature enables the possibility to force a volume to detach, and - roll back an unsuccessful detach operation after you disconnect the volume. diff --git a/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml b/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml deleted file mode 100644 index 1dc33aaf9..000000000 --- a/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - Defines the identity v3 OS-EP-FILTER EndPoint Groups API client. - This client manages Create, Get, Update, Check, List, and Delete - of EndPoint Group. - diff --git a/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-extensions-9cfd217fd2c6a61f.yaml b/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-extensions-9cfd217fd2c6a61f.yaml deleted file mode 100644 index 69320fb3e..000000000 --- a/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-extensions-9cfd217fd2c6a61f.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Defines the identity v3 OS-EP-FILTER extension API client. - This client manages associations between endpoints, projects - along with groups. diff --git a/releasenotes/notes/add-kwargs-to-delete-vol-of-vol-client-1ecde75beb62933c.yaml b/releasenotes/notes/add-kwargs-to-delete-vol-of-vol-client-1ecde75beb62933c.yaml deleted file mode 100644 index b8c9dfcdb..000000000 --- a/releasenotes/notes/add-kwargs-to-delete-vol-of-vol-client-1ecde75beb62933c.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - The ``delete_volume`` method of the ``VolumesClient`` class - now has an additional ``**params`` argument that enables passing - additional information in the query string of the HTTP request. - diff --git a/releasenotes/notes/add-list-volume-transfers-with-detail-to-transfers-client-80169bf78cf4fa66.yaml b/releasenotes/notes/add-list-volume-transfers-with-detail-to-transfers-client-80169bf78cf4fa66.yaml deleted file mode 100644 index 8e85d3a1b..000000000 --- a/releasenotes/notes/add-list-volume-transfers-with-detail-to-transfers-client-80169bf78cf4fa66.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Add list volume transfers with details API to v2 transfers_client library. - This feature enables the possibility to list volume transfers with details. diff --git a/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml b/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml deleted file mode 100644 index bc7bcc8e6..000000000 --- a/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - A new config option 'manage_snapshot_ref' is added in the volume section, - to specify snapshot ref parameter for different storage backend drivers - when managing an existing snapshot. By default it is set to fit the LVM - driver. diff --git a/releasenotes/notes/add-params-to-identity-v3-list-endpoints-958a155be4e17e5b.yaml b/releasenotes/notes/add-params-to-identity-v3-list-endpoints-958a155be4e17e5b.yaml deleted file mode 100644 index 46f3b49c4..000000000 --- a/releasenotes/notes/add-params-to-identity-v3-list-endpoints-958a155be4e17e5b.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - The ``list_endpoints`` method of the v3 ``EndPointsClient`` class now has - an additional ``**params`` argument that enables passing additional - information in the query string of the HTTP request. diff --git a/releasenotes/notes/add-params-to-v2-list-backups-api-c088d2b4bfe90247.yaml b/releasenotes/notes/add-params-to-v2-list-backups-api-c088d2b4bfe90247.yaml deleted file mode 100644 index cee2d7663..000000000 --- a/releasenotes/notes/add-params-to-v2-list-backups-api-c088d2b4bfe90247.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - The ``list_backups`` method of the v2 ``BackupsClient`` class now has - an additional ``**params`` argument that enables passing additional - information in the query string of the HTTP request. diff --git a/releasenotes/notes/add-save-state-option-5ea67858cbaca969.yaml b/releasenotes/notes/add-save-state-option-5ea67858cbaca969.yaml deleted file mode 100644 index 8fdf4f00a..000000000 --- a/releasenotes/notes/add-save-state-option-5ea67858cbaca969.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - | - Add --save-state option to allow saving state of cloud before tempest run. diff --git a/releasenotes/notes/add-server-diagnostics-validation-schema-b5a3c55b45aa718a.yaml b/releasenotes/notes/add-server-diagnostics-validation-schema-b5a3c55b45aa718a.yaml deleted file mode 100644 index e0ac87cd8..000000000 --- a/releasenotes/notes/add-server-diagnostics-validation-schema-b5a3c55b45aa718a.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - | - Add validation schema for Nova server diagnostics API \ No newline at end of file diff --git a/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml b/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml deleted file mode 100644 index 0de1803e6..000000000 --- a/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Add show host API to the volume v2 hosts_client library. - This feature enables the possibility to show details for a host. diff --git a/releasenotes/notes/add-show-snapshot-metadata-item-api-to-v2-snapshots-client-bd3cbab3c7f0e0b3.yaml b/releasenotes/notes/add-show-snapshot-metadata-item-api-to-v2-snapshots-client-bd3cbab3c7f0e0b3.yaml deleted file mode 100644 index 140df609f..000000000 --- a/releasenotes/notes/add-show-snapshot-metadata-item-api-to-v2-snapshots-client-bd3cbab3c7f0e0b3.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add show snapshot metadata item API to v2 snapshots_client library. - This feature enables the possibility to show a snapshot's metadata for - a specific key. diff --git a/releasenotes/notes/add-show-volume-metadata-item-api-to-v2-volumes-client-47d59ecd999ca9df.yaml b/releasenotes/notes/add-show-volume-metadata-item-api-to-v2-volumes-client-47d59ecd999ca9df.yaml deleted file mode 100644 index 49a935cce..000000000 --- a/releasenotes/notes/add-show-volume-metadata-item-api-to-v2-volumes-client-47d59ecd999ca9df.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add show volume metadata item API to v2 volumes_client library. - This feature enables the possibility to show a volume's metadata for - a specific key. diff --git a/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml b/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml deleted file mode 100644 index 361e38754..000000000 --- a/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -features: - - | - Define v3 volumes_client for the volume service as a library interface, - allowing other projects to use this module as a stable library without - maintenance changes. - Add show volume summary API to v3 volumes_client library, min_microversion - of this API is 3.12. - - * volumes_client(v3) diff --git a/releasenotes/notes/add-update-backup-api-to-v3-backups-client-e8465b2b66617dc0.yaml b/releasenotes/notes/add-update-backup-api-to-v3-backups-client-e8465b2b66617dc0.yaml deleted file mode 100644 index 7cd6887ef..000000000 --- a/releasenotes/notes/add-update-backup-api-to-v3-backups-client-e8465b2b66617dc0.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -features: - - | - Define v3 backups_client for the volume service as a library interface, - allowing other projects to use this module as a stable library without - maintenance changes. - Add update backup API to v3 backups_client library, min_microversion - of this API is 3.9. - - * backups_client(v3) diff --git a/releasenotes/notes/add-volume-group-types-tempest-tests-1298ab8cb4fe8b7b.yaml b/releasenotes/notes/add-volume-group-types-tempest-tests-1298ab8cb4fe8b7b.yaml deleted file mode 100644 index 4fd3bee37..000000000 --- a/releasenotes/notes/add-volume-group-types-tempest-tests-1298ab8cb4fe8b7b.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Add list_group_type and show_group_type in the group_types client for - the volume service. Add tests for create/delete/show/list group types. diff --git a/releasenotes/notes/add-volume-groups-tempest-tests-dd7b2abfe2b48427.yaml b/releasenotes/notes/add-volume-groups-tempest-tests-dd7b2abfe2b48427.yaml deleted file mode 100644 index 898d36678..000000000 --- a/releasenotes/notes/add-volume-groups-tempest-tests-dd7b2abfe2b48427.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add groups and group_types clients for the volume service as library. - Add tempest tests for create group, delete group, show group, and - list group volume APIs. diff --git a/releasenotes/notes/add-volume-quota-class-client-as-library-c4c2b22c36ff807e.yaml b/releasenotes/notes/add-volume-quota-class-client-as-library-c4c2b22c36ff807e.yaml deleted file mode 100644 index e6847ebf4..000000000 --- a/releasenotes/notes/add-volume-quota-class-client-as-library-c4c2b22c36ff807e.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Define v2 quota_classes_client for the volume service as library - interfaces, allowing other projects to use this module as stable libraries - without maintenance changes. - - * quota_classes_client(v2) diff --git a/releasenotes/notes/api_v2_admin_flag-dea5ca9bc2ce63bc.yaml b/releasenotes/notes/api_v2_admin_flag-dea5ca9bc2ce63bc.yaml deleted file mode 100644 index 0c33b69ac..000000000 --- a/releasenotes/notes/api_v2_admin_flag-dea5ca9bc2ce63bc.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - A new configuration flag api_v2_admin is introduced in the identity - feature flag group to allow for enabling/disabling all identity v2 - admin tests. The new flag only applies when the existing api_v2 flag - is set to True diff --git a/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml b/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml deleted file mode 100644 index 1ae251cde..000000000 --- a/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -deprecations: - - | - Image APIs in compute are deprecated, Image native APIs are recommended. - And Glance v1 APIs are deprecated and v2 APIs are current. Image client - compute_images_client and Glance v1 APIs are removed in volume tests. -upgrade: - - | - Switch to use Glance v2 APIs in volume tests, by adding the Glance v2 - client images_client. diff --git a/releasenotes/notes/deprecate-config-forbid_global_implied_dsr-e64cfa66e6e3ded5.yaml b/releasenotes/notes/deprecate-config-forbid_global_implied_dsr-e64cfa66e6e3ded5.yaml deleted file mode 100644 index 2b63402f3..000000000 --- a/releasenotes/notes/deprecate-config-forbid_global_implied_dsr-e64cfa66e6e3ded5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -deprecations: - - The config option ``forbid_global_implied_dsr`` from the ``IdentityFeature`` - group is now deprecated. This feature flag was introduced to support - testing of old OpenStack versions which are not supported anymore. diff --git a/releasenotes/notes/deprecate-default-value-for-v3_endpoint_type-fb9e47c5ba1c719d.yaml b/releasenotes/notes/deprecate-default-value-for-v3_endpoint_type-fb9e47c5ba1c719d.yaml deleted file mode 100644 index c88522e73..000000000 --- a/releasenotes/notes/deprecate-default-value-for-v3_endpoint_type-fb9e47c5ba1c719d.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -deprecations: - - | - Deprecate default value for configuration parameter v3_endpoint_type - of identity section in OpenStack Pike and modify the default value to - publicURL in OpenStack Q release. diff --git a/releasenotes/notes/extra-compute-services-tests-92b6c0618972e02f.yaml b/releasenotes/notes/extra-compute-services-tests-92b6c0618972e02f.yaml deleted file mode 100644 index 414adf18b..000000000 --- a/releasenotes/notes/extra-compute-services-tests-92b6c0618972e02f.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add the ``disable_log_reason`` and the ``update_forced_down`` API endpoints - to the compute ``services_client``. - Add '2.11' compute validation schema for compute services API. diff --git a/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml b/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml deleted file mode 100644 index d94de3e60..000000000 --- a/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add additional API endpoints to the identity v2 client token API: - - list_endpoints_for_token - - check_token_existence diff --git a/releasenotes/notes/identity_client-635275d43abbb807.yaml b/releasenotes/notes/identity_client-635275d43abbb807.yaml deleted file mode 100644 index 6f984b74e..000000000 --- a/releasenotes/notes/identity_client-635275d43abbb807.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Enhances the v3 identity client with the ``check_token_existence`` - endpoint, allowing users to check the existence of tokens diff --git a/releasenotes/notes/intermediate-pike-release-2ce492432ff8f012.yaml b/releasenotes/notes/intermediate-pike-release-2ce492432ff8f012.yaml deleted file mode 100644 index bfebcd9ed..000000000 --- a/releasenotes/notes/intermediate-pike-release-2ce492432ff8f012.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -prelude: > - This is an intermediate release during the Pike development cycle to - make new functionality available to plugins and other consumers. diff --git a/releasenotes/notes/migrate-dynamic-creds-ecebb47528080761.yaml b/releasenotes/notes/migrate-dynamic-creds-ecebb47528080761.yaml deleted file mode 100644 index c20cbc68d..000000000 --- a/releasenotes/notes/migrate-dynamic-creds-ecebb47528080761.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - The tempest module tempest.common.dynamic creds which is used for - dynamically allocating credentials has been migrated into tempest lib. diff --git a/releasenotes/notes/migrate-preprov-creds-ef61a046ee1ec604.yaml b/releasenotes/notes/migrate-preprov-creds-ef61a046ee1ec604.yaml deleted file mode 100644 index aa5f71a20..000000000 --- a/releasenotes/notes/migrate-preprov-creds-ef61a046ee1ec604.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -features: - - The tempest module tempest.common.preprov_creds which is used to provide - credentials from a list of preprovisioned resources has been migrated into - tempest lib at tempest.lib.common.preprov_creds. - - The InvalidTestResource exception class from tempest.exceptions has been - migrated into tempest.lib.exceptions - - The tempest module tempest.common.fixed_network which provided utilities for - finding fixed networks by and helpers for picking the network to use when - multiple tenant networks are available has been migrated into tempest lib - at tempest.lib.common.fixed_network. diff --git a/releasenotes/notes/move-attr-decorator-to-lib-a1e80c42ba9c5392.yaml b/releasenotes/notes/move-attr-decorator-to-lib-a1e80c42ba9c5392.yaml deleted file mode 100644 index 58d45cc87..000000000 --- a/releasenotes/notes/move-attr-decorator-to-lib-a1e80c42ba9c5392.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - A new ``attr`` decorator has been added in the ``tempest.lib.decorators`` - module. For example, use it to tag specific tests, which could be leveraged - by test runners to run only a subset of Tempest tests. diff --git a/releasenotes/notes/move-related_bug-decorator-to-lib-dbfd5c543bbb2805.yaml b/releasenotes/notes/move-related_bug-decorator-to-lib-dbfd5c543bbb2805.yaml deleted file mode 100644 index 8c420c82c..000000000 --- a/releasenotes/notes/move-related_bug-decorator-to-lib-dbfd5c543bbb2805.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - A new ``related_bug`` decorator has been added to - ``tempest.lib.decorators``. Use it to decorate and tag a test that was - added in relation to a launchpad bug report. diff --git a/releasenotes/notes/move-volume-v3-base_client-to-volume-1edbz0f207c3b283.yaml b/releasenotes/notes/move-volume-v3-base_client-to-volume-1edbz0f207c3b283.yaml deleted file mode 100644 index ec81dc530..000000000 --- a/releasenotes/notes/move-volume-v3-base_client-to-volume-1edbz0f207c3b283.yaml +++ /dev/null @@ -1,15 +0,0 @@ -features: - - | - Move base_client from tempest.lib.services.volume.v3 to - tempest.lib.services.volume, so if we want to add new - interfaces based on a v2 client, we can make that v2 - client inherit from volume.base_client.BaseClient to - get microversion support, and then to make the new v3 - client inherit from the v2 client, thus to avoid the - multiple inheritance. -deprecations: - - | - Deprecate class BaseClient from volume.v3.base_client - and move it to volume.base_client. - ``tempest.lib.services.volume.v3.base_client.BaseClient`` - (new ``tempest.lib.services.volume.base_client.BaseClient``) diff --git a/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml b/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml deleted file mode 100644 index 9af57b117..000000000 --- a/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Define v2.0 ``tags_client`` for the network service as a library - interface, allowing other projects to use this module as a stable - library without maintenance changes. - - * tags_client(v2.0) diff --git a/releasenotes/notes/pause_teardown-45c9d60ffa889f7f.yaml b/releasenotes/notes/pause_teardown-45c9d60ffa889f7f.yaml deleted file mode 100644 index a540c7d45..000000000 --- a/releasenotes/notes/pause_teardown-45c9d60ffa889f7f.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -features: - - | - Pause teardown - When pause_teardown flag in tempest.conf is set to True a pdb breakpoint - is added to tearDown and tearDownClass methods in test.py. - This allows to pause cleaning resources process, so that used resources - can be examined. Closer examination of used resources may lead to faster - debugging. diff --git a/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml b/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml deleted file mode 100644 index afb600688..000000000 --- a/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -fixes: - - | - When receiving nullable list as a response body, tempest.lib - rest_client module raised an exception without valid json - deserialization. A new release fixes this bug. diff --git a/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml b/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml deleted file mode 100644 index 4d0f3ce06..000000000 --- a/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - The Heat API tests have been removed from tempest, they were unmaintained. - The future direction of api test for heat is their in-tree Gabbi tests diff --git a/releasenotes/notes/set-cinder-api-v3-option-true-1b3e61e3129b7c00.yaml b/releasenotes/notes/set-cinder-api-v3-option-true-1b3e61e3129b7c00.yaml deleted file mode 100644 index 6959ca7da..000000000 --- a/releasenotes/notes/set-cinder-api-v3-option-true-1b3e61e3129b7c00.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - | - The volume config option 'api_v3' default is changed to - ``True`` because the volume v3 API is CURRENT. diff --git a/releasenotes/notes/tempest-identity-catalog-client-f5c8589a9d7c1eb5.yaml b/releasenotes/notes/tempest-identity-catalog-client-f5c8589a9d7c1eb5.yaml deleted file mode 100644 index dcaaceb5f..000000000 --- a/releasenotes/notes/tempest-identity-catalog-client-f5c8589a9d7c1eb5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Add a new identity catalog client. At this point, the new client - contains a single functionality, "show_catalog", which returns a - catalog object. diff --git a/releasenotes/notes/tempest-workspace-delete-directory-feature-74d6d157a5a05561.yaml b/releasenotes/notes/tempest-workspace-delete-directory-feature-74d6d157a5a05561.yaml deleted file mode 100644 index ec21098fd..000000000 --- a/releasenotes/notes/tempest-workspace-delete-directory-feature-74d6d157a5a05561.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Added tempest workspace remove --name --rmdir - feature to delete the workspace directory as well as entry. diff --git a/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml b/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml deleted file mode 100644 index 1c8fa77bd..000000000 --- a/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -upgrade: - - verify_tempest_config command starts using extension_client of - cinder v2 API only, because cinder v3 API is current and v2 and - v1 are deprecated and v3 extension API is the same as v2. Then - we can reuse the v2 client for v3 API also. diff --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder deleted file mode 100644 index e69de29bb..000000000 diff --git a/releasenotes/source/_templates/.placeholder b/releasenotes/source/_templates/.placeholder deleted file mode 100644 index e69de29bb..000000000 diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index 3137541df..000000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,286 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Tempest Release Notes documentation build configuration file, created by -# sphinx-quickstart on Tue Nov 3 17:40:50 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'openstackdocstheme', - 'reno.sphinxext', -] - -# openstackdocstheme options -repository_name = 'openstack/tempest' -bug_project = 'tempest' -bug_tag = '' - -# Must set this variable to include year, month, day, hours, and minutes. -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'tempest Release Notes' -copyright = u'2016, tempest Developers' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -from tempest.version import version_info as tempest_version -# The full version, including alpha/beta/rc tags. -release = tempest_version.version_string_with_vcs() -# The short X.Y version. -version = tempest_version.canonical_version_string() - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'tempestReleaseNotesdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'olso.configReleaseNotes.tex', - u'olso.config Release Notes Documentation', - u'tempest Developers', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'olso.configreleasenotes', - u'tempest Release Notes Documentation', - [u'tempest Developers'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'tempestReleaseNotes', - u'tempest Release Notes Documentation', - u'tempest Developers', 'olso.configReleaseNotes', - 'An OpenStack library for parsing configuration options from the command' - ' line and configuration files.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False - -# -- Options for Internationalization output ------------------------------ -locale_dirs = ['locale/'] diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index db01da0a0..000000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -=========================== - Tempest Release Notes -=========================== - - .. toctree:: - :maxdepth: 1 - - unreleased - v16.1.0 - v16.0.0 - v15.0.0 - v14.0.0 - v13.0.0 - v12.0.0 - v11.0.0 - v10.0.0 - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`search` diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst deleted file mode 100644 index 875030f9d..000000000 --- a/releasenotes/source/unreleased.rst +++ /dev/null @@ -1,5 +0,0 @@ -============================ -Current Series Release Notes -============================ - -.. release-notes:: diff --git a/releasenotes/source/v10.0.0.rst b/releasenotes/source/v10.0.0.rst deleted file mode 100644 index 38ed2efae..000000000 --- a/releasenotes/source/v10.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v10.0.0 Release Notes -===================== - -.. release-notes:: 10.0.0 Release Notes - :version: 10.0.0 diff --git a/releasenotes/source/v11.0.0.rst b/releasenotes/source/v11.0.0.rst deleted file mode 100644 index 84b145ded..000000000 --- a/releasenotes/source/v11.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v11.0.0 Release Notes -===================== - -.. release-notes:: 11.0.0 Release Notes - :version: 11.0.0 diff --git a/releasenotes/source/v12.0.0.rst b/releasenotes/source/v12.0.0.rst deleted file mode 100644 index 0bc8343b1..000000000 --- a/releasenotes/source/v12.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v12.0.0 Release Notes -===================== - -.. release-notes:: 12.0.0 Release Notes - :version: 12.0.0 diff --git a/releasenotes/source/v13.0.0.rst b/releasenotes/source/v13.0.0.rst deleted file mode 100644 index 39816e4b8..000000000 --- a/releasenotes/source/v13.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v13.0.0 Release Notes -===================== - -.. release-notes:: 13.0.0 Release Notes - :version: 13.0.0 diff --git a/releasenotes/source/v14.0.0.rst b/releasenotes/source/v14.0.0.rst deleted file mode 100644 index 440c85bed..000000000 --- a/releasenotes/source/v14.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v14.0.0 Release Notes -===================== - -.. release-notes:: 14.0.0 Release Notes - :version: 14.0.0 diff --git a/releasenotes/source/v15.0.0.rst b/releasenotes/source/v15.0.0.rst deleted file mode 100644 index 2ee189452..000000000 --- a/releasenotes/source/v15.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v15.0.0 Release Notes -===================== - -.. release-notes:: 15.0.0 Release Notes - :version: 15.0.0 diff --git a/releasenotes/source/v16.0.0.rst b/releasenotes/source/v16.0.0.rst deleted file mode 100644 index ae2959964..000000000 --- a/releasenotes/source/v16.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v16.0.0 Release Notes -===================== - -.. release-notes:: 16.0.0 Release Notes - :version: 16.0.0 \ No newline at end of file diff --git a/releasenotes/source/v16.1.0.rst b/releasenotes/source/v16.1.0.rst deleted file mode 100644 index e24a70fef..000000000 --- a/releasenotes/source/v16.1.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v16.1.0 Release Notes -===================== - -.. release-notes:: 16.1.0 Release Notes - :version: 16.1.0 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index a74f5c265..000000000 --- a/requirements.txt +++ /dev/null @@ -1,25 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -pbr!=2.1.0,>=2.0.0 # Apache-2.0 -cliff>=2.8.0 # Apache-2.0 -jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT -testtools>=1.4.0 # MIT -paramiko>=2.0 # LGPLv2.1+ -netaddr!=0.7.16,>=0.7.13 # BSD -testrepository>=0.0.18 # Apache-2.0/BSD -oslo.concurrency>=3.8.0 # Apache-2.0 -oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0 -oslo.log>=3.22.0 # Apache-2.0 -oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0 -oslo.utils>=3.20.0 # Apache-2.0 -six>=1.9.0 # MIT -fixtures>=3.0.0 # Apache-2.0/BSD -PyYAML>=3.10.0 # MIT -python-subunit>=0.0.18 # Apache-2.0/BSD -stevedore>=1.20.0 # Apache-2.0 -PrettyTable<0.8,>=0.7.1 # BSD -os-testr>=0.8.0 # Apache-2.0 -urllib3>=1.21.1 # MIT -debtcollector>=1.2.0 # Apache-2.0 -unittest2 # BSD diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index f52137edf..000000000 --- a/setup.cfg +++ /dev/null @@ -1,58 +0,0 @@ -[metadata] -name = tempest -summary = OpenStack Integration Testing -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = https://docs.openstack.org/tempest/latest/ -classifier = - Intended Audience :: Information Technology - Intended Audience :: System Administrators - Intended Audience :: Developers - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 - Programming Language :: Python :: 3.5 - -[files] -packages = - tempest -data_files = - etc/tempest = etc/* - -[entry_points] -console_scripts = - verify-tempest-config = tempest.cmd.verify_tempest_config:main - tempest-account-generator = tempest.cmd.account_generator:main - tempest = tempest.cmd.main:main - skip-tracker = tempest.lib.cmd.skip_tracker:main - check-uuid = tempest.lib.cmd.check_uuid:run - subunit-describe-calls = tempest.cmd.subunit_describe_calls:entry_point -tempest.cm = - account-generator = tempest.cmd.account_generator:TempestAccountGenerator - init = tempest.cmd.init:TempestInit - cleanup = tempest.cmd.cleanup:TempestCleanup - list-plugins = tempest.cmd.list_plugins:TempestListPlugins - verify-config = tempest.cmd.verify_tempest_config:TempestVerifyConfig - workspace_register = tempest.cmd.workspace:TempestWorkspaceRegister - workspace_rename = tempest.cmd.workspace:TempestWorkspaceRename - workspace_move = tempest.cmd.workspace:TempestWorkspaceMove - workspace_remove = tempest.cmd.workspace:TempestWorkspaceRemove - workspace_list = tempest.cmd.workspace:TempestWorkspaceList - run = tempest.cmd.run:TempestRun -oslo.config.opts = - tempest.config = tempest.config:list_opts - -[build_sphinx] -all-files = 1 -warning-is-error = 1 -build-dir = doc/build -source-dir = doc/source - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 566d84432..000000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) diff --git a/tempest/README.rst b/tempest/README.rst deleted file mode 100644 index 663653e4e..000000000 --- a/tempest/README.rst +++ /dev/null @@ -1,55 +0,0 @@ -============================ -Tempest Field Guide Overview -============================ - -Tempest is designed to be useful for a large number of different -environments. This includes being useful for gating commits to -OpenStack core projects, being used to validate OpenStack cloud -implementations for both correctness, as well as a burn in tool for -OpenStack clouds. - -As such Tempest tests come in many flavors, each with their own rules -and guidelines. Below is the overview of the Tempest respository structure -to make this clear. - -| tempest/ -| api/ - API tests -| scenario/ - complex scenario tests -| tests/ - unit tests for Tempest internals - -Each of these directories contains different types of tests. What -belongs in each directory, the rules and examples for good tests, are -documented in a README.rst file in the directory. - -:ref:`api_field_guide` ----------------------- - -API tests are validation tests for the OpenStack API. They should not -use the existing Python clients for OpenStack, but should instead use -the Tempest implementations of clients. Having raw clients let us -pass invalid JSON to the APIs and see the results, something we could -not get with the native clients. - -When it makes sense, API testing should be moved closer to the -projects themselves, possibly as functional tests in their unit test -frameworks. - - -:ref:`scenario_field_guide` ---------------------------- - -Scenario tests are complex "through path" tests for OpenStack -functionality. They are typically a series of steps where complicated -state requiring multiple services is set up exercised, and torn down. - -Scenario tests should not use the existing Python clients for OpenStack, -but should instead use the Tempest implementations of clients. - - -:ref:`unit_tests_field_guide` ------------------------------ - -Unit tests are the self checks for Tempest. They provide functional -verification and regression checking for the internal components of Tempest. -They should be used to just verify that the individual pieces of Tempest are -working as expected. diff --git a/tempest/__init__.py b/tempest/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/README.rst b/tempest/api/README.rst deleted file mode 100644 index a79692219..000000000 --- a/tempest/api/README.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. _api_field_guide: - -Tempest Field Guide to API tests -================================ - - -What are these tests? ---------------------- - -One of Tempest's prime function is to ensure that your OpenStack cloud -works with the OpenStack API as documented. The current largest -portion of Tempest code is devoted to test cases that do exactly this. - -It's also important to test not only the expected positive path on -APIs, but also to provide them with invalid data to ensure they fail -in expected and documented ways. The latter type of tests is called -``negative tests`` in Tempest source code. Over the course of the OpenStack -project Tempest has discovered many fundamental bugs by doing just -this. - -In order for some APIs to return meaningful results, there must be -enough data in the system. This means these tests might start by -spinning up a server, image, etc, then operating on it. - - -Why are these tests in Tempest? -------------------------------- - -This is one of the core missions for the Tempest project, and where it -started. Many people use this bit of function in Tempest to ensure -their clouds haven't broken the OpenStack API. - -It could be argued that some of the negative testing could be done -back in the projects themselves, and we might evolve there over time, -but currently in the OpenStack gate this is a fundamentally important -place to keep things. - - -Scope of these tests --------------------- - -API tests should always use the Tempest implementation of the -OpenStack API, as we want to ensure that bugs aren't hidden by the -official clients. - -They should test specific API calls, and can build up complex state if -it's needed for the API call to be meaningful. - -They should send not only good data, but bad data at the API and look -for error codes. - -They should all be able to be run on their own, not depending on the -state created by a previous test. diff --git a/tempest/api/__init__.py b/tempest/api/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/__init__.py b/tempest/api/compute/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/admin/__init__.py b/tempest/api/compute/admin/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py deleted file mode 100644 index 69cbfb5da..000000000 --- a/tempest/api/compute/admin/test_agents.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class AgentsAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Agents API""" - - @classmethod - def setup_clients(cls): - super(AgentsAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.agents_client - - @classmethod - def resource_setup(cls): - super(AgentsAdminTestJSON, cls).resource_setup() - cls.params_agent = cls._param_helper( - hypervisor='common', os='linux', architecture='x86_64', - version='7.0', url='xxx://xxxx/xxx/xxx', - md5hash='add6bb58e139be103324d04d82d8f545') - - @staticmethod - def _param_helper(**kwargs): - rand_key = 'architecture' - if rand_key in kwargs: - # NOTE: The rand_name is for avoiding agent conflicts. - # If you try to create an agent with the same hypervisor, - # os and architecture as an existing agent, Nova will return - # an HTTPConflict or HTTPServerError. - kwargs[rand_key] = data_utils.rand_name(kwargs[rand_key]) - return kwargs - - @decorators.idempotent_id('1fc6bdc8-0b6d-4cc7-9f30-9b04fabe5b90') - def test_create_agent(self): - # Create an agent. - params = self._param_helper( - hypervisor='kvm', os='win', architecture='x86', - version='7.0', url='xxx://xxxx/xxx/xxx', - md5hash='add6bb58e139be103324d04d82d8f545') - body = self.client.create_agent(**params)['agent'] - self.addCleanup(self.client.delete_agent, body['agent_id']) - for expected_item, value in params.items(): - self.assertEqual(value, body[expected_item]) - - @decorators.idempotent_id('dc9ffd51-1c50-4f0e-a820-ae6d2a568a9e') - def test_update_agent(self): - # Create and update an agent. - body = self.client.create_agent(**self.params_agent)['agent'] - self.addCleanup(self.client.delete_agent, body['agent_id']) - agent_id = body['agent_id'] - params = self._param_helper( - version='8.0', url='xxx://xxxx/xxx/xxx2', - md5hash='add6bb58e139be103324d04d82d8f547') - body = self.client.update_agent(agent_id, **params)['agent'] - for expected_item, value in params.items(): - self.assertEqual(value, body[expected_item]) - - @decorators.idempotent_id('470e0b89-386f-407b-91fd-819737d0b335') - def test_delete_agent(self): - # Create an agent and delete it. - body = self.client.create_agent(**self.params_agent)['agent'] - self.client.delete_agent(body['agent_id']) - - # Verify the list doesn't contain the deleted agent. - agents = self.client.list_agents()['agents'] - self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'], - agents)) - - @decorators.idempotent_id('6a326c69-654b-438a-80a3-34bcc454e138') - def test_list_agents(self): - # Create an agent and list all agents. - body = self.client.create_agent(**self.params_agent)['agent'] - self.addCleanup(self.client.delete_agent, body['agent_id']) - agents = self.client.list_agents()['agents'] - self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents) - self.assertIn(body['agent_id'], map(lambda x: x['agent_id'], agents)) - - @decorators.idempotent_id('eabadde4-3cd7-4ec4-a4b5-5a936d2d4408') - def test_list_agents_with_filter(self): - # Create agents and list the agent builds by the filter. - body = self.client.create_agent(**self.params_agent)['agent'] - self.addCleanup(self.client.delete_agent, body['agent_id']) - params = self._param_helper( - hypervisor='xen', os='linux', architecture='x86', - version='7.0', url='xxx://xxxx/xxx/xxx1', - md5hash='add6bb58e139be103324d04d82d8f546') - agent_xen = self.client.create_agent(**params)['agent'] - self.addCleanup(self.client.delete_agent, agent_xen['agent_id']) - - agent_id_xen = agent_xen['agent_id'] - agents = (self.client.list_agents(hypervisor=agent_xen['hypervisor']) - ['agents']) - self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents) - self.assertIn(agent_id_xen, map(lambda x: x['agent_id'], agents)) - self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'], - agents)) diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py deleted file mode 100644 index 902ea9a4a..000000000 --- a/tempest/api/compute/admin/test_aggregates.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright 2013 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class AggregatesAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Aggregates API that require admin privileges""" - - @classmethod - def setup_clients(cls): - super(AggregatesAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.aggregates_client - - @classmethod - def resource_setup(cls): - super(AggregatesAdminTestJSON, cls).resource_setup() - cls.aggregate_name_prefix = 'test_aggregate' - cls.az_name_prefix = 'test_az' - - cls.host = None - hypers = cls.os_admin.hypervisor_client.list_hypervisors( - detail=True)['hypervisors'] - - if CONF.compute.hypervisor_type: - hypers = [hyper for hyper in hypers - if (hyper['hypervisor_type'] == - CONF.compute.hypervisor_type)] - - hosts_available = [hyper['service']['host'] for hyper in hypers - if (hyper['state'] == 'up' and - hyper['status'] == 'enabled')] - if hosts_available: - cls.host = hosts_available[0] - else: - msg = "no available compute node found" - if CONF.compute.hypervisor_type: - msg += " for hypervisor_type %s" % CONF.compute.hypervisor_type - raise testtools.TestCase.failureException(msg) - - def _create_test_aggregate(self, **kwargs): - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name(self.aggregate_name_prefix) - aggregate = self.client.create_aggregate(**kwargs)['aggregate'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.client.delete_aggregate, aggregate['id']) - self.assertEqual(kwargs['name'], aggregate['name']) - - return aggregate - - @decorators.idempotent_id('0d148aa3-d54c-4317-aa8d-42040a475e20') - def test_aggregate_create_delete(self): - # Create and delete an aggregate. - aggregate = self._create_test_aggregate() - self.assertIsNone(aggregate['availability_zone']) - - self.client.delete_aggregate(aggregate['id']) - self.client.wait_for_resource_deletion(aggregate['id']) - - @decorators.idempotent_id('5873a6f8-671a-43ff-8838-7ce430bb6d0b') - def test_aggregate_create_delete_with_az(self): - # Create and delete an aggregate. - az_name = data_utils.rand_name(self.az_name_prefix) - aggregate = self._create_test_aggregate(availability_zone=az_name) - self.assertEqual(az_name, aggregate['availability_zone']) - - self.client.delete_aggregate(aggregate['id']) - self.client.wait_for_resource_deletion(aggregate['id']) - - @decorators.idempotent_id('68089c38-04b1-4758-bdf0-cf0daec4defd') - def test_aggregate_create_verify_entry_in_list(self): - # Create an aggregate and ensure it is listed. - aggregate = self._create_test_aggregate() - aggregates = self.client.list_aggregates()['aggregates'] - self.assertIn((aggregate['id'], aggregate['availability_zone']), - map(lambda x: (x['id'], x['availability_zone']), - aggregates)) - - @decorators.idempotent_id('36ec92ca-7a73-43bc-b920-7531809e8540') - def test_aggregate_create_update_metadata_get_details(self): - # Create an aggregate and ensure its details are returned. - aggregate = self._create_test_aggregate() - body = self.client.show_aggregate(aggregate['id'])['aggregate'] - self.assertEqual(aggregate['name'], body['name']) - self.assertEqual(aggregate['availability_zone'], - body['availability_zone']) - self.assertEqual({}, body["metadata"]) - - # set the metadata of the aggregate - meta = {"key": "value"} - body = self.client.set_metadata(aggregate['id'], metadata=meta) - self.assertEqual(meta, body['aggregate']["metadata"]) - - # verify the metadata has been set - body = self.client.show_aggregate(aggregate['id'])['aggregate'] - self.assertEqual(meta, body["metadata"]) - - @decorators.idempotent_id('4d2b2004-40fa-40a1-aab2-66f4dab81beb') - def test_aggregate_create_update_with_az(self): - # Update an aggregate and ensure properties are updated correctly - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - az_name = data_utils.rand_name(self.az_name_prefix) - aggregate = self._create_test_aggregate( - name=aggregate_name, availability_zone=az_name) - - self.assertEqual(az_name, aggregate['availability_zone']) - self.assertIsNotNone(aggregate['id']) - - aggregate_id = aggregate['id'] - new_aggregate_name = aggregate_name + '_new' - new_az_name = az_name + '_new' - - resp_aggregate = self.client.update_aggregate( - aggregate_id, - name=new_aggregate_name, - availability_zone=new_az_name)['aggregate'] - self.assertEqual(new_aggregate_name, resp_aggregate['name']) - self.assertEqual(new_az_name, resp_aggregate['availability_zone']) - - aggregates = self.client.list_aggregates()['aggregates'] - self.assertIn((aggregate_id, new_aggregate_name, new_az_name), - map(lambda x: - (x['id'], x['name'], x['availability_zone']), - aggregates)) - - @decorators.idempotent_id('c8e85064-e79b-4906-9931-c11c24294d02') - def test_aggregate_add_remove_host(self): - # Add a host to the given aggregate and remove. - self.useFixture(fixtures.LockFixture('availability_zone')) - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - aggregate = self._create_test_aggregate(name=aggregate_name) - - body = (self.client.add_host(aggregate['id'], host=self.host) - ['aggregate']) - self.assertEqual(aggregate_name, body['name']) - self.assertEqual(aggregate['availability_zone'], - body['availability_zone']) - self.assertIn(self.host, body['hosts']) - - body = (self.client.remove_host(aggregate['id'], host=self.host) - ['aggregate']) - self.assertEqual(aggregate_name, body['name']) - self.assertEqual(aggregate['availability_zone'], - body['availability_zone']) - self.assertNotIn(self.host, body['hosts']) - - @decorators.idempotent_id('7f6a1cc5-2446-4cdb-9baa-b6ae0a919b72') - def test_aggregate_add_host_list(self): - # Add a host to the given aggregate and list. - self.useFixture(fixtures.LockFixture('availability_zone')) - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - aggregate = self._create_test_aggregate(name=aggregate_name) - - self.client.add_host(aggregate['id'], host=self.host) - self.addCleanup(self.client.remove_host, aggregate['id'], - host=self.host) - - aggregates = self.client.list_aggregates()['aggregates'] - aggs = [agg for agg in aggregates if agg['id'] == aggregate['id']] - self.assertEqual(1, len(aggs)) - agg = aggs[0] - self.assertEqual(aggregate_name, agg['name']) - self.assertIsNone(agg['availability_zone']) - self.assertIn(self.host, agg['hosts']) - - @decorators.idempotent_id('eeef473c-7c52-494d-9f09-2ed7fc8fc036') - def test_aggregate_add_host_get_details(self): - # Add a host to the given aggregate and get details. - self.useFixture(fixtures.LockFixture('availability_zone')) - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - aggregate = self._create_test_aggregate(name=aggregate_name) - - self.client.add_host(aggregate['id'], host=self.host) - self.addCleanup(self.client.remove_host, aggregate['id'], - host=self.host) - - body = self.client.show_aggregate(aggregate['id'])['aggregate'] - self.assertEqual(aggregate_name, body['name']) - self.assertIsNone(body['availability_zone']) - self.assertIn(self.host, body['hosts']) - - @decorators.idempotent_id('96be03c7-570d-409c-90f8-e4db3c646996') - def test_aggregate_add_host_create_server_with_az(self): - # Add a host to the given aggregate and create a server. - self.useFixture(fixtures.LockFixture('availability_zone')) - az_name = data_utils.rand_name(self.az_name_prefix) - aggregate = self._create_test_aggregate(availability_zone=az_name) - - self.client.add_host(aggregate['id'], host=self.host) - self.addCleanup(self.client.remove_host, aggregate['id'], - host=self.host) - admin_servers_client = self.os_admin.servers_client - server = self.create_test_server(availability_zone=az_name, - wait_until='ACTIVE') - body = admin_servers_client.show_server(server['id'])['server'] - self.assertEqual(self.host, body['OS-EXT-SRV-ATTR:host']) diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py deleted file mode 100644 index 41be620d4..000000000 --- a/tempest/api/compute/admin/test_aggregates_negative.py +++ /dev/null @@ -1,180 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class AggregatesAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Aggregates API that require admin privileges""" - - @classmethod - def setup_clients(cls): - super(AggregatesAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_admin.aggregates_client - cls.user_client = cls.aggregates_client - - @classmethod - def resource_setup(cls): - super(AggregatesAdminNegativeTestJSON, cls).resource_setup() - cls.aggregate_name_prefix = 'test_aggregate' - - hosts_all = cls.os_admin.hosts_client.list_hosts()['hosts'] - hosts = ([host['host_name'] - for host in hosts_all if host['service'] == 'compute']) - cls.host = hosts[0] - - def _create_test_aggregate(self): - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - aggregate = (self.client.create_aggregate(name=aggregate_name) - ['aggregate']) - self.addCleanup(self.client.delete_aggregate, aggregate['id']) - return aggregate - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('86a1cb14-da37-4a70-b056-903fd56dfe29') - def test_aggregate_create_as_user(self): - # Regular user is not allowed to create an aggregate. - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - self.assertRaises(lib_exc.Forbidden, - self.user_client.create_aggregate, - name=aggregate_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3b8a1929-3793-4e92-bcb4-dfa572ee6c1d') - def test_aggregate_create_aggregate_name_length_less_than_1(self): - # the length of aggregate name should >= 1 and <=255 - self.assertRaises(lib_exc.BadRequest, - self.client.create_aggregate, - name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4c194563-543b-4e70-a719-557bbe947fac') - def test_aggregate_create_aggregate_name_length_exceeds_255(self): - # the length of aggregate name should >= 1 and <=255 - aggregate_name = 'a' * 256 - self.assertRaises(lib_exc.BadRequest, - self.client.create_aggregate, - name=aggregate_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9c23a291-b0b1-487b-b464-132e061151b3') - def test_aggregate_create_with_existent_aggregate_name(self): - # creating an aggregate with existent aggregate name is forbidden - aggregate = self._create_test_aggregate() - self.assertRaises(lib_exc.Conflict, - self.client.create_aggregate, - name=aggregate['name']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('cd6de795-c15d-45f1-8d9e-813c6bb72a3d') - def test_aggregate_delete_as_user(self): - # Regular user is not allowed to delete an aggregate. - aggregate = self._create_test_aggregate() - self.assertRaises(lib_exc.Forbidden, - self.user_client.delete_aggregate, - aggregate['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b7d475a6-5dcd-4ff4-b70a-cd9de66a6672') - def test_aggregate_list_as_user(self): - # Regular user is not allowed to list aggregates. - self.assertRaises(lib_exc.Forbidden, - self.user_client.list_aggregates) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('557cad12-34c9-4ff4-95f0-22f0dfbaf7dc') - def test_aggregate_get_details_as_user(self): - # Regular user is not allowed to get aggregate details. - aggregate = self._create_test_aggregate() - self.assertRaises(lib_exc.Forbidden, - self.user_client.show_aggregate, - aggregate['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c74f4bf1-4708-4ff2-95a0-f49eaca951bd') - def test_aggregate_delete_with_invalid_id(self): - # Delete an aggregate with invalid id should raise exceptions. - self.assertRaises(lib_exc.NotFound, - self.client.delete_aggregate, -1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3c916244-2c46-49a4-9b55-b20bb0ae512c') - def test_aggregate_get_details_with_invalid_id(self): - # Get aggregate details with invalid id should raise exceptions. - self.assertRaises(lib_exc.NotFound, - self.client.show_aggregate, -1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0ef07828-12b4-45ba-87cc-41425faf5711') - def test_aggregate_add_non_exist_host(self): - # Adding a non-exist host to an aggregate should raise exceptions. - hosts_all = self.os_admin.hosts_client.list_hosts()['hosts'] - hosts = map(lambda x: x['host_name'], hosts_all) - while True: - non_exist_host = data_utils.rand_name('nonexist_host') - if non_exist_host not in hosts: - break - aggregate = self._create_test_aggregate() - self.assertRaises(lib_exc.NotFound, self.client.add_host, - aggregate['id'], host=non_exist_host) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7324c334-bd13-4c93-8521-5877322c3d51') - def test_aggregate_add_host_as_user(self): - # Regular user is not allowed to add a host to an aggregate. - aggregate = self._create_test_aggregate() - self.assertRaises(lib_exc.Forbidden, - self.user_client.add_host, - aggregate['id'], host=self.host) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('19dd44e1-c435-4ee1-a402-88c4f90b5950') - def test_aggregate_add_existent_host(self): - self.useFixture(fixtures.LockFixture('availability_zone')) - aggregate = self._create_test_aggregate() - - self.client.add_host(aggregate['id'], host=self.host) - self.addCleanup(self.client.remove_host, aggregate['id'], - host=self.host) - - self.assertRaises(lib_exc.Conflict, self.client.add_host, - aggregate['id'], host=self.host) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7a53af20-137a-4e44-a4ae-e19260e626d9') - def test_aggregate_remove_host_as_user(self): - # Regular user is not allowed to remove a host from an aggregate. - self.useFixture(fixtures.LockFixture('availability_zone')) - aggregate = self._create_test_aggregate() - - self.client.add_host(aggregate['id'], host=self.host) - self.addCleanup(self.client.remove_host, aggregate['id'], - host=self.host) - - self.assertRaises(lib_exc.Forbidden, - self.user_client.remove_host, - aggregate['id'], host=self.host) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('95d6a6fa-8da9-4426-84d0-eec0329f2e4d') - def test_aggregate_remove_nonexistent_host(self): - aggregate = self._create_test_aggregate() - - self.assertRaises(lib_exc.NotFound, self.client.remove_host, - aggregate['id'], host='nonexist_host') diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py deleted file mode 100644 index 83fe21531..000000000 --- a/tempest/api/compute/admin/test_auto_allocate_network.py +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright 2016 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common import credentials_factory as credentials -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_excs -from tempest import test - -CONF = config.CONF -LOG = log.getLogger(__name__) - - -# NOTE(mriedem): This is in the admin directory only because it requires -# force_tenant_isolation=True, but doesn't extend BaseV2ComputeAdminTest -# because it doesn't actually use any admin credentials in the tests. -class AutoAllocateNetworkTest(base.BaseV2ComputeTest): - """Tests auto-allocating networks with the v2.37 microversion. - - These tests rely on Neutron being enabled. Also, the tenant must not have - any network resources available to it so we can make sure that Nova - calls to Neutron to automatically allocate the network topology. - """ - - force_tenant_isolation = True - - min_microversion = '2.37' - max_microversion = 'latest' - - @classmethod - def skip_checks(cls): - super(AutoAllocateNetworkTest, cls).skip_checks() - identity_version = cls.get_identity_version() - if not credentials.is_admin_available( - identity_version=identity_version): - msg = "Missing Identity Admin API credentials in configuration." - raise cls.skipException(msg) - if not CONF.service_available.neutron: - raise cls.skipException('Neutron is required') - if not test.is_extension_enabled('auto-allocated-topology', 'network'): - raise cls.skipException( - 'auto-allocated-topology extension is not available') - - @classmethod - def setup_credentials(cls): - # Do not create network resources for these tests. - cls.set_network_resources() - super(AutoAllocateNetworkTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(AutoAllocateNetworkTest, cls).setup_clients() - cls.networks_client = cls.os_primary.networks_client - cls.routers_client = cls.os_primary.routers_client - cls.subnets_client = cls.os_primary.subnets_client - cls.ports_client = cls.os_primary.ports_client - - @classmethod - def resource_setup(cls): - super(AutoAllocateNetworkTest, cls).resource_setup() - # Sanity check that there are no networks available to the tenant. - # This is essentially what Nova does for getting available networks. - tenant_id = cls.networks_client.tenant_id - # (1) Retrieve non-public network list owned by the tenant. - search_opts = {'tenant_id': tenant_id, 'shared': False} - nets = cls.networks_client.list_networks( - **search_opts).get('networks', []) - if nets: - raise lib_excs.TempestException( - 'Found tenant networks: %s' % nets) - # (2) Retrieve shared network list. - search_opts = {'shared': True} - nets = cls.networks_client.list_networks( - **search_opts).get('networks', []) - if nets: - raise lib_excs.TempestException( - 'Found shared networks: %s' % nets) - - @classmethod - def resource_cleanup(cls): - """Deletes any auto_allocated_network and it's associated resources.""" - - # Find the auto-allocated router for the tenant. - # This is a bit hacky since we don't have a great way to find the - # auto-allocated router given the private tenant network we have. - routers = cls.routers_client.list_routers().get('routers', []) - if len(routers) > 1: - # This indicates a race where nova is concurrently calling the - # neutron auto-allocated-topology API for multiple server builds - # at the same time (it's called from nova-compute when setting up - # networking for a server). Neutron will detect duplicates and - # automatically clean them up, but there is a window where the API - # can return multiple and we don't have a good way to filter those - # out right now, so we'll just handle them. - LOG.info('(%s) Found more than one router for tenant.', - test_utils.find_test_caller()) - - # Remove any networks, duplicate or otherwise, that these tests - # created. All such networks will be in the current tenant. Neutron - # will cleanup duplicate resources automatically, so ignore 404s. - search_opts = {'tenant_id': cls.networks_client.tenant_id} - networks = cls.networks_client.list_networks( - **search_opts).get('networks', []) - - for router in routers: - # Disassociate the subnets from the router. Because of the race - # mentioned above the subnets might not be associated with the - # router so ignore any 404. - for network in networks: - for subnet_id in network['subnets']: - test_utils.call_and_ignore_notfound_exc( - cls.routers_client.remove_router_interface, - router['id'], subnet_id=subnet_id) - - # Delete the router. - cls.routers_client.delete_router(router['id']) - - for network in networks: - # Get and delete the ports for the given network. - ports = cls.ports_client.list_ports( - network_id=network['id']).get('ports', []) - for port in ports: - test_utils.call_and_ignore_notfound_exc( - cls.ports_client.delete_port, port['id']) - - # Delete the subnets. - for subnet_id in network['subnets']: - test_utils.call_and_ignore_notfound_exc( - cls.subnets_client.delete_subnet, subnet_id) - - # Delete the network. - test_utils.call_and_ignore_notfound_exc( - cls.networks_client.delete_network, network['id']) - - @decorators.idempotent_id('5eb7b8fa-9c23-47a2-9d7d-02ed5809dd34') - def test_server_create_no_allocate(self): - """Tests that no networking is allocated for the server.""" - # create the server with no networking - server, _ = compute.create_test_server( - self.os_primary, networks='none', wait_until='ACTIVE') - self.addCleanup(self.delete_server, server['id']) - # get the server ips - addresses = self.servers_client.list_addresses( - server['id'])['addresses'] - # assert that there is no networking - self.assertEqual({}, addresses) - - @decorators.idempotent_id('2e6cf129-9e28-4e8a-aaaa-045ea826b2a6') - def test_server_multi_create_auto_allocate(self): - """Tests that networking is auto-allocated for multiple servers.""" - - # Create multiple servers with auto networking to make sure the - # automatic network allocation is atomic. Using a minimum of three - # servers is essential for this scenario because: - # - # - First request sees no networks for the tenant so it auto-allocates - # one from Neutron, let's call that net1. - # - Second request sees no networks for the tenant so it auto-allocates - # one from Neutron. Neutron creates net2 but sees it's a duplicate - # so it queues net2 for deletion and returns net1 from the API and - # Nova uses that for the second server request. - # - Third request sees net1 and net2 for the tenant and fails with a - # NetworkAmbiguous 400 error. - _, servers = compute.create_test_server( - self.os_primary, networks='auto', wait_until='ACTIVE', - min_count=3) - server_nets = set() - for server in servers: - self.addCleanup(self.delete_server, server['id']) - # get the server ips - addresses = self.servers_client.list_addresses( - server['id'])['addresses'] - # assert that there is networking (should only be one) - self.assertEqual(1, len(addresses)) - server_nets.add(list(addresses.keys())[0]) - # all servers should be on the same network - self.assertEqual(1, len(server_nets)) - - # List the networks for the tenant; we filter on admin_state_up=True - # because the auto-allocated-topology code in Neutron won't set that - # to True until the network is ready and is returned from the API. - # Duplicate networks created from a race should have - # admin_state_up=False. - search_opts = {'tenant_id': self.networks_client.tenant_id, - 'shared': False, - 'admin_state_up': True} - nets = self.networks_client.list_networks( - **search_opts).get('networks', []) - self.assertEqual(1, len(nets)) - # verify the single private tenant network is the one that the servers - # are using also - self.assertIn(nets[0]['name'], server_nets) diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py deleted file mode 100644 index bbd39b685..000000000 --- a/tempest/api/compute/admin/test_availability_zone.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators - - -class AZAdminV2TestJSON(base.BaseV2ComputeAdminTest): - """Tests Availability Zone API List""" - - @classmethod - def setup_clients(cls): - super(AZAdminV2TestJSON, cls).setup_clients() - cls.client = cls.availability_zone_admin_client - - @decorators.idempotent_id('d3431479-8a09-4f76-aa2d-26dc580cb27c') - def test_get_availability_zone_list(self): - # List of availability zone - availability_zone = self.client.list_availability_zones() - self.assertNotEmpty(availability_zone['availabilityZoneInfo']) - - @decorators.idempotent_id('ef726c58-530f-44c2-968c-c7bed22d5b8c') - def test_get_availability_zone_list_detail(self): - # List of availability zones and available services - availability_zone = self.client.list_availability_zones(detail=True) - self.assertNotEmpty(availability_zone['availabilityZoneInfo']) diff --git a/tempest/api/compute/admin/test_availability_zone_negative.py b/tempest/api/compute/admin/test_availability_zone_negative.py deleted file mode 100644 index a58c22cb2..000000000 --- a/tempest/api/compute/admin/test_availability_zone_negative.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2013 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class AZAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Availability Zone API List""" - - @classmethod - def setup_clients(cls): - super(AZAdminNegativeTestJSON, cls).setup_clients() - cls.non_adm_client = cls.availability_zone_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bf34dca2-fdc3-4073-9c02-7648d9eae0d7') - def test_get_availability_zone_list_detail_with_non_admin_user(self): - # List of availability zones and available services with - # non-administrator user - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.list_availability_zones, detail=True) diff --git a/tempest/api/compute/admin/test_create_server.py b/tempest/api/compute/admin/test_create_server.py deleted file mode 100644 index 3449aba2b..000000000 --- a/tempest/api/compute/admin/test_create_server.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest.common.utils.linux import remote_client -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest): - disk_config = 'AUTO' - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(ServersWithSpecificFlavorTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServersWithSpecificFlavorTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - - super(ServersWithSpecificFlavorTestJSON, cls).resource_setup() - - @decorators.idempotent_id('b3c7bcfc-bb5b-4e22-b517-c7f686b802ca') - @testtools.skipUnless(CONF.validation.run_validation, - 'Instance validation tests are disabled.') - def test_verify_created_server_ephemeral_disk(self): - # Verify that the ephemeral disk is created when creating server - flavor_base = self.flavors_client.show_flavor( - self.flavor_ref)['flavor'] - - def create_flavor_with_ephemeral(ephem_disk): - name = 'flavor_with_ephemeral_%s' % ephem_disk - flavor_name = data_utils.rand_name(name) - - ram = flavor_base['ram'] - vcpus = flavor_base['vcpus'] - disk = flavor_base['disk'] - - # Create a flavor with ephemeral disk - flavor = self.create_flavor(name=flavor_name, ram=ram, vcpus=vcpus, - disk=disk, ephemeral=ephem_disk) - return flavor['id'] - - flavor_with_eph_disk_id = create_flavor_with_ephemeral(ephem_disk=1) - flavor_no_eph_disk_id = create_flavor_with_ephemeral(ephem_disk=0) - - admin_pass = self.image_ssh_password - - server_no_eph_disk = self.create_test_server( - validatable=True, - wait_until='ACTIVE', - adminPass=admin_pass, - flavor=flavor_no_eph_disk_id) - - # Get partition number of server without ephemeral disk. - server_no_eph_disk = self.client.show_server( - server_no_eph_disk['id'])['server'] - linux_client = remote_client.RemoteClient( - self.get_server_ip(server_no_eph_disk), - self.ssh_user, - admin_pass, - self.validation_resources['keypair']['private_key'], - server=server_no_eph_disk, - servers_client=self.client) - disks_num = len(linux_client.get_disks().split('\n')) - - # Explicit server deletion necessary for Juno compatibility - self.client.delete_server(server_no_eph_disk['id']) - - server_with_eph_disk = self.create_test_server( - validatable=True, - wait_until='ACTIVE', - adminPass=admin_pass, - flavor=flavor_with_eph_disk_id) - - server_with_eph_disk = self.client.show_server( - server_with_eph_disk['id'])['server'] - linux_client = remote_client.RemoteClient( - self.get_server_ip(server_with_eph_disk), - self.ssh_user, - admin_pass, - self.validation_resources['keypair']['private_key'], - server=server_with_eph_disk, - servers_client=self.client) - disks_num_eph = len(linux_client.get_disks().split('\n')) - self.assertEqual(disks_num + 1, disks_num_eph) diff --git a/tempest/api/compute/admin/test_delete_server.py b/tempest/api/compute/admin/test_delete_server.py deleted file mode 100644 index 83444b90d..000000000 --- a/tempest/api/compute/admin/test_delete_server.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class DeleteServersAdminTestJSON(base.BaseV2ComputeAdminTest): - # NOTE: Server creations of each test class should be under 10 - # for preventing "Quota exceeded for instances". - - @classmethod - def setup_clients(cls): - super(DeleteServersAdminTestJSON, cls).setup_clients() - cls.non_admin_client = cls.servers_client - cls.admin_client = cls.os_admin.servers_client - - @decorators.idempotent_id('99774678-e072-49d1-9d2a-49a59bc56063') - def test_delete_server_while_in_error_state(self): - # Delete a server while it's VM state is error - server = self.create_test_server(wait_until='ACTIVE') - self.admin_client.reset_state(server['id'], state='error') - # Verify server's state - server = self.non_admin_client.show_server(server['id'])['server'] - self.assertEqual(server['status'], 'ERROR') - self.non_admin_client.delete_server(server['id']) - waiters.wait_for_server_termination(self.servers_client, - server['id'], - ignore_error=True) - - @decorators.idempotent_id('73177903-6737-4f27-a60c-379e8ae8cf48') - def test_admin_delete_servers_of_others(self): - # Administrator can delete servers of others - server = self.create_test_server(wait_until='ACTIVE') - self.admin_client.delete_server(server['id']) - waiters.wait_for_server_termination(self.servers_client, server['id']) diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py deleted file mode 100644 index 1e09eeb44..000000000 --- a/tempest/api/compute/admin/test_fixed_ips.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2013 IBM Corp -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class FixedIPsTestJson(base.BaseV2ComputeAdminTest): - - @classmethod - def skip_checks(cls): - super(FixedIPsTestJson, cls).skip_checks() - if CONF.service_available.neutron: - msg = ("%s skipped as neutron is available" % cls.__name__) - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(FixedIPsTestJson, cls).setup_clients() - cls.client = cls.os_admin.fixed_ips_client - - @classmethod - def resource_setup(cls): - super(FixedIPsTestJson, cls).resource_setup() - server = cls.create_test_server(wait_until='ACTIVE') - server = cls.servers_client.show_server(server['id'])['server'] - for ip_set in server['addresses']: - for ip in server['addresses'][ip_set]: - if ip['OS-EXT-IPS:type'] == 'fixed': - cls.ip = ip['addr'] - break - if cls.ip: - break - - @decorators.idempotent_id('16b7d848-2f7c-4709-85a3-2dfb4576cc52') - @test.services('network') - def test_list_fixed_ip_details(self): - fixed_ip = self.client.show_fixed_ip(self.ip) - self.assertEqual(fixed_ip['fixed_ip']['address'], self.ip) - - @decorators.idempotent_id('5485077b-7e46-4cec-b402-91dc3173433b') - @test.services('network') - def test_set_reserve(self): - self.client.reserve_fixed_ip(self.ip, reserve="None") - - @decorators.idempotent_id('7476e322-b9ff-4710-bf82-49d51bac6e2e') - @test.services('network') - def test_set_unreserve(self): - self.client.reserve_fixed_ip(self.ip, unreserve="None") diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py deleted file mode 100644 index a77011e6a..000000000 --- a/tempest/api/compute/admin/test_fixed_ips_negative.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2013 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FixedIPsNegativeTestJson(base.BaseV2ComputeAdminTest): - - @classmethod - def skip_checks(cls): - super(FixedIPsNegativeTestJson, cls).skip_checks() - if CONF.service_available.neutron: - msg = ("%s skipped as neutron is available" % cls.__name__) - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(FixedIPsNegativeTestJson, cls).setup_clients() - cls.client = cls.os_admin.fixed_ips_client - cls.non_admin_client = cls.fixed_ips_client - - @classmethod - def resource_setup(cls): - super(FixedIPsNegativeTestJson, cls).resource_setup() - server = cls.create_test_server(wait_until='ACTIVE') - server = cls.servers_client.show_server(server['id'])['server'] - for ip_set in server['addresses']: - for ip in server['addresses'][ip_set]: - if ip['OS-EXT-IPS:type'] == 'fixed': - cls.ip = ip['addr'] - break - if cls.ip: - break - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9f17f47d-daad-4adc-986e-12370c93e407') - @test.services('network') - def test_list_fixed_ip_details_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.show_fixed_ip, self.ip) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ce60042c-fa60-4836-8d43-1c8e3359dc47') - @test.services('network') - def test_set_reserve_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.reserve_fixed_ip, - self.ip, reserve="None") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f1f7a35b-0390-48c5-9803-5f27461439db') - @test.services('network') - def test_set_unreserve_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.reserve_fixed_ip, - self.ip, unreserve="None") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f51cf464-7fc5-4352-bc3e-e75cfa2cb717') - @test.services('network') - def test_set_reserve_with_invalid_ip(self): - # NOTE(maurosr): since this exercises the same code snippet, we do it - # only for reserve action - # NOTE(eliqiao): in Juno, the exception is NotFound, but in master, we - # change the error code to BadRequest, both exceptions should be - # accepted by tempest - self.assertRaises((lib_exc.NotFound, lib_exc.BadRequest), - self.client.reserve_fixed_ip, - "my.invalid.ip", reserve="None") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fd26ef50-f135-4232-9d32-281aab3f9176') - @test.services('network') - def test_fixed_ip_with_invalid_action(self): - self.assertRaises(lib_exc.BadRequest, - self.client.reserve_fixed_ip, - self.ip, invalid_action="None") diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py deleted file mode 100644 index 36ebc252f..000000000 --- a/tempest/api/compute/admin/test_flavors.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import uuid - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class FlavorsAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Flavors API Create and Delete that require admin privileges""" - - @classmethod - def skip_checks(cls): - super(FlavorsAdminTestJSON, cls).skip_checks() - if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): - msg = "OS-FLV-EXT-DATA extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(FlavorsAdminTestJSON, cls).resource_setup() - - cls.flavor_name_prefix = 'test_flavor_' - cls.ram = 512 - cls.vcpus = 1 - cls.disk = 10 - cls.ephemeral = 10 - cls.swap = 1024 - cls.rxtx = 2 - - @decorators.idempotent_id('8b4330e1-12c4-4554-9390-e6639971f086') - def test_create_flavor_with_int_id(self): - flavor_id = data_utils.rand_int_id(start=1000) - new_flavor_id = self.create_flavor(ram=self.ram, - vcpus=self.vcpus, - disk=self.disk, - id=flavor_id)['id'] - self.assertEqual(new_flavor_id, str(flavor_id)) - - @decorators.idempotent_id('94c9bb4e-2c2a-4f3c-bb1f-5f0daf918e6d') - def test_create_flavor_with_uuid_id(self): - flavor_id = data_utils.rand_uuid() - new_flavor_id = self.create_flavor(ram=self.ram, - vcpus=self.vcpus, - disk=self.disk, - id=flavor_id)['id'] - self.assertEqual(new_flavor_id, flavor_id) - - @decorators.idempotent_id('f83fe669-6758-448a-a85e-32d351f36fe0') - def test_create_flavor_with_none_id(self): - # If nova receives a request with None as flavor_id, - # nova generates flavor_id of uuid. - flavor_id = None - new_flavor_id = self.create_flavor(ram=self.ram, - vcpus=self.vcpus, - disk=self.disk, - id=flavor_id)['id'] - self.assertEqual(new_flavor_id, str(uuid.UUID(new_flavor_id))) - - @decorators.idempotent_id('8261d7b0-be58-43ec-a2e5-300573c3f6c5') - def test_create_flavor_verify_entry_in_list_details(self): - # Create a flavor and ensure it's details are listed - # This operation requires the user to have 'admin' role - flavor_name = data_utils.rand_name(self.flavor_name_prefix) - - # Create the flavor - self.create_flavor(name=flavor_name, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - ephemeral=self.ephemeral, - swap=self.swap, - rxtx_factor=self.rxtx) - - # Check if flavor is present in list - flavors_list = self.admin_flavors_client.list_flavors( - detail=True)['flavors'] - self.assertIn(flavor_name, [f['name'] for f in flavors_list]) - - @decorators.idempotent_id('63dc64e6-2e79-4fdf-868f-85500d308d66') - def test_create_list_flavor_without_extra_data(self): - # Create a flavor and ensure it is listed - # This operation requires the user to have 'admin' role - - def verify_flavor_response_extension(flavor): - # check some extensions for the flavor create/show/detail response - self.assertEqual(flavor['swap'], '') - self.assertEqual(int(flavor['rxtx_factor']), 1) - self.assertEqual(flavor['OS-FLV-EXT-DATA:ephemeral'], 0) - self.assertEqual(flavor['os-flavor-access:is_public'], True) - - flavor_name = data_utils.rand_name(self.flavor_name_prefix) - new_flavor_id = data_utils.rand_int_id(start=1000) - - # Create the flavor - flavor = self.create_flavor(name=flavor_name, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - id=new_flavor_id) - self.assertEqual(flavor['name'], flavor_name) - self.assertEqual(flavor['ram'], self.ram) - self.assertEqual(flavor['vcpus'], self.vcpus) - self.assertEqual(flavor['disk'], self.disk) - self.assertEqual(int(flavor['id']), new_flavor_id) - verify_flavor_response_extension(flavor) - - # Verify flavor is retrieved - flavor = self.admin_flavors_client.show_flavor(new_flavor_id)['flavor'] - self.assertEqual(flavor['name'], flavor_name) - verify_flavor_response_extension(flavor) - - # Check if flavor is present in list - flavors_list = [ - f for f in self.flavors_client.list_flavors(detail=True)['flavors'] - if f['name'] == flavor_name - ] - self.assertNotEmpty(flavors_list) - verify_flavor_response_extension(flavors_list[0]) - - @decorators.idempotent_id('be6cc18c-7c5d-48c0-ac16-17eaf03c54eb') - def test_list_non_public_flavor(self): - # Create a flavor with os-flavor-access:is_public false. - # The flavor should not be present in list_details as the - # tenant is not automatically added access list. - # This operation requires the user to have 'admin' role - flavor_name = data_utils.rand_name(self.flavor_name_prefix) - - # Create the flavor - self.create_flavor(name=flavor_name, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - is_public="False") - # Verify flavor is not retrieved - flavors_list = self.admin_flavors_client.list_flavors( - detail=True)['flavors'] - self.assertNotIn(flavor_name, [f['name'] for f in flavors_list]) - - # Verify flavor is not retrieved with other user - flavors_list = self.flavors_client.list_flavors(detail=True)['flavors'] - self.assertNotIn(flavor_name, [f['name'] for f in flavors_list]) - - @decorators.idempotent_id('bcc418ef-799b-47cc-baa1-ce01368b8987') - def test_create_server_with_non_public_flavor(self): - # Create a flavor with os-flavor-access:is_public false - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - is_public="False") - - # Verify flavor is not used by other user - self.assertRaises(lib_exc.BadRequest, - self.os_primary.servers_client.create_server, - name='test', imageRef=self.image_ref, - flavorRef=flavor['id']) - - @decorators.idempotent_id('b345b196-bfbd-4231-8ac1-6d7fe15ff3a3') - def test_list_public_flavor_with_other_user(self): - # Create a Flavor with public access. - # Try to List/Get flavor with another user - flavor_name = data_utils.rand_name(self.flavor_name_prefix) - - # Create the flavor - self.create_flavor(name=flavor_name, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - is_public="True") - # Verify flavor is retrieved with new user - flavors_list = self.flavors_client.list_flavors(detail=True)['flavors'] - self.assertIn(flavor_name, [f['name'] for f in flavors_list]) - - @decorators.idempotent_id('fb9cbde6-3a0e-41f2-a983-bdb0a823c44e') - def test_is_public_string_variations(self): - flavor_name_not_public = data_utils.rand_name(self.flavor_name_prefix) - flavor_name_public = data_utils.rand_name(self.flavor_name_prefix) - - # Create a non public flavor - self.create_flavor(name=flavor_name_not_public, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - is_public="False") - - # Create a public flavor - self.create_flavor(name=flavor_name_public, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - is_public="True") - - def _test_string_variations(variations, flavor_name): - for string in variations: - params = {'is_public': string} - flavors = (self.admin_flavors_client.list_flavors(detail=True, - **params) - ['flavors']) - self.assertIn(flavor_name, [f['name'] for f in flavors]) - - _test_string_variations(['f', 'false', 'no', '0'], - flavor_name_not_public) - - _test_string_variations(['t', 'true', 'yes', '1'], - flavor_name_public) - - @decorators.idempotent_id('3b541a2e-2ac2-4b42-8b8d-ba6e22fcd4da') - def test_create_flavor_using_string_ram(self): - new_flavor_id = data_utils.rand_int_id(start=1000) - - ram = "1024" - flavor = self.create_flavor(ram=ram, vcpus=self.vcpus, - disk=self.disk, - id=new_flavor_id) - self.assertEqual(flavor['ram'], int(ram)) - self.assertEqual(int(flavor['id']), new_flavor_id) diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py deleted file mode 100644 index 2c236ec71..000000000 --- a/tempest/api/compute/admin/test_flavors_access.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2013 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest import test - - -class FlavorsAccessTestJSON(base.BaseV2ComputeAdminTest): - """Tests Flavor Access API extension. - - Add and remove Flavor Access require admin privileges. - """ - - @classmethod - def skip_checks(cls): - super(FlavorsAccessTestJSON, cls).skip_checks() - if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): - msg = "OS-FLV-EXT-DATA extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(FlavorsAccessTestJSON, cls).resource_setup() - - # Non admin tenant ID - cls.tenant_id = cls.flavors_client.tenant_id - cls.ram = 512 - cls.vcpus = 1 - cls.disk = 10 - - @decorators.idempotent_id('ea2c2211-29fa-4db9-97c3-906d36fad3e0') - def test_flavor_access_list_with_private_flavor(self): - # Test to make sure that list flavor access on a newly created - # private flavor will return an empty access list - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - - flavor_access = (self.admin_flavors_client.list_flavor_access( - flavor['id'])['flavor_access']) - self.assertEmpty(flavor_access) - - @decorators.idempotent_id('59e622f6-bdf6-45e3-8ba8-fedad905a6b4') - def test_flavor_access_add_remove(self): - # Test to add and remove flavor access to a given tenant. - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - - # Add flavor access to a tenant. - resp_body = { - "tenant_id": str(self.tenant_id), - "flavor_id": str(flavor['id']), - } - add_body = (self.admin_flavors_client.add_flavor_access( - flavor['id'], self.tenant_id)['flavor_access']) - self.assertIn(resp_body, add_body) - - # The flavor is present in list. - flavors = self.flavors_client.list_flavors(detail=True)['flavors'] - self.assertIn(flavor['id'], map(lambda x: x['id'], flavors)) - - # Remove flavor access from a tenant. - remove_body = (self.admin_flavors_client.remove_flavor_access( - flavor['id'], self.tenant_id)['flavor_access']) - self.assertNotIn(resp_body, remove_body) - - # The flavor is not present in list. - flavors = self.flavors_client.list_flavors(detail=True)['flavors'] - self.assertNotIn(flavor['id'], map(lambda x: x['id'], flavors)) diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py deleted file mode 100644 index be165cb2f..000000000 --- a/tempest/api/compute/admin/test_flavors_access_negative.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2013 IBM Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class FlavorsAccessNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Flavor Access API extension. - - Add and remove Flavor Access require admin privileges. - """ - - credentials = ['primary', 'admin', 'alt'] - - @classmethod - def skip_checks(cls): - super(FlavorsAccessNegativeTestJSON, cls).skip_checks() - if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): - msg = "OS-FLV-EXT-DATA extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(FlavorsAccessNegativeTestJSON, cls).resource_setup() - - cls.tenant_id = cls.flavors_client.tenant_id - cls.ram = 512 - cls.vcpus = 1 - cls.disk = 10 - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0621c53e-d45d-40e7-951d-43e5e257b272') - def test_flavor_access_list_with_public_flavor(self): - # Test to list flavor access with exceptions by querying public flavor - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='True') - self.assertRaises(lib_exc.NotFound, - self.admin_flavors_client.list_flavor_access, - flavor['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('41eaaade-6d37-4f28-9c74-f21b46ca67bd') - def test_flavor_non_admin_add(self): - # Test to add flavor access as a user without admin privileges. - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - self.assertRaises(lib_exc.Forbidden, - self.flavors_client.add_flavor_access, - flavor['id'], - self.tenant_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('073e79a6-c311-4525-82dc-6083d919cb3a') - def test_flavor_non_admin_remove(self): - # Test to remove flavor access as a user without admin privileges. - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - - # Add flavor access to a tenant. - self.admin_flavors_client.add_flavor_access(flavor['id'], - self.tenant_id) - self.addCleanup(self.admin_flavors_client.remove_flavor_access, - flavor['id'], self.tenant_id) - self.assertRaises(lib_exc.Forbidden, - self.flavors_client.remove_flavor_access, - flavor['id'], - self.tenant_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f3592cc0-0306-483c-b210-9a7b5346eddc') - def test_add_flavor_access_duplicate(self): - # Create a new flavor. - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - - # Add flavor access to a tenant. - self.admin_flavors_client.add_flavor_access(flavor['id'], - self.tenant_id) - self.addCleanup(self.admin_flavors_client.remove_flavor_access, - flavor['id'], self.tenant_id) - - # An exception should be raised when adding flavor access to the same - # tenant - self.assertRaises(lib_exc.Conflict, - self.admin_flavors_client.add_flavor_access, - flavor['id'], - self.tenant_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1f710927-3bc7-4381-9f82-0ca6e42644b7') - def test_remove_flavor_access_not_found(self): - # Create a new flavor. - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - - # An exception should be raised when flavor access is not found - self.assertRaises(lib_exc.NotFound, - self.admin_flavors_client.remove_flavor_access, - flavor['id'], - self.os_alt.servers_client.tenant_id) diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py deleted file mode 100644 index 747cb42da..000000000 --- a/tempest/api/compute/admin/test_flavors_extra_specs.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class FlavorsExtraSpecsTestJSON(base.BaseV2ComputeAdminTest): - """Tests Flavor Extra Spec API extension. - - SET, UNSET, UPDATE Flavor Extra specs require admin privileges. - GET Flavor Extra specs can be performed even by without admin privileges. - """ - - @classmethod - def skip_checks(cls): - super(FlavorsExtraSpecsTestJSON, cls).skip_checks() - if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): - msg = "OS-FLV-EXT-DATA extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(FlavorsExtraSpecsTestJSON, cls).resource_setup() - flavor_name = data_utils.rand_name('test_flavor') - ram = 512 - vcpus = 1 - disk = 10 - ephemeral = 10 - new_flavor_id = data_utils.rand_int_id(start=1000) - swap = 1024 - rxtx = 1 - # Create a flavor so as to set/get/unset extra specs - cls.flavor = cls.admin_flavors_client.create_flavor( - name=flavor_name, - ram=ram, vcpus=vcpus, - disk=disk, - id=new_flavor_id, - ephemeral=ephemeral, - swap=swap, - rxtx_factor=rxtx)['flavor'] - - @classmethod - def resource_cleanup(cls): - cls.admin_flavors_client.delete_flavor(cls.flavor['id']) - cls.admin_flavors_client.wait_for_resource_deletion(cls.flavor['id']) - super(FlavorsExtraSpecsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('0b2f9d4b-1ca2-4b99-bb40-165d4bb94208') - def test_flavor_set_get_update_show_unset_keys(self): - # Test to SET, GET, UPDATE, SHOW, UNSET flavor extra - # spec as a user with admin privileges. - # Assigning extra specs values that are to be set - specs = {"key1": "value1", "key2": "value2"} - # SET extra specs to the flavor created in setUp - set_body = self.admin_flavors_client.set_flavor_extra_spec( - self.flavor['id'], **specs)['extra_specs'] - self.assertEqual(set_body, specs) - # GET extra specs and verify - get_body = (self.admin_flavors_client.list_flavor_extra_specs( - self.flavor['id'])['extra_specs']) - self.assertEqual(get_body, specs) - - # UPDATE the value of the extra specs key1 - update_body = \ - self.admin_flavors_client.update_flavor_extra_spec( - self.flavor['id'], "key1", key1="value") - self.assertEqual({"key1": "value"}, update_body) - - # GET extra specs and verify the value of the key2 - # is the same as before - get_body = self.admin_flavors_client.list_flavor_extra_specs( - self.flavor['id'])['extra_specs'] - self.assertEqual(get_body, {"key1": "value", "key2": "value2"}) - - # UNSET extra specs that were set in this test - self.admin_flavors_client.unset_flavor_extra_spec(self.flavor['id'], - "key1") - self.admin_flavors_client.unset_flavor_extra_spec(self.flavor['id'], - "key2") - get_body = self.admin_flavors_client.list_flavor_extra_specs( - self.flavor['id'])['extra_specs'] - self.assertEmpty(get_body) - - @decorators.idempotent_id('a99dad88-ae1c-4fba-aeb4-32f898218bd0') - def test_flavor_non_admin_get_all_keys(self): - specs = {"key1": "value1", "key2": "value2"} - self.admin_flavors_client.set_flavor_extra_spec(self.flavor['id'], - **specs) - body = (self.flavors_client.list_flavor_extra_specs( - self.flavor['id'])['extra_specs']) - - for key in specs: - self.assertEqual(body[key], specs[key]) - - @decorators.idempotent_id('12805a7f-39a3-4042-b989-701d5cad9c90') - def test_flavor_non_admin_get_specific_key(self): - body = self.admin_flavors_client.set_flavor_extra_spec( - self.flavor['id'], key1="value1", key2="value2")['extra_specs'] - self.assertEqual(body['key1'], 'value1') - self.assertIn('key2', body) - body = self.flavors_client.show_flavor_extra_spec( - self.flavor['id'], 'key1') - self.assertEqual(body['key1'], 'value1') - self.assertNotIn('key2', body) diff --git a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py deleted file mode 100644 index f39feb9e6..000000000 --- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class FlavorsExtraSpecsNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Negative Tests Flavor Extra Spec API extension. - - SET, UNSET, UPDATE Flavor Extra specs require admin privileges. - """ - - @classmethod - def skip_checks(cls): - super(FlavorsExtraSpecsNegativeTestJSON, cls).skip_checks() - if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): - msg = "OS-FLV-EXT-DATA extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(FlavorsExtraSpecsNegativeTestJSON, cls).resource_setup() - - flavor_name = data_utils.rand_name('test_flavor') - ram = 512 - vcpus = 1 - disk = 10 - ephemeral = 10 - new_flavor_id = data_utils.rand_int_id(start=1000) - swap = 1024 - rxtx = 1 - # Create a flavor - cls.flavor = cls.admin_flavors_client.create_flavor( - name=flavor_name, - ram=ram, vcpus=vcpus, - disk=disk, - id=new_flavor_id, - ephemeral=ephemeral, - swap=swap, - rxtx_factor=rxtx)['flavor'] - - @classmethod - def resource_cleanup(cls): - cls.admin_flavors_client.delete_flavor(cls.flavor['id']) - cls.admin_flavors_client.wait_for_resource_deletion(cls.flavor['id']) - super(FlavorsExtraSpecsNegativeTestJSON, cls).resource_cleanup() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a00a3b81-5641-45a8-ab2b-4a8ec41e1d7d') - def test_flavor_non_admin_set_keys(self): - # Test to SET flavor extra spec as a user without admin privileges. - self.assertRaises(lib_exc.Forbidden, - self.flavors_client.set_flavor_extra_spec, - self.flavor['id'], - key1="value1", key2="value2") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1ebf4ef8-759e-48fe-a801-d451d80476fb') - def test_flavor_non_admin_update_specific_key(self): - # non admin user is not allowed to update flavor extra spec - body = self.admin_flavors_client.set_flavor_extra_spec( - self.flavor['id'], key1="value1", key2="value2")['extra_specs'] - self.assertEqual(body['key1'], 'value1') - self.assertRaises(lib_exc.Forbidden, - self.flavors_client. - update_flavor_extra_spec, - self.flavor['id'], - 'key1', - key1='value1_new') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('28f12249-27c7-44c1-8810-1f382f316b11') - def test_flavor_non_admin_unset_keys(self): - self.admin_flavors_client.set_flavor_extra_spec( - self.flavor['id'], key1="value1", key2="value2") - - self.assertRaises(lib_exc.Forbidden, - self.flavors_client.unset_flavor_extra_spec, - self.flavor['id'], - 'key1') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('440b9f3f-3c7f-4293-a106-0ceda350f8de') - def test_flavor_unset_nonexistent_key(self): - self.assertRaises(lib_exc.NotFound, - self.admin_flavors_client.unset_flavor_extra_spec, - self.flavor['id'], - 'nonexistent_key') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('329a7be3-54b2-48be-8052-bf2ce4afd898') - def test_flavor_get_nonexistent_key(self): - self.assertRaises(lib_exc.NotFound, - self.flavors_client.show_flavor_extra_spec, - self.flavor['id'], - "nonexistent_key") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('25b822b8-9f49-44f6-80de-d99f0482e5cb') - def test_flavor_update_mismatch_key(self): - # the key will be updated should be match the key in the body - self.assertRaises(lib_exc.BadRequest, - self.admin_flavors_client.update_flavor_extra_spec, - self.flavor['id'], - "key2", - key1="value") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f5889590-bf66-41cc-b4b1-6e6370cfd93f') - def test_flavor_update_more_key(self): - # there should be just one item in the request body - self.assertRaises(lib_exc.BadRequest, - self.admin_flavors_client.update_flavor_extra_spec, - self.flavor['id'], - "key1", - key1="value", - key2="value") diff --git a/tempest/api/compute/admin/test_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py deleted file mode 100644 index 496f11994..000000000 --- a/tempest/api/compute/admin/test_floating_ips_bulk.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2014 NEC Technologies India Ltd. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest import test - -CONF = config.CONF - - -class FloatingIPsBulkAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Floating IPs Bulk APIs that require admin privileges. - - API documentation - http://docs.openstack.org/api/openstack-compute/2/ - content/ext-os-floating-ips-bulk.html - """ - - @classmethod - def setup_clients(cls): - super(FloatingIPsBulkAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.floating_ips_bulk_client - - @classmethod - def resource_setup(cls): - super(FloatingIPsBulkAdminTestJSON, cls).resource_setup() - cls.ip_range = CONF.validation.floating_ip_range - cls.verify_unallocated_floating_ip_range(cls.ip_range) - - @classmethod - def verify_unallocated_floating_ip_range(cls, ip_range): - # Verify whether configure floating IP range is not already allocated. - body = cls.client.list_floating_ips_bulk()['floating_ip_info'] - allocated_ips_list = map(lambda x: x['address'], body) - for ip_addr in netaddr.IPNetwork(ip_range).iter_hosts(): - if str(ip_addr) in allocated_ips_list: - msg = ("Configured unallocated floating IP range is already " - "allocated. Configure the correct unallocated range " - "as 'floating_ip_range'") - raise exceptions.InvalidConfiguration(msg) - return - - @decorators.idempotent_id('2c8f145f-8012-4cb8-ac7e-95a587f0e4ab') - @test.services('network') - def test_create_list_delete_floating_ips_bulk(self): - # Create, List and delete the Floating IPs Bulk - pool = 'test_pool' - # NOTE(GMann): Reserving the IP range but those are not attached - # anywhere. Using the below mentioned interface which is not ever - # expected to be used. Clean Up has been done for created IP range - interface = 'eth0' - body = (self.client.create_floating_ips_bulk(self.ip_range, - pool, - interface) - ['floating_ips_bulk_create']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.client.delete_floating_ips_bulk, self.ip_range) - self.assertEqual(self.ip_range, body['ip_range']) - ips_list = self.client.list_floating_ips_bulk()['floating_ip_info'] - self.assertNotEmpty(ips_list) - for ip in netaddr.IPNetwork(self.ip_range).iter_hosts(): - self.assertIn(str(ip), map(lambda x: x['address'], ips_list)) - body = (self.client.delete_floating_ips_bulk(self.ip_range) - ['floating_ips_bulk_delete']) - self.assertEqual(self.ip_range, body) diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py deleted file mode 100644 index 0e1e7edf6..000000000 --- a/tempest/api/compute/admin/test_hosts.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib import decorators - - -class HostsAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests hosts API using admin privileges.""" - - @classmethod - def setup_clients(cls): - super(HostsAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.hosts_client - - @decorators.idempotent_id('9bfaf98d-e2cb-44b0-a07e-2558b2821e4f') - def test_list_hosts(self): - hosts = self.client.list_hosts()['hosts'] - self.assertGreaterEqual(len(hosts), 2, str(hosts)) - - @decorators.idempotent_id('5dc06f5b-d887-47a2-bb2a-67762ef3c6de') - def test_list_hosts_with_zone(self): - self.useFixture(fixtures.LockFixture('availability_zone')) - hosts = self.client.list_hosts()['hosts'] - host = hosts[0] - hosts = self.client.list_hosts(zone=host['zone'])['hosts'] - self.assertNotEmpty(hosts) - self.assertIn(host, hosts) - - @decorators.idempotent_id('9af3c171-fbf4-4150-a624-22109733c2a6') - def test_list_hosts_with_a_blank_zone(self): - # If send the request with a blank zone, the request will be successful - # and it will return all the hosts list - hosts = self.client.list_hosts(zone='')['hosts'] - self.assertNotEmpty(hosts) - - @decorators.idempotent_id('c6ddbadb-c94e-4500-b12f-8ffc43843ff8') - def test_list_hosts_with_nonexistent_zone(self): - # If send the request with a nonexistent zone, the request will be - # successful and no hosts will be returned - hosts = self.client.list_hosts(zone='xxx')['hosts'] - self.assertEmpty(hosts) - - @decorators.idempotent_id('38adbb12-aee2-4498-8aec-329c72423aa4') - def test_show_host_detail(self): - hosts = self.client.list_hosts()['hosts'] - - hosts = [host for host in hosts if host['service'] == 'compute'] - self.assertNotEmpty(hosts) - - for host in hosts: - hostname = host['host_name'] - resources = self.client.show_host(hostname)['host'] - self.assertNotEmpty(resources) - host_resource = resources[0]['resource'] - self.assertIsNotNone(host_resource) - self.assertIsNotNone(host_resource['cpu']) - self.assertIsNotNone(host_resource['disk_gb']) - self.assertIsNotNone(host_resource['memory_mb']) - self.assertIsNotNone(host_resource['project']) - self.assertEqual(hostname, host_resource['host']) diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py deleted file mode 100644 index 5bd810419..000000000 --- a/tempest/api/compute/admin/test_hosts_negative.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class HostsAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests hosts API using admin privileges.""" - - @classmethod - def setup_clients(cls): - super(HostsAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_admin.hosts_client - cls.non_admin_client = cls.os_primary.hosts_client - - @classmethod - def resource_setup(cls): - super(HostsAdminNegativeTestJSON, cls).resource_setup() - hosts = cls.client.list_hosts()['hosts'] - if not hosts: - raise lib_exc.NotFound("no host found") - cls.hostname = hosts[0]['host_name'] - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dd032027-0210-4d9c-860e-69b1b8deed5f') - def test_list_hosts_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.list_hosts) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e75b0a1a-041f-47a1-8b4a-b72a6ff36d3f') - def test_show_host_detail_with_nonexistent_hostname(self): - self.assertRaises(lib_exc.NotFound, - self.client.show_host, 'nonexistent_hostname') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('19ebe09c-bfd4-4b7c-81a2-e2e0710f59cc') - def test_show_host_detail_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.show_host, - self.hostname) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e40c72b1-0239-4ed6-ba21-81a184df1f7c') - def test_update_host_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.update_host, - self.hostname, - status='enable', - maintenance_mode='enable') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fbe2bf3e-3246-4a95-a59f-94e4e298ec77') - def test_update_host_with_invalid_status(self): - # 'status' can only be 'enable' or 'disable' - self.assertRaises(lib_exc.BadRequest, - self.client.update_host, - self.hostname, - status='invalid', - maintenance_mode='enable') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ab1e230e-5e22-41a9-8699-82b9947915d4') - def test_update_host_with_invalid_maintenance_mode(self): - # 'maintenance_mode' can only be 'enable' or 'disable' - self.assertRaises(lib_exc.BadRequest, - self.client.update_host, - self.hostname, - status='enable', - maintenance_mode='invalid') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0cd85f75-6992-4a4a-b1bd-d11e37fd0eee') - def test_update_host_without_param(self): - # 'status' or 'maintenance_mode' needed for host update - self.assertRaises(lib_exc.BadRequest, - self.client.update_host, - self.hostname) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('23c92146-2100-4d68-b2d6-c7ade970c9c1') - def test_update_nonexistent_host(self): - self.assertRaises(lib_exc.NotFound, - self.client.update_host, - 'nonexistent_hostname', - status='enable', - maintenance_mode='enable') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0d981ac3-4320-4898-b674-82b61fbb60e4') - def test_startup_nonexistent_host(self): - self.assertRaises(lib_exc.NotFound, - self.client.startup_host, - 'nonexistent_hostname') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9f4ebb7e-b2ae-4e5b-a38f-0fd1bb0ddfca') - def test_startup_host_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.startup_host, - self.hostname) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9e637444-29cf-4244-88c8-831ae82c31b6') - def test_shutdown_nonexistent_host(self): - self.assertRaises(lib_exc.NotFound, - self.client.shutdown_host, - 'nonexistent_hostname') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a803529c-7e3f-4d3c-a7d6-8e1c203d27f6') - def test_shutdown_host_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.shutdown_host, - self.hostname) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f86bfd7b-0b13-4849-ae29-0322e83ee58b') - def test_reboot_nonexistent_host(self): - self.assertRaises(lib_exc.NotFound, - self.client.reboot_host, - 'nonexistent_hostname') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('02d79bb9-eb57-4612-abf6-2cb38897d2f8') - def test_reboot_host_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.reboot_host, - self.hostname) diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py deleted file mode 100644 index 0db802cf5..000000000 --- a/tempest/api/compute/admin/test_hypervisor.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2013 IBM Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators - - -class HypervisorAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Hypervisors API that require admin privileges""" - - @classmethod - def setup_clients(cls): - super(HypervisorAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.hypervisor_client - - def _list_hypervisors(self): - # List of hypervisors - hypers = self.client.list_hypervisors()['hypervisors'] - return hypers - - def assertHypervisors(self, hypers): - self.assertNotEmpty(hypers, "No hypervisors found: %s" % hypers) - - @decorators.idempotent_id('7f0ceacd-c64d-4e96-b8ee-d02943142cc5') - def test_get_hypervisor_list(self): - # List of hypervisor and available hypervisors hostname - hypers = self._list_hypervisors() - self.assertHypervisors(hypers) - - @decorators.idempotent_id('1e7fdac2-b672-4ad1-97a4-bad0e3030118') - def test_get_hypervisor_list_details(self): - # Display the details of the all hypervisor - hypers = self.client.list_hypervisors(detail=True)['hypervisors'] - self.assertHypervisors(hypers) - - @decorators.idempotent_id('94ff9eae-a183-428e-9cdb-79fde71211cc') - def test_get_hypervisor_show_details(self): - # Display the details of the specified hypervisor - hypers = self._list_hypervisors() - self.assertHypervisors(hypers) - - details = self.client.show_hypervisor(hypers[0]['id'])['hypervisor'] - self.assertNotEmpty(details) - self.assertEqual(details['hypervisor_hostname'], - hypers[0]['hypervisor_hostname']) - - @decorators.idempotent_id('e81bba3f-6215-4e39-a286-d52d2f906862') - def test_get_hypervisor_show_servers(self): - # Show instances about the specific hypervisors - hypers = self._list_hypervisors() - self.assertHypervisors(hypers) - - hostname = hypers[0]['hypervisor_hostname'] - hypervisors = (self.client.list_servers_on_hypervisor(hostname) - ['hypervisors']) - self.assertNotEmpty(hypervisors) - - @decorators.idempotent_id('797e4f28-b6e0-454d-a548-80cc77c00816') - def test_get_hypervisor_stats(self): - # Verify the stats of the all hypervisor - stats = (self.client.show_hypervisor_statistics() - ['hypervisor_statistics']) - self.assertNotEmpty(stats) - - @decorators.idempotent_id('91a50d7d-1c2b-4f24-b55a-a1fe20efca70') - def test_get_hypervisor_uptime(self): - # Verify that GET shows the specified hypervisor uptime - hypers = self._list_hypervisors() - - # Ironic will register each baremetal node as a 'hypervisor', - # so the hypervisor list can contain many hypervisors of type - # 'ironic'. If they are ALL ironic, skip this test since ironic - # doesn't support hypervisor uptime. Otherwise, remove them - # from the list of hypervisors to test. - ironic_only = True - hypers_without_ironic = [] - for hyper in hypers: - details = (self.client.show_hypervisor(hyper['id']) - ['hypervisor']) - if details['hypervisor_type'] != 'ironic': - hypers_without_ironic.append(hyper) - ironic_only = False - - if ironic_only: - raise self.skipException( - "Ironic does not support hypervisor uptime") - - has_valid_uptime = False - for hyper in hypers_without_ironic: - # because hypervisors might be disabled, this loops looking - # for any good hit. - try: - uptime = (self.client.show_hypervisor_uptime(hyper['id']) - ['hypervisor']) - if uptime: - has_valid_uptime = True - break - except Exception: - pass - self.assertTrue( - has_valid_uptime, - "None of the hypervisors had a valid uptime: %s" % hypers) - - @decorators.idempotent_id('d7e1805b-3b14-4a3b-b6fd-50ec6d9f361f') - def test_search_hypervisor(self): - hypers = self._list_hypervisors() - self.assertHypervisors(hypers) - hypers = self.client.search_hypervisor( - hypers[0]['hypervisor_hostname'])['hypervisors'] - self.assertHypervisors(hypers) diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py deleted file mode 100644 index 431e823bb..000000000 --- a/tempest/api/compute/admin/test_hypervisor_negative.py +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class HypervisorAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Hypervisors API that require admin privileges""" - - @classmethod - def setup_clients(cls): - super(HypervisorAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_admin.hypervisor_client - cls.non_adm_client = cls.hypervisor_client - - def _list_hypervisors(self): - # List of hypervisors - hypers = self.client.list_hypervisors()['hypervisors'] - return hypers - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c136086a-0f67-4b2b-bc61-8482bd68989f') - def test_show_nonexistent_hypervisor(self): - nonexistent_hypervisor_id = data_utils.rand_uuid() - - self.assertRaises( - lib_exc.NotFound, - self.client.show_hypervisor, - nonexistent_hypervisor_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('51e663d0-6b89-4817-a465-20aca0667d03') - def test_show_hypervisor_with_non_admin_user(self): - hypers = self._list_hypervisors() - self.assertNotEmpty(hypers) - - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.show_hypervisor, - hypers[0]['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('2a0a3938-832e-4859-95bf-1c57c236b924') - def test_show_servers_with_non_admin_user(self): - hypers = self._list_hypervisors() - self.assertNotEmpty(hypers) - - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.list_servers_on_hypervisor, - hypers[0]['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('02463d69-0ace-4d33-a4a8-93d7883a2bba') - def test_show_servers_with_nonexistent_hypervisor(self): - nonexistent_hypervisor_id = data_utils.rand_uuid() - - self.assertRaises( - lib_exc.NotFound, - self.client.list_servers_on_hypervisor, - nonexistent_hypervisor_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e2b061bb-13f9-40d8-9d6e-d5bf17595849') - def test_get_hypervisor_stats_with_non_admin_user(self): - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.show_hypervisor_statistics) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f60aa680-9a3a-4c7d-90e1-fae3a4891303') - def test_get_nonexistent_hypervisor_uptime(self): - nonexistent_hypervisor_id = data_utils.rand_uuid() - - self.assertRaises( - lib_exc.NotFound, - self.client.show_hypervisor_uptime, - nonexistent_hypervisor_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6c3461f9-c04c-4e2a-bebb-71dc9cb47df2') - def test_get_hypervisor_uptime_with_non_admin_user(self): - hypers = self._list_hypervisors() - self.assertNotEmpty(hypers) - - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.show_hypervisor_uptime, - hypers[0]['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('51b3d536-9b14-409c-9bce-c6f7c794994e') - def test_get_hypervisor_list_with_non_admin_user(self): - # List of hypervisor and available services with non admin user - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.list_hypervisors) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dc02db05-e801-4c5f-bc8e-d915290ab345') - def test_get_hypervisor_list_details_with_non_admin_user(self): - # List of hypervisor details and available services with non admin user - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.list_hypervisors, detail=True) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('19a45cc1-1000-4055-b6d2-28e8b2ec4faa') - def test_search_nonexistent_hypervisor(self): - self.assertRaises( - lib_exc.NotFound, - self.client.search_hypervisor, - 'nonexistent_hypervisor_name') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5b6a6c79-5dc1-4fa5-9c58-9c8085948e74') - def test_search_hypervisor_with_non_admin_user(self): - hypers = self._list_hypervisors() - self.assertNotEmpty(hypers) - - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.search_hypervisor, - hypers[0]['hypervisor_hostname']) diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log.py b/tempest/api/compute/admin/test_instance_usage_audit_log.py deleted file mode 100644 index e4a2ffdd2..000000000 --- a/tempest/api/compute/admin/test_instance_usage_audit_log.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2013 IBM Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import datetime - -from six.moves.urllib import parse as urllib - -from tempest.api.compute import base -from tempest.lib import decorators - - -class InstanceUsageAuditLogTestJSON(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(InstanceUsageAuditLogTestJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.instance_usages_audit_log_client - - @decorators.idempotent_id('25319919-33d9-424f-9f99-2c203ee48b9d') - def test_list_instance_usage_audit_logs(self): - # list instance usage audit logs - body = (self.adm_client.list_instance_usage_audit_logs() - ["instance_usage_audit_logs"]) - expected_items = ['total_errors', 'total_instances', 'log', - 'num_hosts_running', 'num_hosts_done', - 'num_hosts', 'hosts_not_run', 'overall_status', - 'period_ending', 'period_beginning', - 'num_hosts_not_run'] - for item in expected_items: - self.assertIn(item, body) - - @decorators.idempotent_id('6e40459d-7c5f-400b-9e83-449fbc8e7feb') - def test_get_instance_usage_audit_log(self): - # Get instance usage audit log before specified time - now = datetime.datetime.now() - body = (self.adm_client.show_instance_usage_audit_log( - urllib.quote(now.strftime("%Y-%m-%d %H:%M:%S"))) - ["instance_usage_audit_log"]) - - expected_items = ['total_errors', 'total_instances', 'log', - 'num_hosts_running', 'num_hosts_done', 'num_hosts', - 'hosts_not_run', 'overall_status', 'period_ending', - 'period_beginning', 'num_hosts_not_run'] - for item in expected_items: - self.assertIn(item, body) diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py deleted file mode 100644 index de8e221a5..000000000 --- a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2013 IBM Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import datetime - -from six.moves.urllib import parse as urllib - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class InstanceUsageAuditLogNegativeTestJSON(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(InstanceUsageAuditLogNegativeTestJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.instance_usages_audit_log_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a9d33178-d2c9-4131-ad3b-f4ca8d0308a2') - def test_instance_usage_audit_logs_with_nonadmin_user(self): - # the instance_usage_audit_logs API just can be accessed by admin user - self.assertRaises(lib_exc.Forbidden, - self.instance_usages_audit_log_client. - list_instance_usage_audit_logs) - now = datetime.datetime.now() - self.assertRaises(lib_exc.Forbidden, - self.instance_usages_audit_log_client. - show_instance_usage_audit_log, - urllib.quote(now.strftime("%Y-%m-%d %H:%M:%S"))) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9b952047-3641-41c7-ba91-a809fc5974c8') - def test_get_instance_usage_audit_logs_with_invalid_time(self): - self.assertRaises(lib_exc.BadRequest, - self.adm_client.show_instance_usage_audit_log, - "invalid_time") diff --git a/tempest/api/compute/admin/test_keypairs_v210.py b/tempest/api/compute/admin/test_keypairs_v210.py deleted file mode 100644 index e24c7c100..000000000 --- a/tempest/api/compute/admin/test_keypairs_v210.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2016 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute.keypairs import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class KeyPairsV210TestJSON(base.BaseKeypairTest): - credentials = ['primary', 'admin'] - min_microversion = '2.10' - - @classmethod - def setup_clients(cls): - super(KeyPairsV210TestJSON, cls).setup_clients() - cls.client = cls.os_admin.keypairs_client - cls.non_admin_client = cls.os_primary.keypairs_client - - def _create_and_check_keypairs(self, user_id): - key_list = list() - for _ in range(2): - k_name = data_utils.rand_name('keypair') - keypair = self.create_keypair(k_name, - keypair_type='ssh', - user_id=user_id) - self.assertEqual(k_name, keypair['name'], - "The created keypair name is not equal " - "to the requested name!") - self.assertEqual(user_id, keypair['user_id'], - "The created keypair is not for requested user!") - keypair.pop('private_key', None) - keypair.pop('user_id') - key_list.append(keypair) - return key_list - - @decorators.idempotent_id('3c8484af-cfb3-48f6-b8ba-d5d58bbf3eac') - def test_admin_manage_keypairs_for_other_users(self): - user_id = self.non_admin_client.user_id - key_list = self._create_and_check_keypairs(user_id) - first_keyname = key_list[0]['name'] - keypair_detail = self.client.show_keypair(first_keyname, - user_id=user_id)['keypair'] - self.assertEqual(first_keyname, keypair_detail['name']) - self.assertEqual(user_id, keypair_detail['user_id'], - "The fetched keypair is not for requested user!") - # Create a admin keypair - admin_keypair = self.create_keypair(keypair_type='ssh') - admin_keypair.pop('private_key', None) - admin_keypair.pop('user_id') - - # Admin fetch keypairs list of non admin user - keypairs = self.client.list_keypairs(user_id=user_id)['keypairs'] - fetched_list = [keypair['keypair'] for keypair in keypairs] - - # Check admin keypair is not present in non admin user keypairs list - self.assertNotIn(admin_keypair, fetched_list, - "The fetched user keypairs has admin keypair!") - - # Now check if all the created keypairs are in the fetched list - missing_kps = [kp for kp in key_list if kp not in fetched_list] - self.assertFalse(missing_kps, - "Failed to find keypairs %s in fetched list" - % ', '.join(m_key['name'] for m_key in missing_kps)) diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py deleted file mode 100644 index 3f1bdce00..000000000 --- a/tempest/api/compute/admin/test_live_migration.py +++ /dev/null @@ -1,235 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from oslo_log import log as logging -import testtools - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class LiveMigrationTest(base.BaseV2ComputeAdminTest): - max_microversion = '2.24' - block_migration = None - - @classmethod - def skip_checks(cls): - super(LiveMigrationTest, cls).skip_checks() - - if not CONF.compute_feature_enabled.live_migration: - skip_msg = ("%s skipped as live-migration is " - "not available" % cls.__name__) - raise cls.skipException(skip_msg) - if CONF.compute.min_compute_nodes < 2: - raise cls.skipException( - "Less than 2 compute nodes, skipping migration test.") - - @classmethod - def setup_clients(cls): - super(LiveMigrationTest, cls).setup_clients() - cls.admin_migration_client = cls.os_admin.migrations_client - - def _migrate_server_to(self, server_id, dest_host, volume_backed=False): - kwargs = dict() - block_migration = getattr(self, 'block_migration', None) - if self.block_migration is None: - kwargs['disk_over_commit'] = False - block_migration = (CONF.compute_feature_enabled. - block_migration_for_live_migration and - not volume_backed) - self.admin_servers_client.live_migrate_server( - server_id, host=dest_host, block_migration=block_migration, - **kwargs) - - def _live_migrate(self, server_id, target_host, state, - volume_backed=False): - self._migrate_server_to(server_id, target_host, volume_backed) - waiters.wait_for_server_status(self.servers_client, server_id, state) - migration_list = (self.admin_migration_client.list_migrations() - ['migrations']) - - msg = ("Live Migration failed. Migrations list for Instance " - "%s: [" % server_id) - for live_migration in migration_list: - if (live_migration['instance_uuid'] == server_id): - msg += "\n%s" % live_migration - msg += "]" - self.assertEqual(target_host, self.get_host_for_server(server_id), - msg) - - def _test_live_migration(self, state='ACTIVE', volume_backed=False): - """Tests live migration between two hosts. - - Requires CONF.compute_feature_enabled.live_migration to be True. - - :param state: The vm_state the migrated server should be in before and - after the live migration. Supported values are 'ACTIVE' - and 'PAUSED'. - :param volume_backed: If the instance is volume backed or not. If - volume_backed, *block* migration is not used. - """ - # Live migrate an instance to another host - server_id = self.create_test_server(wait_until="ACTIVE", - volume_backed=volume_backed)['id'] - source_host = self.get_host_for_server(server_id) - destination_host = self.get_host_other_than(server_id) - - if state == 'PAUSED': - self.admin_servers_client.pause_server(server_id) - waiters.wait_for_server_status(self.admin_servers_client, - server_id, state) - - LOG.info("Live migrate from source %s to destination %s", - source_host, destination_host) - self._live_migrate(server_id, destination_host, state, volume_backed) - if CONF.compute_feature_enabled.live_migrate_back_and_forth: - # If live_migrate_back_and_forth is enabled it is a grenade job. - # Therefore test should validate whether LM is compatible in both - # ways, so live migrate VM back to the source host - LOG.info("Live migrate back to source %s", source_host) - self._live_migrate(server_id, source_host, state, volume_backed) - - @decorators.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b') - def test_live_block_migration(self): - self._test_live_migration() - - @decorators.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - def test_live_block_migration_paused(self): - self._test_live_migration(state='PAUSED') - - @decorators.skip_because(bug="1524898") - @decorators.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd') - @test.services('volume') - def test_volume_backed_live_migration(self): - self._test_live_migration(volume_backed=True) - - @decorators.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812') - @testtools.skipIf(not CONF.compute_feature_enabled. - block_migration_for_live_migration, - 'Block Live migration not available') - @testtools.skipIf(not CONF.compute_feature_enabled. - block_migrate_cinder_iscsi, - 'Block Live migration not configured for iSCSI') - def test_iscsi_volume(self): - server = self.create_test_server(wait_until="ACTIVE") - server_id = server['id'] - target_host = self.get_host_other_than(server_id) - - volume = self.create_volume() - - # Attach the volume to the server - self.attach_volume(server, volume, device='/dev/xvdb') - server = self.admin_servers_client.show_server(server_id)['server'] - volume_id1 = server["os-extended-volumes:volumes_attached"][0]["id"] - self._migrate_server_to(server_id, target_host) - waiters.wait_for_server_status(self.servers_client, - server_id, 'ACTIVE') - - server = self.admin_servers_client.show_server(server_id)['server'] - volume_id2 = server["os-extended-volumes:volumes_attached"][0]["id"] - - self.assertEqual(target_host, self.get_host_for_server(server_id)) - self.assertEqual(volume_id1, volume_id2) - - -class LiveMigrationRemoteConsolesV26Test(LiveMigrationTest): - min_microversion = '2.6' - max_microversion = 'latest' - - @decorators.idempotent_id('6190af80-513e-4f0f-90f2-9714e84955d7') - @testtools.skipUnless(CONF.compute_feature_enabled.serial_console, - 'Serial console not supported.') - @testtools.skipUnless( - test.is_scheduler_filter_enabled("DifferentHostFilter"), - 'DifferentHostFilter is not available.') - def test_live_migration_serial_console(self): - """Test the live-migration of an instance which has a serial console - - The serial console feature of an instance uses ports on the host. - These ports need to be updated when they are already in use by - another instance on the target host. This test checks if this - update behavior is correctly done, by connecting to the serial - consoles of the instances before and after the live migration. - """ - server01_id = self.create_test_server(wait_until='ACTIVE')['id'] - hints = {'different_host': server01_id} - server02_id = self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE')['id'] - host01_id = self.get_host_for_server(server01_id) - host02_id = self.get_host_for_server(server02_id) - self.assertNotEqual(host01_id, host02_id) - - # At this step we have 2 instances on different hosts, both with - # serial consoles, both with port 10000 (the default value). - # https://bugs.launchpad.net/nova/+bug/1455252 describes the issue - # when live-migrating in such a scenario. - - self._verify_console_interaction(server01_id) - self._verify_console_interaction(server02_id) - - self._migrate_server_to(server01_id, host02_id) - waiters.wait_for_server_status(self.servers_client, - server01_id, 'ACTIVE') - self.assertEqual(host02_id, self.get_host_for_server(server01_id)) - self._verify_console_interaction(server01_id) - # At this point, both instances have a valid serial console - # connection, which means the ports got updated. - - def _verify_console_interaction(self, server_id): - body = self.servers_client.get_remote_console(server_id, - console_type='serial', - protocol='serial') - console_url = body['remote_console']['url'] - data = "test_live_migration_serial_console" - console_output = '' - t = 0.0 - interval = 0.1 - - ws = compute.create_websocket(console_url) - try: - # NOTE (markus_z): It can take a long time until the terminal - # of the instance is available for interaction. Hence the - # long timeout value. - while data not in console_output and t <= 120.0: - try: - ws.send_frame(data) - recieved = ws.receive_frame() - console_output += recieved - except Exception: - # In case we had an issue with send/receive on the - # websocket connection, we create a new one. - ws = compute.create_websocket(console_url) - time.sleep(interval) - t += interval - finally: - ws.close() - self.assertIn(data, console_output) - - -class LiveAutoBlockMigrationV225Test(LiveMigrationTest): - min_microversion = '2.25' - max_microversion = 'latest' - block_migration = 'auto' diff --git a/tempest/api/compute/admin/test_live_migration_negative.py b/tempest/api/compute/admin/test_live_migration_negative.py deleted file mode 100644 index deabbc2d3..000000000 --- a/tempest/api/compute/admin/test_live_migration_negative.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class LiveMigrationNegativeTest(base.BaseV2ComputeAdminTest): - @classmethod - def skip_checks(cls): - super(LiveMigrationNegativeTest, cls).skip_checks() - if not CONF.compute_feature_enabled.live_migration: - raise cls.skipException("Live migration is not enabled") - - def _migrate_server_to(self, server_id, dest_host): - bmflm = CONF.compute_feature_enabled.block_migration_for_live_migration - self.admin_servers_client.live_migrate_server( - server_id, host=dest_host, block_migration=bmflm, - disk_over_commit=False) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7fb7856e-ae92-44c9-861a-af62d7830bcb') - def test_invalid_host_for_migration(self): - # Migrating to an invalid host should not change the status - target_host = data_utils.rand_name('host') - server = self.create_test_server(wait_until="ACTIVE") - - self.assertRaises(lib_exc.BadRequest, self._migrate_server_to, - server['id'], target_host) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6e2f94f5-2ee8-4830-bef5-5bc95bb0795b') - def test_live_block_migration_suspended(self): - server = self.create_test_server(wait_until="ACTIVE") - - self.admin_servers_client.suspend_server(server['id']) - waiters.wait_for_server_status(self.servers_client, - server['id'], 'SUSPENDED') - - destination_host = self.get_host_other_than(server['id']) - - self.assertRaises(lib_exc.Conflict, self._migrate_server_to, - server['id'], destination_host) diff --git a/tempest/api/compute/admin/test_migrations.py b/tempest/api/compute/admin/test_migrations.py deleted file mode 100644 index a626ebb71..000000000 --- a/tempest/api/compute/admin/test_migrations.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class MigrationsAdminTest(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(MigrationsAdminTest, cls).setup_clients() - cls.client = cls.os_admin.migrations_client - - @decorators.idempotent_id('75c0b83d-72a0-4cf8-a153-631e83e7d53f') - def test_list_migrations(self): - # Admin can get the migrations list - self.client.list_migrations() - - @decorators.idempotent_id('1b512062-8093-438e-b47a-37d2f597cd64') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_list_migrations_in_flavor_resize_situation(self): - # Admin can get the migrations list which contains the resized server - server = self.create_test_server(wait_until="ACTIVE") - server_id = server['id'] - - self.resize_server(server_id, self.flavor_ref_alt) - - body = self.client.list_migrations()['migrations'] - - instance_uuids = [x['instance_uuid'] for x in body] - self.assertIn(server_id, instance_uuids) - - def _flavor_clean_up(self, flavor_id): - try: - self.admin_flavors_client.delete_flavor(flavor_id) - self.admin_flavors_client.wait_for_resource_deletion(flavor_id) - except exceptions.NotFound: - pass - - @decorators.idempotent_id('33f1fec3-ba18-4470-8e4e-1d888e7c3593') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_revert_deleted_flavor(self): - # Tests that we can revert the resize on an instance whose original - # flavor has been deleted. - - # First we have to create a flavor that we can delete so make a copy - # of the normal flavor from which we'd create a server. - flavor = self.admin_flavors_client.show_flavor( - self.flavor_ref)['flavor'] - flavor = self.admin_flavors_client.create_flavor( - name=data_utils.rand_name('test_resize_flavor_'), - ram=flavor['ram'], - disk=flavor['disk'], - vcpus=flavor['vcpus'] - )['flavor'] - self.addCleanup(self._flavor_clean_up, flavor['id']) - - # Now boot a server with the copied flavor. - server = self.create_test_server( - wait_until='ACTIVE', flavor=flavor['id']) - - # Delete the flavor we used to boot the instance. - self._flavor_clean_up(flavor['id']) - - # Now resize the server and wait for it to go into verify state. - self.servers_client.resize_server(server['id'], self.flavor_ref_alt) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'VERIFY_RESIZE') - - # Now revert the resize, it should be OK even though the original - # flavor used to boot the server was deleted. - self.servers_client.revert_resize_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - server = self.servers_client.show_server(server['id'])['server'] - self.assertEqual(flavor['id'], server['flavor']['id']) - - def _test_cold_migrate_server(self, revert=False): - if CONF.compute.min_compute_nodes < 2: - msg = "Less than 2 compute nodes, skipping multinode tests." - raise self.skipException(msg) - - server = self.create_test_server(wait_until="ACTIVE") - src_host = self.admin_servers_client.show_server( - server['id'])['server']['OS-EXT-SRV-ATTR:host'] - - self.admin_servers_client.migrate_server(server['id']) - - waiters.wait_for_server_status(self.servers_client, - server['id'], 'VERIFY_RESIZE') - - if revert: - self.servers_client.revert_resize_server(server['id']) - assert_func = self.assertEqual - else: - self.servers_client.confirm_resize_server(server['id']) - assert_func = self.assertNotEqual - - waiters.wait_for_server_status(self.servers_client, - server['id'], 'ACTIVE') - dst_host = self.admin_servers_client.show_server( - server['id'])['server']['OS-EXT-SRV-ATTR:host'] - assert_func(src_host, dst_host) - - @decorators.idempotent_id('4bf0be52-3b6f-4746-9a27-3143636fe30d') - @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, - 'Cold migration not available.') - def test_cold_migration(self): - self._test_cold_migrate_server(revert=False) - - @decorators.idempotent_id('caa1aa8b-f4ef-4374-be0d-95f001c2ac2d') - @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, - 'Cold migration not available.') - def test_revert_cold_migration(self): - self._test_cold_migrate_server(revert=True) diff --git a/tempest/api/compute/admin/test_networks.py b/tempest/api/compute/admin/test_networks.py deleted file mode 100644 index acb0d90d5..000000000 --- a/tempest/api/compute/admin/test_networks.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class NetworksTest(base.BaseV2ComputeAdminTest): - """Tests Nova Networks API that usually requires admin privileges. - - API docs: - http://developer.openstack.org/api-ref-compute-v2-ext.html#ext-os-networks - """ - - @classmethod - def setup_clients(cls): - super(NetworksTest, cls).setup_clients() - cls.client = cls.os_admin.compute_networks_client - - @decorators.idempotent_id('d206d211-8912-486f-86e2-a9d090d1f416') - def test_get_network(self): - networks = self.client.list_networks()['networks'] - if CONF.compute.fixed_network_name: - configured_network = [x for x in networks if x['label'] == - CONF.compute.fixed_network_name] - self.assertEqual(1, len(configured_network), - "{0} networks with label {1}".format( - len(configured_network), - CONF.compute.fixed_network_name)) - elif CONF.network.public_network_id: - configured_network = [x for x in networks if x['id'] == - CONF.network.public_network_id] - else: - raise self.skipException( - "Environment has no known-for-sure existing network.") - configured_network = configured_network[0] - network = (self.client.show_network(configured_network['id']) - ['network']) - self.assertEqual(configured_network['label'], network['label']) - - @decorators.idempotent_id('df3d1046-6fa5-4b2c-ad0c-cfa46a351cb9') - def test_list_all_networks(self): - networks = self.client.list_networks()['networks'] - # Check the configured network is in the list - if CONF.compute.fixed_network_name: - configured_network = CONF.compute.fixed_network_name - self.assertIn(configured_network, [x['label'] for x in networks]) - else: - network_labels = [x['label'] for x in networks] - self.assertNotEmpty(network_labels) diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py deleted file mode 100644 index 937540e2a..000000000 --- a/tempest/api/compute/admin/test_quotas.py +++ /dev/null @@ -1,187 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging -from testtools import matchers - -from tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -LOG = logging.getLogger(__name__) - - -class QuotasAdminTestJSON(base.BaseV2ComputeAdminTest): - force_tenant_isolation = True - - def setUp(self): - # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests. - self.useFixture(fixtures.LockFixture('compute_quotas')) - super(QuotasAdminTestJSON, self).setUp() - - @classmethod - def setup_clients(cls): - super(QuotasAdminTestJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.quotas_client - - @classmethod - def resource_setup(cls): - super(QuotasAdminTestJSON, cls).resource_setup() - - # NOTE(afazekas): these test cases should always create and use a new - # tenant most of them should be skipped if we can't do that - cls.demo_tenant_id = cls.quotas_client.tenant_id - - cls.default_quota_set = set(('injected_file_content_bytes', - 'metadata_items', 'injected_files', - 'ram', 'floating_ips', - 'fixed_ips', 'key_pairs', - 'injected_file_path_bytes', - 'instances', 'security_group_rules', - 'cores', 'security_groups')) - - @decorators.idempotent_id('3b0a7c8f-cf58-46b8-a60c-715a32a8ba7d') - def test_get_default_quotas(self): - # Admin can get the default resource quota set for a tenant - expected_quota_set = self.default_quota_set | set(['id']) - quota_set = self.adm_client.show_default_quota_set( - self.demo_tenant_id)['quota_set'] - self.assertEqual(quota_set['id'], self.demo_tenant_id) - for quota in expected_quota_set: - self.assertIn(quota, quota_set.keys()) - - @decorators.idempotent_id('55fbe2bf-21a9-435b-bbd2-4162b0ed799a') - def test_update_all_quota_resources_for_tenant(self): - # Admin can update all the resource quota limits for a tenant - default_quota_set = self.adm_client.show_default_quota_set( - self.demo_tenant_id)['quota_set'] - new_quota_set = {'injected_file_content_bytes': 20480, - 'metadata_items': 256, 'injected_files': 10, - 'ram': 10240, 'floating_ips': 20, 'fixed_ips': 10, - 'key_pairs': 200, 'injected_file_path_bytes': 512, - 'instances': 20, 'security_group_rules': 20, - 'cores': 2, 'security_groups': 20, - 'server_groups': 20, 'server_group_members': 20} - # Update limits for all quota resources - quota_set = self.adm_client.update_quota_set( - self.demo_tenant_id, - force=True, - **new_quota_set)['quota_set'] - - default_quota_set.pop('id') - self.addCleanup(self.adm_client.update_quota_set, - self.demo_tenant_id, **default_quota_set) - for quota in new_quota_set: - self.assertIn(quota, quota_set.keys()) - - # TODO(afazekas): merge these test cases - @decorators.idempotent_id('ce9e0815-8091-4abd-8345-7fe5b85faa1d') - def test_get_updated_quotas(self): - # Verify that GET shows the updated quota set of project - project_name = data_utils.rand_name('cpu_quota_project') - project_desc = project_name + '-desc' - project = self.identity_utils.create_project(name=project_name, - description=project_desc) - project_id = project['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - - self.adm_client.update_quota_set(project_id, ram='5120') - quota_set = self.adm_client.show_quota_set(project_id)['quota_set'] - self.assertEqual(5120, quota_set['ram']) - - # Verify that GET shows the updated quota set of user - user_name = data_utils.rand_name('cpu_quota_user') - password = data_utils.rand_password() - email = user_name + '@testmail.tm' - user = self.identity_utils.create_user(username=user_name, - password=password, - project=project, - email=email) - user_id = user['id'] - self.addCleanup(self.identity_utils.delete_user, user_id) - - self.adm_client.update_quota_set(project_id, - user_id=user_id, - ram='2048') - quota_set = self.adm_client.show_quota_set( - project_id, user_id=user_id)['quota_set'] - self.assertEqual(2048, quota_set['ram']) - - @decorators.idempotent_id('389d04f0-3a41-405f-9317-e5f86e3c44f0') - def test_delete_quota(self): - # Admin can delete the resource quota set for a project - project_name = data_utils.rand_name('ram_quota_project') - project_desc = project_name + '-desc' - project = self.identity_utils.create_project(name=project_name, - description=project_desc) - project_id = project['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - quota_set_default = (self.adm_client.show_quota_set(project_id) - ['quota_set']) - ram_default = quota_set_default['ram'] - - self.adm_client.update_quota_set(project_id, ram='5120') - - self.adm_client.delete_quota_set(project_id) - - quota_set_new = self.adm_client.show_quota_set(project_id)['quota_set'] - self.assertEqual(ram_default, quota_set_new['ram']) - - -class QuotaClassesAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests the os-quota-class-sets API to update default quotas.""" - - def setUp(self): - # All test cases in this class need to externally lock on doing - # anything with default quota values. - self.useFixture(fixtures.LockFixture('compute_quotas')) - super(QuotaClassesAdminTestJSON, self).setUp() - - @classmethod - def resource_setup(cls): - super(QuotaClassesAdminTestJSON, cls).resource_setup() - cls.adm_client = cls.os_admin.quota_classes_client - - def _restore_default_quotas(self, original_defaults): - LOG.debug("restoring quota class defaults") - self.adm_client.update_quota_class_set( - 'default', **original_defaults)['quota_class_set'] - - # NOTE(sdague): this test is problematic as it changes - # global state, and possibly needs to be part of a set of - # tests that get run all by themselves at the end under a - # 'danger' flag. - @decorators.idempotent_id('7932ab0f-5136-4075-b201-c0e2338df51a') - def test_update_default_quotas(self): - LOG.debug("get the current 'default' quota class values") - body = (self.adm_client.show_quota_class_set('default') - ['quota_class_set']) - self.assertIn('id', body) - self.assertEqual('default', body.pop('id')) - # restore the defaults when the test is done - self.addCleanup(self._restore_default_quotas, body.copy()) - # increment all of the values for updating the default quota class - for quota, default in body.items(): - # NOTE(sdague): we need to increment a lot, otherwise - # there is a real chance that we go from -1 (unlimited) - # to a very small number which causes issues. - body[quota] = default + 100 - LOG.debug("update limits for the default quota class set") - update_body = self.adm_client.update_quota_class_set( - 'default', **body)['quota_class_set'] - LOG.debug("assert that the response has all of the changed values") - self.assertThat(update_body.items(), - matchers.ContainsAll(body.items())) diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py deleted file mode 100644 index 747f32032..000000000 --- a/tempest/api/compute/admin/test_quotas_negative.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class QuotasAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - force_tenant_isolation = True - - @classmethod - def setup_clients(cls): - super(QuotasAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_primary.quotas_client - cls.adm_client = cls.os_admin.quotas_client - cls.sg_client = cls.security_groups_client - cls.sgr_client = cls.security_group_rules_client - - @classmethod - def resource_setup(cls): - super(QuotasAdminNegativeTestJSON, cls).resource_setup() - # NOTE(afazekas): these test cases should always create and use a new - # tenant most of them should be skipped if we can't do that - cls.demo_tenant_id = cls.client.tenant_id - - def _update_quota(self, quota_item, quota_value): - quota_set = (self.adm_client.show_quota_set(self.demo_tenant_id) - ['quota_set']) - default_quota_value = quota_set[quota_item] - - self.adm_client.update_quota_set(self.demo_tenant_id, - force=True, - **{quota_item: quota_value}) - self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id, - **{quota_item: default_quota_value}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('733abfe8-166e-47bb-8363-23dbd7ff3476') - def test_update_quota_normal_user(self): - self.assertRaises(lib_exc.Forbidden, - self.client.update_quota_set, - self.demo_tenant_id, - ram=0) - - # TODO(afazekas): Add dedicated tenant to the skipped quota tests. - # It can be moved into the setUpClass as well. - @decorators.attr(type=['negative']) - @decorators.idempotent_id('91058876-9947-4807-9f22-f6eb17140d9b') - def test_create_server_when_cpu_quota_is_full(self): - # Disallow server creation when tenant's vcpu quota is full - self._update_quota('cores', 0) - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.create_test_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6fdd7012-584d-4327-a61c-49122e0d5864') - def test_create_server_when_memory_quota_is_full(self): - # Disallow server creation when tenant's memory quota is full - self._update_quota('ram', 0) - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.create_test_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7c6be468-0274-449a-81c3-ac1c32ee0161') - def test_create_server_when_instances_quota_is_full(self): - # Once instances quota limit is reached, disallow server creation - self._update_quota('instances', 0) - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.create_test_server) - - @decorators.skip_because(bug="1186354", - condition=CONF.service_available.neutron) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7c6c8f3b-2bf6-4918-b240-57b136a66aa0') - @test.services('network') - def test_security_groups_exceed_limit(self): - # Negative test: Creation Security Groups over limit should FAIL - # Set the quota to number of used security groups - sg_quota = self.limits_client.show_limits()['limits']['absolute'][ - 'totalSecurityGroupsUsed'] - self._update_quota('security_groups', sg_quota) - - # Check we cannot create anymore - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised when out of quota - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.sg_client.create_security_group, - name="sg-overlimit", description="sg-desc") - - @decorators.skip_because(bug="1186354", - condition=CONF.service_available.neutron) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6e9f436d-f1ed-4f8e-a493-7275dfaa4b4d') - @test.services('network') - def test_security_groups_rules_exceed_limit(self): - # Negative test: Creation of Security Group Rules should FAIL - # when we reach limit maxSecurityGroupRules - self._update_quota('security_group_rules', 0) - - s_name = data_utils.rand_name('securitygroup') - s_description = data_utils.rand_name('description') - securitygroup = self.sg_client.create_security_group( - name=s_name, description=s_description)['security_group'] - self.addCleanup(self.sg_client.delete_security_group, - securitygroup['id']) - - secgroup_id = securitygroup['id'] - ip_protocol = 'tcp' - - # Check we cannot create SG rule anymore - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised when out of quota - self.assertRaises((lib_exc.OverLimit, lib_exc.Forbidden), - self.sgr_client.create_security_group_rule, - parent_group_id=secgroup_id, ip_protocol=ip_protocol, - from_port=1025, to_port=1025) diff --git a/tempest/api/compute/admin/test_security_group_default_rules.py b/tempest/api/compute/admin/test_security_group_default_rules.py deleted file mode 100644 index f2f3b573e..000000000 --- a/tempest/api/compute/admin/test_security_group_default_rules.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class SecurityGroupDefaultRulesTest(base.BaseV2ComputeAdminTest): - - @classmethod - # TODO(GMann): Once Bug# 1311500 is fixed, these test can run - # for Neutron also. - @testtools.skipIf(CONF.service_available.neutron, - "Skip as this functionality is not yet " - "implemented in Neutron. Related Bug#1311500") - def setup_credentials(cls): - # A network and a subnet will be created for these tests - cls.set_network_resources(network=True, subnet=True) - super(SecurityGroupDefaultRulesTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(SecurityGroupDefaultRulesTest, cls).setup_clients() - cls.adm_client = cls.os_admin.security_group_default_rules_client - - def _create_security_group_default_rules(self, ip_protocol='tcp', - from_port=22, to_port=22, - cidr='10.10.0.0/24'): - # Create Security Group default rule - rule = self.adm_client.create_security_default_group_rule( - ip_protocol=ip_protocol, - from_port=from_port, - to_port=to_port, - cidr=cidr)['security_group_default_rule'] - self.assertEqual(ip_protocol, rule['ip_protocol']) - self.assertEqual(from_port, rule['from_port']) - self.assertEqual(to_port, rule['to_port']) - self.assertEqual(cidr, rule['ip_range']['cidr']) - return rule - - @decorators.idempotent_id('6d880615-eec3-4d29-97c5-7a074dde239d') - def test_create_delete_security_group_default_rules(self): - # Create and delete Security Group default rule - ip_protocols = ['tcp', 'udp', 'icmp'] - for ip_protocol in ip_protocols: - rule = self._create_security_group_default_rules(ip_protocol) - # Delete Security Group default rule - self.adm_client.delete_security_group_default_rule(rule['id']) - self.assertRaises(lib_exc.NotFound, - self.adm_client.show_security_group_default_rule, - rule['id']) - - @decorators.idempotent_id('4d752e0a-33a1-4c3a-b498-ff8667ca22e5') - def test_create_security_group_default_rule_without_cidr(self): - ip_protocol = 'udp' - from_port = 80 - to_port = 80 - rule = self.adm_client.create_security_default_group_rule( - ip_protocol=ip_protocol, - from_port=from_port, - to_port=to_port)['security_group_default_rule'] - self.addCleanup(self.adm_client.delete_security_group_default_rule, - rule['id']) - self.assertNotEqual(0, rule['id']) - self.assertEqual('0.0.0.0/0', rule['ip_range']['cidr']) - - @decorators.idempotent_id('29f2d218-69b0-4a95-8f3d-6bd0ef732b3a') - def test_create_security_group_default_rule_with_blank_cidr(self): - ip_protocol = 'icmp' - from_port = 10 - to_port = 10 - cidr = '' - rule = self.adm_client.create_security_default_group_rule( - ip_protocol=ip_protocol, - from_port=from_port, - to_port=to_port, - cidr=cidr)['security_group_default_rule'] - self.addCleanup(self.adm_client.delete_security_group_default_rule, - rule['id']) - self.assertNotEqual(0, rule['id']) - self.assertEqual('0.0.0.0/0', rule['ip_range']['cidr']) - - @decorators.idempotent_id('6e6de55e-9146-4ae0-89f2-3569586e0b9b') - def test_security_group_default_rules_list(self): - ip_protocol = 'tcp' - from_port = 22 - to_port = 22 - cidr = '10.10.0.0/24' - rule = self._create_security_group_default_rules(ip_protocol, - from_port, - to_port, - cidr) - self.addCleanup(self.adm_client.delete_security_group_default_rule, - rule['id']) - rules = (self.adm_client.list_security_group_default_rules() - ['security_group_default_rules']) - self.assertNotEmpty(rules) - self.assertIn(rule, rules) - - @decorators.idempotent_id('15cbb349-86b4-4f71-a048-04b7ef3f150b') - def test_default_security_group_default_rule_show(self): - ip_protocol = 'tcp' - from_port = 22 - to_port = 22 - cidr = '10.10.0.0/24' - rule = self._create_security_group_default_rules(ip_protocol, - from_port, - to_port, - cidr) - self.addCleanup(self.adm_client.delete_security_group_default_rule, - rule['id']) - fetched_rule = self.adm_client.show_security_group_default_rule( - rule['id'])['security_group_default_rule'] - self.assertEqual(rule, fetched_rule) diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py deleted file mode 100644 index 8abe03aac..000000000 --- a/tempest/api/compute/admin/test_security_groups.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2013 NTT Data -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class SecurityGroupsTestAdminJSON(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(SecurityGroupsTestAdminJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.compute_security_groups_client - cls.client = cls.security_groups_client - - def _delete_security_group(self, securitygroup_id, admin=True): - if admin: - self.adm_client.delete_security_group(securitygroup_id) - else: - self.client.delete_security_group(securitygroup_id) - - @decorators.idempotent_id('49667619-5af9-4c63-ab5d-2cfdd1c8f7f1') - @test.services('network') - def test_list_security_groups_list_all_tenants_filter(self): - # Admin can list security groups of all tenants - # List of all security groups created - security_group_list = [] - # Create two security groups for a non-admin tenant - for _ in range(2): - name = data_utils.rand_name('securitygroup') - description = data_utils.rand_name('description') - securitygroup = self.client.create_security_group( - name=name, description=description)['security_group'] - self.addCleanup(self._delete_security_group, - securitygroup['id'], admin=False) - security_group_list.append(securitygroup) - - client_tenant_id = securitygroup['tenant_id'] - # Create two security groups for admin tenant - for _ in range(2): - name = data_utils.rand_name('securitygroup') - description = data_utils.rand_name('description') - adm_securitygroup = self.adm_client.create_security_group( - name=name, description=description)['security_group'] - self.addCleanup(self._delete_security_group, - adm_securitygroup['id']) - security_group_list.append(adm_securitygroup) - - # Fetch all security groups based on 'all_tenants' search filter - fetched_list = self.adm_client.list_security_groups( - all_tenants='true')['security_groups'] - sec_group_id_list = [sg['id'] for sg in fetched_list] - # Now check if all created Security Groups are present in fetched list - for sec_group in security_group_list: - self.assertIn(sec_group['id'], sec_group_id_list) - - # Fetch all security groups for non-admin user with 'all_tenants' - # search filter - fetched_list = (self.client.list_security_groups(all_tenants='true') - ['security_groups']) - # Now check if all created Security Groups are present in fetched list - for sec_group in fetched_list: - self.assertEqual(sec_group['tenant_id'], client_tenant_id, - "Failed to get all security groups for " - "non admin user.") diff --git a/tempest/api/compute/admin/test_server_diagnostics.py b/tempest/api/compute/admin/test_server_diagnostics.py deleted file mode 100644 index 005efddb8..000000000 --- a/tempest/api/compute/admin/test_server_diagnostics.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2017 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from tempest.api.compute import base -from tempest.lib import decorators - - -class ServerDiagnosticsTest(base.BaseV2ComputeAdminTest): - min_microversion = None - max_microversion = '2.47' - - @classmethod - def setup_clients(cls): - super(ServerDiagnosticsTest, cls).setup_clients() - cls.client = cls.os_admin.servers_client - - @decorators.idempotent_id('31ff3486-b8a0-4f56-a6c0-aab460531db3') - def test_get_server_diagnostics(self): - server_id = self.create_test_server(wait_until='ACTIVE')['id'] - diagnostics = self.client.show_server_diagnostics(server_id) - - # NOTE(snikitin): Before microversion 2.48 response data from each - # hypervisor (libvirt, xen, vmware) was different. None of the fields - # were equal. As this test is common for libvirt, xen and vmware CI - # jobs we can't check any field in the response because all fields are - # different. - self.assertNotEmpty(diagnostics) - - -class ServerDiagnosticsV248Test(base.BaseV2ComputeAdminTest): - min_microversion = '2.48' - max_microversion = 'latest' - - @classmethod - def setup_clients(cls): - super(ServerDiagnosticsV248Test, cls).setup_clients() - cls.client = cls.os_admin.servers_client - - @decorators.idempotent_id('64d0d48c-dff1-11e6-bf01-fe55135034f3') - def test_get_server_diagnostics(self): - server_id = self.create_test_server(wait_until='ACTIVE')['id'] - # Response status and filed types will be checked by json schema - self.client.show_server_diagnostics(server_id) - - # NOTE(snikitin): This is a special case for Xen hypervisor. In Xen - # case we're getting diagnostics stats from the RRDs which are updated - # every 5 seconds. It means that diagnostics information may be - # incomplete during first 5 seconds of VM life. In such cases methods - # which get diagnostics stats from Xen may raise exceptions or - # return `NaN` values. Such behavior must be handled correctly. - # Response must contain all diagnostics fields (may be with `None` - # values) and response status must be 200. Line above checks it by - # json schema. - time.sleep(10) - diagnostics = self.client.show_server_diagnostics(server_id) - - # NOTE(snikitin): After 10 seconds diagnostics fields must contain - # not None values. But we will check only "memory_details.maximum" - # field because only this field meets all the following conditions: - # 1) This field may be unset because of Xen 5 seconds timeout. - # 2) This field is present in responses from all three supported - # hypervisors (libvirt, xen, vmware). - self.assertIsNotNone(diagnostics['memory_details']['maximum']) diff --git a/tempest/api/compute/admin/test_server_diagnostics_negative.py b/tempest/api/compute/admin/test_server_diagnostics_negative.py deleted file mode 100644 index d5b66741c..000000000 --- a/tempest/api/compute/admin/test_server_diagnostics_negative.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2017 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ServerDiagnosticsNegativeTest(base.BaseV2ComputeAdminTest): - min_microversion = None - max_microversion = '2.47' - - @classmethod - def setup_clients(cls): - super(ServerDiagnosticsNegativeTest, cls).setup_clients() - cls.client = cls.servers_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e84e2234-60d2-42fa-8b30-e2d3049724ac') - def test_get_server_diagnostics_by_non_admin(self): - # Non-admin user cannot view server diagnostics according to policy - server_id = self.create_test_server(wait_until='ACTIVE')['id'] - self.assertRaises(lib_exc.Forbidden, - self.client.show_server_diagnostics, server_id) - - -class ServerDiagnosticsNegativeV248Test(ServerDiagnosticsNegativeTest): - min_microversion = '2.48' - max_microversion = 'latest' diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py deleted file mode 100644 index d9a78009c..000000000 --- a/tempest/api/compute/admin/test_servers.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common import waiters -from tempest.lib.common import fixed_network -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class ServersAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Servers API using admin privileges""" - - @classmethod - def setup_clients(cls): - super(ServersAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.servers_client - cls.non_admin_client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServersAdminTestJSON, cls).resource_setup() - - cls.s1_name = data_utils.rand_name(cls.__name__ + '-server') - server = cls.create_test_server(name=cls.s1_name) - cls.s1_id = server['id'] - - cls.s2_name = data_utils.rand_name(cls.__name__ + '-server') - server = cls.create_test_server(name=cls.s2_name, - wait_until='ACTIVE') - cls.s2_id = server['id'] - waiters.wait_for_server_status(cls.non_admin_client, - cls.s1_id, 'ACTIVE') - - @decorators.idempotent_id('06f960bb-15bb-48dc-873d-f96e89be7870') - def test_list_servers_filter_by_error_status(self): - # Filter the list of servers by server error status - params = {'status': 'error'} - self.client.reset_state(self.s1_id, state='error') - body = self.non_admin_client.list_servers(**params) - # Reset server's state to 'active' - self.client.reset_state(self.s1_id, state='active') - # Verify server's state - server = self.client.show_server(self.s1_id)['server'] - self.assertEqual(server['status'], 'ACTIVE') - servers = body['servers'] - # Verify error server in list result - self.assertIn(self.s1_id, map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2_id, map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('d56e9540-73ed-45e0-9b88-98fc419087eb') - def test_list_servers_detailed_filter_by_invalid_status(self): - params = {'status': 'invalid_status'} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - self.assertEmpty(servers) - - @decorators.idempotent_id('51717b38-bdc1-458b-b636-1cf82d99f62f') - def test_list_servers_by_admin(self): - # Listing servers by admin user returns a list which doesn't - # contain the other tenants' server by default - body = self.client.list_servers(detail=True) - servers = body['servers'] - - # This case is for the test environments which contain - # the existing servers before testing - servers_name = [server['name'] for server in servers] - self.assertNotIn(self.s1_name, servers_name) - self.assertNotIn(self.s2_name, servers_name) - - @decorators.idempotent_id('9f5579ae-19b4-4985-a091-2a5d56106580') - def test_list_servers_by_admin_with_all_tenants(self): - # Listing servers by admin user with all tenants parameter - # Here should be listed all servers - params = {'all_tenants': ''} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - servers_name = [server['name'] for server in servers] - - self.assertIn(self.s1_name, servers_name) - self.assertIn(self.s2_name, servers_name) - - @decorators.related_bug('1659811') - @decorators.idempotent_id('7e5d6b8f-454a-4ba1-8ae2-da857af8338b') - def test_list_servers_by_admin_with_specified_tenant(self): - # In nova v2, tenant_id is ignored unless all_tenants is specified - - # List the primary tenant but get nothing due to odd specified behavior - tenant_id = self.non_admin_client.tenant_id - params = {'tenant_id': tenant_id} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - servers_name = [x['name'] for x in servers] - self.assertNotIn(self.s1_name, servers_name) - self.assertNotIn(self.s2_name, servers_name) - - # List the primary tenant with all_tenants is specified - params = {'all_tenants': '', 'tenant_id': tenant_id} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - servers_name = [x['name'] for x in servers] - self.assertIn(self.s1_name, servers_name) - self.assertIn(self.s2_name, servers_name) - - # List the admin tenant shouldn't get servers created by other tenants - admin_tenant_id = self.client.tenant_id - params = {'all_tenants': '', 'tenant_id': admin_tenant_id} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - servers_name = [x['name'] for x in servers] - self.assertNotIn(self.s1_name, servers_name) - self.assertNotIn(self.s2_name, servers_name) - - @decorators.idempotent_id('86c7a8f7-50cf-43a9-9bac-5b985317134f') - def test_list_servers_filter_by_exist_host(self): - # Filter the list of servers by existent host - name = data_utils.rand_name(self.__class__.__name__ + '-server') - network = self.get_tenant_network() - network_kwargs = fixed_network.set_networks_kwarg(network) - # We need to create the server as an admin, so we can't use - # self.create_test_server() here as this method creates the server - # in the "primary" (i.e non-admin) tenant. - test_server, _ = compute.create_test_server( - self.os_admin, wait_until="ACTIVE", name=name, **network_kwargs) - self.addCleanup(self.client.delete_server, test_server['id']) - server = self.client.show_server(test_server['id'])['server'] - self.assertEqual(server['status'], 'ACTIVE') - hostname = server['OS-EXT-SRV-ATTR:host'] - params = {'host': hostname} - body = self.client.list_servers(**params) - servers = body['servers'] - nonexistent_params = {'host': 'nonexistent_host'} - nonexistent_body = self.client.list_servers(**nonexistent_params) - nonexistent_servers = nonexistent_body['servers'] - self.assertIn(test_server['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(test_server['id'], - map(lambda x: x['id'], nonexistent_servers)) - - @decorators.idempotent_id('ee8ae470-db70-474d-b752-690b7892cab1') - def test_reset_state_server(self): - # Reset server's state to 'error' - self.client.reset_state(self.s1_id, state='error') - - # Verify server's state - server = self.client.show_server(self.s1_id)['server'] - self.assertEqual(server['status'], 'ERROR') - - # Reset server's state to 'active' - self.client.reset_state(self.s1_id, state='active') - - # Verify server's state - server = self.client.show_server(self.s1_id)['server'] - self.assertEqual(server['status'], 'ACTIVE') - - @decorators.idempotent_id('682cb127-e5bb-4f53-87ce-cb9003604442') - def test_rebuild_server_in_error_state(self): - # The server in error state should be rebuilt using the provided - # image and changed to ACTIVE state - - # resetting vm state require admin privilege - self.client.reset_state(self.s1_id, state='error') - rebuilt_server = self.non_admin_client.rebuild_server( - self.s1_id, self.image_ref_alt)['server'] - self.addCleanup(waiters.wait_for_server_status, self.non_admin_client, - self.s1_id, 'ACTIVE') - self.addCleanup(self.non_admin_client.rebuild_server, self.s1_id, - self.image_ref) - - # Verify the properties in the initial response are correct - self.assertEqual(self.s1_id, rebuilt_server['id']) - rebuilt_image_id = rebuilt_server['image']['id'] - self.assertEqual(self.image_ref_alt, rebuilt_image_id) - self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id']) - waiters.wait_for_server_status(self.non_admin_client, - rebuilt_server['id'], 'ACTIVE', - raise_on_error=False) - # Verify the server properties after rebuilding - server = (self.non_admin_client.show_server(rebuilt_server['id']) - ['server']) - rebuilt_image_id = server['image']['id'] - self.assertEqual(self.image_ref_alt, rebuilt_image_id) - - @decorators.idempotent_id('7a1323b4-a6a2-497a-96cb-76c07b945c71') - def test_reset_network_inject_network_info(self): - # Reset Network of a Server - server = self.create_test_server(wait_until='ACTIVE') - self.client.reset_network(server['id']) - # Inject the Network Info into Server - self.client.inject_network_info(server['id']) - - @decorators.idempotent_id('fdcd9b33-0903-4e00-a1f7-b5f6543068d6') - def test_create_server_with_scheduling_hint(self): - # Create a server with scheduler hints. - hints = { - 'same_host': self.s1_id - } - self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE') diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py deleted file mode 100644 index 36567707f..000000000 --- a/tempest/api/compute/admin/test_servers_negative.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ServersAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Servers API using admin privileges""" - - @classmethod - def setup_clients(cls): - super(ServersAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_admin.servers_client - cls.quotas_client = cls.os_admin.quotas_client - - @classmethod - def resource_setup(cls): - super(ServersAdminNegativeTestJSON, cls).resource_setup() - cls.tenant_id = cls.client.tenant_id - - server = cls.create_test_server(wait_until='ACTIVE') - cls.s1_id = server['id'] - - @decorators.idempotent_id('28dcec23-f807-49da-822c-56a92ea3c687') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - @decorators.attr(type=['negative']) - def test_resize_server_using_overlimit_ram(self): - # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests. - self.useFixture(fixtures.LockFixture('compute_quotas')) - quota_set = self.quotas_client.show_quota_set( - self.tenant_id)['quota_set'] - ram = quota_set['ram'] - if ram == -1: - raise self.skipException("ram quota set is -1," - " cannot test overlimit") - ram += 1 - vcpus = 1 - disk = 5 - flavor_ref = self.create_flavor(ram=ram, vcpus=vcpus, disk=disk) - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.client.resize_server, - self.servers[0]['id'], - flavor_ref['id']) - - @decorators.idempotent_id('7368a427-2f26-4ad9-9ba9-911a0ec2b0db') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - @decorators.attr(type=['negative']) - def test_resize_server_using_overlimit_vcpus(self): - # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests. - self.useFixture(fixtures.LockFixture('compute_quotas')) - quota_set = self.quotas_client.show_quota_set( - self.tenant_id)['quota_set'] - vcpus = quota_set['cores'] - if vcpus == -1: - raise self.skipException("cores quota set is -1," - " cannot test overlimit") - vcpus += 1 - ram = 512 - disk = 5 - flavor_ref = self.create_flavor(ram=ram, vcpus=vcpus, disk=disk) - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.client.resize_server, - self.servers[0]['id'], - flavor_ref['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b0b4d8af-1256-41ef-9ee7-25f1c19dde80') - def test_reset_state_server_invalid_state(self): - self.assertRaises(lib_exc.BadRequest, - self.client.reset_state, self.s1_id, - state='invalid') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4cdcc984-fab0-4577-9a9d-6d558527ee9d') - def test_reset_state_server_invalid_type(self): - self.assertRaises(lib_exc.BadRequest, - self.client.reset_state, self.s1_id, - state=1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e741298b-8df2-46f0-81cb-8f814ff2504c') - def test_reset_state_server_nonexistent_server(self): - self.assertRaises(lib_exc.NotFound, - self.client.reset_state, '999', state='error') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('46a4e1ca-87ae-4d28-987a-1b6b136a0221') - def test_migrate_non_existent_server(self): - # migrate a non existent server - self.assertRaises(lib_exc.NotFound, - self.client.migrate_server, - data_utils.rand_uuid()) - - @decorators.idempotent_id('b0b17f83-d14e-4fc4-8f31-bcc9f3cfa629') - @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, - 'Cold migration not available.') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type=['negative']) - def test_migrate_server_invalid_state(self): - # create server. - server = self.create_test_server(wait_until='ACTIVE') - server_id = server['id'] - # suspend the server. - self.client.suspend_server(server_id) - waiters.wait_for_server_status(self.client, - server_id, 'SUSPENDED') - # migrate a suspended server should fail - self.assertRaises(lib_exc.Conflict, - self.client.migrate_server, - server_id) diff --git a/tempest/api/compute/admin/test_servers_on_multinodes.py b/tempest/api/compute/admin/test_servers_on_multinodes.py deleted file mode 100644 index 858998af9..000000000 --- a/tempest/api/compute/admin/test_servers_on_multinodes.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class ServersOnMultiNodesTest(base.BaseV2ComputeAdminTest): - - @classmethod - def resource_setup(cls): - super(ServersOnMultiNodesTest, cls).resource_setup() - cls.server01 = cls.create_test_server(wait_until='ACTIVE')['id'] - cls.host01 = cls._get_host(cls.server01) - - @classmethod - def skip_checks(cls): - super(ServersOnMultiNodesTest, cls).skip_checks() - - if CONF.compute.min_compute_nodes < 2: - raise cls.skipException( - "Less than 2 compute nodes, skipping multi-nodes test.") - - @classmethod - def _get_host(cls, server_id): - return cls.os_admin.servers_client.show_server( - server_id)['server']['OS-EXT-SRV-ATTR:host'] - - @decorators.idempotent_id('26a9d5df-6890-45f2-abc4-a659290cb130') - @testtools.skipUnless( - test.is_scheduler_filter_enabled("SameHostFilter"), - 'SameHostFilter is not available.') - def test_create_servers_on_same_host(self): - hints = {'same_host': self.server01} - server02 = self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE')['id'] - host02 = self._get_host(server02) - self.assertEqual(self.host01, host02) - - @decorators.idempotent_id('cc7ca884-6e3e-42a3-a92f-c522fcf25e8e') - @testtools.skipUnless( - test.is_scheduler_filter_enabled("DifferentHostFilter"), - 'DifferentHostFilter is not available.') - def test_create_servers_on_different_hosts(self): - hints = {'different_host': self.server01} - server02 = self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE')['id'] - host02 = self._get_host(server02) - self.assertNotEqual(self.host01, host02) - - @decorators.idempotent_id('7869cc84-d661-4e14-9f00-c18cdc89cf57') - @testtools.skipUnless( - test.is_scheduler_filter_enabled("DifferentHostFilter"), - 'DifferentHostFilter is not available.') - def test_create_servers_on_different_hosts_with_list_of_servers(self): - # This scheduler-hint supports list of servers also. - hints = {'different_host': [self.server01]} - server02 = self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE')['id'] - host02 = self._get_host(server02) - self.assertNotEqual(self.host01, host02) diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py deleted file mode 100644 index f3eb597f9..000000000 --- a/tempest/api/compute/admin/test_services.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2013 NEC Corporation -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators - - -class ServicesAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Services API. List and Enable/Disable require admin privileges.""" - - @classmethod - def setup_clients(cls): - super(ServicesAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.services_client - - @decorators.idempotent_id('5be41ef4-53d1-41cc-8839-5c2a48a1b283') - def test_list_services(self): - services = self.client.list_services()['services'] - self.assertNotEmpty(services) - - @decorators.idempotent_id('f345b1ec-bc6e-4c38-a527-3ca2bc00bef5') - def test_get_service_by_service_binary_name(self): - binary_name = 'nova-compute' - services = self.client.list_services(binary=binary_name)['services'] - self.assertNotEmpty(services) - for service in services: - self.assertEqual(binary_name, service['binary']) - - @decorators.idempotent_id('affb42d5-5b4b-43c8-8b0b-6dca054abcca') - def test_get_service_by_host_name(self): - services = self.client.list_services()['services'] - host_name = services[0]['host'] - services_on_host = [service for service in services if - service['host'] == host_name] - - services = self.client.list_services(host=host_name)['services'] - - # we could have a periodic job checkin between the 2 service - # lookups, so only compare binary lists. - s1 = map(lambda x: x['binary'], services) - s2 = map(lambda x: x['binary'], services_on_host) - - # sort the lists before comparing, to take out dependency - # on order. - self.assertEqual(sorted(s1), sorted(s2)) - - @decorators.idempotent_id('39397f6f-37b8-4234-8671-281e44c74025') - def test_get_service_by_service_and_host_name(self): - services = self.client.list_services()['services'] - host_name = services[0]['host'] - binary_name = services[0]['binary'] - - services = self.client.list_services(host=host_name, - binary=binary_name)['services'] - self.assertEqual(1, len(services)) - self.assertEqual(host_name, services[0]['host']) - self.assertEqual(binary_name, services[0]['binary']) diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py deleted file mode 100644 index 201670ab2..000000000 --- a/tempest/api/compute/admin/test_services_negative.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2013 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ServicesAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Services API. List and Enable/Disable require admin privileges.""" - - @classmethod - def setup_clients(cls): - super(ServicesAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_admin.services_client - cls.non_admin_client = cls.services_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1126d1f8-266e-485f-a687-adc547492646') - def test_list_services_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.list_services) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d0884a69-f693-4e79-a9af-232d15643bf7') - def test_get_service_by_invalid_params(self): - # return all services if send the request with invalid parameter - services = self.client.list_services()['services'] - services_xxx = (self.client.list_services(xxx='nova-compute') - ['services']) - self.assertEqual(len(services), len(services_xxx)) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1e966d4a-226e-47c7-b601-0b18a27add54') - def test_get_service_by_invalid_service_and_valid_host(self): - services = self.client.list_services()['services'] - host_name = services[0]['host'] - services = self.client.list_services(host=host_name, - binary='xxx')['services'] - self.assertEmpty(services) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('64e7e7fb-69e8-4cb6-a71d-8d5eb0c98655') - def test_get_service_with_valid_service_and_invalid_host(self): - services = self.client.list_services()['services'] - binary_name = services[0]['binary'] - services = self.client.list_services(host='xxx', - binary=binary_name)['services'] - self.assertEmpty(services) diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py deleted file mode 100644 index d4c60b349..000000000 --- a/tempest/api/compute/admin/test_simple_tenant_usage.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import datetime - -from tempest.api.compute import base -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as e - -# Time that waits for until returning valid response -# TODO(takmatsu): Ideally this value would come from configuration. -VALID_WAIT = 30 - - -class TenantUsagesTestJSON(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(TenantUsagesTestJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.tenant_usages_client - cls.client = cls.os_primary.tenant_usages_client - - @classmethod - def resource_setup(cls): - super(TenantUsagesTestJSON, cls).resource_setup() - cls.tenant_id = cls.client.tenant_id - - # Create a server in the demo tenant - cls.create_test_server(wait_until='ACTIVE') - - now = datetime.datetime.now() - cls.start = cls._parse_strtime(now - datetime.timedelta(days=1)) - cls.end = cls._parse_strtime(now + datetime.timedelta(days=1)) - - @classmethod - def _parse_strtime(cls, at): - # Returns formatted datetime - return at.strftime('%Y-%m-%dT%H:%M:%S.%f') - - def call_until_valid(self, func, duration, *args, **kwargs): - # Call until get valid response for "duration" - # because tenant usage doesn't become available immediately - # after create VM. - def is_valid(): - try: - self.resp = func(*args, **kwargs) - return True - except e.InvalidHTTPResponseBody: - return False - self.assertEqual(test_utils.call_until_true(is_valid, duration, 1), - True, "%s not return valid response in %s secs" % ( - func.__name__, duration)) - return self.resp - - @decorators.idempotent_id('062c8ae9-9912-4249-8b51-e38d664e926e') - def test_list_usage_all_tenants(self): - # Get usage for all tenants - tenant_usage = self.call_until_valid( - self.adm_client.list_tenant_usages, VALID_WAIT, - start=self.start, end=self.end, detailed="1")['tenant_usages'][0] - self.assertEqual(len(tenant_usage), 8) - - @decorators.idempotent_id('94135049-a4c5-4934-ad39-08fa7da4f22e') - def test_get_usage_tenant(self): - # Get usage for a specific tenant - tenant_usage = self.call_until_valid( - self.adm_client.show_tenant_usage, VALID_WAIT, - self.tenant_id, start=self.start, end=self.end)['tenant_usage'] - - self.assertEqual(len(tenant_usage), 8) - - @decorators.idempotent_id('9d00a412-b40e-4fd9-8eba-97b496316116') - def test_get_usage_tenant_with_non_admin_user(self): - # Get usage for a specific tenant with non admin user - tenant_usage = self.call_until_valid( - self.client.show_tenant_usage, VALID_WAIT, - self.tenant_id, start=self.start, end=self.end)['tenant_usage'] - self.assertEqual(len(tenant_usage), 8) diff --git a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py deleted file mode 100644 index cb60b8d30..000000000 --- a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import datetime - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class TenantUsagesNegativeTestJSON(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(TenantUsagesNegativeTestJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.tenant_usages_client - cls.client = cls.os_primary.tenant_usages_client - - @classmethod - def resource_setup(cls): - super(TenantUsagesNegativeTestJSON, cls).resource_setup() - now = datetime.datetime.now() - cls.start = cls._parse_strtime(now - datetime.timedelta(days=1)) - cls.end = cls._parse_strtime(now + datetime.timedelta(days=1)) - - @classmethod - def _parse_strtime(cls, at): - # Returns formatted datetime - return at.strftime('%Y-%m-%dT%H:%M:%S.%f') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8b21e135-d94b-4991-b6e9-87059609c8ed') - def test_get_usage_tenant_with_empty_tenant_id(self): - # Get usage for a specific tenant empty - params = {'start': self.start, - 'end': self.end} - self.assertRaises(lib_exc.NotFound, - self.adm_client.show_tenant_usage, - '', **params) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4079dd2a-9e8d-479f-869d-6fa985ce45b6') - def test_get_usage_tenant_with_invalid_date(self): - # Get usage for tenant with invalid date - params = {'start': self.end, - 'end': self.start} - self.assertRaises(lib_exc.BadRequest, - self.adm_client.show_tenant_usage, - self.client.tenant_id, **params) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bbe6fe2c-15d8-404c-a0a2-44fad0ad5cc7') - def test_list_usage_all_tenants_with_non_admin_user(self): - # Get usage for all tenants with non admin user - params = {'start': self.start, - 'end': self.end, - 'detailed': "1"} - self.assertRaises(lib_exc.Forbidden, - self.client.list_tenant_usages, **params) diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py deleted file mode 100644 index 22a5bc48e..000000000 --- a/tempest/api/compute/admin/test_volume_swap.py +++ /dev/null @@ -1,123 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class TestVolumeSwap(base.BaseV2ComputeAdminTest): - """The test suite for swapping of volume with admin user. - - The following is the scenario outline: - 1. Create a volume "volume1" with non-admin. - 2. Create a volume "volume2" with non-admin. - 3. Boot an instance "instance1" with non-admin. - 4. Attach "volume1" to "instance1" with non-admin. - 5. Swap volume from "volume1" to "volume2" as admin. - 6. Check the swap volume is successful and "volume2" - is attached to "instance1" and "volume1" is in available state. - 7. Swap volume from "volume2" to "volume1" as admin. - 8. Check the swap volume is successful and "volume1" - is attached to "instance1" and "volume2" is in available state. - """ - - @classmethod - def skip_checks(cls): - super(TestVolumeSwap, cls).skip_checks() - if not CONF.compute_feature_enabled.swap_volume: - raise cls.skipException("Swapping volumes is not supported.") - - def _wait_for_server_volume_swap(self, server_id, old_volume_id, - new_volume_id): - """Waits for a server to swap the old volume to a new one.""" - volume_attachments = self.servers_client.list_volume_attachments( - server_id)['volumeAttachments'] - attached_volume_ids = [attachment['volumeId'] - for attachment in volume_attachments] - start = int(time.time()) - - while (old_volume_id in attached_volume_ids) \ - or (new_volume_id not in attached_volume_ids): - time.sleep(self.servers_client.build_interval) - volume_attachments = self.servers_client.list_volume_attachments( - server_id)['volumeAttachments'] - attached_volume_ids = [attachment['volumeId'] - for attachment in volume_attachments] - - if int(time.time()) - start >= self.servers_client.build_timeout: - old_vol_bdm_status = 'in BDM' \ - if old_volume_id in attached_volume_ids else 'not in BDM' - new_vol_bdm_status = 'in BDM' \ - if new_volume_id in attached_volume_ids else 'not in BDM' - message = ('Failed to swap old volume %(old_volume_id)s ' - '(current %(old_vol_bdm_status)s) to new volume ' - '%(new_volume_id)s (current %(new_vol_bdm_status)s)' - ' on server %(server_id)s within the required time ' - '(%(timeout)s s)' % - {'old_volume_id': old_volume_id, - 'old_vol_bdm_status': old_vol_bdm_status, - 'new_volume_id': new_volume_id, - 'new_vol_bdm_status': new_vol_bdm_status, - 'server_id': server_id, - 'timeout': self.servers_client.build_timeout}) - raise lib_exc.TimeoutException(message) - - @decorators.idempotent_id('1769f00d-a693-4d67-a631-6a3496773813') - @test.services('volume') - def test_volume_swap(self): - # Create two volumes. - # NOTE(gmann): Volumes are created before server creation so that - # volumes cleanup can happen successfully irrespective of which volume - # is attached to server. - volume1 = self.create_volume() - volume2 = self.create_volume() - # Boot server - server = self.create_test_server(wait_until='ACTIVE') - # Attach "volume1" to server - self.attach_volume(server, volume1) - # Swap volume from "volume1" to "volume2" - self.admin_servers_client.update_attached_volume( - server['id'], volume1['id'], volumeId=volume2['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume1['id'], 'available') - waiters.wait_for_volume_resource_status(self.volumes_client, - volume2['id'], 'in-use') - self._wait_for_server_volume_swap(server['id'], volume1['id'], - volume2['id']) - # Verify "volume2" is attached to the server - vol_attachments = self.servers_client.list_volume_attachments( - server['id'])['volumeAttachments'] - self.assertEqual(1, len(vol_attachments)) - self.assertIn(volume2['id'], vol_attachments[0]['volumeId']) - - # Swap volume from "volume2" to "volume1" - self.admin_servers_client.update_attached_volume( - server['id'], volume2['id'], volumeId=volume1['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume2['id'], 'available') - waiters.wait_for_volume_resource_status(self.volumes_client, - volume1['id'], 'in-use') - self._wait_for_server_volume_swap(server['id'], volume2['id'], - volume1['id']) - # Verify "volume1" is attached to the server - vol_attachments = self.servers_client.list_volume_attachments( - server['id'])['volumeAttachments'] - self.assertEqual(1, len(vol_attachments)) - self.assertIn(volume1['id'], vol_attachments[0]['volumeId']) diff --git a/tempest/api/compute/admin/test_volumes_negative.py b/tempest/api/compute/admin/test_volumes_negative.py deleted file mode 100644 index 4a7f36f2b..000000000 --- a/tempest/api/compute/admin/test_volumes_negative.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class VolumesAdminNegativeTest(base.BaseV2ComputeAdminTest): - - @classmethod - def skip_checks(cls): - super(VolumesAdminNegativeTest, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def resource_setup(cls): - super(VolumesAdminNegativeTest, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('309b5ecd-0585-4a7e-a36f-d2b2bf55259d') - def test_update_attached_volume_with_nonexistent_volume_in_uri(self): - volume = self.create_volume() - nonexistent_volume = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.admin_servers_client.update_attached_volume, - self.server['id'], nonexistent_volume, - volumeId=volume['id']) - - @decorators.related_bug('1629110', status_code=400) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7dcac15a-b107-46d3-a5f6-cb863f4e454a') - def test_update_attached_volume_with_nonexistent_volume_in_body(self): - volume = self.create_volume() - self.attach_volume(self.server, volume) - - nonexistent_volume = data_utils.rand_uuid() - self.assertRaises(lib_exc.BadRequest, - self.admin_servers_client.update_attached_volume, - self.server['id'], volume['id'], - volumeId=nonexistent_volume) diff --git a/tempest/api/compute/api_microversion_fixture.py b/tempest/api/compute/api_microversion_fixture.py deleted file mode 100644 index 695af5200..000000000 --- a/tempest/api/compute/api_microversion_fixture.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures - -from tempest.lib.services.compute import base_compute_client - - -class APIMicroversionFixture(fixtures.Fixture): - - def __init__(self, compute_microversion): - self.compute_microversion = compute_microversion - - def _setUp(self): - super(APIMicroversionFixture, self)._setUp() - base_compute_client.COMPUTE_MICROVERSION = self.compute_microversion - self.addCleanup(self._reset_compute_microversion) - - def _reset_compute_microversion(self): - base_compute_client.COMPUTE_MICROVERSION = None diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py deleted file mode 100644 index feabe35d1..000000000 --- a/tempest/api/compute/base.py +++ /dev/null @@ -1,507 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from oslo_log import log as logging - -from tempest.api.compute import api_microversion_fixture -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest import exceptions -from tempest.lib.common import api_version_request -from tempest.lib.common import api_version_utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -import tempest.test - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest, - tempest.test.BaseTestCase): - """Base test case class for all Compute API tests.""" - - force_tenant_isolation = False - - # TODO(andreaf) We should care also for the alt_manager here - # but only once client lazy load in the manager is done - credentials = ['primary'] - - @classmethod - def skip_checks(cls): - super(BaseV2ComputeTest, cls).skip_checks() - if not CONF.service_available.nova: - raise cls.skipException("Nova is not available") - cfg_min_version = CONF.compute.min_microversion - cfg_max_version = CONF.compute.max_microversion - api_version_utils.check_skip_with_microversion(cls.min_microversion, - cls.max_microversion, - cfg_min_version, - cfg_max_version) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(BaseV2ComputeTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(BaseV2ComputeTest, cls).setup_clients() - cls.servers_client = cls.os_primary.servers_client - cls.server_groups_client = cls.os_primary.server_groups_client - cls.flavors_client = cls.os_primary.flavors_client - cls.compute_images_client = cls.os_primary.compute_images_client - cls.extensions_client = cls.os_primary.extensions_client - cls.floating_ip_pools_client = cls.os_primary.floating_ip_pools_client - cls.floating_ips_client = cls.os_primary.compute_floating_ips_client - cls.keypairs_client = cls.os_primary.keypairs_client - cls.security_group_rules_client = ( - cls.os_primary.compute_security_group_rules_client) - cls.security_groups_client =\ - cls.os_primary.compute_security_groups_client - cls.quotas_client = cls.os_primary.quotas_client - cls.compute_networks_client = cls.os_primary.compute_networks_client - cls.limits_client = cls.os_primary.limits_client - cls.volumes_extensions_client =\ - cls.os_primary.volumes_extensions_client - cls.snapshots_extensions_client =\ - cls.os_primary.snapshots_extensions_client - cls.interfaces_client = cls.os_primary.interfaces_client - cls.fixed_ips_client = cls.os_primary.fixed_ips_client - cls.availability_zone_client = cls.os_primary.availability_zone_client - cls.agents_client = cls.os_primary.agents_client - cls.aggregates_client = cls.os_primary.aggregates_client - cls.services_client = cls.os_primary.services_client - cls.instance_usages_audit_log_client = ( - cls.os_primary.instance_usages_audit_log_client) - cls.hypervisor_client = cls.os_primary.hypervisor_client - cls.certificates_client = cls.os_primary.certificates_client - cls.migrations_client = cls.os_primary.migrations_client - cls.security_group_default_rules_client = ( - cls.os_primary.security_group_default_rules_client) - cls.versions_client = cls.os_primary.compute_versions_client - - cls.volumes_client = cls.os_primary.volumes_v2_client - - @classmethod - def resource_setup(cls): - super(BaseV2ComputeTest, cls).resource_setup() - cls.request_microversion = ( - api_version_utils.select_request_microversion( - cls.min_microversion, - CONF.compute.min_microversion)) - cls.build_interval = CONF.compute.build_interval - cls.build_timeout = CONF.compute.build_timeout - cls.image_ref = CONF.compute.image_ref - cls.image_ref_alt = CONF.compute.image_ref_alt - cls.flavor_ref = CONF.compute.flavor_ref - cls.flavor_ref_alt = CONF.compute.flavor_ref_alt - cls.ssh_user = CONF.validation.image_ssh_user - cls.image_ssh_user = CONF.validation.image_ssh_user - cls.image_ssh_password = CONF.validation.image_ssh_password - cls.servers = [] - cls.images = [] - cls.security_groups = [] - cls.server_groups = [] - cls.volumes = [] - - @classmethod - def resource_cleanup(cls): - cls.clear_resources('images', cls.images, - cls.compute_images_client.delete_image) - cls.clear_servers() - cls.clear_resources('security groups', cls.security_groups, - cls.security_groups_client.delete_security_group) - cls.clear_resources('server groups', cls.server_groups, - cls.server_groups_client.delete_server_group) - cls.clear_volumes() - super(BaseV2ComputeTest, cls).resource_cleanup() - - @classmethod - def clear_servers(cls): - LOG.debug('Clearing servers: %s', ','.join( - server['id'] for server in cls.servers)) - for server in cls.servers: - try: - test_utils.call_and_ignore_notfound_exc( - cls.servers_client.delete_server, server['id']) - except Exception: - LOG.exception('Deleting server %s failed', server['id']) - - for server in cls.servers: - try: - waiters.wait_for_server_termination(cls.servers_client, - server['id']) - except Exception: - LOG.exception('Waiting for deletion of server %s failed', - server['id']) - - @classmethod - def server_check_teardown(cls): - """Checks is the shared server clean enough for subsequent test. - - Method will delete the server when it's dirty. - The setUp method is responsible for creating a new server. - Exceptions raised in tearDown class are fails the test case, - This method supposed to use only by tearDown methods, when - the shared server_id is stored in the server_id of the class. - """ - if getattr(cls, 'server_id', None) is not None: - try: - waiters.wait_for_server_status(cls.servers_client, - cls.server_id, 'ACTIVE') - except Exception as exc: - LOG.exception(exc) - cls.servers_client.delete_server(cls.server_id) - waiters.wait_for_server_termination(cls.servers_client, - cls.server_id) - cls.server_id = None - raise - - @classmethod - def clear_resources(cls, resource_name, resources, resource_del_func): - LOG.debug('Clearing %s: %s', resource_name, - ','.join(map(str, resources))) - for res_id in resources: - try: - test_utils.call_and_ignore_notfound_exc( - resource_del_func, res_id) - except Exception as exc: - LOG.exception('Exception raised deleting %s: %s', - resource_name, res_id) - LOG.exception(exc) - - @classmethod - def create_test_server(cls, validatable=False, volume_backed=False, - **kwargs): - """Wrapper utility that returns a test server. - - This wrapper utility calls the common create test server and - returns a test server. The purpose of this wrapper is to minimize - the impact on the code of the tests already using this - function. - - :param validatable: Whether the server will be pingable or sshable. - :param volume_backed: Whether the instance is volume backed or not. - """ - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name(cls.__name__ + "-server") - - request_version = api_version_request.APIVersionRequest( - cls.request_microversion) - v2_37_version = api_version_request.APIVersionRequest('2.37') - - # NOTE(snikitin): since microversion v2.37 'networks' field is required - if request_version >= v2_37_version and 'networks' not in kwargs: - kwargs['networks'] = 'none' - - tenant_network = cls.get_tenant_network() - body, servers = compute.create_test_server( - cls.os_primary, - validatable, - validation_resources=cls.validation_resources, - tenant_network=tenant_network, - volume_backed=volume_backed, - **kwargs) - - cls.servers.extend(servers) - - return body - - @classmethod - def create_security_group(cls, name=None, description=None): - if name is None: - name = data_utils.rand_name(cls.__name__ + "-securitygroup") - if description is None: - description = data_utils.rand_name('description') - body = cls.security_groups_client.create_security_group( - name=name, description=description)['security_group'] - cls.security_groups.append(body['id']) - - return body - - @classmethod - def create_test_server_group(cls, name="", policy=None): - if not name: - name = data_utils.rand_name(cls.__name__ + "-Server-Group") - if policy is None: - policy = ['affinity'] - body = cls.server_groups_client.create_server_group( - name=name, policies=policy)['server_group'] - cls.server_groups.append(body['id']) - return body - - def wait_for(self, condition): - """Repeatedly calls condition() until a timeout.""" - start_time = int(time.time()) - while True: - try: - condition() - except Exception: - pass - else: - return - if int(time.time()) - start_time >= self.build_timeout: - condition() - return - time.sleep(self.build_interval) - - @staticmethod - def _delete_volume(volumes_client, volume_id): - """Deletes the given volume and waits for it to be gone.""" - try: - volumes_client.delete_volume(volume_id) - # TODO(mriedem): We should move the wait_for_resource_deletion - # into the delete_volume method as a convenience to the caller. - volumes_client.wait_for_resource_deletion(volume_id) - except lib_exc.NotFound: - LOG.warning("Unable to delete volume '%s' since it was not found. " - "Maybe it was already deleted?", volume_id) - - @classmethod - def prepare_instance_network(cls): - if (CONF.validation.auth_method != 'disabled' and - CONF.validation.connect_method == 'floating'): - cls.set_network_resources(network=True, subnet=True, router=True, - dhcp=True) - - @classmethod - def create_image_from_server(cls, server_id, **kwargs): - """Wrapper utility that returns an image created from the server.""" - name = kwargs.pop('name', - data_utils.rand_name(cls.__name__ + "-image")) - wait_until = kwargs.pop('wait_until', None) - wait_for_server = kwargs.pop('wait_for_server', True) - - image = cls.compute_images_client.create_image(server_id, name=name, - **kwargs) - image_id = data_utils.parse_image_id(image.response['location']) - cls.images.append(image_id) - - if wait_until is not None: - try: - waiters.wait_for_image_status(cls.compute_images_client, - image_id, wait_until) - except lib_exc.NotFound: - if wait_until.upper() == 'ACTIVE': - # If the image is not found after create_image returned - # that means the snapshot failed in nova-compute and nova - # deleted the image. There should be a compute fault - # recorded with the server in that case, so get the server - # and dump some details. - server = ( - cls.servers_client.show_server(server_id)['server']) - if 'fault' in server: - raise exceptions.SnapshotNotFoundException( - server['fault'], image_id=image_id) - else: - raise exceptions.SnapshotNotFoundException( - image_id=image_id) - else: - raise - image = cls.compute_images_client.show_image(image_id)['image'] - - if wait_until.upper() == 'ACTIVE': - if wait_for_server: - waiters.wait_for_server_status(cls.servers_client, - server_id, 'ACTIVE') - return image - - @classmethod - def rebuild_server(cls, server_id, validatable=False, **kwargs): - # Destroy an existing server and creates a new one - if server_id: - cls.delete_server(server_id) - - cls.password = data_utils.rand_password() - server = cls.create_test_server( - validatable, - wait_until='ACTIVE', - adminPass=cls.password, - **kwargs) - return server['id'] - - @classmethod - def delete_server(cls, server_id): - """Deletes an existing server and waits for it to be gone.""" - try: - cls.servers_client.delete_server(server_id) - waiters.wait_for_server_termination(cls.servers_client, - server_id) - except Exception: - LOG.exception('Failed to delete server %s', server_id) - - @classmethod - def resize_server(cls, server_id, new_flavor_id, **kwargs): - """resize and confirm_resize an server, waits for it to be ACTIVE.""" - cls.servers_client.resize_server(server_id, new_flavor_id, **kwargs) - waiters.wait_for_server_status(cls.servers_client, server_id, - 'VERIFY_RESIZE') - cls.servers_client.confirm_resize_server(server_id) - waiters.wait_for_server_status(cls.servers_client, server_id, 'ACTIVE') - - @classmethod - def delete_volume(cls, volume_id): - """Deletes the given volume and waits for it to be gone.""" - cls._delete_volume(cls.volumes_client, volume_id) - - @classmethod - def get_server_ip(cls, server): - """Get the server fixed or floating IP. - - Based on the configuration we're in, return a correct ip - address for validating that a guest is up. - """ - if CONF.validation.connect_method == 'floating': - return cls.validation_resources['floating_ip']['ip'] - elif CONF.validation.connect_method == 'fixed': - addresses = server['addresses'][CONF.validation.network_for_ssh] - for address in addresses: - if address['version'] == CONF.validation.ip_version_for_ssh: - return address['addr'] - raise exceptions.ServerUnreachable(server_id=server['id']) - else: - raise lib_exc.InvalidConfiguration() - - def setUp(self): - super(BaseV2ComputeTest, self).setUp() - self.useFixture(api_microversion_fixture.APIMicroversionFixture( - self.request_microversion)) - - @classmethod - def create_volume(cls, image_ref=None, **kwargs): - """Create a volume and wait for it to become 'available'. - - :param image_ref: Specify an image id to create a bootable volume. - :**kwargs: other parameters to create volume. - :returns: The available volume. - """ - if 'size' not in kwargs: - kwargs['size'] = CONF.volume.volume_size - if 'display_name' not in kwargs: - vol_name = data_utils.rand_name(cls.__name__ + '-volume') - kwargs['display_name'] = vol_name - if image_ref is not None: - kwargs['imageRef'] = image_ref - volume = cls.volumes_client.create_volume(**kwargs)['volume'] - cls.volumes.append(volume) - waiters.wait_for_volume_resource_status(cls.volumes_client, - volume['id'], 'available') - return volume - - @classmethod - def clear_volumes(cls): - LOG.debug('Clearing volumes: %s', ','.join( - volume['id'] for volume in cls.volumes)) - for volume in cls.volumes: - try: - test_utils.call_and_ignore_notfound_exc( - cls.volumes_client.delete_volume, volume['id']) - except Exception: - LOG.exception('Deleting volume %s failed', volume['id']) - - for volume in cls.volumes: - try: - cls.volumes_client.wait_for_resource_deletion(volume['id']) - except Exception: - LOG.exception('Waiting for deletion of volume %s failed', - volume['id']) - - def attach_volume(self, server, volume, device=None, check_reserved=False): - """Attaches volume to server and waits for 'in-use' volume status. - - The volume will be detached when the test tears down. - - :param server: The server to which the volume will be attached. - :param volume: The volume to attach. - :param device: Optional mountpoint for the attached volume. Note that - this is not guaranteed for all hypervisors and is not recommended. - :param check_reserved: Consider a status of reserved as valid for - completion. This is to handle new Cinder attach where we more - accurately use 'reserved' for things like attaching to a shelved - server. - """ - attach_kwargs = dict(volumeId=volume['id']) - if device: - attach_kwargs['device'] = device - - attachment = self.servers_client.attach_volume( - server['id'], **attach_kwargs)['volumeAttachment'] - # On teardown detach the volume and wait for it to be available. This - # is so we don't error out when trying to delete the volume during - # teardown. - self.addCleanup(waiters.wait_for_volume_resource_status, - self.volumes_client, volume['id'], 'available') - # Ignore 404s on detach in case the server is deleted or the volume - # is already detached. - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.servers_client.detach_volume, - server['id'], volume['id']) - statuses = ['in-use'] - if check_reserved: - statuses.append('reserved') - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], statuses) - return attachment - - -class BaseV2ComputeAdminTest(BaseV2ComputeTest): - """Base test case class for Compute Admin API tests.""" - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(BaseV2ComputeAdminTest, cls).setup_clients() - cls.availability_zone_admin_client = ( - cls.os_admin.availability_zone_client) - cls.admin_flavors_client = cls.os_admin.flavors_client - cls.admin_servers_client = cls.os_admin.servers_client - - def create_flavor(self, ram, vcpus, disk, name=None, - is_public='True', **kwargs): - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + "-flavor") - id = kwargs.pop('id', data_utils.rand_int_id(start=1000)) - client = self.admin_flavors_client - flavor = client.create_flavor( - ram=ram, vcpus=vcpus, disk=disk, name=name, - id=id, is_public=is_public, **kwargs)['flavor'] - self.addCleanup(client.wait_for_resource_deletion, flavor['id']) - self.addCleanup(client.delete_flavor, flavor['id']) - return flavor - - def get_host_for_server(self, server_id): - server_details = self.admin_servers_client.show_server(server_id) - return server_details['server']['OS-EXT-SRV-ATTR:host'] - - def get_host_other_than(self, server_id): - source_host = self.get_host_for_server(server_id) - - list_hosts_resp = self.os_admin.hosts_client.list_hosts()['hosts'] - hosts = [ - host_record['host_name'] - for host_record in list_hosts_resp - if host_record['service'] == 'compute' - ] - - for target_host in hosts: - if source_host != target_host: - return target_host diff --git a/tempest/api/compute/certificates/__init__.py b/tempest/api/compute/certificates/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/certificates/test_certificates.py b/tempest/api/compute/certificates/test_certificates.py deleted file mode 100644 index a39fec95d..000000000 --- a/tempest/api/compute/certificates/test_certificates.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class CertificatesV2TestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(CertificatesV2TestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.nova_cert: - raise cls.skipException("Nova cert is not available") - - @decorators.idempotent_id('c070a441-b08e-447e-a733-905909535b1b') - def test_create_root_certificate(self): - # create certificates - body = self.certificates_client.create_certificate()['certificate'] - self.assertIn('data', body) - self.assertIn('private_key', body) - - @decorators.idempotent_id('3ac273d0-92d2-4632-bdfc-afbc21d4606c') - def test_get_root_certificate(self): - # get the root certificate - body = (self.certificates_client.show_certificate('root') - ['certificate']) - self.assertIn('data', body) - self.assertIn('private_key', body) diff --git a/tempest/api/compute/flavors/__init__.py b/tempest/api/compute/flavors/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py deleted file mode 100644 index d5bb45ad9..000000000 --- a/tempest/api/compute/flavors/test_flavors.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators - - -class FlavorsV2TestJSON(base.BaseV2ComputeTest): - _min_disk = 'minDisk' - _min_ram = 'minRam' - - @decorators.attr(type='smoke') - @decorators.idempotent_id('e36c0eaa-dff5-4082-ad1f-3f9a80aa3f59') - def test_list_flavors(self): - # List of all flavors should contain the expected flavor - flavors = self.flavors_client.list_flavors()['flavors'] - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_min_detail = {'id': flavor['id'], 'links': flavor['links'], - 'name': flavor['name']} - self.assertIn(flavor_min_detail, flavors) - - @decorators.idempotent_id('6e85fde4-b3cd-4137-ab72-ed5f418e8c24') - def test_list_flavors_with_detail(self): - # Detailed list of all flavors should contain the expected flavor - flavors = self.flavors_client.list_flavors(detail=True)['flavors'] - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - self.assertIn(flavor, flavors) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('1f12046b-753d-40d2-abb6-d8eb8b30cb2f') - def test_get_flavor(self): - # The expected flavor details should be returned - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - self.assertEqual(self.flavor_ref, flavor['id']) - - @decorators.idempotent_id('8d7691b3-6ed4-411a-abc9-2839a765adab') - def test_list_flavors_limit_results(self): - # Only the expected number of flavors should be returned - params = {'limit': 1} - flavors = self.flavors_client.list_flavors(**params)['flavors'] - self.assertEqual(1, len(flavors)) - - @decorators.idempotent_id('b26f6327-2886-467a-82be-cef7a27709cb') - def test_list_flavors_detailed_limit_results(self): - # Only the expected number of flavors (detailed) should be returned - params = {'limit': 1} - flavors = self.flavors_client.list_flavors(detail=True, - **params)['flavors'] - self.assertEqual(1, len(flavors)) - - @decorators.idempotent_id('e800f879-9828-4bd0-8eae-4f17189951fb') - def test_list_flavors_using_marker(self): - # The list of flavors should start from the provided marker - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {'marker': flavor_id} - flavors = self.flavors_client.list_flavors(**params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id], - 'The list of flavors did not start after the marker.') - - @decorators.idempotent_id('6db2f0c0-ddee-4162-9c84-0703d3dd1107') - def test_list_flavors_detailed_using_marker(self): - # The list of flavors should start from the provided marker - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {'marker': flavor_id} - flavors = self.flavors_client.list_flavors(detail=True, - **params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id], - 'The list of flavors did not start after the marker.') - - @decorators.idempotent_id('3df2743e-3034-4e57-a4cb-b6527f6eac79') - def test_list_flavors_detailed_filter_by_min_disk(self): - # The detailed list of flavors should be filtered by disk space - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {self._min_disk: flavor['disk'] + 1} - flavors = self.flavors_client.list_flavors(detail=True, - **params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id]) - - @decorators.idempotent_id('09fe7509-b4ee-4b34-bf8b-39532dc47292') - def test_list_flavors_detailed_filter_by_min_ram(self): - # The detailed list of flavors should be filtered by RAM - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {self._min_ram: flavor['ram'] + 1} - flavors = self.flavors_client.list_flavors(detail=True, - **params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id]) - - @decorators.idempotent_id('10645a4d-96f5-443f-831b-730711e11dd4') - def test_list_flavors_filter_by_min_disk(self): - # The list of flavors should be filtered by disk space - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {self._min_disk: flavor['disk'] + 1} - flavors = self.flavors_client.list_flavors(**params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id]) - - @decorators.idempotent_id('935cf550-e7c8-4da6-8002-00f92d5edfaa') - def test_list_flavors_filter_by_min_ram(self): - # The list of flavors should be filtered by RAM - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {self._min_ram: flavor['ram'] + 1} - flavors = self.flavors_client.list_flavors(**params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id]) diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py deleted file mode 100644 index ebb9d2ec5..000000000 --- a/tempest/api/compute/flavors/test_flavors_negative.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2017 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import random - -import six - -from tempest.api.compute import base -from tempest.common import image as common_image -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FlavorsV2NegativeTest(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(FlavorsV2NegativeTest, cls).setup_clients() - if CONF.image_feature_enabled.api_v1: - cls.images_client = cls.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - cls.images_client = cls.os_primary.image_client_v2 - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - - @decorators.attr(type=['negative']) - @test.services('image') - @decorators.idempotent_id('90f0d93a-91c1-450c-91e6-07d18172cefe') - def test_boot_with_low_ram(self): - """Try boot a vm with lower than min ram - - Create an image with min_ram value - Try to create server with flavor of insufficient ram size from - that image - """ - flavor = self.flavors_client.show_flavor( - CONF.compute.flavor_ref)['flavor'] - min_img_ram = flavor['ram'] + 1 - size = random.randint(1024, 4096) - image_file = six.BytesIO(data_utils.random_bytes(size)) - params = { - 'name': data_utils.rand_name('image'), - 'container_format': CONF.image.container_formats[0], - 'disk_format': CONF.image.disk_formats[0], - 'min_ram': min_img_ram - } - - if CONF.image_feature_enabled.api_v1: - params.update({'is_public': False}) - params = {'headers': common_image.image_meta_to_headers(**params)} - else: - params.update({'visibility': 'private'}) - - image = self.images_client.create_image(**params) - image = image['image'] if 'image' in image else image - self.addCleanup(self.images_client.delete_image, image['id']) - - if CONF.image_feature_enabled.api_v1: - self.images_client.update_image(image['id'], data=image_file) - else: - self.images_client.store_image_file(image['id'], data=image_file) - - self.assertEqual(min_img_ram, image['min_ram']) - - # Try to create server with flavor of insufficient ram size - self.assertRaisesRegex(lib_exc.BadRequest, - "Flavor's memory is too small for " - "requested image", - self.create_test_server, - image_id=image['id'], - flavor=flavor['id']) diff --git a/tempest/api/compute/floating_ips/__init__.py b/tempest/api/compute/floating_ips/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/floating_ips/base.py b/tempest/api/compute/floating_ips/base.py deleted file mode 100644 index 142eaec67..000000000 --- a/tempest/api/compute/floating_ips/base.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base - - -class BaseFloatingIPsTest(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - # Floating IP actions might need a full network configuration - cls.set_network_resources(network=True, subnet=True, - router=True, dhcp=True) - super(BaseFloatingIPsTest, cls).setup_credentials() diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py deleted file mode 100644 index faa7b5d92..000000000 --- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py +++ /dev/null @@ -1,148 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute.floating_ips import base -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FloatingIPsTestJSON(base.BaseFloatingIPsTest): - server_id = None - floating_ip = None - - @classmethod - def skip_checks(cls): - super(FloatingIPsTestJSON, cls).skip_checks() - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_clients(cls): - super(FloatingIPsTestJSON, cls).setup_clients() - cls.client = cls.floating_ips_client - - @classmethod - def resource_setup(cls): - super(FloatingIPsTestJSON, cls).resource_setup() - cls.floating_ip_id = None - - # Server creation - server = cls.create_test_server(wait_until='ACTIVE') - cls.server_id = server['id'] - # Floating IP creation - body = cls.client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - cls.floating_ip_id = body['id'] - cls.floating_ip = body['ip'] - - @classmethod - def resource_cleanup(cls): - # Deleting the floating IP which is created in this method - if cls.floating_ip_id: - cls.client.delete_floating_ip(cls.floating_ip_id) - super(FloatingIPsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('f7bfb946-297e-41b8-9e8c-aba8e9bb5194') - @test.services('network') - def test_allocate_floating_ip(self): - # Positive test:Allocation of a new floating IP to a project - # should be successful - body = self.client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - floating_ip_id_allocated = body['id'] - self.addCleanup(self.client.delete_floating_ip, - floating_ip_id_allocated) - floating_ip_details = self.client.show_floating_ip( - floating_ip_id_allocated)['floating_ip'] - # Checking if the details of allocated IP is in list of floating IP - body = self.client.list_floating_ips()['floating_ips'] - self.assertIn(floating_ip_details, body) - - @decorators.idempotent_id('de45e989-b5ca-4a9b-916b-04a52e7bbb8b') - @test.services('network') - def test_delete_floating_ip(self): - # Positive test:Deletion of valid floating IP from project - # should be successful - # Creating the floating IP that is to be deleted in this method - floating_ip_body = self.client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.client.delete_floating_ip, floating_ip_body['id']) - # Deleting the floating IP from the project - self.client.delete_floating_ip(floating_ip_body['id']) - # Check it was really deleted. - self.client.wait_for_resource_deletion(floating_ip_body['id']) - - @decorators.idempotent_id('307efa27-dc6f-48a0-8cd2-162ce3ef0b52') - @test.services('network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_associate_disassociate_floating_ip(self): - # Positive test:Associate and disassociate the provided floating IP - # to a specific server should be successful - - # Association of floating IP to fixed IP address - self.client.associate_floating_ip_to_server( - self.floating_ip, - self.server_id) - - # Check instance_id in the floating_ip body - body = (self.client.show_floating_ip(self.floating_ip_id) - ['floating_ip']) - self.assertEqual(self.server_id, body['instance_id']) - - # Disassociation of floating IP that was associated in this method - self.client.disassociate_floating_ip_from_server( - self.floating_ip, - self.server_id) - - @decorators.idempotent_id('6edef4b2-aaf1-4abc-bbe3-993e2561e0fe') - @test.services('network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_associate_already_associated_floating_ip(self): - # positive test:Association of an already associated floating IP - # to specific server should change the association of the Floating IP - # Create server so as to use for Multiple association - body = self.create_test_server(wait_until='ACTIVE') - self.new_server_id = body['id'] - self.addCleanup(self.servers_client.delete_server, self.new_server_id) - - # Associating floating IP for the first time - self.client.associate_floating_ip_to_server( - self.floating_ip, - self.server_id) - # Associating floating IP for the second time - self.client.associate_floating_ip_to_server( - self.floating_ip, - self.new_server_id) - - self.addCleanup(self.client.disassociate_floating_ip_from_server, - self.floating_ip, - self.new_server_id) - - # Make sure no longer associated with old server - self.assertRaises((lib_exc.NotFound, - lib_exc.UnprocessableEntity, - lib_exc.Conflict), - self.client.disassociate_floating_ip_from_server, - self.floating_ip, self.server_id) diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py deleted file mode 100644 index 483bd953a..000000000 --- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute.floating_ips import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FloatingIPsNegativeTestJSON(base.BaseFloatingIPsTest): - - @classmethod - def skip_checks(cls): - super(FloatingIPsNegativeTestJSON, cls).skip_checks() - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_clients(cls): - super(FloatingIPsNegativeTestJSON, cls).setup_clients() - cls.client = cls.floating_ips_client - - @classmethod - def resource_setup(cls): - super(FloatingIPsNegativeTestJSON, cls).resource_setup() - - # Server creation - server = cls.create_test_server(wait_until='ACTIVE') - cls.server_id = server['id'] - # Generating a nonexistent floatingIP id - body = cls.client.list_floating_ips()['floating_ips'] - floating_ip_ids = [floating_ip['id'] for floating_ip in body] - while True: - if CONF.service_available.neutron: - cls.non_exist_id = data_utils.rand_uuid() - else: - cls.non_exist_id = data_utils.rand_int_id(start=999) - if cls.non_exist_id not in floating_ip_ids: - break - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6e0f059b-e4dd-48fb-8207-06e3bba5b074') - @test.services('network') - def test_allocate_floating_ip_from_nonexistent_pool(self): - # Negative test:Allocation of a new floating IP from a nonexistent_pool - # to a project should fail - self.assertRaises(lib_exc.NotFound, - self.client.create_floating_ip, - pool="non_exist_pool") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ae1c55a8-552b-44d4-bfb6-2a115a15d0ba') - @test.services('network') - def test_delete_nonexistent_floating_ip(self): - # Negative test:Deletion of a nonexistent floating IP - # from project should fail - - # Deleting the non existent floating IP - self.assertRaises(lib_exc.NotFound, self.client.delete_floating_ip, - self.non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('595fa616-1a71-4670-9614-46564ac49a4c') - @test.services('network') - def test_associate_nonexistent_floating_ip(self): - # Negative test:Association of a non existent floating IP - # to specific server should fail - # Associating non existent floating IP - self.assertRaises(lib_exc.NotFound, - self.client.associate_floating_ip_to_server, - "0.0.0.0", self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0a081a66-e568-4e6b-aa62-9587a876dca8') - @test.services('network') - def test_dissociate_nonexistent_floating_ip(self): - # Negative test:Dissociation of a non existent floating IP should fail - # Dissociating non existent floating IP - self.assertRaises(lib_exc.NotFound, - self.client.disassociate_floating_ip_from_server, - "0.0.0.0", self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('804b4fcb-bbf5-412f-925d-896672b61eb3') - @test.services('network') - def test_associate_ip_to_server_without_passing_floating_ip(self): - # Negative test:Association of empty floating IP to specific server - # should raise NotFound or BadRequest(In case of Nova V2.1) exception. - self.assertRaises((lib_exc.NotFound, lib_exc.BadRequest), - self.client.associate_floating_ip_to_server, - '', self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('58a80596-ffb2-11e6-9393-fa163e4fa634') - @test.services('network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_associate_ip_to_server_with_floating_ip(self): - # The VM have one port - # Associate floating IP A to the VM - # Associate floating IP B which is from same pool with floating IP A - # to the VM, should raise BadRequest exception - body = self.client.create_floating_ip( - pool=CONF.network.public_network_id)['floating_ip'] - self.addCleanup(self.client.delete_floating_ip, body['id']) - self.client.associate_floating_ip_to_server(body['ip'], self.server_id) - self.addCleanup(self.client.disassociate_floating_ip_from_server, - body['ip'], self.server_id) - - body = self.client.create_floating_ip( - pool=CONF.network.public_network_id)['floating_ip'] - self.addCleanup(self.client.delete_floating_ip, body['id']) - self.assertRaises(lib_exc.BadRequest, - self.client.associate_floating_ip_to_server, - body['ip'], self.server_id) diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py deleted file mode 100644 index 913b992da..000000000 --- a/tempest/api/compute/floating_ips/test_list_floating_ips.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class FloatingIPDetailsTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(FloatingIPDetailsTestJSON, cls).skip_checks() - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_clients(cls): - super(FloatingIPDetailsTestJSON, cls).setup_clients() - cls.client = cls.floating_ips_client - cls.pools_client = cls.floating_ip_pools_client - - @classmethod - def resource_setup(cls): - super(FloatingIPDetailsTestJSON, cls).resource_setup() - cls.floating_ip = [] - cls.floating_ip_id = [] - for _ in range(3): - body = cls.client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - cls.floating_ip.append(body) - cls.floating_ip_id.append(body['id']) - - @classmethod - def resource_cleanup(cls): - for f_id in cls.floating_ip_id: - cls.client.delete_floating_ip(f_id) - super(FloatingIPDetailsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('16db31c3-fb85-40c9-bbe2-8cf7b67ff99f') - @test.services('network') - def test_list_floating_ips(self): - # Positive test:Should return the list of floating IPs - body = self.client.list_floating_ips()['floating_ips'] - floating_ips = body - self.assertNotEmpty(floating_ips, - "Expected floating IPs. Got zero.") - for i in range(3): - self.assertIn(self.floating_ip[i], floating_ips) - - @decorators.idempotent_id('eef497e0-8ff7-43c8-85ef-558440574f84') - @test.services('network') - def test_get_floating_ip_details(self): - # Positive test:Should be able to GET the details of floatingIP - # Creating a floating IP for which details are to be checked - body = self.client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - floating_ip_id = body['id'] - self.addCleanup(self.client.delete_floating_ip, - floating_ip_id) - floating_ip_instance_id = body['instance_id'] - floating_ip_ip = body['ip'] - floating_ip_fixed_ip = body['fixed_ip'] - body = self.client.show_floating_ip(floating_ip_id)['floating_ip'] - # Comparing the details of floating IP - self.assertEqual(floating_ip_instance_id, - body['instance_id']) - self.assertEqual(floating_ip_ip, body['ip']) - self.assertEqual(floating_ip_fixed_ip, - body['fixed_ip']) - self.assertEqual(floating_ip_id, body['id']) - - @decorators.idempotent_id('df389fc8-56f5-43cc-b290-20eda39854d3') - @test.services('network') - def test_list_floating_ip_pools(self): - # Positive test:Should return the list of floating IP Pools - floating_ip_pools = self.pools_client.list_floating_ip_pools() - self.assertNotEmpty(floating_ip_pools['floating_ip_pools'], - "Expected floating IP Pools. Got zero.") diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py deleted file mode 100644 index b5bbb8c69..000000000 --- a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FloatingIPDetailsNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(FloatingIPDetailsNegativeTestJSON, cls).skip_checks() - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_clients(cls): - super(FloatingIPDetailsNegativeTestJSON, cls).setup_clients() - cls.client = cls.floating_ips_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7ab18834-4a4b-4f28-a2c5-440579866695') - @test.services('network') - def test_get_nonexistent_floating_ip_details(self): - # Negative test:Should not be able to GET the details - # of non-existent floating IP - # Creating a non-existent floatingIP id - if CONF.service_available.neutron: - non_exist_id = data_utils.rand_uuid() - else: - non_exist_id = data_utils.rand_int_id(start=999) - self.assertRaises(lib_exc.NotFound, - self.client.show_floating_ip, non_exist_id) diff --git a/tempest/api/compute/images/__init__.py b/tempest/api/compute/images/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py deleted file mode 100644 index 8d503dcb3..000000000 --- a/tempest/api/compute/images/test_image_metadata.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - -from tempest.api.compute import base -from tempest.common import image as common_image -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class ImagesMetadataTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ImagesMetadataTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesMetadataTestJSON, cls).setup_clients() - # Check if glance v1 is available to determine which client to use. We - # prefer glance v1 for the compute API tests since the compute image - # API proxy was written for glance v1. - if CONF.image_feature_enabled.api_v1: - cls.glance_client = cls.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - cls.glance_client = cls.os_primary.image_client_v2 - else: - raise exceptions.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - cls.client = cls.compute_images_client - - @classmethod - def resource_setup(cls): - super(ImagesMetadataTestJSON, cls).resource_setup() - cls.image_id = None - - params = { - 'name': data_utils.rand_name('image'), - 'container_format': 'bare', - 'disk_format': 'raw' - } - if CONF.image_feature_enabled.api_v1: - params.update({'is_public': False}) - params = {'headers': common_image.image_meta_to_headers(**params)} - else: - params.update({'visibility': 'private'}) - - body = cls.glance_client.create_image(**params) - body = body['image'] if 'image' in body else body - cls.image_id = body['id'] - cls.images.append(cls.image_id) - image_file = six.BytesIO((b'*' * 1024)) - if CONF.image_feature_enabled.api_v1: - cls.glance_client.update_image(cls.image_id, data=image_file) - else: - cls.glance_client.store_image_file(cls.image_id, data=image_file) - waiters.wait_for_image_status(cls.client, cls.image_id, 'ACTIVE') - - def setUp(self): - super(ImagesMetadataTestJSON, self).setUp() - meta = {'os_version': 'value1', 'os_distro': 'value2'} - self.client.set_image_metadata(self.image_id, meta) - - @decorators.idempotent_id('37ec6edd-cf30-4c53-bd45-ae74db6b0531') - def test_list_image_metadata(self): - # All metadata key/value pairs for an image should be returned - resp_metadata = self.client.list_image_metadata(self.image_id) - expected = {'metadata': { - 'os_version': 'value1', 'os_distro': 'value2'}} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('ece7befc-d3ce-42a4-b4be-c3067a418c29') - def test_set_image_metadata(self): - # The metadata for the image should match the new values - req_metadata = {'os_version': 'value2', 'architecture': 'value3'} - self.client.set_image_metadata(self.image_id, - req_metadata) - - resp_metadata = (self.client.list_image_metadata(self.image_id) - ['metadata']) - self.assertEqual(req_metadata, resp_metadata) - - @decorators.idempotent_id('7b491c11-a9d5-40fe-a696-7f7e03d3fea2') - def test_update_image_metadata(self): - # The metadata for the image should match the updated values - req_metadata = {'os_version': 'alt1', 'architecture': 'value3'} - self.client.update_image_metadata(self.image_id, - req_metadata) - - resp_metadata = self.client.list_image_metadata(self.image_id) - expected = {'metadata': { - 'os_version': 'alt1', - 'os_distro': 'value2', - 'architecture': 'value3'}} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('4f5db52f-6685-4c75-b848-f4bb363f9aa6') - def test_get_image_metadata_item(self): - # The value for a specific metadata key should be returned - meta = self.client.show_image_metadata_item(self.image_id, - 'os_distro')['meta'] - self.assertEqual('value2', meta['os_distro']) - - @decorators.idempotent_id('f2de776a-4778-4d90-a5da-aae63aee64ae') - def test_set_image_metadata_item(self): - # The value provided for the given meta item should be set for - # the image - meta = {'os_version': 'alt'} - self.client.set_image_metadata_item(self.image_id, - 'os_version', meta) - resp_metadata = self.client.list_image_metadata(self.image_id) - expected = {'metadata': {'os_version': 'alt', 'os_distro': 'value2'}} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('a013796c-ba37-4bb5-8602-d944511def14') - def test_delete_image_metadata_item(self): - # The metadata value/key pair should be deleted from the image - self.client.delete_image_metadata_item(self.image_id, - 'os_version') - resp_metadata = self.client.list_image_metadata(self.image_id) - expected = {'metadata': {'os_distro': 'value2'}} - self.assertEqual(expected, resp_metadata) diff --git a/tempest/api/compute/images/test_image_metadata_negative.py b/tempest/api/compute/images/test_image_metadata_negative.py deleted file mode 100644 index 03d078940..000000000 --- a/tempest/api/compute/images/test_image_metadata_negative.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImagesMetadataNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ImagesMetadataNegativeTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('94069db2-792f-4fa8-8bd3-2271a6e0c095') - def test_list_nonexistent_image_metadata(self): - # Negative test: List on nonexistent image - # metadata should not happen - self.assertRaises(lib_exc.NotFound, self.client.list_image_metadata, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a403ef9e-9f95-427c-b70a-3ce3388796f1') - def test_update_nonexistent_image_metadata(self): - # Negative test:An update should not happen for a non-existent image - meta = {'os_distro': 'alt1', 'os_version': 'alt2'} - self.assertRaises(lib_exc.NotFound, - self.client.update_image_metadata, - data_utils.rand_uuid(), meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('41ae052c-6ee6-405c-985e-5712393a620d') - def test_get_nonexistent_image_metadata_item(self): - # Negative test: Get on non-existent image should not happen - self.assertRaises(lib_exc.NotFound, - self.client.show_image_metadata_item, - data_utils.rand_uuid(), 'os_version') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dc64f2ce-77e8-45b0-88c8-e15041d08eaf') - def test_set_nonexistent_image_metadata(self): - # Negative test: Metadata should not be set to a non-existent image - meta = {'os_distro': 'alt1', 'os_version': 'alt2'} - self.assertRaises(lib_exc.NotFound, self.client.set_image_metadata, - data_utils.rand_uuid(), meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('2154fd03-ab54-457c-8874-e6e3eb56e9cf') - def test_set_nonexistent_image_metadata_item(self): - # Negative test: Metadata item should not be set to a - # nonexistent image - meta = {'os_distro': 'alt'} - self.assertRaises(lib_exc.NotFound, - self.client.set_image_metadata_item, - data_utils.rand_uuid(), 'os_distro', - meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('848e157f-6bcf-4b2e-a5dd-5124025a8518') - def test_delete_nonexistent_image_metadata_item(self): - # Negative test: Shouldn't be able to delete metadata - # item from non-existent image - self.assertRaises(lib_exc.NotFound, - self.client.delete_image_metadata_item, - data_utils.rand_uuid(), 'os_distro') diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py deleted file mode 100644 index 29bd6dae1..000000000 --- a/tempest/api/compute/images/test_images.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -import testtools - -CONF = config.CONF - - -class ImagesTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ImagesTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - if not CONF.compute_feature_enabled.snapshot: - skip_msg = ("%s skipped as instance snapshotting is not supported" - % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @decorators.idempotent_id('aa06b52b-2db5-4807-b218-9441f75d74e3') - def test_delete_saving_image(self): - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.servers_client.delete_server, server['id']) - image = self.create_image_from_server(server['id'], - wait_until='SAVING') - self.client.delete_image(image['id']) - msg = ('The image with ID {image_id} failed to be deleted' - .format(image_id=image['id'])) - self.assertTrue(self.client.is_resource_deleted(image['id']), msg) - - @decorators.idempotent_id('aaacd1d0-55a2-4ce8-818a-b5439df8adc9') - def test_create_image_from_stopped_server(self): - server = self.create_test_server(wait_until='ACTIVE') - self.servers_client.stop_server(server['id']) - waiters.wait_for_server_status(self.servers_client, - server['id'], 'SHUTOFF') - self.addCleanup(self.servers_client.delete_server, server['id']) - snapshot_name = data_utils.rand_name('test-snap') - image = self.create_image_from_server(server['id'], - name=snapshot_name, - wait_until='ACTIVE', - wait_for_server=False) - self.addCleanup(self.client.delete_image, image['id']) - self.assertEqual(snapshot_name, image['name']) - - @decorators.idempotent_id('71bcb732-0261-11e7-9086-fa163e4fa634') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - def test_create_image_from_paused_server(self): - server = self.create_test_server(wait_until='ACTIVE') - self.servers_client.pause_server(server['id']) - waiters.wait_for_server_status(self.servers_client, - server['id'], 'PAUSED') - self.addCleanup(self.servers_client.delete_server, server['id']) - - snapshot_name = data_utils.rand_name('test-snap') - image = self.create_image_from_server(server['id'], - name=snapshot_name, - wait_until='ACTIVE', - wait_for_server=False) - self.addCleanup(self.client.delete_image, image['id']) - self.assertEqual(snapshot_name, image['name']) - - @decorators.idempotent_id('8ca07fec-0262-11e7-907e-fa163e4fa634') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - def test_create_image_from_suspended_server(self): - server = self.create_test_server(wait_until='ACTIVE') - self.servers_client.suspend_server(server['id']) - waiters.wait_for_server_status(self.servers_client, - server['id'], 'SUSPENDED') - self.addCleanup(self.servers_client.delete_server, server['id']) - - snapshot_name = data_utils.rand_name('test-snap') - image = self.create_image_from_server(server['id'], - name=snapshot_name, - wait_until='ACTIVE', - wait_for_server=False) - self.addCleanup(self.client.delete_image, image['id']) - self.assertEqual(snapshot_name, image['name']) diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py deleted file mode 100644 index e29238968..000000000 --- a/tempest/api/compute/images/test_images_negative.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ImagesNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ImagesNegativeTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - if not CONF.compute_feature_enabled.snapshot: - skip_msg = ("%s skipped as instance snapshotting is not supported" - % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesNegativeTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6cd5a89d-5b47-46a7-93bc-3916f0d84973') - def test_create_image_from_deleted_server(self): - # An image should not be created if the server instance is removed - server = self.create_test_server(wait_until='ACTIVE') - - # Delete server before trying to create image - self.servers_client.delete_server(server['id']) - waiters.wait_for_server_termination(self.servers_client, server['id']) - # Create a new image after server is deleted - meta = {'image_type': 'test'} - self.assertRaises(lib_exc.NotFound, - self.create_image_from_server, - server['id'], metadata=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('82c5b0c4-9dbd-463c-872b-20c4755aae7f') - def test_create_image_from_invalid_server(self): - # An image should not be created with invalid server id - # Create a new image with invalid server id - meta = {'image_type': 'test'} - self.assertRaises(lib_exc.NotFound, self.create_image_from_server, - data_utils.rand_name('invalid'), metadata=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ec176029-73dc-4037-8d72-2e4ff60cf538') - def test_create_image_specify_uuid_35_characters_or_less(self): - # Return an error if Image ID passed is 35 characters or less - snapshot_name = data_utils.rand_name('test-snap') - test_uuid = ('a' * 35) - self.assertRaises(lib_exc.NotFound, self.client.create_image, - test_uuid, name=snapshot_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('36741560-510e-4cc2-8641-55fe4dfb2437') - def test_create_image_specify_uuid_37_characters_or_more(self): - # Return an error if Image ID passed is 37 characters or more - snapshot_name = data_utils.rand_name('test-snap') - test_uuid = ('a' * 37) - self.assertRaises(lib_exc.NotFound, self.client.create_image, - test_uuid, name=snapshot_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('381acb65-785a-4942-94ce-d8f8c84f1f0f') - def test_delete_image_with_invalid_image_id(self): - # An image should not be deleted with invalid image id - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - data_utils.rand_name('invalid')) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('137aef61-39f7-44a1-8ddf-0adf82511701') - def test_delete_non_existent_image(self): - # Return an error while trying to delete a non-existent image - - non_existent_image_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - non_existent_image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e6e41425-af5c-4fe6-a4b5-7b7b963ffda5') - def test_delete_image_blank_id(self): - # Return an error while trying to delete an image with blank Id - self.assertRaises(lib_exc.NotFound, self.client.delete_image, '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('924540c3-f1f1-444c-8f58-718958b6724e') - def test_delete_image_non_hex_string_id(self): - # Return an error while trying to delete an image with non hex id - invalid_image_id = data_utils.rand_uuid()[:-1] + "j" - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - invalid_image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('68e2c175-bd26-4407-ac0f-4ea9ce2139ea') - def test_delete_image_negative_image_id(self): - # Return an error while trying to delete an image with negative id - self.assertRaises(lib_exc.NotFound, self.client.delete_image, -1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b340030d-82cd-4066-a314-c72fb7c59277') - def test_delete_image_with_id_over_character_limit(self): - # Return an error while trying to delete image with id over limit - invalid_image_id = data_utils.rand_uuid() + "1" - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - invalid_image_id) diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py deleted file mode 100644 index 5987d39f0..000000000 --- a/tempest/api/compute/images/test_images_oneserver.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ImagesOneServerTestJSON(base.BaseV2ComputeTest): - - @classmethod - def resource_setup(cls): - super(ImagesOneServerTestJSON, cls).resource_setup() - cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id'] - - @classmethod - def skip_checks(cls): - super(ImagesOneServerTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - if not CONF.compute_feature_enabled.snapshot: - skip_msg = ("%s skipped as instance snapshotting is not supported" - % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesOneServerTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - def _get_default_flavor_disk_size(self, flavor_id): - flavor = self.flavors_client.show_flavor(flavor_id)['flavor'] - return flavor['disk'] - - @decorators.idempotent_id('3731d080-d4c5-4872-b41a-64d0d0021314') - def test_create_delete_image(self): - # Create a new image - name = data_utils.rand_name('image') - meta = {'image_type': 'test'} - image = self.create_image_from_server(self.server_id, name=name, - metadata=meta, - wait_until='ACTIVE') - - # Verify the image was created correctly - self.assertEqual(name, image['name']) - self.assertEqual('test', image['metadata']['image_type']) - - original_image = self.client.show_image(self.image_ref)['image'] - - # Verify minRAM is the same as the original image - self.assertEqual(image['minRam'], original_image['minRam']) - - # Verify minDisk is the same as the original image or the flavor size - flavor_disk_size = self._get_default_flavor_disk_size(self.flavor_ref) - self.assertIn(str(image['minDisk']), - (str(original_image['minDisk']), str(flavor_disk_size))) - - # Verify the image was deleted correctly - self.client.delete_image(image['id']) - self.images.remove(image['id']) - self.client.wait_for_resource_deletion(image['id']) - - @decorators.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6') - def test_create_image_specify_multibyte_character_image_name(self): - # prefix character is: - # http://unicode.org/cldr/utility/character.jsp?a=20A1 - - # We use a string with 3 byte utf-8 character due to nova/glance which - # will return 400(Bad Request) if we attempt to send a name which has - # 4 byte utf-8 character. - utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8')) - body = self.client.create_image(self.server_id, name=utf8_name) - image_id = data_utils.parse_image_id(body.response['location']) - self.addCleanup(self.client.delete_image, image_id) diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py deleted file mode 100644 index cf32ba3ef..000000000 --- a/tempest/api/compute/images/test_images_oneserver_negative.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class ImagesOneServerNegativeTestJSON(base.BaseV2ComputeTest): - - def tearDown(self): - """Terminate test instances created after a test is executed.""" - self.server_check_teardown() - super(ImagesOneServerNegativeTestJSON, self).tearDown() - - def setUp(self): - # NOTE(afazekas): Normally we use the same server with all test cases, - # but if it has an issue, we build a new one - super(ImagesOneServerNegativeTestJSON, self).setUp() - # Check if the server is in a clean state after test - try: - waiters.wait_for_server_status(self.servers_client, self.server_id, - 'ACTIVE') - except Exception: - LOG.exception('server %s timed out to become ACTIVE. rebuilding', - self.server_id) - # Rebuild server if cannot reach the ACTIVE state - # Usually it means the server had a serious accident - self._reset_server() - - def _reset_server(self): - self.__class__.server_id = self.rebuild_server(self.server_id) - - @classmethod - def skip_checks(cls): - super(ImagesOneServerNegativeTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - if not CONF.compute_feature_enabled.snapshot: - skip_msg = ("%s skipped as instance snapshotting is not supported" - % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesOneServerNegativeTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @classmethod - def resource_setup(cls): - super(ImagesOneServerNegativeTestJSON, cls).resource_setup() - server = cls.create_test_server(wait_until='ACTIVE') - cls.server_id = server['id'] - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('55d1d38c-dd66-4933-9c8e-7d92aeb60ddc') - def test_create_image_specify_invalid_metadata(self): - # Return an error when creating image with invalid metadata - meta = {'': ''} - self.assertRaises(lib_exc.BadRequest, self.create_image_from_server, - self.server_id, metadata=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3d24d11f-5366-4536-bd28-cff32b748eca') - def test_create_image_specify_metadata_over_limits(self): - # Return an error when creating image with meta data over 255 chars - meta = {'a' * 256: 'b' * 256} - self.assertRaises(lib_exc.BadRequest, self.create_image_from_server, - self.server_id, metadata=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0460efcf-ee88-4f94-acef-1bf658695456') - def test_create_second_image_when_first_image_is_being_saved(self): - # Disallow creating another image when first image is being saved - - # Create first snapshot - image = self.create_image_from_server(self.server_id) - self.addCleanup(self._reset_server) - - # Create second snapshot - self.assertRaises(lib_exc.Conflict, self.create_image_from_server, - self.server_id) - - image_id = data_utils.parse_image_id(image.response['location']) - self.client.delete_image(image_id) - self.images.remove(image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('084f0cbc-500a-4963-8a4e-312905862581') - def test_create_image_specify_name_over_character_limit(self): - # Return an error if snapshot name over 255 characters is passed - - snapshot_name = ('a' * 256) - self.assertRaises(lib_exc.BadRequest, self.client.create_image, - self.server_id, name=snapshot_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0894954d-2db2-4195-a45b-ffec0bc0187e') - def test_delete_image_that_is_not_yet_active(self): - # Return an error while trying to delete an image what is creating - - image = self.create_image_from_server(self.server_id) - image_id = data_utils.parse_image_id(image.response['location']) - - self.addCleanup(self._reset_server) - - # Do not wait, attempt to delete the image, ensure it's successful - self.client.delete_image(image_id) - self.images.remove(image_id) - self.assertRaises(lib_exc.NotFound, - self.client.show_image, image_id) diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py deleted file mode 100644 index acc8b3e29..000000000 --- a/tempest/api/compute/images/test_list_image_filters.py +++ /dev/null @@ -1,290 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -import six -import testtools - -from tempest.api.compute import base -from tempest.common import image as common_image -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class ListImageFiltersTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ListImageFiltersTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ListImageFiltersTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - # Check if glance v1 is available to determine which client to use. We - # prefer glance v1 for the compute API tests since the compute image - # API proxy was written for glance v1. - if CONF.image_feature_enabled.api_v1: - cls.glance_client = cls.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - cls.glance_client = cls.os_primary.image_client_v2 - else: - raise exceptions.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - - @classmethod - def resource_setup(cls): - super(ListImageFiltersTestJSON, cls).resource_setup() - - def _create_image(): - params = { - 'name': data_utils.rand_name(cls.__name__ + '-image'), - 'container_format': 'bare', - 'disk_format': 'raw' - } - if CONF.image_feature_enabled.api_v1: - params.update({'is_public': False}) - params = {'headers': - common_image.image_meta_to_headers(**params)} - else: - params.update({'visibility': 'private'}) - - body = cls.glance_client.create_image(**params) - body = body['image'] if 'image' in body else body - image_id = body['id'] - cls.images.append(image_id) - # Wait 1 second between creation and upload to ensure a delta - # between created_at and updated_at. - time.sleep(1) - image_file = six.BytesIO((b'*' * 1024)) - if CONF.image_feature_enabled.api_v1: - cls.glance_client.update_image(image_id, data=image_file) - else: - cls.glance_client.store_image_file(image_id, data=image_file) - waiters.wait_for_image_status(cls.client, image_id, 'ACTIVE') - body = cls.client.show_image(image_id)['image'] - return body - - # Create non-snapshot images via glance - cls.image1 = _create_image() - cls.image1_id = cls.image1['id'] - cls.image2 = _create_image() - cls.image2_id = cls.image2['id'] - cls.image3 = _create_image() - cls.image3_id = cls.image3['id'] - - if not CONF.compute_feature_enabled.snapshot: - return - - # Create instances and snapshots via nova - cls.server1 = cls.create_test_server() - cls.server2 = cls.create_test_server(wait_until='ACTIVE') - # NOTE(sdague) this is faster than doing the sync wait_util on both - waiters.wait_for_server_status(cls.servers_client, - cls.server1['id'], 'ACTIVE') - - # Create images to be used in the filter tests - cls.snapshot1 = cls.create_image_from_server( - cls.server1['id'], wait_until='ACTIVE') - cls.snapshot1_id = cls.snapshot1['id'] - - # Servers have a hidden property for when they are being imaged - # Performing back-to-back create image calls on a single - # server will sometimes cause failures - cls.snapshot3 = cls.create_image_from_server( - cls.server2['id'], wait_until='ACTIVE') - cls.snapshot3_id = cls.snapshot3['id'] - - # Wait for the server to be active after the image upload - cls.snapshot2 = cls.create_image_from_server( - cls.server1['id'], wait_until='ACTIVE') - cls.snapshot2_id = cls.snapshot2['id'] - - @decorators.idempotent_id('a3f5b513-aeb3-42a9-b18e-f091ef73254d') - def test_list_images_filter_by_status(self): - # The list of images should contain only images with the - # provided status - params = {'status': 'ACTIVE'} - images = self.client.list_images(**params)['images'] - - self.assertNotEmpty([i for i in images if i['id'] == self.image1_id]) - self.assertNotEmpty([i for i in images if i['id'] == self.image2_id]) - self.assertNotEmpty([i for i in images if i['id'] == self.image3_id]) - - @decorators.idempotent_id('33163b73-79f5-4d07-a7ea-9213bcc468ff') - def test_list_images_filter_by_name(self): - # List of all images should contain the expected images filtered - # by name - params = {'name': self.image1['name']} - images = self.client.list_images(**params)['images'] - - self.assertNotEmpty([i for i in images if i['id'] == self.image1_id]) - self.assertEmpty([i for i in images if i['id'] == self.image2_id]) - self.assertEmpty([i for i in images if i['id'] == self.image3_id]) - - @decorators.idempotent_id('9f238683-c763-45aa-b848-232ec3ce3105') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - def test_list_images_filter_by_server_id(self): - # The images should contain images filtered by server id - params = {'server': self.server1['id']} - images = self.client.list_images(**params)['images'] - - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot1_id], - "Failed to find image %s in images. " - "Got images %s" % (self.image1_id, images)) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot2_id]) - self.assertEmpty([i for i in images if i['id'] == self.snapshot3_id]) - - @decorators.idempotent_id('05a377b8-28cf-4734-a1e6-2ab5c38bf606') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - def test_list_images_filter_by_server_ref(self): - # The list of servers should be filtered by server ref - server_links = self.server2['links'] - - # Try all server link types - for link in server_links: - params = {'server': link['href']} - images = self.client.list_images(**params)['images'] - - self.assertEmpty([i for i in images - if i['id'] == self.snapshot1_id]) - self.assertEmpty([i for i in images - if i['id'] == self.snapshot2_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot3_id]) - - @decorators.idempotent_id('e3356918-4d3e-4756-81d5-abc4524ba29f') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - def test_list_images_filter_by_type(self): - # The list of servers should be filtered by image type - params = {'type': 'snapshot'} - images = self.client.list_images(**params)['images'] - - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot1_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot2_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot3_id]) - self.assertEmpty([i for i in images if i['id'] == self.image_ref]) - - @decorators.idempotent_id('3a484ca9-67ba-451e-b494-7fcf28d32d62') - def test_list_images_limit_results(self): - # Verify only the expected number of results are returned - params = {'limit': '1'} - images = self.client.list_images(**params)['images'] - self.assertEqual(1, len([x for x in images if 'id' in x])) - - @decorators.idempotent_id('18bac3ae-da27-436c-92a9-b22474d13aab') - def test_list_images_filter_by_changes_since(self): - # Verify only updated images are returned in the detailed list - - # Becoming ACTIVE will modify the updated time - # Filter by the image's created time - params = {'changes-since': self.image3['created']} - images = self.client.list_images(**params)['images'] - found = [i for i in images if i['id'] == self.image3_id] - self.assertNotEmpty(found) - - @decorators.idempotent_id('9b0ea018-6185-4f71-948a-a123a107988e') - def test_list_images_with_detail_filter_by_status(self): - # Detailed list of all images should only contain images - # with the provided status - params = {'status': 'ACTIVE'} - images = self.client.list_images(detail=True, **params)['images'] - - self.assertNotEmpty([i for i in images if i['id'] == self.image1_id]) - self.assertNotEmpty([i for i in images if i['id'] == self.image2_id]) - self.assertNotEmpty([i for i in images if i['id'] == self.image3_id]) - - @decorators.idempotent_id('644ea267-9bd9-4f3b-af9f-dffa02396a17') - def test_list_images_with_detail_filter_by_name(self): - # Detailed list of all images should contain the expected - # images filtered by name - params = {'name': self.image1['name']} - images = self.client.list_images(detail=True, **params)['images'] - - self.assertNotEmpty([i for i in images if i['id'] == self.image1_id]) - self.assertEmpty([i for i in images if i['id'] == self.image2_id]) - self.assertEmpty([i for i in images if i['id'] == self.image3_id]) - - @decorators.idempotent_id('ba2fa9a9-b672-47cc-b354-3b4c0600e2cb') - def test_list_images_with_detail_limit_results(self): - # Verify only the expected number of results (with full details) - # are returned - params = {'limit': '1'} - images = self.client.list_images(detail=True, **params)['images'] - self.assertEqual(1, len(images)) - - @decorators.idempotent_id('8c78f822-203b-4bf6-8bba-56ebd551cf84') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - def test_list_images_with_detail_filter_by_server_ref(self): - # Detailed list of servers should be filtered by server ref - server_links = self.server2['links'] - - # Try all server link types - for link in server_links: - params = {'server': link['href']} - images = self.client.list_images(detail=True, **params)['images'] - - self.assertEmpty([i for i in images - if i['id'] == self.snapshot1_id]) - self.assertEmpty([i for i in images - if i['id'] == self.snapshot2_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot3_id]) - - @decorators.idempotent_id('888c0cc0-7223-43c5-9db0-b125fd0a393b') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - def test_list_images_with_detail_filter_by_type(self): - # The detailed list of servers should be filtered by image type - params = {'type': 'snapshot'} - images = self.client.list_images(detail=True, **params)['images'] - self.client.show_image(self.image_ref) - - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot1_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot2_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot3_id]) - self.assertEmpty([i for i in images if i['id'] == self.image_ref]) - - @decorators.idempotent_id('7d439e18-ac2e-4827-b049-7e18004712c4') - def test_list_images_with_detail_filter_by_changes_since(self): - # Verify an update image is returned - - # Becoming ACTIVE will modify the updated time - # Filter by the image's created time - params = {'changes-since': self.image1['created']} - images = self.client.list_images(detail=True, **params)['images'] - self.assertNotEmpty([i for i in images if i['id'] == self.image1_id]) diff --git a/tempest/api/compute/images/test_list_image_filters_negative.py b/tempest/api/compute/images/test_list_image_filters_negative.py deleted file mode 100644 index d37f8fc80..000000000 --- a/tempest/api/compute/images/test_list_image_filters_negative.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ListImageFiltersNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ListImageFiltersNegativeTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ListImageFiltersNegativeTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('391b0440-432c-4d4b-b5da-c5096aa247eb') - def test_get_nonexistent_image(self): - # Check raises a NotFound - nonexistent_image = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.show_image, - nonexistent_image) diff --git a/tempest/api/compute/images/test_list_images.py b/tempest/api/compute/images/test_list_images.py deleted file mode 100644 index e2dbd72f3..000000000 --- a/tempest/api/compute/images/test_list_images.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class ListImagesTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ListImagesTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ListImagesTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @decorators.idempotent_id('490d0898-e12a-463f-aef0-c50156b9f789') - def test_get_image(self): - # Returns the correct details for a single image - image = self.client.show_image(self.image_ref)['image'] - self.assertEqual(self.image_ref, image['id']) - - @decorators.idempotent_id('fd51b7f4-d4a3-4331-9885-866658112a6f') - def test_list_images(self): - # The list of all images should contain the image - images = self.client.list_images()['images'] - found = [i for i in images if i['id'] == self.image_ref] - self.assertNotEmpty(found) - - @decorators.idempotent_id('9f94cb6b-7f10-48c5-b911-a0b84d7d4cd6') - def test_list_images_with_detail(self): - # Detailed list of all images should contain the expected images - images = self.client.list_images(detail=True)['images'] - found = [i for i in images if i['id'] == self.image_ref] - self.assertNotEmpty(found) diff --git a/tempest/api/compute/keypairs/__init__.py b/tempest/api/compute/keypairs/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/keypairs/base.py b/tempest/api/compute/keypairs/base.py deleted file mode 100644 index 005181064..000000000 --- a/tempest/api/compute/keypairs/base.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2015 Deutsche Telekom AG -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils - - -class BaseKeypairTest(base.BaseV2ComputeTest): - """Base test case class for all keypair API tests.""" - - @classmethod - def setup_clients(cls): - super(BaseKeypairTest, cls).setup_clients() - cls.client = cls.keypairs_client - - def _delete_keypair(self, keypair_name, **params): - self.client.delete_keypair(keypair_name, **params) - - def create_keypair(self, keypair_name=None, - pub_key=None, keypair_type=None, - user_id=None): - if keypair_name is None: - keypair_name = data_utils.rand_name( - self.__class__.__name__ + '-keypair') - kwargs = {'name': keypair_name} - delete_params = {} - if pub_key: - kwargs.update({'public_key': pub_key}) - if keypair_type: - kwargs.update({'type': keypair_type}) - if user_id: - kwargs.update({'user_id': user_id}) - delete_params['user_id'] = user_id - body = self.client.create_keypair(**kwargs)['keypair'] - self.addCleanup(self._delete_keypair, keypair_name, **delete_params) - return body diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py deleted file mode 100644 index 0b7a9675d..000000000 --- a/tempest/api/compute/keypairs/test_keypairs.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute.keypairs import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class KeyPairsV2TestJSON(base.BaseKeypairTest): - max_microversion = '2.1' - - @decorators.idempotent_id('1d1dbedb-d7a0-432a-9d09-83f543c3c19b') - def test_keypairs_create_list_delete(self): - # Keypairs created should be available in the response list - # Create 3 keypairs - key_list = list() - for _ in range(3): - keypair = self.create_keypair() - # Need to pop these keys so that our compare doesn't fail later, - # as the keypair dicts from list API doesn't have them. - keypair.pop('private_key') - keypair.pop('user_id') - key_list.append(keypair) - # Fetch all keypairs and verify the list - # has all created keypairs - fetched_list = self.client.list_keypairs()['keypairs'] - new_list = list() - for keypair in fetched_list: - new_list.append(keypair['keypair']) - fetched_list = new_list - # Now check if all the created keypairs are in the fetched list - missing_kps = [kp for kp in key_list if kp not in fetched_list] - self.assertFalse(missing_kps, - "Failed to find keypairs %s in fetched list" - % ', '.join(m_key['name'] for m_key in missing_kps)) - - @decorators.idempotent_id('6c1d3123-4519-4742-9194-622cb1714b7d') - def test_keypair_create_delete(self): - # Keypair should be created, verified and deleted - k_name = data_utils.rand_name('keypair') - keypair = self.create_keypair(k_name) - private_key = keypair['private_key'] - key_name = keypair['name'] - self.assertEqual(key_name, k_name, - "The created keypair name is not equal " - "to the requested name") - self.assertIsNotNone(private_key, - "Field private_key is empty or not found.") - - @decorators.idempotent_id('a4233d5d-52d8-47cc-9a25-e1864527e3df') - def test_get_keypair_detail(self): - # Keypair should be created, Got details by name and deleted - k_name = data_utils.rand_name('keypair') - self.create_keypair(k_name) - keypair_detail = self.client.show_keypair(k_name)['keypair'] - self.assertIn('name', keypair_detail) - self.assertIn('public_key', keypair_detail) - self.assertEqual(keypair_detail['name'], k_name, - "The created keypair name is not equal " - "to requested name") - public_key = keypair_detail['public_key'] - self.assertIsNotNone(public_key, - "Field public_key is empty or not found.") - - @decorators.idempotent_id('39c90c6a-304a-49dd-95ec-2366129def05') - def test_keypair_create_with_pub_key(self): - # Keypair should be created with a given public key - k_name = data_utils.rand_name('keypair') - pub_key = ("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCs" - "Ne3/1ILNCqFyfYWDeTKLD6jEXC2OQHLmietMWW+/vd" - "aZq7KZEwO0jhglaFjU1mpqq4Gz5RX156sCTNM9vRbw" - "KAxfsdF9laBYVsex3m3Wmui3uYrKyumsoJn2g9GNnG1P" - "I1mrVjZ61i0GY3khna+wzlTpCCmy5HNlrmbj3XLqBUpip" - "TOXmsnr4sChzC53KCd8LXuwc1i/CZPvF+3XipvAgFSE53pCt" - "LOeB1kYMOBaiUPLQTWXR3JpckqFIQwhIH0zoHlJvZE8hh90" - "XcPojYN56tI0OlrGqojbediJYD0rUsJu4weZpbn8vilb3JuDY+jws" - "snSA8wzBx3A/8y9Pp1B nova@ubuntu") - keypair = self.create_keypair(k_name, pub_key) - self.assertNotIn('private_key', keypair, - "Field private_key is not empty!") - key_name = keypair['name'] - self.assertEqual(key_name, k_name, - "The created keypair name is not equal " - "to the requested name!") diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py deleted file mode 100644 index 205076c56..000000000 --- a/tempest/api/compute/keypairs/test_keypairs_negative.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM Corp -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute.keypairs import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class KeyPairsNegativeTestJSON(base.BaseKeypairTest): - @decorators.attr(type=['negative']) - @decorators.idempotent_id('29cca892-46ae-4d48-bc32-8fe7e731eb81') - def test_keypair_create_with_invalid_pub_key(self): - # Keypair should not be created with a non RSA public key - pub_key = "ssh-rsa JUNK nova@ubuntu" - self.assertRaises(lib_exc.BadRequest, - self.create_keypair, pub_key=pub_key) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7cc32e47-4c42-489d-9623-c5e2cb5a2fa5') - def test_keypair_delete_nonexistent_key(self): - # Non-existent key deletion should throw a proper error - k_name = data_utils.rand_name("keypair-non-existent") - self.assertRaises(lib_exc.NotFound, self.client.delete_keypair, - k_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dade320e-69ca-42a9-ba4a-345300f127e0') - def test_create_keypair_with_empty_public_key(self): - # Keypair should not be created with an empty public key - pub_key = ' ' - self.assertRaises(lib_exc.BadRequest, self.create_keypair, - pub_key=pub_key) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fc100c19-2926-4b9c-8fdc-d0589ee2f9ff') - def test_create_keypair_when_public_key_bits_exceeds_maximum(self): - # Keypair should not be created when public key bits are too long - pub_key = 'ssh-rsa ' + 'A' * 2048 + ' openstack@ubuntu' - self.assertRaises(lib_exc.BadRequest, self.create_keypair, - pub_key=pub_key) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0359a7f1-f002-4682-8073-0c91e4011b7c') - def test_create_keypair_with_duplicate_name(self): - # Keypairs with duplicate names should not be created - k_name = data_utils.rand_name('keypair') - self.client.create_keypair(name=k_name) - # Now try the same keyname to create another key - self.assertRaises(lib_exc.Conflict, self.create_keypair, - k_name) - self.client.delete_keypair(k_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1398abe1-4a84-45fb-9294-89f514daff00') - def test_create_keypair_with_empty_name_string(self): - # Keypairs with name being an empty string should not be created - self.assertRaises(lib_exc.BadRequest, self.create_keypair, - '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3faa916f-779f-4103-aca7-dc3538eee1b7') - def test_create_keypair_with_long_keynames(self): - # Keypairs with name longer than 255 chars should not be created - k_name = 'keypair-'.ljust(260, '0') - self.assertRaises(lib_exc.BadRequest, self.create_keypair, - k_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('45fbe5e0-acb5-49aa-837a-ff8d0719db91') - def test_create_keypair_invalid_name(self): - # Keypairs with name being an invalid name should not be created - k_name = 'key_/.\@:' - self.assertRaises(lib_exc.BadRequest, self.create_keypair, - k_name) diff --git a/tempest/api/compute/keypairs/test_keypairs_v22.py b/tempest/api/compute/keypairs/test_keypairs_v22.py deleted file mode 100644 index f39bb1212..000000000 --- a/tempest/api/compute/keypairs/test_keypairs_v22.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute.keypairs import test_keypairs -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class KeyPairsV22TestJSON(test_keypairs.KeyPairsV2TestJSON): - min_microversion = '2.2' - max_microversion = 'latest' - - def _check_keypair_type(self, keypair, keypair_type): - if keypair_type is None: - keypair_type = 'ssh' - self.assertEqual(keypair_type, keypair['type']) - - def _test_keypairs_create_list_show(self, keypair_type=None): - k_name = data_utils.rand_name('keypair') - keypair = self.create_keypair(k_name, keypair_type=keypair_type) - # Verify whether 'type' is present in keypair create response of - # version 2.2 and it is with default value 'ssh'. - self._check_keypair_type(keypair, keypair_type) - keypair_detail = self.client.show_keypair(k_name)['keypair'] - self._check_keypair_type(keypair_detail, keypair_type) - fetched_list = self.client.list_keypairs()['keypairs'] - for keypair in fetched_list: - # Verify whether 'type' is present in keypair list response of - # version 2.2 and it is with default value 'ssh'. - if keypair['keypair']['name'] == k_name: - self._check_keypair_type(keypair['keypair'], keypair_type) - - @decorators.idempotent_id('8726fa85-7f98-4b20-af9e-f710a4f3391c') - def test_keypairsv22_create_list_show(self): - self._test_keypairs_create_list_show() - - @decorators.idempotent_id('89d59d43-f735-441a-abcf-0601727f47b6') - def test_keypairsv22_create_list_show_with_type(self): - keypair_type = 'x509' - self._test_keypairs_create_list_show(keypair_type=keypair_type) diff --git a/tempest/api/compute/limits/__init__.py b/tempest/api/compute/limits/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py deleted file mode 100644 index 0585fec3d..000000000 --- a/tempest/api/compute/limits/test_absolute_limits.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators - - -class AbsoluteLimitsTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(AbsoluteLimitsTestJSON, cls).setup_clients() - cls.client = cls.limits_client - - @decorators.idempotent_id('b54c66af-6ab6-4cf0-a9e5-a0cb58d75e0b') - def test_absLimits_get(self): - # To check if all limits are present in the response - limits = self.client.show_limits()['limits'] - absolute_limits = limits['absolute'] - expected_elements = ['maxImageMeta', 'maxPersonality', - 'maxPersonalitySize', - 'maxServerMeta', 'maxTotalCores', - 'maxTotalFloatingIps', 'maxSecurityGroups', - 'maxSecurityGroupRules', 'maxTotalInstances', - 'maxTotalKeypairs', 'maxTotalRAMSize', - 'maxServerGroups', 'maxServerGroupMembers', - 'totalCoresUsed', 'totalFloatingIpsUsed', - 'totalSecurityGroupsUsed', 'totalInstancesUsed', - 'totalRAMUsed', 'totalServerGroupsUsed'] - # check whether all expected elements exist - missing_elements =\ - [ele for ele in expected_elements if ele not in absolute_limits] - self.assertEmpty(missing_elements, - "Failed to find element %s in absolute limits list" - % ', '.join(ele for ele in missing_elements)) diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py deleted file mode 100644 index bef4eb526..000000000 --- a/tempest/api/compute/limits/test_absolute_limits_negative.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class AbsoluteLimitsNegativeTestJSON(base.BaseV2ComputeTest): - - def setUp(self): - # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests. - self.useFixture(fixtures.LockFixture('compute_quotas')) - super(AbsoluteLimitsNegativeTestJSON, self).setUp() - - @classmethod - def setup_clients(cls): - super(AbsoluteLimitsNegativeTestJSON, cls).setup_clients() - cls.client = cls.limits_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('215cd465-d8ae-49c9-bf33-9c911913a5c8') - def test_max_image_meta_exceed_limit(self): - # We should not create vm with image meta over maxImageMeta limit - # Get max limit value - limits = self.client.show_limits()['limits'] - max_meta = limits['absolute']['maxImageMeta'] - - # No point in running this test if there is no limit. - if max_meta == -1: - raise self.skipException('no limit for maxImageMeta') - - # Create server should fail, since we are passing > metadata Limit! - max_meta_data = max_meta + 1 - - meta_data = {} - for xx in range(max_meta_data): - meta_data[str(xx)] = str(xx) - - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised when out of quota - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.create_test_server, metadata=meta_data) diff --git a/tempest/api/compute/security_groups/__init__.py b/tempest/api/compute/security_groups/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/security_groups/base.py b/tempest/api/compute/security_groups/base.py deleted file mode 100644 index 6148e160c..000000000 --- a/tempest/api/compute/security_groups/base.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest import test - -CONF = config.CONF - - -class BaseSecurityGroupsTest(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - # A network and a subnet will be created for these tests - cls.set_network_resources(network=True, subnet=True) - super(BaseSecurityGroupsTest, cls).setup_credentials() - - @staticmethod - def generate_random_security_group_id(): - if (CONF.service_available.neutron and - test.is_extension_enabled('security-group', 'network')): - return data_utils.rand_uuid() - else: - return data_utils.rand_int_id(start=999) diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py deleted file mode 100644 index 124db0e45..000000000 --- a/tempest/api/compute/security_groups/test_security_group_rules.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute.security_groups import base -from tempest.lib import decorators -from tempest import test - - -class SecurityGroupRulesTestJSON(base.BaseSecurityGroupsTest): - - @classmethod - def setup_clients(cls): - super(SecurityGroupRulesTestJSON, cls).setup_clients() - cls.client = cls.security_group_rules_client - - @classmethod - def resource_setup(cls): - super(SecurityGroupRulesTestJSON, cls).resource_setup() - cls.ip_protocol = 'tcp' - cls.from_port = 22 - cls.to_port = 22 - - def setUp(cls): - super(SecurityGroupRulesTestJSON, cls).setUp() - - from_port = cls.from_port - to_port = cls.to_port - group = {} - ip_range = {} - cls.expected = { - 'parent_group_id': None, - 'ip_protocol': cls.ip_protocol, - 'from_port': from_port, - 'to_port': to_port, - 'ip_range': ip_range, - 'group': group - } - - def _check_expected_response(self, actual_rule): - for key in self.expected: - self.assertEqual(self.expected[key], actual_rule[key], - "Miss-matched key is %s" % key) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('850795d7-d4d3-4e55-b527-a774c0123d3a') - @test.services('network') - def test_security_group_rules_create(self): - # Positive test: Creation of Security Group rule - # should be successful - # Creating a Security Group to add rules to it - security_group = self.create_security_group() - securitygroup_id = security_group['id'] - # Adding rules to the created Security Group - rule = self.client.create_security_group_rule( - parent_group_id=securitygroup_id, - ip_protocol=self.ip_protocol, - from_port=self.from_port, - to_port=self.to_port)['security_group_rule'] - self.expected['parent_group_id'] = securitygroup_id - self.expected['ip_range'] = {'cidr': '0.0.0.0/0'} - self._check_expected_response(rule) - - @decorators.idempotent_id('7a01873e-3c38-4f30-80be-31a043cfe2fd') - @test.services('network') - def test_security_group_rules_create_with_optional_cidr(self): - # Positive test: Creation of Security Group rule - # with optional argument cidr - # should be successful - - # Creating a Security Group to add rules to it - security_group = self.create_security_group() - parent_group_id = security_group['id'] - - # Adding rules to the created Security Group with optional cidr - cidr = '10.2.3.124/24' - rule = self.client.create_security_group_rule( - parent_group_id=parent_group_id, - ip_protocol=self.ip_protocol, - from_port=self.from_port, - to_port=self.to_port, - cidr=cidr)['security_group_rule'] - self.expected['parent_group_id'] = parent_group_id - self.expected['ip_range'] = {'cidr': cidr} - self._check_expected_response(rule) - - @decorators.idempotent_id('7f5d2899-7705-4d4b-8458-4505188ffab6') - @test.services('network') - def test_security_group_rules_create_with_optional_group_id(self): - # Positive test: Creation of Security Group rule - # with optional argument group_id - # should be successful - - # Creating a Security Group to add rules to it - security_group = self.create_security_group() - parent_group_id = security_group['id'] - - # Creating a Security Group so as to assign group_id to the rule - security_group = self.create_security_group() - group_id = security_group['id'] - group_name = security_group['name'] - - # Adding rules to the created Security Group with optional group_id - rule = self.client.create_security_group_rule( - parent_group_id=parent_group_id, - ip_protocol=self.ip_protocol, - from_port=self.from_port, - to_port=self.to_port, - group_id=group_id)['security_group_rule'] - self.expected['parent_group_id'] = parent_group_id - self.expected['group'] = {'tenant_id': self.client.tenant_id, - 'name': group_name} - self._check_expected_response(rule) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('a6154130-5a55-4850-8be4-5e9e796dbf17') - @test.services('network') - def test_security_group_rules_list(self): - # Positive test: Created Security Group rules should be - # in the list of all rules - # Creating a Security Group to add rules to it - security_group = self.create_security_group() - securitygroup_id = security_group['id'] - - # Add a first rule to the created Security Group - rule = self.client.create_security_group_rule( - parent_group_id=securitygroup_id, - ip_protocol=self.ip_protocol, - from_port=self.from_port, - to_port=self.to_port)['security_group_rule'] - rule1_id = rule['id'] - - # Add a second rule to the created Security Group - ip_protocol2 = 'icmp' - from_port2 = -1 - to_port2 = -1 - rule = self.client.create_security_group_rule( - parent_group_id=securitygroup_id, - ip_protocol=ip_protocol2, - from_port=from_port2, - to_port=to_port2)['security_group_rule'] - rule2_id = rule['id'] - # Delete the Security Group rule2 at the end of this method - self.addCleanup( - self.security_group_rules_client.delete_security_group_rule, - rule2_id) - - # Get rules of the created Security Group - rules = self.security_groups_client.show_security_group( - securitygroup_id)['security_group']['rules'] - self.assertNotEmpty([i for i in rules if i['id'] == rule1_id]) - self.assertNotEmpty([i for i in rules if i['id'] == rule2_id]) - - @decorators.idempotent_id('fc5c5acf-2091-43a6-a6ae-e42760e9ffaf') - @test.services('network') - def test_security_group_rules_delete_when_peer_group_deleted(self): - # Positive test:rule will delete when peer group deleting - # Creating a Security Group to add rules to it - security_group = self.create_security_group() - sg1_id = security_group['id'] - # Creating other Security Group to access to group1 - security_group = self.create_security_group() - sg2_id = security_group['id'] - # Adding rules to the Group1 - self.client.create_security_group_rule( - parent_group_id=sg1_id, - ip_protocol=self.ip_protocol, - from_port=self.from_port, - to_port=self.to_port, - group_id=sg2_id)['security_group_rule'] - - # Delete group2 - self.security_groups_client.delete_security_group(sg2_id) - # Get rules of the Group1 - rules = (self.security_groups_client.show_security_group(sg1_id) - ['security_group']['rules']) - # The group1 has no rules because group2 has deleted - self.assertEmpty(rules) diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py deleted file mode 100644 index 4efb8b75c..000000000 --- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute.security_groups import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class SecurityGroupRulesNegativeTestJSON(base.BaseSecurityGroupsTest): - - @classmethod - def setup_clients(cls): - super(SecurityGroupRulesNegativeTestJSON, cls).setup_clients() - cls.rules_client = cls.security_group_rules_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1d507e98-7951-469b-82c3-23f1e6b8c254') - @test.services('network') - def test_create_security_group_rule_with_non_existent_id(self): - # Negative test: Creation of Security Group rule should FAIL - # with non existent Parent group id - # Adding rules to the non existent Security Group id - parent_group_id = self.generate_random_security_group_id() - ip_protocol = 'tcp' - from_port = 22 - to_port = 22 - self.assertRaises(lib_exc.NotFound, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('2244d7e4-adb7-4ecb-9930-2d77e123ce4f') - @test.services('network') - def test_create_security_group_rule_with_invalid_id(self): - # Negative test: Creation of Security Group rule should FAIL - # with Parent group id which is not integer - # Adding rules to the non int Security Group id - parent_group_id = data_utils.rand_name('non_int_id') - ip_protocol = 'tcp' - from_port = 22 - to_port = 22 - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8bd56d02-3ffa-4d67-9933-b6b9a01d6089') - @test.services('network') - def test_create_security_group_rule_duplicate(self): - # Negative test: Create Security Group rule duplicate should fail - # Creating a Security Group to add rule to it - sg = self.create_security_group() - # Adding rules to the created Security Group - parent_group_id = sg['id'] - ip_protocol = 'tcp' - from_port = 22 - to_port = 22 - - rule = self.rules_client.create_security_group_rule( - parent_group_id=parent_group_id, ip_protocol=ip_protocol, - from_port=from_port, to_port=to_port)['security_group_rule'] - self.addCleanup(self.rules_client.delete_security_group_rule, - rule['id']) - # Add the same rule to the group should fail - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('84c81249-9f6e-439c-9bbf-cbb0d2cddbdf') - @test.services('network') - def test_create_security_group_rule_with_invalid_ip_protocol(self): - # Negative test: Creation of Security Group rule should FAIL - # with invalid ip_protocol - # Creating a Security Group to add rule to it - sg = self.create_security_group() - # Adding rules to the created Security Group - parent_group_id = sg['id'] - ip_protocol = data_utils.rand_name('999') - from_port = 22 - to_port = 22 - - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('12bbc875-1045-4f7a-be46-751277baedb9') - @test.services('network') - def test_create_security_group_rule_with_invalid_from_port(self): - # Negative test: Creation of Security Group rule should FAIL - # with invalid from_port - # Creating a Security Group to add rule to it - sg = self.create_security_group() - # Adding rules to the created Security Group - parent_group_id = sg['id'] - ip_protocol = 'tcp' - from_port = data_utils.rand_int_id(start=65536) - to_port = 22 - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ff88804d-144f-45d1-bf59-dd155838a43a') - @test.services('network') - def test_create_security_group_rule_with_invalid_to_port(self): - # Negative test: Creation of Security Group rule should FAIL - # with invalid to_port - # Creating a Security Group to add rule to it - sg = self.create_security_group() - # Adding rules to the created Security Group - parent_group_id = sg['id'] - ip_protocol = 'tcp' - from_port = 22 - to_port = data_utils.rand_int_id(start=65536) - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('00296fa9-0576-496a-ae15-fbab843189e0') - @test.services('network') - def test_create_security_group_rule_with_invalid_port_range(self): - # Negative test: Creation of Security Group rule should FAIL - # with invalid port range. - # Creating a Security Group to add rule to it. - sg = self.create_security_group() - # Adding a rule to the created Security Group - secgroup_id = sg['id'] - ip_protocol = 'tcp' - from_port = 22 - to_port = 21 - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=secgroup_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('56fddcca-dbb8-4494-a0db-96e9f869527c') - @test.services('network') - def test_delete_security_group_rule_with_non_existent_id(self): - # Negative test: Deletion of Security Group rule should be FAIL - # with non existent id - non_existent_rule_id = self.generate_random_security_group_id() - self.assertRaises(lib_exc.NotFound, - self.rules_client.delete_security_group_rule, - non_existent_rule_id) diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py deleted file mode 100644 index 930a58ef0..000000000 --- a/tempest/api/compute/security_groups/test_security_groups.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute.security_groups import base -from tempest.common import waiters -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class SecurityGroupsTestJSON(base.BaseSecurityGroupsTest): - - @classmethod - def setup_clients(cls): - super(SecurityGroupsTestJSON, cls).setup_clients() - cls.client = cls.security_groups_client - - @decorators.attr(type='smoke') - @decorators.idempotent_id('eb2b087d-633d-4d0d-a7bd-9e6ba35b32de') - @test.services('network') - def test_security_groups_create_list_delete(self): - # Positive test:Should return the list of Security Groups - # Create 3 Security Groups - security_group_list = [] - for _ in range(3): - body = self.create_security_group() - security_group_list.append(body) - # Fetch all Security Groups and verify the list - # has all created Security Groups - fetched_list = self.client.list_security_groups()['security_groups'] - # Now check if all the created Security Groups are in fetched list - missing_sgs = \ - [sg for sg in security_group_list if sg not in fetched_list] - self.assertFalse(missing_sgs, - "Failed to find Security Group %s in fetched " - "list" % ', '.join(m_group['name'] - for m_group in missing_sgs)) - # Delete all security groups - for sg in security_group_list: - self.client.delete_security_group(sg['id']) - self.client.wait_for_resource_deletion(sg['id']) - # Now check if all the created Security Groups are deleted - fetched_list = self.client.list_security_groups()['security_groups'] - deleted_sgs = \ - [sg for sg in security_group_list if sg in fetched_list] - self.assertFalse(deleted_sgs, - "Failed to delete Security Group %s " - "list" % ', '.join(m_group['name'] - for m_group in deleted_sgs)) - - @decorators.idempotent_id('ecc0da4a-2117-48af-91af-993cca39a615') - @test.services('network') - def test_security_group_create_get_delete(self): - # Security Group should be created, fetched and deleted - # with char space between name along with - # leading and trailing spaces - s_name = ' %s ' % data_utils.rand_name('securitygroup ') - securitygroup = self.create_security_group(name=s_name) - self.assertIn('name', securitygroup) - securitygroup_name = securitygroup['name'] - self.assertEqual(securitygroup_name, s_name, - "The created Security Group name is " - "not equal to the requested name") - # Now fetch the created Security Group by its 'id' - fetched_group = (self.client.show_security_group(securitygroup['id']) - ['security_group']) - self.assertEqual(securitygroup, fetched_group, - "The fetched Security Group is different " - "from the created Group") - self.client.delete_security_group(securitygroup['id']) - self.client.wait_for_resource_deletion(securitygroup['id']) - - @decorators.idempotent_id('fe4abc0d-83f5-4c50-ad11-57a1127297a2') - @test.services('network') - def test_server_security_groups(self): - # Checks that security groups may be added and linked to a server - # and not deleted if the server is active. - # Create a couple security groups that we will use - # for the server resource this test creates - sg = self.create_security_group() - sg2 = self.create_security_group() - - # Create server and add the security group created - # above to the server we just created - server = self.create_test_server(wait_until='ACTIVE') - server_id = server['id'] - self.servers_client.add_security_group(server_id, name=sg['name']) - - # Check that we are not able to delete the security - # group since it is in use by an active server - self.assertRaises(lib_exc.BadRequest, - self.client.delete_security_group, - sg['id']) - - # Reboot and add the other security group - self.servers_client.reboot_server(server_id, type='HARD') - waiters.wait_for_server_status(self.servers_client, server_id, - 'ACTIVE') - self.servers_client.add_security_group(server_id, name=sg2['name']) - - # Check that we are not able to delete the other security - # group since it is in use by an active server - self.assertRaises(lib_exc.BadRequest, - self.client.delete_security_group, - sg2['id']) - - # Shutdown the server and then verify we can destroy the - # security groups, since no active server instance is using them - self.servers_client.delete_server(server_id) - waiters.wait_for_server_termination(self.servers_client, server_id) - - self.client.delete_security_group(sg['id']) - self.client.delete_security_group(sg2['id']) - - @decorators.idempotent_id('7d4e1d3c-3209-4d6d-b020-986304ebad1f') - @test.services('network') - def test_update_security_groups(self): - # Update security group name and description - # Create a security group - securitygroup = self.create_security_group() - self.assertIn('id', securitygroup) - securitygroup_id = securitygroup['id'] - # Update the name and description - s_new_name = data_utils.rand_name('sg-hth') - s_new_des = data_utils.rand_name('description-hth') - self.client.update_security_group(securitygroup_id, - name=s_new_name, - description=s_new_des) - # get the security group - fetched_group = (self.client.show_security_group(securitygroup_id) - ['security_group']) - self.assertEqual(s_new_name, fetched_group['name']) - self.assertEqual(s_new_des, fetched_group['description']) - - @decorators.idempotent_id('79517d60-535a-438f-af3d-e6feab1cbea7') - @test.services('network') - def test_list_security_groups_by_server(self): - # Create a couple security groups that we will use - # for the server resource this test creates - sg = self.create_security_group() - sg2 = self.create_security_group() - assigned_security_groups_ids = [sg['id'], sg2['id']] - # Create server and add the security group created - # above to the server we just created - server_id = self.create_test_server(wait_until='ACTIVE')['id'] - # add security groups to server - self.servers_client.add_security_group(server_id, name=sg['name']) - self.servers_client.add_security_group(server_id, name=sg2['name']) - - # list security groups for a server - fetched_groups = ( - self.servers_client.list_security_groups_by_server( - server_id)['security_groups']) - fetched_security_groups_ids = [i['id'] for i in fetched_groups] - # verifying the security groups ids in list - missing_security_groups =\ - [p for p in assigned_security_groups_ids - if p not in fetched_security_groups_ids] - self.assertEmpty(missing_security_groups, - "Failed to find security_groups %s in fetched list" % - ', '.join(missing_security_groups)) diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py deleted file mode 100644 index 207778a4c..000000000 --- a/tempest/api/compute/security_groups/test_security_groups_negative.py +++ /dev/null @@ -1,192 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute.security_groups import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class SecurityGroupsNegativeTestJSON(base.BaseSecurityGroupsTest): - - @classmethod - def setup_clients(cls): - super(SecurityGroupsNegativeTestJSON, cls).setup_clients() - cls.client = cls.security_groups_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('673eaec1-9b3e-48ed-bdf1-2786c1b9661c') - @test.services('network') - def test_security_group_get_nonexistent_group(self): - # Negative test:Should not be able to GET the details - # of non-existent Security Group - non_exist_id = self.generate_random_security_group_id() - self.assertRaises(lib_exc.NotFound, self.client.show_security_group, - non_exist_id) - - @decorators.skip_because(bug="1161411", - condition=CONF.service_available.neutron) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1759c3cb-b0fc-44b7-86ce-c99236be911d') - @test.services('network') - def test_security_group_create_with_invalid_group_name(self): - # Negative test: Security Group should not be created with group name - # as an empty string/with white spaces/chars more than 255 - s_description = data_utils.rand_name('description') - # Create Security Group with empty string as group name - self.assertRaises(lib_exc.BadRequest, - self.client.create_security_group, - name="", description=s_description) - # Create Security Group with white space in group name - self.assertRaises(lib_exc.BadRequest, - self.client.create_security_group, - name=" ", description=s_description) - # Create Security Group with group name longer than 255 chars - s_name = 'securitygroup-'.ljust(260, '0') - self.assertRaises(lib_exc.BadRequest, - self.client.create_security_group, - name=s_name, description=s_description) - - @decorators.skip_because(bug="1161411", - condition=CONF.service_available.neutron) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('777b6f14-aca9-4758-9e84-38783cfa58bc') - @test.services('network') - def test_security_group_create_with_invalid_group_description(self): - # Negative test: Security Group should not be created with description - # longer than 255 chars. Empty description is allowed by the API - # reference, however. - s_name = data_utils.rand_name('securitygroup') - # Create Security Group with group description longer than 255 chars - s_description = 'description-'.ljust(260, '0') - self.assertRaises(lib_exc.BadRequest, - self.client.create_security_group, - name=s_name, description=s_description) - - @decorators.idempotent_id('9fdb4abc-6b66-4b27-b89c-eb215a956168') - @testtools.skipIf(CONF.service_available.neutron, - "Neutron allows duplicate names for security groups") - @decorators.attr(type=['negative']) - @test.services('network') - def test_security_group_create_with_duplicate_name(self): - # Negative test:Security Group with duplicate name should not - # be created - s_name = data_utils.rand_name('securitygroup') - s_description = data_utils.rand_name('description') - self.create_security_group(name=s_name, description=s_description) - # Now try the Security Group with the same 'Name' - self.assertRaises(lib_exc.BadRequest, - self.client.create_security_group, - name=s_name, description=s_description) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('36a1629f-c6da-4a26-b8b8-55e7e5d5cd58') - @test.services('network') - def test_delete_the_default_security_group(self): - # Negative test:Deletion of the "default" Security Group should Fail - default_security_group_id = None - body = self.client.list_security_groups()['security_groups'] - for i in range(len(body)): - if body[i]['name'] == 'default': - default_security_group_id = body[i]['id'] - break - # Deleting the "default" Security Group - self.assertRaises(lib_exc.BadRequest, - self.client.delete_security_group, - default_security_group_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6727c00b-214c-4f9e-9a52-017ac3e98411') - @test.services('network') - def test_delete_nonexistent_security_group(self): - # Negative test:Deletion of a non-existent Security Group should fail - non_exist_id = self.generate_random_security_group_id() - self.assertRaises(lib_exc.NotFound, - self.client.delete_security_group, non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1438f330-8fa4-4aeb-8a94-37c250106d7f') - @test.services('network') - def test_delete_security_group_without_passing_id(self): - # Negative test:Deletion of a Security Group with out passing ID - # should Fail - self.assertRaises(lib_exc.NotFound, - self.client.delete_security_group, '') - - @decorators.idempotent_id('00579617-fe04-4e1c-9d08-ca7467d2e34b') - @testtools.skipIf(CONF.service_available.neutron, - "Neutron does not check the security group ID") - @decorators.attr(type=['negative']) - @test.services('network') - def test_update_security_group_with_invalid_sg_id(self): - # Update security_group with invalid sg_id should fail - s_name = data_utils.rand_name('sg') - s_description = data_utils.rand_name('description') - # Create a non int sg_id - sg_id_invalid = data_utils.rand_name('sg') - self.assertRaises(lib_exc.BadRequest, - self.client.update_security_group, sg_id_invalid, - name=s_name, description=s_description) - - @decorators.idempotent_id('cda8d8b4-59f8-4087-821d-20cf5a03b3b1') - @testtools.skipIf(CONF.service_available.neutron, - "Neutron does not check the security group name") - @decorators.attr(type=['negative']) - @test.services('network') - def test_update_security_group_with_invalid_sg_name(self): - # Update security_group with invalid sg_name should fail - securitygroup = self.create_security_group() - self.assertIn('id', securitygroup) - securitygroup_id = securitygroup['id'] - # Update Security Group with group name longer than 255 chars - s_new_name = 'securitygroup-'.ljust(260, '0') - self.assertRaises(lib_exc.BadRequest, - self.client.update_security_group, - securitygroup_id, name=s_new_name) - - @decorators.idempotent_id('97d12b1c-a610-4194-93f1-ba859e718b45') - @testtools.skipIf(CONF.service_available.neutron, - "Neutron does not check the security group description") - @decorators.attr(type=['negative']) - @test.services('network') - def test_update_security_group_with_invalid_sg_des(self): - # Update security_group with invalid sg_des should fail - securitygroup = self.create_security_group() - self.assertIn('id', securitygroup) - securitygroup_id = securitygroup['id'] - # Update Security Group with group description longer than 255 chars - s_new_des = 'des-'.ljust(260, '0') - self.assertRaises(lib_exc.BadRequest, - self.client.update_security_group, - securitygroup_id, description=s_new_des) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('27edee9c-873d-4da6-a68a-3c256efebe8f') - @test.services('network') - def test_update_non_existent_security_group(self): - # Update a non-existent Security Group should Fail - non_exist_id = self.generate_random_security_group_id() - s_name = data_utils.rand_name('sg') - s_description = data_utils.rand_name('description') - self.assertRaises(lib_exc.NotFound, - self.client.update_security_group, - non_exist_id, name=s_name, - description=s_description) diff --git a/tempest/api/compute/servers/__init__.py b/tempest/api/compute/servers/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py deleted file mode 100644 index 65d5042b5..000000000 --- a/tempest/api/compute/servers/test_attach_interfaces.py +++ /dev/null @@ -1,281 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common.utils import net_utils -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class AttachInterfacesTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(AttachInterfacesTestJSON, cls).skip_checks() - if not CONF.service_available.neutron: - raise cls.skipException("Neutron is required") - if not CONF.compute_feature_enabled.interface_attach: - raise cls.skipException("Interface attachment is not available.") - - @classmethod - def setup_credentials(cls): - # This test class requires network and subnet - cls.set_network_resources(network=True, subnet=True) - super(AttachInterfacesTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(AttachInterfacesTestJSON, cls).setup_clients() - cls.subnets_client = cls.os_primary.subnets_client - cls.ports_client = cls.os_primary.ports_client - - def wait_for_port_detach(self, port_id): - """Waits for the port's device_id to be unset. - - :param port_id: The id of the port being detached. - :returns: The final port dict from the show_port response. - """ - port = self.ports_client.show_port(port_id)['port'] - device_id = port['device_id'] - start = int(time.time()) - - # NOTE(mriedem): Nova updates the port's device_id to '' rather than - # None, but it's not contractual so handle Falsey either way. - while device_id: - time.sleep(self.build_interval) - port = self.ports_client.show_port(port_id)['port'] - device_id = port['device_id'] - - timed_out = int(time.time()) - start >= self.build_timeout - - if device_id and timed_out: - message = ('Port %s failed to detach (device_id %s) within ' - 'the required time (%s s).' % - (port_id, device_id, self.build_timeout)) - raise lib_exc.TimeoutException(message) - - return port - - def _check_interface(self, iface, port_id=None, network_id=None, - fixed_ip=None, mac_addr=None): - if port_id: - self.assertEqual(iface['port_id'], port_id) - if network_id: - self.assertEqual(iface['net_id'], network_id) - if fixed_ip: - self.assertEqual(iface['fixed_ips'][0]['ip_address'], fixed_ip) - if mac_addr: - self.assertEqual(iface['mac_addr'], mac_addr) - - def _create_server_get_interfaces(self): - server = self.create_test_server(wait_until='ACTIVE') - ifs = (self.interfaces_client.list_interfaces(server['id']) - ['interfaceAttachments']) - body = waiters.wait_for_interface_status( - self.interfaces_client, server['id'], ifs[0]['port_id'], 'ACTIVE') - ifs[0]['port_state'] = body['port_state'] - return server, ifs - - def _test_create_interface(self, server): - iface = (self.interfaces_client.create_interface(server['id']) - ['interfaceAttachment']) - iface = waiters.wait_for_interface_status( - self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE') - self._check_interface(iface) - return iface - - def _test_create_interface_by_network_id(self, server, ifs): - network_id = ifs[0]['net_id'] - iface = self.interfaces_client.create_interface( - server['id'], net_id=network_id)['interfaceAttachment'] - iface = waiters.wait_for_interface_status( - self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE') - self._check_interface(iface, network_id=network_id) - return iface - - def _test_create_interface_by_port_id(self, server, ifs): - network_id = ifs[0]['net_id'] - port = self.ports_client.create_port(network_id=network_id) - port_id = port['port']['id'] - self.addCleanup(self.ports_client.delete_port, port_id) - iface = self.interfaces_client.create_interface( - server['id'], port_id=port_id)['interfaceAttachment'] - iface = waiters.wait_for_interface_status( - self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE') - self._check_interface(iface, port_id=port_id) - return iface - - def _test_create_interface_by_fixed_ips(self, server, ifs): - network_id = ifs[0]['net_id'] - subnet_id = ifs[0]['fixed_ips'][0]['subnet_id'] - ip_list = net_utils.get_unused_ip_addresses(self.ports_client, - self.subnets_client, - network_id, - subnet_id, - 1) - - fixed_ips = [{'ip_address': ip_list[0]}] - iface = self.interfaces_client.create_interface( - server['id'], net_id=network_id, - fixed_ips=fixed_ips)['interfaceAttachment'] - self.addCleanup(self.ports_client.delete_port, iface['port_id']) - iface = waiters.wait_for_interface_status( - self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE') - self._check_interface(iface, fixed_ip=ip_list[0]) - return iface - - def _test_show_interface(self, server, ifs): - iface = ifs[0] - _iface = self.interfaces_client.show_interface( - server['id'], iface['port_id'])['interfaceAttachment'] - self._check_interface(iface, port_id=_iface['port_id'], - network_id=_iface['net_id'], - fixed_ip=_iface['fixed_ips'][0]['ip_address'], - mac_addr=_iface['mac_addr']) - - def _test_delete_interface(self, server, ifs): - # NOTE(danms): delete not the first or last, but one in the middle - iface = ifs[1] - self.interfaces_client.delete_interface(server['id'], iface['port_id']) - _ifs = (self.interfaces_client.list_interfaces(server['id']) - ['interfaceAttachments']) - start = int(time.time()) - - while len(ifs) == len(_ifs): - time.sleep(self.build_interval) - _ifs = (self.interfaces_client.list_interfaces(server['id']) - ['interfaceAttachments']) - timed_out = int(time.time()) - start >= self.build_timeout - if len(ifs) == len(_ifs) and timed_out: - message = ('Failed to delete interface within ' - 'the required time: %s sec.' % self.build_timeout) - raise lib_exc.TimeoutException(message) - - self.assertNotIn(iface['port_id'], [i['port_id'] for i in _ifs]) - return _ifs - - def _compare_iface_list(self, list1, list2): - # NOTE(danms): port_state will likely have changed, so just - # confirm the port_ids are the same at least - list1 = [x['port_id'] for x in list1] - list2 = [x['port_id'] for x in list2] - - self.assertEqual(sorted(list1), sorted(list2)) - - @decorators.idempotent_id('73fe8f02-590d-4bf1-b184-e9ca81065051') - @test.services('network') - def test_create_list_show_delete_interfaces(self): - server, ifs = self._create_server_get_interfaces() - interface_count = len(ifs) - self.assertGreater(interface_count, 0) - self._check_interface(ifs[0]) - - try: - iface = self._test_create_interface(server) - except lib_exc.BadRequest as e: - msg = ('Multiple possible networks found, use a Network ID to be ' - 'more specific.') - if not CONF.compute.fixed_network_name and e.message == msg: - raise - else: - ifs.append(iface) - - iface = self._test_create_interface_by_network_id(server, ifs) - ifs.append(iface) - - iface = self._test_create_interface_by_port_id(server, ifs) - ifs.append(iface) - - iface = self._test_create_interface_by_fixed_ips(server, ifs) - ifs.append(iface) - - _ifs = (self.interfaces_client.list_interfaces(server['id']) - ['interfaceAttachments']) - self._compare_iface_list(ifs, _ifs) - - self._test_show_interface(server, ifs) - - _ifs = self._test_delete_interface(server, ifs) - self.assertEqual(len(ifs) - 1, len(_ifs)) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('c7e0e60b-ee45-43d0-abeb-8596fd42a2f9') - @test.services('network') - def test_add_remove_fixed_ip(self): - # Add and Remove the fixed IP to server. - server, ifs = self._create_server_get_interfaces() - interface_count = len(ifs) - self.assertGreater(interface_count, 0) - self._check_interface(ifs[0]) - network_id = ifs[0]['net_id'] - self.servers_client.add_fixed_ip(server['id'], networkId=network_id) - # Remove the fixed IP from server. - server_detail = self.os_primary.servers_client.show_server( - server['id'])['server'] - # Get the Fixed IP from server. - fixed_ip = None - for ip_set in server_detail['addresses']: - for ip in server_detail['addresses'][ip_set]: - if ip['OS-EXT-IPS:type'] == 'fixed': - fixed_ip = ip['addr'] - break - if fixed_ip is not None: - break - self.servers_client.remove_fixed_ip(server['id'], address=fixed_ip) - - @decorators.skip_because(bug='1607714') - @decorators.idempotent_id('2f3a0127-95c7-4977-92d2-bc5aec602fb4') - def test_reassign_port_between_servers(self): - """Tests the following: - - 1. Create a port in Neutron. - 2. Create two servers in Nova. - 3. Attach the port to the first server. - 4. Detach the port from the first server. - 5. Attach the port to the second server. - 6. Detach the port from the second server. - """ - network = self.get_tenant_network() - network_id = network['id'] - port = self.ports_client.create_port(network_id=network_id) - port_id = port['port']['id'] - self.addCleanup(self.ports_client.delete_port, port_id) - - # create two servers - _, servers = compute.create_test_server( - self.os_primary, tenant_network=network, - wait_until='ACTIVE', min_count=2) - # add our cleanups for the servers since we bypassed the base class - for server in servers: - self.addCleanup(self.delete_server, server['id']) - - for server in servers: - # attach the port to the server - iface = self.interfaces_client.create_interface( - server['id'], port_id=port_id)['interfaceAttachment'] - self._check_interface(iface, port_id=port_id) - - # detach the port from the server; this is a cast in the compute - # API so we have to poll the port until the device_id is unset. - self.interfaces_client.delete_interface(server['id'], port_id) - self.wait_for_port_detach(port_id) diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py deleted file mode 100644 index 36828d6b4..000000000 --- a/tempest/api/compute/servers/test_availability_zone.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2014 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators - - -class AZV2TestJSON(base.BaseV2ComputeTest): - """Tests Availability Zone API List""" - - @classmethod - def setup_clients(cls): - super(AZV2TestJSON, cls).setup_clients() - cls.client = cls.availability_zone_client - - @decorators.idempotent_id('a8333aa2-205c-449f-a828-d38c2489bf25') - def test_get_availability_zone_list_with_non_admin_user(self): - # List of availability zone with non-administrator user - availability_zone = self.client.list_availability_zones() - self.assertNotEmpty(availability_zone['availabilityZoneInfo']) diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py deleted file mode 100644 index aa5c43d8d..000000000 --- a/tempest/api/compute/servers/test_create_server.py +++ /dev/null @@ -1,172 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr -import testtools - -from tempest.api.compute import base -from tempest.common.utils.linux import remote_client -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class ServersTestJSON(base.BaseV2ComputeTest): - disk_config = 'AUTO' - volume_backed = False - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(ServersTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServersTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - super(ServersTestJSON, cls).resource_setup() - cls.meta = {'hello': 'world'} - cls.accessIPv4 = '1.1.1.1' - cls.accessIPv6 = '0000:0000:0000:0000:0000:babe:220.12.22.2' - cls.name = data_utils.rand_name(cls.__name__ + '-server') - cls.password = data_utils.rand_password() - disk_config = cls.disk_config - server_initial = cls.create_test_server( - validatable=True, - wait_until='ACTIVE', - name=cls.name, - metadata=cls.meta, - accessIPv4=cls.accessIPv4, - accessIPv6=cls.accessIPv6, - disk_config=disk_config, - adminPass=cls.password, - volume_backed=cls.volume_backed) - cls.server = (cls.client.show_server(server_initial['id']) - ['server']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('5de47127-9977-400a-936f-abcfbec1218f') - def test_verify_server_details(self): - # Verify the specified server attributes are set correctly - self.assertEqual(self.accessIPv4, self.server['accessIPv4']) - # NOTE(maurosr): See http://tools.ietf.org/html/rfc5952 (section 4) - # Here we compare directly with the canonicalized format. - self.assertEqual(self.server['accessIPv6'], - str(netaddr.IPAddress(self.accessIPv6))) - self.assertEqual(self.name, self.server['name']) - if self.volume_backed: - # Image is an empty string as per documentation - self.assertEqual("", self.server['image']) - else: - self.assertEqual(self.image_ref, self.server['image']['id']) - self.assertEqual(self.flavor_ref, self.server['flavor']['id']) - self.assertEqual(self.meta, self.server['metadata']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('9a438d88-10c6-4bcd-8b5b-5b6e25e1346f') - def test_list_servers(self): - # The created server should be in the list of all servers - body = self.client.list_servers() - servers = body['servers'] - found = [i for i in servers if i['id'] == self.server['id']] - self.assertNotEmpty(found) - - @decorators.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997') - def test_list_servers_with_detail(self): - # The created server should be in the detailed list of all servers - body = self.client.list_servers(detail=True) - servers = body['servers'] - found = [i for i in servers if i['id'] == self.server['id']] - self.assertNotEmpty(found) - - @decorators.idempotent_id('cbc0f52f-05aa-492b-bdc1-84b575ca294b') - @testtools.skipUnless(CONF.validation.run_validation, - 'Instance validation tests are disabled.') - def test_verify_created_server_vcpus(self): - # Verify that the number of vcpus reported by the instance matches - # the amount stated by the flavor - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - linux_client = remote_client.RemoteClient( - self.get_server_ip(self.server), - self.ssh_user, - self.password, - self.validation_resources['keypair']['private_key'], - server=self.server, - servers_client=self.client) - output = linux_client.exec_command('grep -c ^processor /proc/cpuinfo') - self.assertEqual(flavor['vcpus'], int(output)) - - @decorators.idempotent_id('ac1ad47f-984b-4441-9274-c9079b7a0666') - @testtools.skipUnless(CONF.validation.run_validation, - 'Instance validation tests are disabled.') - def test_host_name_is_same_as_server_name(self): - # Verify the instance host name is the same as the server name - linux_client = remote_client.RemoteClient( - self.get_server_ip(self.server), - self.ssh_user, - self.password, - self.validation_resources['keypair']['private_key'], - server=self.server, - servers_client=self.client) - hostname = linux_client.exec_command("hostname").rstrip() - msg = ('Failed while verifying servername equals hostname. Expected ' - 'hostname "%s" but got "%s".' % (self.name, hostname)) - self.assertEqual(self.name.lower(), hostname, msg) - - @decorators.idempotent_id('ed20d3fb-9d1f-4329-b160-543fbd5d9811') - @testtools.skipUnless( - test.is_scheduler_filter_enabled("ServerGroupAffinityFilter"), - 'ServerGroupAffinityFilter is not available.') - def test_create_server_with_scheduler_hint_group(self): - # Create a server with the scheduler hint "group". - group_id = self.create_test_server_group()['id'] - hints = {'group': group_id} - server = self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE') - - # Check a server is in the group - server_group = (self.server_groups_client.show_server_group(group_id) - ['server_group']) - self.assertIn(server['id'], server_group['members']) - - -class ServersTestManualDisk(ServersTestJSON): - disk_config = 'MANUAL' - - @classmethod - def skip_checks(cls): - super(ServersTestManualDisk, cls).skip_checks() - if not CONF.compute_feature_enabled.disk_config: - msg = "DiskConfig extension not enabled." - raise cls.skipException(msg) - - -class ServersTestBootFromVolume(ServersTestJSON): - """Run the `ServersTestJSON` tests with a volume backed VM""" - volume_backed = True - - @classmethod - def skip_checks(cls): - super(ServersTestBootFromVolume, cls).skip_checks() - if not test.get_service_list()['volume']: - msg = "Volume service not enabled." - raise cls.skipException(msg) diff --git a/tempest/api/compute/servers/test_create_server_multi_nic.py b/tempest/api/compute/servers/test_create_server_multi_nic.py deleted file mode 100644 index 3447d858d..000000000 --- a/tempest/api/compute/servers/test_create_server_multi_nic.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr -import testtools - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ServersTestMultiNic(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(ServersTestMultiNic, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServersTestMultiNic, cls).setup_clients() - cls.client = cls.servers_client - cls.networks_client = cls.os_primary.networks_client - cls.subnets_client = cls.os_primary.subnets_client - - def _create_net_subnet_ret_net_from_cidr(self, cidr): - name_net = data_utils.rand_name(self.__class__.__name__) - net = self.networks_client.create_network(name=name_net) - self.addCleanup(self.networks_client.delete_network, - net['network']['id']) - - subnet = self.subnets_client.create_subnet( - network_id=net['network']['id'], - cidr=cidr, - ip_version=4) - self.addCleanup(self.subnets_client.delete_subnet, - subnet['subnet']['id']) - return net - - @decorators.idempotent_id('0578d144-ed74-43f8-8e57-ab10dbf9b3c2') - @testtools.skipUnless(CONF.service_available.neutron, - 'Neutron service must be available.') - def test_verify_multiple_nics_order(self): - # Verify that the networks order given at the server creation is - # preserved within the server. - net1 = self._create_net_subnet_ret_net_from_cidr('19.80.0.0/24') - net2 = self._create_net_subnet_ret_net_from_cidr('19.86.0.0/24') - - networks = [{'uuid': net1['network']['id']}, - {'uuid': net2['network']['id']}] - - server_multi_nics = self.create_test_server( - networks=networks, wait_until='ACTIVE') - - # Cleanup server; this is needed in the test case because with the LIFO - # nature of the cleanups, if we don't delete the server first, the port - # will still be part of the subnet and we'll get a 409 from Neutron - # when trying to delete the subnet. The tear down in the base class - # will try to delete the server and get a 404 but it's ignored so - # we're OK. - self.addCleanup(self.delete_server, server_multi_nics['id']) - - addresses = (self.client.list_addresses(server_multi_nics['id']) - ['addresses']) - - # We can't predict the ip addresses assigned to the server on networks. - # Sometimes the assigned addresses are ['19.80.0.2', '19.86.0.2'], at - # other times ['19.80.0.3', '19.86.0.3']. So we check if the first - # address is in first network, similarly second address is in second - # network. - addr = [addresses[net1['network']['name']][0]['addr'], - addresses[net2['network']['name']][0]['addr']] - networks = [netaddr.IPNetwork('19.80.0.0/24'), - netaddr.IPNetwork('19.86.0.0/24')] - for address, network in zip(addr, networks): - self.assertIn(address, network) - - @decorators.idempotent_id('1678d144-ed74-43f8-8e57-ab10dbf9b3c2') - @testtools.skipUnless(CONF.service_available.neutron, - 'Neutron service must be available.') - def test_verify_duplicate_network_nics(self): - # Verify that server creation does not fail when more than one nic - # is created on the same network. - net1 = self._create_net_subnet_ret_net_from_cidr('19.80.0.0/24') - net2 = self._create_net_subnet_ret_net_from_cidr('19.86.0.0/24') - - networks = [{'uuid': net1['network']['id']}, - {'uuid': net2['network']['id']}, - {'uuid': net1['network']['id']}] - - server_multi_nics = self.create_test_server( - networks=networks, wait_until='ACTIVE') - self.addCleanup(self.delete_server, server_multi_nics['id']) - - addresses = (self.client.list_addresses(server_multi_nics['id']) - ['addresses']) - - addr = [addresses[net1['network']['name']][0]['addr'], - addresses[net2['network']['name']][0]['addr'], - addresses[net1['network']['name']][1]['addr']] - networks = [netaddr.IPNetwork('19.80.0.0/24'), - netaddr.IPNetwork('19.86.0.0/24'), - netaddr.IPNetwork('19.80.0.0/24')] - for address, network in zip(addr, networks): - self.assertIn(address, network) diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py deleted file mode 100644 index 2b03b2be7..000000000 --- a/tempest/api/compute/servers/test_delete_server.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class DeleteServersTestJSON(base.BaseV2ComputeTest): - - # NOTE: Server creations of each test class should be under 10 - # for preventing "Quota exceeded for instances" - - @classmethod - def setup_clients(cls): - super(DeleteServersTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @decorators.idempotent_id('9e6e0c87-3352-42f7-9faf-5d6210dbd159') - def test_delete_server_while_in_building_state(self): - # Delete a server while it's VM state is Building - server = self.create_test_server(wait_until='BUILD') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('925fdfb4-5b13-47ea-ac8a-c36ae6fddb05') - def test_delete_active_server(self): - # Delete a server while it's VM state is Active - server = self.create_test_server(wait_until='ACTIVE') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('546d368c-bb6c-4645-979a-83ed16f3a6be') - def test_delete_server_while_in_shutoff_state(self): - # Delete a server while it's VM state is Shutoff - server = self.create_test_server(wait_until='ACTIVE') - self.client.stop_server(server['id']) - waiters.wait_for_server_status(self.client, server['id'], 'SHUTOFF') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('943bd6e8-4d7a-4904-be83-7a6cc2d4213b') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - def test_delete_server_while_in_pause_state(self): - # Delete a server while it's VM state is Pause - server = self.create_test_server(wait_until='ACTIVE') - self.client.pause_server(server['id']) - waiters.wait_for_server_status(self.client, server['id'], 'PAUSED') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('1f82ebd3-8253-4f4e-b93f-de9b7df56d8b') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - def test_delete_server_while_in_suspended_state(self): - # Delete a server while it's VM state is Suspended - server = self.create_test_server(wait_until='ACTIVE') - self.client.suspend_server(server['id']) - waiters.wait_for_server_status(self.client, server['id'], 'SUSPENDED') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('bb0cb402-09dd-4947-b6e5-5e7e1cfa61ad') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - def test_delete_server_while_in_shelved_state(self): - # Delete a server while it's VM state is Shelved - server = self.create_test_server(wait_until='ACTIVE') - compute.shelve_server(self.client, server['id']) - - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('ab0c38b4-cdd8-49d3-9b92-0cb898723c01') - @testtools.skipIf(not CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_delete_server_while_in_verify_resize_state(self): - # Delete a server while it's VM state is VERIFY_RESIZE - server = self.create_test_server(wait_until='ACTIVE') - self.client.resize_server(server['id'], self.flavor_ref_alt) - waiters.wait_for_server_status(self.client, server['id'], - 'VERIFY_RESIZE') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('d0f3f0d6-d9b6-4a32-8da4-23015dcab23c') - @test.services('volume') - def test_delete_server_while_in_attached_volume(self): - # Delete a server while a volume is attached to it - device = '/dev/%s' % CONF.compute.volume_device_name - server = self.create_test_server(wait_until='ACTIVE') - - volume = self.create_volume() - self.attach_volume(server, volume, device=device) - - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') diff --git a/tempest/api/compute/servers/test_device_tagging.py b/tempest/api/compute/servers/test_device_tagging.py deleted file mode 100644 index 7ee1b0259..000000000 --- a/tempest/api/compute/servers/test_device_tagging.py +++ /dev/null @@ -1,288 +0,0 @@ -# Copyright (C) 2016, Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import json - -from oslo_log import log as logging - -from tempest.api.compute import base -from tempest.common.utils.linux import remote_client -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest import test - - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class DeviceTaggingTest(base.BaseV2ComputeTest): - - min_microversion = '2.32' - # NOTE(mriedem): max_version looks odd but it's actually correct. Due to a - # bug in the 2.32 microversion, tags on block devices only worked with the - # 2.32 microversion specifically. And tags on networks only worked between - # 2.32 and 2.36 inclusive; the 2.37 microversion broke tags for networks. - max_microversion = '2.32' - - @classmethod - def skip_checks(cls): - super(DeviceTaggingTest, cls).skip_checks() - if not CONF.service_available.neutron: - raise cls.skipException('Neutron is required') - if not CONF.validation.run_validation: - raise cls.skipException('Validation must be enabled') - if (not CONF.compute_feature_enabled.config_drive - and not CONF.compute_feature_enabled.metadata_service): - raise cls.skipException('One of metadata or config drive must be ' - 'enabled') - - @classmethod - def setup_clients(cls): - super(DeviceTaggingTest, cls).setup_clients() - cls.networks_client = cls.os_primary.networks_client - cls.ports_client = cls.os_primary.ports_client - cls.subnets_client = cls.os_primary.subnets_client - cls.interfaces_client = cls.os_primary.interfaces_client - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True, - dhcp=True) - super(DeviceTaggingTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - super(DeviceTaggingTest, cls).resource_setup() - - def verify_device_metadata(self, md_json): - md_dict = json.loads(md_json) - for d in md_dict['devices']: - if d['type'] == 'nic': - if d['mac'] == self.port1['mac_address']: - self.assertEqual(d['tags'], ['port-1']) - if d['mac'] == self.port2['mac_address']: - self.assertEqual(d['tags'], ['port-2']) - if d['mac'] == self.net_2_100_mac: - self.assertEqual(d['tags'], ['net-2-100']) - if d['mac'] == self.net_2_200_mac: - self.assertEqual(d['tags'], ['net-2-200']) - - # A hypervisor may present multiple paths to a tagged disk, so - # there may be duplicated tags in the metadata, use set() to - # remove duplicated tags. - found_devices = [d['tags'][0] for d in md_dict['devices']] - self.assertEqual(set(found_devices), set(['port-1', 'port-2', - 'net-1', 'net-2-100', - 'net-2-200', 'boot', - 'other'])) - - @decorators.idempotent_id('a2e65a6c-66f1-4442-aaa8-498c31778d96') - @test.services('network', 'volume', 'image') - def test_device_tagging(self): - # Create volumes - # The create_volume methods waits for the volumes to be available and - # the base class will clean them up on tearDown. - boot_volume = self.create_volume(CONF.compute.image_ref) - other_volume = self.create_volume() - untagged_volume = self.create_volume() - - # Create networks - net1 = self.networks_client.create_network( - name=data_utils.rand_name('device-tagging-net1'))['network'] - self.addCleanup(self.networks_client.delete_network, net1['id']) - - net2 = self.networks_client.create_network( - name=data_utils.rand_name('device-tagging-net2'))['network'] - self.addCleanup(self.networks_client.delete_network, net2['id']) - - # Create subnets - subnet1 = self.subnets_client.create_subnet( - network_id=net1['id'], - cidr='10.1.1.0/24', - ip_version=4)['subnet'] - self.addCleanup(self.subnets_client.delete_subnet, subnet1['id']) - - subnet2 = self.subnets_client.create_subnet( - network_id=net2['id'], - cidr='10.2.2.0/24', - ip_version=4)['subnet'] - self.addCleanup(self.subnets_client.delete_subnet, subnet2['id']) - - # Create ports - self.port1 = self.ports_client.create_port( - network_id=net1['id'], - fixed_ips=[{'subnet_id': subnet1['id']}])['port'] - self.addCleanup(self.ports_client.delete_port, self.port1['id']) - - self.port2 = self.ports_client.create_port( - network_id=net1['id'], - fixed_ips=[{'subnet_id': subnet1['id']}])['port'] - self.addCleanup(self.ports_client.delete_port, self.port2['id']) - - # Create server - admin_pass = data_utils.rand_password() - config_drive_enabled = CONF.compute_feature_enabled.config_drive - - server = self.create_test_server( - validatable=True, - config_drive=config_drive_enabled, - adminPass=admin_pass, - name=data_utils.rand_name('device-tagging-server'), - networks=[ - # Validation network for ssh - { - 'uuid': self.get_tenant_network()['id'] - }, - # Different tags for different ports - { - 'port': self.port1['id'], - 'tag': 'port-1' - }, - { - 'port': self.port2['id'], - 'tag': 'port-2' - }, - # Two nics on same net, one tagged one not - { - 'uuid': net1['id'], - 'tag': 'net-1' - }, - { - 'uuid': net1['id'] - }, - # Two nics on same net, different IP - { - 'uuid': net2['id'], - 'fixed_ip': '10.2.2.100', - 'tag': 'net-2-100' - }, - { - 'uuid': net2['id'], - 'fixed_ip': '10.2.2.200', - 'tag': 'net-2-200' - } - ], - block_device_mapping_v2=[ - # Boot volume - { - 'uuid': boot_volume['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'boot_index': 0, - 'tag': 'boot' - }, - # Other volume - { - 'uuid': other_volume['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'boot_index': 1, - 'tag': 'other' - }, - # Untagged volume - { - 'uuid': untagged_volume['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'boot_index': 2 - } - ]) - - self.addCleanup(self.delete_server, server['id']) - - self.ssh_client = remote_client.RemoteClient( - self.get_server_ip(server), - CONF.validation.image_ssh_user, - admin_pass, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.servers_client) - - # Find the MAC addresses of our fixed IPs - self.net_2_100_mac = None - self.net_2_200_mac = None - ifaces = self.interfaces_client.list_interfaces(server['id']) - for iface in ifaces['interfaceAttachments']: - if 'fixed_ips' in iface: - for ip in iface['fixed_ips']: - if ip['ip_address'] == '10.2.2.100': - self.net_2_100_mac = iface['mac_addr'] - if ip['ip_address'] == '10.2.2.200': - self.net_2_200_mac = iface['mac_addr'] - # Make sure we have the MACs we need, there's no reason for some to be - # missing - self.assertTrue(self.net_2_100_mac) - self.assertTrue(self.net_2_200_mac) - - # Verify metadata from metadata service - if CONF.compute_feature_enabled.metadata_service: - md_url = 'http://169.254.169.254/openstack/latest/meta_data.json' - LOG.info('Attempting to verify tagged devices in server %s via ' - 'the metadata service: %s', server['id'], md_url) - - def get_and_verify_metadata(): - try: - self.ssh_client.exec_command('curl -V') - except exceptions.SSHExecCommandFailed: - if not CONF.compute_feature_enabled.config_drive: - raise self.skipException('curl not found in guest ' - 'and config drive is ' - 'disabled') - LOG.warning('curl was not found in the guest, device ' - 'tagging metadata was not checked in the ' - 'metadata API') - return True - cmd = 'curl %s' % md_url - md_json = self.ssh_client.exec_command(cmd) - self.verify_device_metadata(md_json) - return True - - if not test_utils.call_until_true(get_and_verify_metadata, - CONF.compute.build_timeout, - CONF.compute.build_interval): - raise exceptions.TimeoutException('Timeout while verifying ' - 'metadata on server.') - - # Verify metadata on config drive - if CONF.compute_feature_enabled.config_drive: - cmd_blkid = 'blkid -t LABEL=config-2 -o device' - LOG.info('Attempting to verify tagged devices in server %s via ' - 'the config drive.', server['id']) - dev_name = self.ssh_client.exec_command(cmd_blkid) - dev_name = dev_name.rstrip() - try: - self.ssh_client.exec_command('sudo mount %s /mnt' % dev_name) - except exceptions.SSHExecCommandFailed: - # So the command failed, let's try to know why and print some - # useful information. - lsblk = self.ssh_client.exec_command('sudo lsblk --fs --ascii') - LOG.error("Mounting %s on /mnt failed. Right after the " - "failure 'lsblk' in the guest reported:\n%s", - dev_name, lsblk) - raise - - cmd_md = 'sudo cat /mnt/openstack/latest/meta_data.json' - md_json = self.ssh_client.exec_command(cmd_md) - self.verify_device_metadata(md_json) - - -class DeviceTaggingTestV2_42(DeviceTaggingTest): - min_microversion = '2.42' - max_microversion = 'latest' diff --git a/tempest/api/compute/servers/test_disk_config.py b/tempest/api/compute/servers/test_disk_config.py deleted file mode 100644 index bc4806995..000000000 --- a/tempest/api/compute/servers/test_disk_config.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class ServerDiskConfigTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ServerDiskConfigTestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.disk_config: - msg = "DiskConfig extension not enabled." - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(ServerDiskConfigTestJSON, cls).setup_clients() - cls.client = cls.os_primary.servers_client - - def _update_server_with_disk_config(self, server_id, disk_config): - server = self.client.show_server(server_id)['server'] - if disk_config != server['OS-DCF:diskConfig']: - server = self.client.update_server( - server_id, disk_config=disk_config)['server'] - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - server = self.client.show_server(server['id'])['server'] - self.assertEqual(disk_config, server['OS-DCF:diskConfig']) - - @decorators.idempotent_id('bef56b09-2e8c-4883-a370-4950812f430e') - def test_rebuild_server_with_manual_disk_config(self): - # A server should be rebuilt using the manual disk config option - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.client.delete_server, server['id']) - self._update_server_with_disk_config(server['id'], - disk_config='AUTO') - - server = self.client.rebuild_server(server['id'], - self.image_ref_alt, - disk_config='MANUAL')['server'] - - # Wait for the server to become active - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - - # Verify the specified attributes are set correctly - server = self.client.show_server(server['id'])['server'] - self.assertEqual('MANUAL', server['OS-DCF:diskConfig']) - - @decorators.idempotent_id('9c9fae77-4feb-402f-8450-bf1c8b609713') - def test_rebuild_server_with_auto_disk_config(self): - # A server should be rebuilt using the auto disk config option - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.client.delete_server, server['id']) - self._update_server_with_disk_config(server['id'], - disk_config='MANUAL') - - server = self.client.rebuild_server(server['id'], - self.image_ref_alt, - disk_config='AUTO')['server'] - - # Wait for the server to become active - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - - # Verify the specified attributes are set correctly - server = self.client.show_server(server['id'])['server'] - self.assertEqual('AUTO', server['OS-DCF:diskConfig']) - - @decorators.idempotent_id('414e7e93-45b5-44bc-8e03-55159c6bfc97') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_from_manual_to_auto(self): - # A server should be resized from manual to auto disk config - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.client.delete_server, server['id']) - self._update_server_with_disk_config(server['id'], - disk_config='MANUAL') - # Resize with auto option - self.resize_server(server['id'], self.flavor_ref_alt, - disk_config='AUTO') - - server = self.client.show_server(server['id'])['server'] - self.assertEqual('AUTO', server['OS-DCF:diskConfig']) - - @decorators.idempotent_id('693d16f3-556c-489a-8bac-3d0ca2490bad') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_from_auto_to_manual(self): - # A server should be resized from auto to manual disk config - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.client.delete_server, server['id']) - self._update_server_with_disk_config(server['id'], - disk_config='AUTO') - # Resize with manual option - self.resize_server(server['id'], self.flavor_ref_alt, - disk_config='MANUAL') - - server = self.client.show_server(server['id'])['server'] - self.assertEqual('MANUAL', server['OS-DCF:diskConfig']) - - @decorators.idempotent_id('5ef18867-358d-4de9-b3c9-94d4ba35742f') - def test_update_server_from_auto_to_manual(self): - # A server should be updated from auto to manual disk config - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.client.delete_server, server['id']) - self._update_server_with_disk_config(server['id'], - disk_config='AUTO') - - # Update the disk_config attribute to manual - server = self.client.update_server(server['id'], - disk_config='MANUAL')['server'] - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - - # Verify the disk_config attribute is set correctly - server = self.client.show_server(server['id'])['server'] - self.assertEqual('MANUAL', server['OS-DCF:diskConfig']) diff --git a/tempest/api/compute/servers/test_instance_actions.py b/tempest/api/compute/servers/test_instance_actions.py deleted file mode 100644 index b916a42d6..000000000 --- a/tempest/api/compute/servers/test_instance_actions.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import waiters -from tempest.lib import decorators - - -class InstanceActionsTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(InstanceActionsTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(InstanceActionsTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - cls.request_id = cls.server.response['x-compute-request-id'] - - @decorators.idempotent_id('77ca5cc5-9990-45e0-ab98-1de8fead201a') - def test_list_instance_actions(self): - # List actions of the provided server - self.client.reboot_server(self.server['id'], type='HARD') - waiters.wait_for_server_status(self.client, - self.server['id'], 'ACTIVE') - - body = (self.client.list_instance_actions(self.server['id']) - ['instanceActions']) - self.assertEqual(len(body), 2, str(body)) - self.assertEqual(sorted([i['action'] for i in body]), - ['create', 'reboot']) - - @decorators.idempotent_id('aacc71ca-1d70-4aa5-bbf6-0ff71470e43c') - def test_get_instance_action(self): - # Get the action details of the provided server - body = self.client.show_instance_action( - self.server['id'], self.request_id)['instanceAction'] - self.assertEqual(self.server['id'], body['instance_uuid']) - self.assertEqual('create', body['action']) - - -class InstanceActionsV221TestJSON(base.BaseV2ComputeTest): - - min_microversion = '2.21' - max_microversion = 'latest' - - @classmethod - def setup_clients(cls): - super(InstanceActionsV221TestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @decorators.idempotent_id('0a0f85d4-10fa-41f6-bf80-a54fb4aa2ae1') - def test_get_list_deleted_instance_actions(self): - - # List actions of the deleted server - server = self.create_test_server(wait_until='ACTIVE') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - body = (self.client.list_instance_actions(server['id']) - ['instanceActions']) - self.assertEqual(len(body), 2, str(body)) - self.assertEqual(sorted([i['action'] for i in body]), - ['create', 'delete']) diff --git a/tempest/api/compute/servers/test_instance_actions_negative.py b/tempest/api/compute/servers/test_instance_actions_negative.py deleted file mode 100644 index 1d3a79086..000000000 --- a/tempest/api/compute/servers/test_instance_actions_negative.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class InstanceActionsNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(InstanceActionsNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(InstanceActionsNegativeTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('67e1fce6-7ec2-45c6-92d4-0a8f1a632910') - def test_list_instance_actions_non_existent_server(self): - # List actions of the non-existent server id - non_existent_server_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.list_instance_actions, - non_existent_server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0269f40a-6f18-456c-b336-c03623c897f1') - def test_get_instance_action_invalid_request(self): - # Get the action details of the provided server with invalid request - self.assertRaises(lib_exc.NotFound, self.client.show_instance_action, - self.server['id'], '999') diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py deleted file mode 100644 index a4ed8e11f..000000000 --- a/tempest/api/compute/servers/test_list_server_filters.py +++ /dev/null @@ -1,323 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common import fixed_network -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -CONF = config.CONF - - -class ListServerFiltersTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, dhcp=True) - super(ListServerFiltersTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ListServerFiltersTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ListServerFiltersTestJSON, cls).resource_setup() - - network = cls.get_tenant_network() - if network: - cls.fixed_network_name = network.get('name') - else: - cls.fixed_network_name = None - network_kwargs = fixed_network.set_networks_kwarg(network) - cls.s1_name = data_utils.rand_name(cls.__name__ + '-instance') - cls.s1 = cls.create_test_server(name=cls.s1_name, **network_kwargs) - - cls.s2_name = data_utils.rand_name(cls.__name__ + '-instance') - # If image_ref_alt is "" or None then we still want to boot a server - # but we rely on `testtools.skipUnless` decorator to actually skip - # the irrelevant tests. - cls.s2 = cls.create_test_server( - name=cls.s2_name, image_id=cls.image_ref_alt or cls.image_ref) - - cls.s3_name = data_utils.rand_name(cls.__name__ + '-instance') - cls.s3 = cls.create_test_server(name=cls.s3_name, - flavor=cls.flavor_ref_alt, - wait_until='ACTIVE') - - waiters.wait_for_server_status(cls.client, cls.s1['id'], - 'ACTIVE') - waiters.wait_for_server_status(cls.client, cls.s2['id'], - 'ACTIVE') - - @decorators.idempotent_id('05e8a8e7-9659-459a-989d-92c2f501f4ba') - @testtools.skipUnless(CONF.compute.image_ref != CONF.compute.image_ref_alt, - "Need distinct images to run this test") - def test_list_servers_filter_by_image(self): - # Filter the list of servers by image - params = {'image': self.image_ref} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('573637f5-7325-47bb-9144-3476d0416908') - def test_list_servers_filter_by_flavor(self): - # Filter the list of servers by flavor - params = {'flavor': self.flavor_ref_alt} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertNotIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('9b067a7b-7fee-4f6a-b29c-be43fe18fc5a') - def test_list_servers_filter_by_server_name(self): - # Filter the list of servers by server name - params = {'name': self.s1_name} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers)) - - @decorators.idempotent_id('ca78e20e-fddb-4ce6-b7f7-bcbf8605e66e') - def test_list_servers_filter_by_active_status(self): - # Filter the list of servers by server active status - params = {'status': 'active'} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('451dbbb2-f330-4a9f-b0e1-5f5d2cb0f34c') - def test_list_servers_filter_by_shutoff_status(self): - # Filter the list of servers by server shutoff status - params = {'status': 'shutoff'} - self.client.stop_server(self.s1['id']) - waiters.wait_for_server_status(self.client, self.s1['id'], - 'SHUTOFF') - body = self.client.list_servers(**params) - self.client.start_server(self.s1['id']) - waiters.wait_for_server_status(self.client, self.s1['id'], - 'ACTIVE') - servers = body['servers'] - - self.assertIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('614cdfc1-d557-4bac-915b-3e67b48eee76') - def test_list_servers_filter_by_limit(self): - # Verify only the expected number of servers are returned - params = {'limit': 1} - servers = self.client.list_servers(**params) - self.assertEqual(1, len([x for x in servers['servers'] if 'id' in x])) - - @decorators.idempotent_id('b1495414-2d93-414c-8019-849afe8d319e') - def test_list_servers_filter_by_zero_limit(self): - # Verify only the expected number of servers are returned - params = {'limit': 0} - servers = self.client.list_servers(**params) - self.assertEmpty(servers['servers']) - - @decorators.idempotent_id('37791bbd-90c0-4de0-831e-5f38cba9c6b3') - def test_list_servers_filter_by_exceed_limit(self): - # Verify only the expected number of servers are returned - params = {'limit': 100000} - servers = self.client.list_servers(**params) - all_servers = self.client.list_servers() - self.assertEqual(len([x for x in all_servers['servers'] if 'id' in x]), - len([x for x in servers['servers'] if 'id' in x])) - - @decorators.idempotent_id('b3304c3b-97df-46d2-8cd3-e2b6659724e7') - @testtools.skipUnless(CONF.compute.image_ref != CONF.compute.image_ref_alt, - "Need distinct images to run this test") - def test_list_servers_detailed_filter_by_image(self): - # Filter the detailed list of servers by image - params = {'image': self.image_ref} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - - self.assertIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('80c574cc-0925-44ba-8602-299028357dd9') - def test_list_servers_detailed_filter_by_flavor(self): - # Filter the detailed list of servers by flavor - params = {'flavor': self.flavor_ref_alt} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - - self.assertNotIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('f9eb2b70-735f-416c-b260-9914ac6181e4') - def test_list_servers_detailed_filter_by_server_name(self): - # Filter the detailed list of servers by server name - params = {'name': self.s1_name} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers)) - - @decorators.idempotent_id('de2612ab-b7dd-4044-b0b1-d2539601911f') - def test_list_servers_detailed_filter_by_server_status(self): - # Filter the detailed list of servers by server status - params = {'status': 'active'} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - test_ids = [s['id'] for s in (self.s1, self.s2, self.s3)] - - self.assertIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - self.assertEqual(['ACTIVE'] * 3, [x['status'] for x in servers - if x['id'] in test_ids]) - - @decorators.idempotent_id('e9f624ee-92af-4562-8bec-437945a18dcb') - def test_list_servers_filtered_by_name_wildcard(self): - # List all servers that contains '-instance' in name - params = {'name': '-instance'} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertIn(self.s3_name, map(lambda x: x['name'], servers)) - - # Let's take random part of name and try to search it - part_name = self.s1_name[6:-1] - - params = {'name': part_name} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers)) - - @decorators.idempotent_id('24a89b0c-0d55-4a28-847f-45075f19b27b') - def test_list_servers_filtered_by_name_regex(self): - # list of regex that should match s1, s2 and s3 - regexes = ['^.*\-instance\-[0-9]+$', '^.*\-instance\-.*$'] - for regex in regexes: - params = {'name': regex} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertIn(self.s3_name, map(lambda x: x['name'], servers)) - - # Let's take random part of name and try to search it - part_name = self.s1_name[-10:] - - params = {'name': part_name} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers)) - - @decorators.idempotent_id('43a1242e-7b31-48d1-88f2-3f72aa9f2077') - def test_list_servers_filtered_by_ip(self): - # Filter servers by ip - # Here should be listed 1 server - if not self.fixed_network_name: - msg = 'fixed_network_name needs to be configured to run this test' - raise self.skipException(msg) - - # list servers filter by ip is something "regexp match", i.e, - # filter by "10.1.1.1" will return both "10.1.1.1" and "10.1.1.10". - # so here look for the longest server ip, and filter by that ip, - # so as to ensure only one server is returned. - ip_list = {} - self.s1 = self.client.show_server(self.s1['id'])['server'] - # Get first ip address inspite of v4 or v6 - ip_addr = self.s1['addresses'][self.fixed_network_name][0]['addr'] - ip_list[ip_addr] = self.s1['id'] - - self.s2 = self.client.show_server(self.s2['id'])['server'] - ip_addr = self.s2['addresses'][self.fixed_network_name][0]['addr'] - ip_list[ip_addr] = self.s2['id'] - - self.s3 = self.client.show_server(self.s3['id'])['server'] - ip_addr = self.s3['addresses'][self.fixed_network_name][0]['addr'] - ip_list[ip_addr] = self.s3['id'] - - longest_ip = max([[len(ip), ip] for ip in ip_list])[1] - params = {'ip': longest_ip} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(ip_list[longest_ip], map(lambda x: x['id'], servers)) - del ip_list[longest_ip] - for ip in ip_list: - self.assertNotIn(ip_list[ip], map(lambda x: x['id'], servers)) - - @decorators.skip_because(bug="1540645") - @decorators.idempotent_id('a905e287-c35e-42f2-b132-d02b09f3654a') - def test_list_servers_filtered_by_ip_regex(self): - # Filter servers by regex ip - # List all servers filtered by part of ip address. - # Here should be listed all servers - if not self.fixed_network_name: - msg = 'fixed_network_name needs to be configured to run this test' - raise self.skipException(msg) - self.s1 = self.client.show_server(self.s1['id'])['server'] - addr_spec = self.s1['addresses'][self.fixed_network_name][0] - ip = addr_spec['addr'][0:-3] - if addr_spec['version'] == 4: - params = {'ip': ip} - else: - params = {'ip6': ip} - # capture all servers in case something goes wrong - all_servers = self.client.list_servers(detail=True) - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers), - "%s not found in %s, all servers %s" % - (self.s1_name, servers, all_servers)) - self.assertIn(self.s2_name, map(lambda x: x['name'], servers), - "%s not found in %s, all servers %s" % - (self.s2_name, servers, all_servers)) - self.assertIn(self.s3_name, map(lambda x: x['name'], servers), - "%s not found in %s, all servers %s" % - (self.s3_name, servers, all_servers)) - - @decorators.idempotent_id('67aec2d0-35fe-4503-9f92-f13272b867ed') - def test_list_servers_detailed_limit_results(self): - # Verify only the expected number of detailed results are returned - params = {'limit': 1} - servers = self.client.list_servers(detail=True, **params) - self.assertEqual(1, len(servers['servers'])) diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py deleted file mode 100644 index 6c9b28772..000000000 --- a/tempest/api/compute/servers/test_list_servers_negative.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import waiters -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ListServersNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ListServersNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ListServersNegativeTestJSON, cls).resource_setup() - - # The following servers are created for use - # by the test methods in this class. These - # servers are cleaned up automatically in the - # tearDownClass method of the super-class. - body = cls.create_test_server(wait_until='ACTIVE', min_count=3) - - # delete one of the created servers - cls.deleted_id = body['server']['id'] - cls.client.delete_server(cls.deleted_id) - waiters.wait_for_server_termination(cls.client, cls.deleted_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('24a26f1a-1ddc-4eea-b0d7-a90cc874ad8f') - def test_list_servers_with_a_deleted_server(self): - # Verify deleted servers do not show by default in list servers - # List servers and verify server not returned - body = self.client.list_servers() - servers = body['servers'] - actual = [srv for srv in servers - if srv['id'] == self.deleted_id] - self.assertEmpty(actual) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ff01387d-c7ad-47b4-ae9e-64fa214638fe') - def test_list_servers_by_non_existing_image(self): - # Listing servers for a non existing image returns empty list - body = self.client.list_servers(image='non_existing_image') - servers = body['servers'] - self.assertEmpty(servers) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5913660b-223b-44d4-a651-a0fbfd44ca75') - def test_list_servers_by_non_existing_flavor(self): - # Listing servers by non existing flavor returns empty list - body = self.client.list_servers(flavor='non_existing_flavor') - servers = body['servers'] - self.assertEmpty(servers) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e2c77c4a-000a-4af3-a0bd-629a328bde7c') - def test_list_servers_by_non_existing_server_name(self): - # Listing servers for a non existent server name returns empty list - body = self.client.list_servers(name='non_existing_server_name') - servers = body['servers'] - self.assertEmpty(servers) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fcdf192d-0f74-4d89-911f-1ec002b822c4') - def test_list_servers_status_non_existing(self): - # Return an empty list when invalid status is specified - body = self.client.list_servers(status='non_existing_status') - servers = body['servers'] - self.assertEmpty(servers) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d47c17fb-eebd-4287-8e95-f20a7e627b18') - def test_list_servers_by_limits_greater_than_actual_count(self): - # Gather the complete list of servers in the project for reference - full_list = self.client.list_servers()['servers'] - # List servers by specifying a greater value for limit - limit = len(full_list) + 100 - body = self.client.list_servers(limit=limit) - self.assertEqual(len(full_list), len(body['servers'])) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('679bc053-5e70-4514-9800-3dfab1a380a6') - def test_list_servers_by_limits_pass_string(self): - # Return an error if a string value is passed for limit - self.assertRaises(lib_exc.BadRequest, self.client.list_servers, - limit='testing') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('62610dd9-4713-4ee0-8beb-fd2c1aa7f950') - def test_list_servers_by_limits_pass_negative_value(self): - # Return an error if a negative value for limit is passed - self.assertRaises(lib_exc.BadRequest, self.client.list_servers, - limit=-1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('87d12517-e20a-4c9c-97b6-dd1628d6d6c9') - def test_list_servers_by_changes_since_invalid_date(self): - # Return an error when invalid date format is passed - params = {'changes-since': '2011/01/01'} - self.assertRaises(lib_exc.BadRequest, self.client.list_servers, - **params) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('74745ad8-b346-45b5-b9b8-509d7447fc1f') - def test_list_servers_by_changes_since_future_date(self): - # Return an empty list when a date in the future is passed - changes_since = {'changes-since': '2051-01-01T12:34:00Z'} - body = self.client.list_servers(**changes_since) - self.assertEmpty(body['servers']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('93055106-2d34-46fe-af68-d9ddbf7ee570') - def test_list_servers_detail_server_is_deleted(self): - # Server details are not listed for a deleted server - body = self.client.list_servers(detail=True) - servers = body['servers'] - actual = [srv for srv in servers - if srv['id'] == self.deleted_id] - self.assertEmpty(actual) diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py deleted file mode 100644 index 059454dd0..000000000 --- a/tempest/api/compute/servers/test_multiple_create.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2013 IBM Corp -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import compute -from tempest.lib import decorators - - -class MultipleCreateTestJSON(base.BaseV2ComputeTest): - - @decorators.idempotent_id('61e03386-89c3-449c-9bb1-a06f423fd9d1') - def test_multiple_create(self): - tenant_network = self.get_tenant_network() - body, servers = compute.create_test_server( - self.os_primary, - wait_until='ACTIVE', - min_count=2, - tenant_network=tenant_network) - for server in servers: - self.addCleanup(self.servers_client.delete_server, server['id']) - # NOTE(maurosr): do status response check and also make sure that - # reservation_id is not in the response body when the request send - # contains return_reservation_id=False - self.assertNotIn('reservation_id', body) - self.assertEqual(2, len(servers)) - - @decorators.idempotent_id('864777fb-2f1e-44e3-b5b9-3eb6fa84f2f7') - def test_multiple_create_with_reservation_return(self): - body = self.create_test_server(wait_until='ACTIVE', - min_count=1, - max_count=2, - return_reservation_id=True) - self.assertIn('reservation_id', body) diff --git a/tempest/api/compute/servers/test_multiple_create_negative.py b/tempest/api/compute/servers/test_multiple_create_negative.py deleted file mode 100644 index 422510f75..000000000 --- a/tempest/api/compute/servers/test_multiple_create_negative.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2013 IBM Corp -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class MultipleCreateNegativeTestJSON(base.BaseV2ComputeTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('daf29d8d-e928-4a01-9a8c-b129603f3fc0') - def test_min_count_less_than_one(self): - invalid_min_count = 0 - self.assertRaises(lib_exc.BadRequest, self.create_test_server, - min_count=invalid_min_count) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('999aa722-d624-4423-b813-0d1ac9884d7a') - def test_min_count_non_integer(self): - invalid_min_count = 2.5 - self.assertRaises(lib_exc.BadRequest, self.create_test_server, - min_count=invalid_min_count) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a6f9c2ab-e060-4b82-b23c-4532cb9390ff') - def test_max_count_less_than_one(self): - invalid_max_count = 0 - self.assertRaises(lib_exc.BadRequest, self.create_test_server, - max_count=invalid_max_count) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9c5698d1-d7af-4c80-b971-9d403135eea2') - def test_max_count_non_integer(self): - invalid_max_count = 2.5 - self.assertRaises(lib_exc.BadRequest, self.create_test_server, - max_count=invalid_max_count) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('476da616-f1ef-4271-a9b1-b9fc87727cdf') - def test_max_count_less_than_min_count(self): - min_count = 3 - max_count = 2 - self.assertRaises(lib_exc.BadRequest, self.create_test_server, - min_count=min_count, - max_count=max_count) diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py deleted file mode 100644 index 90b0665ca..000000000 --- a/tempest/api/compute/servers/test_novnc.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright 2016-2017 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import struct - -import six -import urllib3 - -from tempest.api.compute import base -from tempest.common import compute -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - -if six.PY2: - ord_func = ord -else: - ord_func = int - - -class NoVNCConsoleTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(NoVNCConsoleTestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.vnc_console: - raise cls.skipException('VNC Console feature is disabled.') - - def setUp(self): - super(NoVNCConsoleTestJSON, self).setUp() - self._websocket = None - - def tearDown(self): - self.server_check_teardown() - super(NoVNCConsoleTestJSON, self).tearDown() - if self._websocket is not None: - self._websocket.close() - - @classmethod - def setup_clients(cls): - super(NoVNCConsoleTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(NoVNCConsoleTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until="ACTIVE") - - def _validate_novnc_html(self, vnc_url): - """Verify we can connect to novnc and get back the javascript.""" - resp = urllib3.PoolManager().request('GET', vnc_url) - # Make sure that the GET request was accepted by the novncproxy - self.assertEqual(resp.status, 200, 'Got a Bad HTTP Response on the ' - 'initial call: ' + six.text_type(resp.status)) - # Do some basic validation to make sure it is an expected HTML document - resp_data = resp.data.decode() - self.assertIn('', resp_data, - 'Not a valid html document in the response.') - self.assertIn('', resp_data, - 'Not a valid html document in the response.') - # Just try to make sure we got JavaScript back for noVNC, since we - # won't actually use it since not inside of a browser - self.assertIn('noVNC', resp_data, - 'Not a valid noVNC javascript html document.') - self.assertIn('L", - data[20:24])[0] + 24), - 'Server initialization was not the right format.') - # Since the rest of the data on the screen is arbitrary, we will - # close the socket and end our validation of the data at this point - # Assert that the latest check was false, meaning that the server - # initialization was the right format - self.assertFalse(data_length <= 24 or - data_length != (struct.unpack(">L", - data[20:24])[0] + 24)) - - def _validate_websocket_upgrade(self): - self.assertTrue( - self._websocket.response.startswith(b'HTTP/1.1 101 Switching ' - b'Protocols\r\n'), - 'Did not get the expected 101 on the websockify call: ' - + six.text_type(self._websocket.response)) - self.assertTrue( - self._websocket.response.find(b'Server: WebSockify') > 0, - 'Did not get the expected WebSocket HTTP Response.') - - @decorators.idempotent_id('c640fdff-8ab4-45a4-a5d8-7e6146cbd0dc') - def test_novnc(self): - body = self.client.get_vnc_console(self.server['id'], - type='novnc')['console'] - self.assertEqual('novnc', body['type']) - # Do the initial HTTP Request to novncproxy to get the NoVNC JavaScript - self._validate_novnc_html(body['url']) - # Do the WebSockify HTTP Request to novncproxy to do the RFB connection - self._websocket = compute.create_websocket(body['url']) - # Validate that we succesfully connected and upgraded to Web Sockets - self._validate_websocket_upgrade() - # Validate the RFB Negotiation to determine if a valid VNC session - self._validate_rfb_negotiation() - - @decorators.idempotent_id('f9c79937-addc-4aaa-9e0e-841eef02aeb7') - def test_novnc_bad_token(self): - body = self.client.get_vnc_console(self.server['id'], - type='novnc')['console'] - self.assertEqual('novnc', body['type']) - # Do the WebSockify HTTP Request to novncproxy with a bad token - url = body['url'].replace('token=', 'token=bad') - self._websocket = compute.create_websocket(url) - # Make sure the novncproxy rejected the connection and closed it - data = self._websocket.receive_frame() - self.assertTrue(data is None or not data, - "The novnc proxy actually sent us some data, but we " - "expected it to close the connection.") diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py deleted file mode 100644 index cd09177b0..000000000 --- a/tempest/api/compute/servers/test_server_actions.py +++ /dev/null @@ -1,589 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging -from six.moves.urllib import parse as urlparse -import testtools - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common.utils.linux import remote_client -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class ServerActionsTestJSON(base.BaseV2ComputeTest): - run_ssh = CONF.validation.run_validation - - def setUp(self): - # NOTE(afazekas): Normally we use the same server with all test cases, - # but if it has an issue, we build a new one - super(ServerActionsTestJSON, self).setUp() - # Check if the server is in a clean state after test - try: - waiters.wait_for_server_status(self.client, - self.server_id, 'ACTIVE') - except lib_exc.NotFound: - # The server was deleted by previous test, create a new one - server = self.create_test_server( - validatable=True, - wait_until='ACTIVE') - self.__class__.server_id = server['id'] - except Exception: - # Rebuild server if something happened to it during a test - self.__class__.server_id = self.rebuild_server( - self.server_id, validatable=True) - - def tearDown(self): - self.server_check_teardown() - super(ServerActionsTestJSON, self).tearDown() - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(ServerActionsTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServerActionsTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - - super(ServerActionsTestJSON, cls).resource_setup() - cls.server_id = cls.rebuild_server(None, validatable=True) - - @decorators.idempotent_id('6158df09-4b82-4ab3-af6d-29cf36af858d') - @testtools.skipUnless(CONF.compute_feature_enabled.change_password, - 'Change password not available.') - def test_change_server_password(self): - # Since this test messes with the password and makes the - # server unreachable, it should create its own server - newserver = self.create_test_server( - validatable=True, - wait_until='ACTIVE') - # The server's password should be set to the provided password - new_password = 'Newpass1234' - self.client.change_password(newserver['id'], adminPass=new_password) - waiters.wait_for_server_status(self.client, newserver['id'], 'ACTIVE') - - if CONF.validation.run_validation: - # Verify that the user can authenticate with the new password - server = self.client.show_server(newserver['id'])['server'] - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.ssh_user, - new_password, - server=server, - servers_client=self.client) - linux_client.validate_authentication() - - def _test_reboot_server(self, reboot_type): - if CONF.validation.run_validation: - # Get the time the server was last rebooted, - server = self.client.show_server(self.server_id)['server'] - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.ssh_user, - self.password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.client) - boot_time = linux_client.get_boot_time() - - # NOTE: This sync is for avoiding the loss of pub key data - # in a server - linux_client.exec_command("sync") - - self.client.reboot_server(self.server_id, type=reboot_type) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - if CONF.validation.run_validation: - # Log in and verify the boot time has changed - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.ssh_user, - self.password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.client) - new_boot_time = linux_client.get_boot_time() - self.assertGreater(new_boot_time, boot_time, - '%s > %s' % (new_boot_time, boot_time)) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2cb1baf6-ac8d-4429-bf0d-ba8a0ba53e32') - def test_reboot_server_hard(self): - # The server should be power cycled - self._test_reboot_server('HARD') - - @decorators.skip_because(bug="1014647") - @decorators.idempotent_id('4640e3ef-a5df-482e-95a1-ceeeb0faa84d') - def test_reboot_server_soft(self): - # The server should be signaled to reboot gracefully - self._test_reboot_server('SOFT') - - @decorators.idempotent_id('1d1c9104-1b0a-11e7-a3d4-fa163e65f5ce') - def test_remove_server_all_security_groups(self): - server = self.create_test_server(wait_until='ACTIVE') - - # Remove all Security group - self.client.remove_security_group( - server['id'], name=server['security_groups'][0]['name']) - - # Verify all Security group - server = self.client.show_server(server['id'])['server'] - self.assertNotIn('security_groups', server) - - def _rebuild_server_and_check(self, image_ref): - rebuilt_server = (self.client.rebuild_server(self.server_id, image_ref) - ['server']) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - msg = ('Server was not rebuilt to the original image. ' - 'The original image: {0}. The current image: {1}' - .format(image_ref, rebuilt_server['image']['id'])) - self.assertEqual(image_ref, rebuilt_server['image']['id'], msg) - - @decorators.idempotent_id('aaa6cdf3-55a7-461a-add9-1c8596b9a07c') - def test_rebuild_server(self): - # Get the IPs the server has before rebuilding it - original_addresses = (self.client.show_server(self.server_id)['server'] - ['addresses']) - # The server should be rebuilt using the provided image and data - meta = {'rebuild': 'server'} - new_name = data_utils.rand_name(self.__class__.__name__ + '-server') - password = 'rebuildPassw0rd' - rebuilt_server = self.client.rebuild_server( - self.server_id, - self.image_ref_alt, - name=new_name, - metadata=meta, - adminPass=password)['server'] - - # If the server was rebuilt on a different image, restore it to the - # original image once the test ends - if self.image_ref_alt != self.image_ref: - self.addCleanup(self._rebuild_server_and_check, self.image_ref) - - # Verify the properties in the initial response are correct - self.assertEqual(self.server_id, rebuilt_server['id']) - rebuilt_image_id = rebuilt_server['image']['id'] - self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id)) - self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id']) - - # Verify the server properties after the rebuild completes - waiters.wait_for_server_status(self.client, - rebuilt_server['id'], 'ACTIVE') - server = self.client.show_server(rebuilt_server['id'])['server'] - rebuilt_image_id = server['image']['id'] - self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id)) - self.assertEqual(new_name, server['name']) - self.assertEqual(original_addresses, server['addresses']) - - if CONF.validation.run_validation: - # Authentication is attempted in the following order of priority: - # 1.The key passed in, if one was passed in. - # 2.Any key we can find through an SSH agent (if allowed). - # 3.Any "id_rsa", "id_dsa" or "id_ecdsa" key discoverable in - # ~/.ssh/ (if allowed). - # 4.Plain username/password auth, if a password was given. - linux_client = remote_client.RemoteClient( - self.get_server_ip(rebuilt_server), - self.ssh_user, - password, - self.validation_resources['keypair']['private_key'], - server=rebuilt_server, - servers_client=self.client) - linux_client.validate_authentication() - - @decorators.idempotent_id('30449a88-5aff-4f9b-9866-6ee9b17f906d') - def test_rebuild_server_in_stop_state(self): - # The server in stop state should be rebuilt using the provided - # image and remain in SHUTOFF state - server = self.client.show_server(self.server_id)['server'] - old_image = server['image']['id'] - new_image = (self.image_ref_alt - if old_image == self.image_ref else self.image_ref) - self.client.stop_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'SHUTOFF') - rebuilt_server = (self.client.rebuild_server(self.server_id, new_image) - ['server']) - # If the server was rebuilt on a different image, restore it to the - # original image once the test ends - if self.image_ref_alt != self.image_ref: - self.addCleanup(self._rebuild_server_and_check, old_image) - - # Verify the properties in the initial response are correct - self.assertEqual(self.server_id, rebuilt_server['id']) - rebuilt_image_id = rebuilt_server['image']['id'] - self.assertEqual(new_image, rebuilt_image_id) - self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id']) - - # Verify the server properties after the rebuild completes - waiters.wait_for_server_status(self.client, - rebuilt_server['id'], 'SHUTOFF') - server = self.client.show_server(rebuilt_server['id'])['server'] - rebuilt_image_id = server['image']['id'] - self.assertEqual(new_image, rebuilt_image_id) - - self.client.start_server(self.server_id) - - @decorators.idempotent_id('b68bd8d6-855d-4212-b59b-2e704044dace') - @test.services('volume') - def test_rebuild_server_with_volume_attached(self): - # create a new volume and attach it to the server - volume = self.create_volume() - - server = self.client.show_server(self.server_id)['server'] - self.attach_volume(server, volume) - - # run general rebuild test - self.test_rebuild_server() - - # make sure the volume is attached to the instance after rebuild - vol_after_rebuild = self.volumes_client.show_volume(volume['id']) - vol_after_rebuild = vol_after_rebuild['volume'] - self.assertEqual('in-use', vol_after_rebuild['status']) - self.assertEqual(self.server_id, - vol_after_rebuild['attachments'][0]['server_id']) - - def _test_resize_server_confirm(self, stop=False): - # The server's RAM and disk space should be modified to that of - # the provided flavor - - if stop: - self.client.stop_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, - 'SHUTOFF') - - self.client.resize_server(self.server_id, self.flavor_ref_alt) - # NOTE(jlk): Explicitly delete the server to get a new one for later - # tests. Avoids resize down race issues. - self.addCleanup(self.delete_server, self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, - 'VERIFY_RESIZE') - - self.client.confirm_resize_server(self.server_id) - expected_status = 'SHUTOFF' if stop else 'ACTIVE' - waiters.wait_for_server_status(self.client, self.server_id, - expected_status) - - server = self.client.show_server(self.server_id)['server'] - self.assertEqual(self.flavor_ref_alt, server['flavor']['id']) - - if stop: - # NOTE(mriedem): tearDown requires the server to be started. - self.client.start_server(self.server_id) - - @decorators.idempotent_id('1499262a-9328-4eda-9068-db1ac57498d2') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_confirm(self): - self._test_resize_server_confirm(stop=False) - - @decorators.idempotent_id('138b131d-66df-48c9-a171-64f45eb92962') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_confirm_from_stopped(self): - self._test_resize_server_confirm(stop=True) - - @decorators.idempotent_id('c03aab19-adb1-44f5-917d-c419577e9e68') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_revert(self): - # The server's RAM and disk space should return to its original - # values after a resize is reverted - - self.client.resize_server(self.server_id, self.flavor_ref_alt) - # NOTE(zhufl): Explicitly delete the server to get a new one for later - # tests. Avoids resize down race issues. - self.addCleanup(self.delete_server, self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, - 'VERIFY_RESIZE') - - self.client.revert_resize_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - server = self.client.show_server(self.server_id)['server'] - self.assertEqual(self.flavor_ref, server['flavor']['id']) - - @decorators.idempotent_id('b963d4f1-94b3-4c40-9e97-7b583f46e470') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting not available, backup not possible.') - @test.services('image') - def test_create_backup(self): - # Positive test:create backup successfully and rotate backups correctly - # create the first and the second backup - - # Check if glance v1 is available to determine which client to use. We - # prefer glance v1 for the compute API tests since the compute image - # API proxy was written for glance v1. - if CONF.image_feature_enabled.api_v1: - glance_client = self.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - glance_client = self.os_primary.image_client_v2 - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - - backup1 = data_utils.rand_name('backup-1') - resp = self.client.create_backup(self.server_id, - backup_type='daily', - rotation=2, - name=backup1).response - oldest_backup_exist = True - - # the oldest one should be deleted automatically in this test - def _clean_oldest_backup(oldest_backup): - if oldest_backup_exist: - try: - glance_client.delete_image(oldest_backup) - except lib_exc.NotFound: - pass - else: - LOG.warning("Deletion of oldest backup %s should not have " - "been successful as it should have been " - "deleted during rotation.", oldest_backup) - - image1_id = data_utils.parse_image_id(resp['location']) - self.addCleanup(_clean_oldest_backup, image1_id) - waiters.wait_for_image_status(glance_client, - image1_id, 'active') - - backup2 = data_utils.rand_name('backup-2') - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - resp = self.client.create_backup(self.server_id, - backup_type='daily', - rotation=2, - name=backup2).response - image2_id = data_utils.parse_image_id(resp['location']) - self.addCleanup(glance_client.delete_image, image2_id) - waiters.wait_for_image_status(glance_client, - image2_id, 'active') - - # verify they have been created - properties = { - 'image_type': 'backup', - 'backup_type': "daily", - 'instance_uuid': self.server_id, - } - params = { - 'status': 'active', - 'sort_key': 'created_at', - 'sort_dir': 'asc' - } - if CONF.image_feature_enabled.api_v1: - for key, value in properties.items(): - params['property-%s' % key] = value - image_list = glance_client.list_images( - detail=True, - **params)['images'] - else: - # Additional properties are flattened in glance v2. - params.update(properties) - image_list = glance_client.list_images(params)['images'] - - self.assertEqual(2, len(image_list)) - self.assertEqual((backup1, backup2), - (image_list[0]['name'], image_list[1]['name'])) - - # create the third one, due to the rotation is 2, - # the first one will be deleted - backup3 = data_utils.rand_name('backup-3') - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - resp = self.client.create_backup(self.server_id, - backup_type='daily', - rotation=2, - name=backup3).response - image3_id = data_utils.parse_image_id(resp['location']) - self.addCleanup(glance_client.delete_image, image3_id) - # the first back up should be deleted - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - glance_client.wait_for_resource_deletion(image1_id) - oldest_backup_exist = False - if CONF.image_feature_enabled.api_v1: - image_list = glance_client.list_images( - detail=True, **params)['images'] - else: - image_list = glance_client.list_images(params)['images'] - self.assertEqual(2, len(image_list), - 'Unexpected number of images for ' - 'v2:test_create_backup; was the oldest backup not ' - 'yet deleted? Image list: %s' % - [image['name'] for image in image_list]) - self.assertEqual((backup2, backup3), - (image_list[0]['name'], image_list[1]['name'])) - - def _get_output(self): - output = self.client.get_console_output( - self.server_id, length=10)['output'] - self.assertTrue(output, "Console output was empty.") - lines = len(output.split('\n')) - self.assertEqual(lines, 10) - - @decorators.idempotent_id('4b8867e6-fffa-4d54-b1d1-6fdda57be2f3') - @testtools.skipUnless(CONF.compute_feature_enabled.console_output, - 'Console output not supported.') - def test_get_console_output(self): - # Positive test:Should be able to GET the console output - # for a given server_id and number of lines - - # This reboot is necessary for outputting some console log after - # creating an instance backup. If an instance backup, the console - # log file is truncated and we cannot get any console log through - # "console-log" API. - # The detail is https://bugs.launchpad.net/nova/+bug/1251920 - self.client.reboot_server(self.server_id, type='HARD') - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - self.wait_for(self._get_output) - - @decorators.idempotent_id('89104062-69d8-4b19-a71b-f47b7af093d7') - @testtools.skipUnless(CONF.compute_feature_enabled.console_output, - 'Console output not supported.') - def test_get_console_output_with_unlimited_size(self): - server = self.create_test_server(wait_until='ACTIVE') - - def _check_full_length_console_log(): - output = self.client.get_console_output(server['id'])['output'] - self.assertTrue(output, "Console output was empty.") - lines = len(output.split('\n')) - - # NOTE: This test tries to get full length console log, and the - # length should be bigger than the one of test_get_console_output. - self.assertGreater(lines, 10, "Cannot get enough console log " - "length. (lines: %s)" % lines) - - self.wait_for(_check_full_length_console_log) - - @decorators.idempotent_id('5b65d4e7-4ecd-437c-83c0-d6b79d927568') - @testtools.skipUnless(CONF.compute_feature_enabled.console_output, - 'Console output not supported.') - def test_get_console_output_server_id_in_shutoff_status(self): - # Positive test:Should be able to GET the console output - # for a given server_id in SHUTOFF status - - # NOTE: SHUTOFF is irregular status. To avoid test instability, - # one server is created only for this test without using - # the server that was created in setUpClass. - server = self.create_test_server(wait_until='ACTIVE') - temp_server_id = server['id'] - - self.client.stop_server(temp_server_id) - waiters.wait_for_server_status(self.client, temp_server_id, 'SHUTOFF') - self.wait_for(self._get_output) - - @decorators.idempotent_id('bd61a9fd-062f-4670-972b-2d6c3e3b9e73') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - def test_pause_unpause_server(self): - self.client.pause_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'PAUSED') - self.client.unpause_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - @decorators.idempotent_id('0d8ee21e-b749-462d-83da-b85b41c86c7f') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - def test_suspend_resume_server(self): - self.client.suspend_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, - 'SUSPENDED') - self.client.resume_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - @decorators.idempotent_id('77eba8e0-036e-4635-944b-f7a8f3b78dc9') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - @test.services('image') - def test_shelve_unshelve_server(self): - if CONF.image_feature_enabled.api_v2: - glance_client = self.os_primary.image_client_v2 - elif CONF.image_feature_enabled.api_v1: - glance_client = self.os_primary.image_client - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - compute.shelve_server(self.client, self.server_id, - force_shelve_offload=True) - - server = self.client.show_server(self.server_id)['server'] - image_name = server['name'] + '-shelved' - params = {'name': image_name} - if CONF.image_feature_enabled.api_v2: - images = glance_client.list_images(params)['images'] - elif CONF.image_feature_enabled.api_v1: - images = glance_client.list_images( - detail=True, **params)['images'] - self.assertEqual(1, len(images)) - self.assertEqual(image_name, images[0]['name']) - - self.client.unshelve_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - glance_client.wait_for_resource_deletion(images[0]['id']) - - @decorators.idempotent_id('af8eafd4-38a7-4a4b-bdbc-75145a580560') - def test_stop_start_server(self): - self.client.stop_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'SHUTOFF') - self.client.start_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - @decorators.idempotent_id('80a8094c-211e-440a-ab88-9e59d556c7ee') - def test_lock_unlock_server(self): - # Lock the server,try server stop(exceptions throw),unlock it and retry - self.client.lock_server(self.server_id) - self.addCleanup(self.client.unlock_server, self.server_id) - server = self.client.show_server(self.server_id)['server'] - self.assertEqual(server['status'], 'ACTIVE') - # Locked server is not allowed to be stopped by non-admin user - self.assertRaises(lib_exc.Conflict, - self.client.stop_server, self.server_id) - self.client.unlock_server(self.server_id) - self.client.stop_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'SHUTOFF') - self.client.start_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - def _validate_url(self, url): - valid_scheme = ['http', 'https'] - parsed_url = urlparse.urlparse(url) - self.assertNotEqual('None', parsed_url.port) - self.assertNotEqual('None', parsed_url.hostname) - self.assertIn(parsed_url.scheme, valid_scheme) - - @decorators.idempotent_id('c6bc11bf-592e-4015-9319-1c98dc64daf5') - @testtools.skipUnless(CONF.compute_feature_enabled.vnc_console, - 'VNC Console feature is disabled.') - def test_get_vnc_console(self): - # Get the VNC console of type 'novnc' and 'xvpvnc' - console_types = ['novnc', 'xvpvnc'] - for console_type in console_types: - body = self.client.get_vnc_console(self.server_id, - type=console_type)['console'] - self.assertEqual(console_type, body['type']) - self.assertNotEqual('', body['url']) - self._validate_url(body['url']) diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py deleted file mode 100644 index 022ceba77..000000000 --- a/tempest/api/compute/servers/test_server_addresses.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest import test - - -class ServerAddressesTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - # This test module might use a network and a subnet - cls.set_network_resources(network=True, subnet=True) - super(ServerAddressesTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServerAddressesTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerAddressesTestJSON, cls).resource_setup() - - cls.server = cls.create_test_server(wait_until='ACTIVE') - - @decorators.attr(type='smoke') - @decorators.idempotent_id('6eb718c0-02d9-4d5e-acd1-4e0c269cef39') - @test.services('network') - def test_list_server_addresses(self): - # All public and private addresses for - # a server should be returned - - addresses = self.client.list_addresses(self.server['id'])['addresses'] - - # We do not know the exact network configuration, but an instance - # should at least have a single public or private address - self.assertNotEmpty(addresses) - for network_addresses in addresses.values(): - self.assertNotEmpty(network_addresses) - for address in network_addresses: - self.assertTrue(address['addr']) - self.assertTrue(address['version']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('87bbc374-5538-4f64-b673-2b0e4443cc30') - @test.services('network') - def test_list_server_addresses_by_network(self): - # Providing a network type should filter - # the addresses return by that type - - addresses = self.client.list_addresses(self.server['id'])['addresses'] - - # Once again we don't know the environment's exact network config, - # but the response for each individual network should be the same - # as the partial result of the full address list - id = self.server['id'] - for addr_type in addresses: - addr = self.client.list_addresses_by_network(id, addr_type) - - addr = addr[addr_type] - for address in addresses[addr_type]: - self.assertTrue(any([a for a in addr if a == address])) diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py deleted file mode 100644 index 76a102bb6..000000000 --- a/tempest/api/compute/servers/test_server_addresses_negative.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class ServerAddressesNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True) - super(ServerAddressesNegativeTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServerAddressesNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerAddressesNegativeTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('02c3f645-2d2e-4417-8525-68c0407d001b') - @test.services('network') - def test_list_server_addresses_invalid_server_id(self): - # List addresses request should fail if server id not in system - self.assertRaises(lib_exc.NotFound, self.client.list_addresses, - '999') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a2ab5144-78c0-4942-a0ed-cc8edccfd9ba') - @test.services('network') - def test_list_server_addresses_by_network_neg(self): - # List addresses by network should fail if network name not valid - self.assertRaises(lib_exc.NotFound, - self.client.list_addresses_by_network, - self.server['id'], 'invalid') diff --git a/tempest/api/compute/servers/test_server_group.py b/tempest/api/compute/servers/test_server_group.py deleted file mode 100644 index 69d7897c2..000000000 --- a/tempest/api/compute/servers/test_server_group.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2014 NEC Technologies India Ltd. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class ServerGroupTestJSON(base.BaseV2ComputeTest): - """These tests check for the server-group APIs. - - They create/delete server-groups with different policies. - policies = affinity/anti-affinity - It also adds the tests for list and get details of server-groups - """ - - @classmethod - def skip_checks(cls): - super(ServerGroupTestJSON, cls).skip_checks() - if not test.is_extension_enabled('os-server-groups', 'compute'): - msg = "os-server-groups extension is not enabled." - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(ServerGroupTestJSON, cls).setup_clients() - cls.client = cls.server_groups_client - - @classmethod - def resource_setup(cls): - super(ServerGroupTestJSON, cls).resource_setup() - cls.policy = ['affinity'] - - cls.created_server_group = cls.create_test_server_group( - policy=cls.policy) - - def _create_server_group(self, name, policy): - # create the test server-group with given policy - server_group = {'name': name, 'policies': policy} - body = self.create_test_server_group(name, policy) - for key in ['name', 'policies']: - self.assertEqual(server_group[key], body[key]) - return body - - def _delete_server_group(self, server_group): - # delete the test server-group - self.client.delete_server_group(server_group['id']) - # validation of server-group deletion - server_group_list = self.client.list_server_groups()['server_groups'] - self.assertNotIn(server_group, server_group_list) - - def _create_delete_server_group(self, policy): - # Create and Delete the server-group with given policy - name = data_utils.rand_name('server-group') - server_group = self._create_server_group(name, policy) - self._delete_server_group(server_group) - - @decorators.idempotent_id('5dc57eda-35b7-4af7-9e5f-3c2be3d2d68b') - def test_create_delete_server_group_with_affinity_policy(self): - # Create and Delete the server-group with affinity policy - self._create_delete_server_group(self.policy) - - @decorators.idempotent_id('3645a102-372f-4140-afad-13698d850d23') - def test_create_delete_server_group_with_anti_affinity_policy(self): - # Create and Delete the server-group with anti-affinity policy - policy = ['anti-affinity'] - self._create_delete_server_group(policy) - - @decorators.idempotent_id('154dc5a4-a2fe-44b5-b99e-f15806a4a113') - def test_create_delete_multiple_server_groups_with_same_name_policy(self): - # Create and Delete the server-groups with same name and same policy - server_groups = [] - server_group_name = data_utils.rand_name('server-group') - for _ in range(0, 2): - server_groups.append(self._create_server_group(server_group_name, - self.policy)) - for key in ['name', 'policies']: - self.assertEqual(server_groups[0][key], server_groups[1][key]) - self.assertNotEqual(server_groups[0]['id'], server_groups[1]['id']) - - for i in range(0, 2): - self._delete_server_group(server_groups[i]) - - @decorators.idempotent_id('b3545034-dd78-48f0-bdc2-a4adfa6d0ead') - def test_show_server_group(self): - # Get the server-group - body = self.client.show_server_group( - self.created_server_group['id'])['server_group'] - self.assertEqual(self.created_server_group, body) - - @decorators.idempotent_id('d4874179-27b4-4d7d-80e4-6c560cdfe321') - def test_list_server_groups(self): - # List the server-group - body = self.client.list_server_groups()['server_groups'] - self.assertIn(self.created_server_group, body) diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py deleted file mode 100644 index f77e7d309..000000000 --- a/tempest/api/compute/servers/test_server_metadata.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators - - -class ServerMetadataTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ServerMetadataTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerMetadataTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(metadata={}, wait_until='ACTIVE') - - def setUp(self): - super(ServerMetadataTestJSON, self).setUp() - meta = {'key1': 'value1', 'key2': 'value2'} - self.client.set_server_metadata(self.server['id'], meta)['metadata'] - - @decorators.idempotent_id('479da087-92b3-4dcf-aeb3-fd293b2d14ce') - def test_list_server_metadata(self): - # All metadata key/value pairs for a server should be returned - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - - # Verify the expected metadata items are in the list - expected = {'key1': 'value1', 'key2': 'value2'} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('211021f6-21de-4657-a68f-908878cfe251') - def test_set_server_metadata(self): - # The server's metadata should be replaced with the provided values - # Create a new set of metadata for the server - req_metadata = {'meta2': 'data2', 'meta3': 'data3'} - self.client.set_server_metadata(self.server['id'], - req_metadata)['metadata'] - - # Verify the expected values are correct, and that the - # previous values have been removed - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - self.assertEqual(resp_metadata, req_metadata) - - @decorators.idempotent_id('344d981e-0c33-4997-8a5d-6c1d803e4134') - def test_update_server_metadata(self): - # The server's metadata values should be updated to the - # provided values - meta = {'key1': 'alt1', 'key3': 'value3'} - self.client.update_server_metadata(self.server['id'], meta) - - # Verify the values have been updated to the proper values - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - expected = {'key1': 'alt1', 'key2': 'value2', 'key3': 'value3'} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('0f58d402-e34a-481d-8af8-b392b17426d9') - def test_update_metadata_empty_body(self): - # The original metadata should not be lost if empty metadata body is - # passed - meta = {} - self.client.update_server_metadata(self.server['id'], meta) - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - expected = {'key1': 'value1', 'key2': 'value2'} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('3043c57d-7e0e-49a6-9a96-ad569c265e6a') - def test_get_server_metadata_item(self): - # The value for a specific metadata key should be returned - meta = self.client.show_server_metadata_item(self.server['id'], - 'key2')['meta'] - self.assertEqual('value2', meta['key2']) - - @decorators.idempotent_id('58c02d4f-5c67-40be-8744-d3fa5982eb1c') - def test_set_server_metadata_item(self): - # The item's value should be updated to the provided value - # Update the metadata value - meta = {'nova': 'alt'} - self.client.set_server_metadata_item(self.server['id'], 'nova', meta) - - # Verify the meta item's value has been updated - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - expected = {'key1': 'value1', 'key2': 'value2', 'nova': 'alt'} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('127642d6-4c7b-4486-b7cd-07265a378658') - def test_delete_server_metadata_item(self): - # The metadata value/key pair should be deleted from the server - self.client.delete_server_metadata_item(self.server['id'], 'key1') - - # Verify the metadata item has been removed - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - expected = {'key2': 'value2'} - self.assertEqual(expected, resp_metadata) diff --git a/tempest/api/compute/servers/test_server_metadata_negative.py b/tempest/api/compute/servers/test_server_metadata_negative.py deleted file mode 100644 index 482ba0946..000000000 --- a/tempest/api/compute/servers/test_server_metadata_negative.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ServerMetadataNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ServerMetadataNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerMetadataNegativeTestJSON, cls).resource_setup() - cls.tenant_id = cls.client.tenant_id - cls.server = cls.create_test_server(metadata={}, wait_until='ACTIVE') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fe114a8f-3a57-4eff-9ee2-4e14628df049') - def test_server_create_metadata_key_too_long(self): - # Attempt to start a server with a meta-data key that is > 255 - # characters - - # Tryset_server_metadata_item a few values - for sz in [256, 257, 511, 1023]: - key = "k" * sz - meta = {key: 'data1'} - self.assertRaises((lib_exc.BadRequest, lib_exc.OverLimit), - self.create_test_server, - metadata=meta) - - # no teardown - all creates should fail - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('92431555-4d8b-467c-b95b-b17daa5e57ff') - def test_create_server_metadata_blank_key(self): - # Blank key should trigger an error. - meta = {'': 'data1'} - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - metadata=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4d9cd7a3-2010-4b41-b8fe-3bbf0b169466') - def test_server_metadata_non_existent_server(self): - # GET on a non-existent server should not succeed - non_existent_server_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.show_server_metadata_item, - non_existent_server_id, - 'test2') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f408e78e-3066-4097-9299-3b0182da812e') - def test_list_server_metadata_non_existent_server(self): - # List metadata on a non-existent server should not succeed - non_existent_server_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.list_server_metadata, - non_existent_server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0025fbd6-a4ba-4cde-b8c2-96805dcfdabc') - def test_wrong_key_passed_in_body(self): - # Raise BadRequest if key in uri does not match - # the key passed in body. - meta = {'testkey': 'testvalue'} - self.assertRaises(lib_exc.BadRequest, - self.client.set_server_metadata_item, - self.server['id'], 'key', meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0df38c2a-3d4e-4db5-98d8-d4d9fa843a12') - def test_set_metadata_non_existent_server(self): - # Set metadata on a non-existent server should not succeed - non_existent_server_id = data_utils.rand_uuid() - meta = {'meta1': 'data1'} - self.assertRaises(lib_exc.NotFound, - self.client.set_server_metadata, - non_existent_server_id, - meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('904b13dc-0ef2-4e4c-91cd-3b4a0f2f49d8') - def test_update_metadata_non_existent_server(self): - # An update should not happen for a non-existent server - non_existent_server_id = data_utils.rand_uuid() - meta = {'key1': 'value1', 'key2': 'value2'} - self.assertRaises(lib_exc.NotFound, - self.client.update_server_metadata, - non_existent_server_id, - meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a452f38c-05c2-4b47-bd44-a4f0bf5a5e48') - def test_update_metadata_with_blank_key(self): - # Blank key should trigger an error - meta = {'': 'data1'} - self.assertRaises(lib_exc.BadRequest, - self.client.update_server_metadata, - self.server['id'], meta=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6bbd88e1-f8b3-424d-ba10-ae21c45ada8d') - def test_delete_metadata_non_existent_server(self): - # Should not be able to delete metadata item from a non-existent server - non_existent_server_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.delete_server_metadata_item, - non_existent_server_id, - 'd') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d8c0a210-a5c3-4664-be04-69d96746b547') - def test_metadata_items_limit(self): - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised while exceeding metadata items limit for - # tenant. - quota_set = self.quotas_client.show_quota_set( - self.tenant_id)['quota_set'] - quota_metadata = quota_set['metadata_items'] - if quota_metadata == -1: - raise self.skipException("No limit for metadata_items") - - req_metadata = {} - for num in range(1, quota_metadata + 2): - req_metadata['key' + str(num)] = 'val' + str(num) - self.assertRaises((lib_exc.OverLimit, lib_exc.Forbidden), - self.client.set_server_metadata, - self.server['id'], req_metadata) - - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised while exceeding metadata items limit for - # tenant. - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.client.update_server_metadata, - self.server['id'], req_metadata) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('96100343-7fa9-40d8-80fa-d29ef588ce1c') - def test_set_server_metadata_blank_key(self): - # Raise a bad request error for blank key. - # set_server_metadata will replace all metadata with new value - meta = {'': 'data1'} - self.assertRaises(lib_exc.BadRequest, - self.client.set_server_metadata, - self.server['id'], meta=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('64a91aee-9723-4863-be44-4c9d9f1e7d0e') - def test_set_server_metadata_missing_metadata(self): - # Raise a bad request error for a missing metadata field - # set_server_metadata will replace all metadata with new value - meta = {'meta1': 'data1'} - self.assertRaises(lib_exc.BadRequest, - self.client.set_server_metadata, - self.server['id'], meta=meta, no_metadata_field=True) diff --git a/tempest/api/compute/servers/test_server_password.py b/tempest/api/compute/servers/test_server_password.py deleted file mode 100644 index e7591a541..000000000 --- a/tempest/api/compute/servers/test_server_password.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2013 IBM Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.api.compute import base -from tempest.lib import decorators - - -class ServerPasswordTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ServerPasswordTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerPasswordTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until="ACTIVE") - - @decorators.idempotent_id('f83b582f-62a8-4f22-85b0-0dee50ff783a') - def test_get_server_password(self): - self.client.show_password(self.server['id']) - - @decorators.idempotent_id('f8229e8b-b625-4493-800a-bde86ac611ea') - def test_delete_server_password(self): - self.client.delete_password(self.server['id']) diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py deleted file mode 100644 index 90b9da413..000000000 --- a/tempest/api/compute/servers/test_server_personality.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import base64 - -from tempest.api.compute import base -from tempest.common.utils.linux import remote_client -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ServerPersonalityTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(ServerPersonalityTestJSON, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - super(ServerPersonalityTestJSON, cls).resource_setup() - - @classmethod - def skip_checks(cls): - super(ServerPersonalityTestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.personality: - raise cls.skipException("Nova personality feature disabled") - - @classmethod - def setup_clients(cls): - super(ServerPersonalityTestJSON, cls).setup_clients() - cls.client = cls.servers_client - cls.user_client = cls.limits_client - - @decorators.idempotent_id('3cfe87fd-115b-4a02-b942-7dc36a337fdf') - def test_create_server_with_personality(self): - file_contents = 'This is a test file.' - file_path = '/test.txt' - personality = [{'path': file_path, - 'contents': base64.encode_as_text(file_contents)}] - password = data_utils.rand_password() - created_server = self.create_test_server(personality=personality, - adminPass=password, - wait_until='ACTIVE', - validatable=True) - server = self.client.show_server(created_server['id'])['server'] - if CONF.validation.run_validation: - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.ssh_user, password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.client) - self.assertEqual(file_contents, - linux_client.exec_command( - 'sudo cat %s' % file_path)) - - @decorators.idempotent_id('128966d8-71fc-443c-8cab-08e24114ecc9') - def test_rebuild_server_with_personality(self): - server = self.create_test_server(wait_until='ACTIVE', validatable=True) - server_id = server['id'] - file_contents = 'Test server rebuild.' - personality = [{'path': 'rebuild.txt', - 'contents': base64.encode_as_text(file_contents)}] - rebuilt_server = self.client.rebuild_server(server_id, - self.image_ref_alt, - personality=personality) - waiters.wait_for_server_status(self.client, server_id, 'ACTIVE') - self.assertEqual(self.image_ref_alt, - rebuilt_server['server']['image']['id']) - - @decorators.idempotent_id('176cd8c9-b9e8-48ee-a480-180beab292bf') - def test_personality_files_exceed_limit(self): - # Server creation should fail if greater than the maximum allowed - # number of files are injected into the server. - file_contents = 'This is a test file.' - personality = [] - limits = self.user_client.show_limits()['limits'] - max_file_limit = limits['absolute']['maxPersonality'] - if max_file_limit == -1: - raise self.skipException("No limit for personality files") - for i in range(0, max_file_limit + 1): - path = 'etc/test' + str(i) + '.txt' - personality.append({'path': path, - 'contents': base64.encode_as_text( - file_contents)}) - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised when out of quota - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.create_test_server, personality=personality) - - @decorators.idempotent_id('52f12ee8-5180-40cc-b417-31572ea3d555') - def test_can_create_server_with_max_number_personality_files(self): - # Server should be created successfully if maximum allowed number of - # files is injected into the server during creation. - file_contents = 'This is a test file.' - limits = self.user_client.show_limits()['limits'] - max_file_limit = limits['absolute']['maxPersonality'] - if max_file_limit == -1: - raise self.skipException("No limit for personality files") - person = [] - for i in range(0, max_file_limit): - # NOTE(andreaf) The cirros disk image is blank before boot - # so we can only inject safely to / - path = '/test' + str(i) + '.txt' - person.append({ - 'path': path, - 'contents': base64.encode_as_text(file_contents + str(i)), - }) - password = data_utils.rand_password() - created_server = self.create_test_server(personality=person, - adminPass=password, - wait_until='ACTIVE', - validatable=True) - server = self.client.show_server(created_server['id'])['server'] - if CONF.validation.run_validation: - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.ssh_user, password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.client) - for i in person: - self.assertEqual(base64.decode_as_text(i['contents']), - linux_client.exec_command( - 'sudo cat %s' % i['path'])) diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py deleted file mode 100644 index b0ef3bcb5..000000000 --- a/tempest/api/compute/servers/test_server_rescue.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ServerRescueTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ServerRescueTestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.rescue: - msg = "Server rescue not available." - raise cls.skipException(msg) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerRescueTestJSON, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(ServerRescueTestJSON, cls).resource_setup() - - password = data_utils.rand_password() - server = cls.create_test_server(adminPass=password, - wait_until='ACTIVE') - cls.servers_client.rescue_server(server['id'], adminPass=password) - waiters.wait_for_server_status(cls.servers_client, server['id'], - 'RESCUE') - cls.rescued_server_id = server['id'] - - @decorators.idempotent_id('fd032140-714c-42e4-a8fd-adcd8df06be6') - def test_rescue_unrescue_instance(self): - password = data_utils.rand_password() - server = self.create_test_server(adminPass=password, - wait_until='ACTIVE') - self.servers_client.rescue_server(server['id'], adminPass=password) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'RESCUE') - self.servers_client.unrescue_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - @decorators.idempotent_id('4842e0cf-e87d-4d9d-b61f-f4791da3cacc') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @testtools.skipUnless(CONF.network_feature_enabled.floating_ips, - "Floating ips are not available") - def test_rescued_vm_associate_dissociate_floating_ip(self): - # Association of floating IP to a rescued vm - floating_ip_body = self.floating_ips_client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - self.addCleanup(self.floating_ips_client.delete_floating_ip, - floating_ip_body['id']) - - self.floating_ips_client.associate_floating_ip_to_server( - str(floating_ip_body['ip']).strip(), self.rescued_server_id) - - # Disassociation of floating IP that was associated in this method - self.floating_ips_client.disassociate_floating_ip_from_server( - str(floating_ip_body['ip']).strip(), self.rescued_server_id) - - @decorators.idempotent_id('affca41f-7195-492d-8065-e09eee245404') - def test_rescued_vm_add_remove_security_group(self): - # Add Security group - sg = self.create_security_group() - self.servers_client.add_security_group(self.rescued_server_id, - name=sg['name']) - - # Delete Security group - self.servers_client.remove_security_group(self.rescued_server_id, - name=sg['name']) diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py deleted file mode 100644 index 5fac433dc..000000000 --- a/tempest/api/compute/servers/test_server_rescue_negative.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class ServerRescueNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ServerRescueNegativeTestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.rescue: - msg = "Server rescue not available." - raise cls.skipException(msg) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerRescueNegativeTestJSON, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(ServerRescueNegativeTestJSON, cls).resource_setup() - cls.device = CONF.compute.volume_device_name - cls.password = data_utils.rand_password() - rescue_password = data_utils.rand_password() - # Server for negative tests - server = cls.create_test_server(adminPass=cls.password, - wait_until='BUILD') - resc_server = cls.create_test_server(adminPass=rescue_password, - wait_until='ACTIVE') - cls.server_id = server['id'] - cls.rescue_id = resc_server['id'] - - cls.servers_client.rescue_server( - cls.rescue_id, adminPass=rescue_password) - waiters.wait_for_server_status(cls.servers_client, - cls.rescue_id, 'RESCUE') - waiters.wait_for_server_status(cls.servers_client, - cls.server_id, 'ACTIVE') - - def _unrescue(self, server_id): - self.servers_client.unrescue_server(server_id) - waiters.wait_for_server_status(self.servers_client, - server_id, 'ACTIVE') - - def _unpause(self, server_id): - self.servers_client.unpause_server(server_id) - waiters.wait_for_server_status(self.servers_client, - server_id, 'ACTIVE') - - @decorators.idempotent_id('cc3a883f-43c0-4fb6-a9bb-5579d64984ed') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type=['negative']) - def test_rescue_paused_instance(self): - # Rescue a paused server - self.servers_client.pause_server(self.server_id) - self.addCleanup(self._unpause, self.server_id) - waiters.wait_for_server_status(self.servers_client, - self.server_id, 'PAUSED') - self.assertRaises(lib_exc.Conflict, - self.servers_client.rescue_server, - self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('db22b618-f157-4566-a317-1b6d467a8094') - def test_rescued_vm_reboot(self): - self.assertRaises(lib_exc.Conflict, self.servers_client.reboot_server, - self.rescue_id, type='HARD') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6dfc0a55-3a77-4564-a144-1587b7971dde') - def test_rescue_non_existent_server(self): - # Rescue a non-existing server - non_existent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.servers_client.rescue_server, - non_existent_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('70cdb8a1-89f8-437d-9448-8844fd82bf46') - def test_rescued_vm_rebuild(self): - self.assertRaises(lib_exc.Conflict, - self.servers_client.rebuild_server, - self.rescue_id, - self.image_ref_alt) - - @decorators.idempotent_id('d0ccac79-0091-4cf4-a1ce-26162d0cc55f') - @test.services('volume') - @decorators.attr(type=['negative']) - def test_rescued_vm_attach_volume(self): - volume = self.create_volume() - - # Rescue the server - self.servers_client.rescue_server(self.server_id, - adminPass=self.password) - waiters.wait_for_server_status(self.servers_client, - self.server_id, 'RESCUE') - self.addCleanup(self._unrescue, self.server_id) - - # Attach the volume to the server - self.assertRaises(lib_exc.Conflict, - self.servers_client.attach_volume, - self.server_id, - volumeId=volume['id'], - device='/dev/%s' % self.device) - - @decorators.idempotent_id('f56e465b-fe10-48bf-b75d-646cda3a8bc9') - @test.services('volume') - @decorators.attr(type=['negative']) - def test_rescued_vm_detach_volume(self): - volume = self.create_volume() - - # Attach the volume to the server - server = self.servers_client.show_server(self.server_id)['server'] - self.attach_volume(server, volume, device='/dev/%s' % self.device) - - # Rescue the server - self.servers_client.rescue_server(self.server_id, - adminPass=self.password) - waiters.wait_for_server_status(self.servers_client, - self.server_id, 'RESCUE') - # addCleanup is a LIFO queue - self.addCleanup(self._unrescue, self.server_id) - - # Detach the volume from the server expecting failure - self.assertRaises(lib_exc.Conflict, - self.servers_client.detach_volume, - self.server_id, - volume['id']) diff --git a/tempest/api/compute/servers/test_server_tags.py b/tempest/api/compute/servers/test_server_tags.py deleted file mode 100644 index 037021537..000000000 --- a/tempest/api/compute/servers/test_server_tags.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2017 AT&T Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class ServerTagsTestJSON(base.BaseV2ComputeTest): - - min_microversion = '2.26' - max_microversion = 'latest' - - @classmethod - def skip_checks(cls): - super(ServerTagsTestJSON, cls).skip_checks() - if not test.is_extension_enabled('os-server-tags', 'compute'): - msg = "os-server-tags extension is not enabled." - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(ServerTagsTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerTagsTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - def _update_server_tags(self, server_id, tags): - if not isinstance(tags, (list, tuple)): - tags = [tags] - for tag in tags: - self.client.update_tag(server_id, tag) - self.addCleanup(self.client.delete_all_tags, server_id) - - @decorators.idempotent_id('8d95abe2-c658-4c42-9a44-c0258500306b') - def test_create_delete_tag(self): - # Check that no tags exist. - fetched_tags = self.client.list_tags(self.server['id'])['tags'] - self.assertEmpty(fetched_tags) - - # Add server tag to the server. - assigned_tag = data_utils.rand_name('tag') - self._update_server_tags(self.server['id'], assigned_tag) - - # Check that added tag exists. - fetched_tags = self.client.list_tags(self.server['id'])['tags'] - self.assertEqual([assigned_tag], fetched_tags) - - # Remove assigned tag from server and check that it was removed. - self.client.delete_tag(self.server['id'], assigned_tag) - fetched_tags = self.client.list_tags(self.server['id'])['tags'] - self.assertEmpty(fetched_tags) - - @decorators.idempotent_id('a2c1af8c-127d-417d-974b-8115f7e3d831') - def test_update_all_tags(self): - # Add server tags to the server. - tags = [data_utils.rand_name('tag'), data_utils.rand_name('tag')] - self._update_server_tags(self.server['id'], tags) - - # Replace tags with new tags and check that they are present. - new_tags = [data_utils.rand_name('tag'), data_utils.rand_name('tag')] - replaced_tags = self.client.update_all_tags( - self.server['id'], new_tags)['tags'] - six.assertCountEqual(self, new_tags, replaced_tags) - - # List the tags and check that the tags were replaced. - fetched_tags = self.client.list_tags(self.server['id'])['tags'] - six.assertCountEqual(self, new_tags, fetched_tags) - - @decorators.idempotent_id('a63b2a74-e918-4b7c-bcab-10c855f3a57e') - def test_delete_all_tags(self): - # Add server tags to the server. - assigned_tags = [data_utils.rand_name('tag'), - data_utils.rand_name('tag')] - self._update_server_tags(self.server['id'], assigned_tags) - - # Delete tags from the server and check that they were deleted. - self.client.delete_all_tags(self.server['id']) - fetched_tags = self.client.list_tags(self.server['id'])['tags'] - self.assertEmpty(fetched_tags) - - @decorators.idempotent_id('81279a66-61c3-4759-b830-a2dbe64cbe08') - def test_check_tag_existence(self): - # Add server tag to the server. - assigned_tag = data_utils.rand_name('tag') - self._update_server_tags(self.server['id'], assigned_tag) - - # Check that added tag exists. Throws a 404 if not found, else a 204, - # which was already checked by the schema validation. - self.client.check_tag_existence(self.server['id'], assigned_tag) diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py deleted file mode 100644 index 7fd1dd1ce..000000000 --- a/tempest/api/compute/servers/test_servers.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ServersTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ServersTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - def tearDown(self): - self.clear_servers() - super(ServersTestJSON, self).tearDown() - - @decorators.idempotent_id('b92d5ec7-b1dd-44a2-87e4-45e888c46ef0') - @testtools.skipUnless(CONF.compute_feature_enabled. - enable_instance_password, - 'Instance password not available.') - def test_create_server_with_admin_password(self): - # If an admin password is provided on server creation, the server's - # root password should be set to that password. - server = self.create_test_server(adminPass='testpassword') - - # Verify the password is set correctly in the response - self.assertEqual('testpassword', server['adminPass']) - - @decorators.idempotent_id('8fea6be7-065e-47cf-89b8-496e6f96c699') - def test_create_with_existing_server_name(self): - # Creating a server with a name that already exists is allowed - - # TODO(sdague): clear out try, we do cleanup one layer up - server_name = data_utils.rand_name( - self.__class__.__name__ + '-server') - server = self.create_test_server(name=server_name, - wait_until='ACTIVE') - id1 = server['id'] - server = self.create_test_server(name=server_name, - wait_until='ACTIVE') - id2 = server['id'] - self.assertNotEqual(id1, id2, "Did not create a new server") - server = self.client.show_server(id1)['server'] - name1 = server['name'] - server = self.client.show_server(id2)['server'] - name2 = server['name'] - self.assertEqual(name1, name2) - - @decorators.idempotent_id('f9e15296-d7f9-4e62-b53f-a04e89160833') - def test_create_specify_keypair(self): - # Specify a keypair while creating a server - - key_name = data_utils.rand_name('key') - self.keypairs_client.create_keypair(name=key_name) - self.addCleanup(self.keypairs_client.delete_keypair, key_name) - self.keypairs_client.list_keypairs() - server = self.create_test_server(key_name=key_name) - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - server = self.client.show_server(server['id'])['server'] - self.assertEqual(key_name, server['key_name']) - - def _update_server_name(self, server_id, status, prefix_name='server'): - # The server name should be changed to the provided value - new_name = data_utils.rand_name(prefix_name) - - # Update the server with a new name - self.client.update_server(server_id, - name=new_name) - waiters.wait_for_server_status(self.client, server_id, status) - - # Verify the name of the server has changed - server = self.client.show_server(server_id)['server'] - self.assertEqual(new_name, server['name']) - return server - - @decorators.idempotent_id('5e6ccff8-349d-4852-a8b3-055df7988dd2') - def test_update_server_name(self): - # The server name should be changed to the provided value - server = self.create_test_server(wait_until='ACTIVE') - # Update instance name with non-ASCII characters - prefix_name = u'\u00CD\u00F1st\u00E1\u00F1c\u00E9' - self._update_server_name(server['id'], 'ACTIVE', prefix_name) - - # stop server and check server name update again - self.client.stop_server(server['id']) - waiters.wait_for_server_status(self.client, server['id'], 'SHUTOFF') - # Update instance name with non-ASCII characters - updated_server = self._update_server_name(server['id'], - 'SHUTOFF', - prefix_name) - self.assertNotIn('progress', updated_server) - - @decorators.idempotent_id('89b90870-bc13-4b73-96af-f9d4f2b70077') - def test_update_access_server_address(self): - # The server's access addresses should reflect the provided values - server = self.create_test_server(wait_until='ACTIVE') - - # Update the IPv4 and IPv6 access addresses - self.client.update_server(server['id'], - accessIPv4='1.1.1.1', - accessIPv6='::babe:202:202') - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - - # Verify the access addresses have been updated - server = self.client.show_server(server['id'])['server'] - self.assertEqual('1.1.1.1', server['accessIPv4']) - self.assertEqual('::babe:202:202', server['accessIPv6']) - - @decorators.idempotent_id('38fb1d02-c3c5-41de-91d3-9bc2025a75eb') - def test_create_server_with_ipv6_addr_only(self): - # Create a server without an IPv4 address(only IPv6 address). - server = self.create_test_server(accessIPv6='2001:2001::3') - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - server = self.client.show_server(server['id'])['server'] - self.assertEqual('2001:2001::3', server['accessIPv6']) - - -class ServerShowV247Test(base.BaseV2ComputeTest): - min_microversion = '2.47' - max_microversion = 'latest' - - @decorators.idempotent_id('88b0bdb2-494c-11e7-a919-92ebcb67fe33') - def test_show_server(self): - server = self.create_test_server() - # All fields will be checked by API schema - self.servers_client.show_server(server['id']) diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py deleted file mode 100644 index 764767b8a..000000000 --- a/tempest/api/compute/servers/test_servers_negative.py +++ /dev/null @@ -1,583 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import sys - -import testtools - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class ServersNegativeTestJSON(base.BaseV2ComputeTest): - - def setUp(self): - super(ServersNegativeTestJSON, self).setUp() - try: - waiters.wait_for_server_status(self.client, self.server_id, - 'ACTIVE') - except Exception: - self.__class__.server_id = self.rebuild_server(self.server_id) - - def tearDown(self): - self.server_check_teardown() - super(ServersNegativeTestJSON, self).tearDown() - - @classmethod - def setup_clients(cls): - super(ServersNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServersNegativeTestJSON, cls).resource_setup() - server = cls.create_test_server(wait_until='ACTIVE') - cls.server_id = server['id'] - - server = cls.create_test_server() - cls.client.delete_server(server['id']) - waiters.wait_for_server_termination(cls.client, server['id']) - cls.deleted_server_id = server['id'] - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dbbfd247-c40c-449e-8f6c-d2aa7c7da7cf') - def test_server_name_blank(self): - # Create a server with name parameter empty - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b8a7235e-5246-4a8f-a08e-b34877c6586f') - @testtools.skipUnless(CONF.compute_feature_enabled.personality, - 'Nova personality feature disabled') - def test_personality_file_contents_not_encoded(self): - # Use an unencoded file when creating a server with personality - - file_contents = 'This is a test file.' - person = [{'path': '/etc/testfile.txt', - 'contents': file_contents}] - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - personality=person) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fcba1052-0a50-4cf3-b1ac-fae241edf02f') - def test_create_with_invalid_image(self): - # Create a server with an unknown image - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - image_id=-1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('18f5227f-d155-4429-807c-ccb103887537') - def test_create_with_invalid_flavor(self): - # Create a server with an unknown flavor - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - flavor=-1,) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7f70a4d1-608f-4794-9e56-cb182765972c') - def test_invalid_access_ip_v4_address(self): - # An access IPv4 address must match a valid address pattern - - IPv4 = '1.1.1.1.1.1' - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, accessIPv4=IPv4) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5226dd80-1e9c-4d8a-b5f9-b26ca4763fd0') - def test_invalid_ip_v6_address(self): - # An access IPv6 address must match a valid address pattern - - IPv6 = 'notvalid' - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, accessIPv6=IPv6) - - @decorators.idempotent_id('7ea45b3e-e770-46fa-bfcc-9daaf6d987c0') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - @decorators.attr(type=['negative']) - def test_resize_nonexistent_server(self): - # Resize a non-existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.resize_server, - nonexistent_server, self.flavor_ref) - - @decorators.idempotent_id('ced1a1d7-2ab6-45c9-b90f-b27d87b30efd') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - @decorators.attr(type=['negative']) - def test_resize_server_with_non_existent_flavor(self): - # Resize a server with non-existent flavor - nonexistent_flavor = data_utils.rand_uuid() - self.assertRaises(lib_exc.BadRequest, self.client.resize_server, - self.server_id, flavor_ref=nonexistent_flavor) - - @decorators.idempotent_id('45436a7d-a388-4a35-a9d8-3adc5d0d940b') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - @decorators.attr(type=['negative']) - def test_resize_server_with_null_flavor(self): - # Resize a server with null flavor - self.assertRaises(lib_exc.BadRequest, self.client.resize_server, - self.server_id, flavor_ref="") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d4c023a0-9c55-4747-9dd5-413b820143c7') - def test_reboot_non_existent_server(self): - # Reboot a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.reboot_server, - nonexistent_server, type='SOFT') - - @decorators.idempotent_id('d1417e7f-a509-41b5-a102-d5eed8613369') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type=['negative']) - def test_pause_paused_server(self): - # Pause a paused server. - self.client.pause_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'PAUSED') - self.assertRaises(lib_exc.Conflict, - self.client.pause_server, - self.server_id) - self.client.unpause_server(self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('98fa0458-1485-440f-873b-fe7f0d714930') - def test_rebuild_deleted_server(self): - # Rebuild a deleted server - self.assertRaises(lib_exc.NotFound, - self.client.rebuild_server, - self.deleted_server_id, self.image_ref) - - @decorators.related_bug('1660878', status_code=409) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('581a397d-5eab-486f-9cf9-1014bbd4c984') - def test_reboot_deleted_server(self): - # Reboot a deleted server - self.assertRaises(lib_exc.NotFound, self.client.reboot_server, - self.deleted_server_id, type='SOFT') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d86141a7-906e-4731-b187-d64a2ea61422') - def test_rebuild_non_existent_server(self): - # Rebuild a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.rebuild_server, - nonexistent_server, - self.image_ref) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fd57f159-68d6-4c2a-902b-03070828a87e') - def test_create_numeric_server_name(self): - server_name = 12345 - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - name=server_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c3e0fb12-07fc-4d76-a22e-37409887afe8') - def test_create_server_name_length_exceeds_256(self): - # Create a server with name length exceeding 255 characters - - server_name = 'a' * 256 - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - name=server_name) - - @decorators.attr(type=['negative']) - @decorators.related_bug('1651064', status_code=500) - @test.services('volume') - @decorators.idempotent_id('12146ac1-d7df-4928-ad25-b1f99e5286cd') - def test_create_server_invalid_bdm_in_2nd_dict(self): - volume = self.create_volume() - bdm_1st = {"source_type": "image", - "delete_on_termination": True, - "boot_index": 0, - "uuid": self.image_ref, - "destination_type": "local"} - bdm_2nd = {"source_type": "volume", - "uuid": volume["id"], - "destination_type": "invalid"} - bdm = [bdm_1st, bdm_2nd] - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - image_id=self.image_ref, - block_device_mapping_v2=bdm) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4e72dc2d-44c5-4336-9667-f7972e95c402') - def test_create_with_invalid_network_uuid(self): - # Pass invalid network uuid while creating a server - - networks = [{'fixed_ip': '10.0.1.1', 'uuid': 'a-b-c-d-e-f-g-h-i-j'}] - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - networks=networks) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7a2efc39-530c-47de-b875-2dd01c8d39bd') - def test_create_with_non_existent_keypair(self): - # Pass a non-existent keypair while creating a server - - key_name = data_utils.rand_name('key') - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - key_name=key_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7fc74810-0bd2-4cd7-8244-4f33a9db865a') - def test_create_server_metadata_exceeds_length_limit(self): - # Pass really long metadata while creating a server - - metadata = {'a': 'b' * 260} - self.assertRaises((lib_exc.BadRequest, lib_exc.OverLimit), - self.create_test_server, - metadata=metadata) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('aa8eed43-e2cb-4ebf-930b-da14f6a21d81') - def test_update_name_of_non_existent_server(self): - # Update name of a non-existent server - - nonexistent_server = data_utils.rand_uuid() - new_name = data_utils.rand_name( - self.__class__.__name__ + '-server') + '_updated' - - self.assertRaises(lib_exc.NotFound, self.client.update_server, - nonexistent_server, name=new_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('38204696-17c6-44da-9590-40f87fb5a899') - def test_update_server_set_empty_name(self): - # Update name of the server to an empty string - - new_name = '' - - self.assertRaises(lib_exc.BadRequest, self.client.update_server, - self.server_id, name=new_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5c8e244c-dada-4590-9944-749c455b431f') - def test_update_server_name_length_exceeds_256(self): - # Update name of server exceed the name length limit - - new_name = 'a' * 256 - self.assertRaises(lib_exc.BadRequest, - self.client.update_server, - self.server_id, - name=new_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1041b4e6-514b-4855-96a5-e974b60870a3') - def test_delete_non_existent_server(self): - # Delete a non existent server - - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.delete_server, - nonexistent_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('75f79124-277c-45e6-a373-a1d6803f4cc4') - def test_delete_server_pass_negative_id(self): - # Pass an invalid string parameter to delete server - - self.assertRaises(lib_exc.NotFound, self.client.delete_server, -1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f4d7279b-5fd2-4bf2-9ba4-ae35df0d18c5') - def test_delete_server_pass_id_exceeding_length_limit(self): - # Pass a server ID that exceeds length limit to delete server - - self.assertRaises(lib_exc.NotFound, self.client.delete_server, - sys.maxsize + 1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c5fa6041-80cd-483b-aa6d-4e45f19d093c') - def test_create_with_nonexistent_security_group(self): - # Create a server with a nonexistent security group - - security_groups = [{'name': 'does_not_exist'}] - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - security_groups=security_groups) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3436b02f-1b1e-4f03-881e-c6a602327439') - def test_get_non_existent_server(self): - # Get a non existent server details - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.show_server, - nonexistent_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a31460a9-49e1-42aa-82ee-06e0bb7c2d03') - def test_stop_non_existent_server(self): - # Stop a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.servers_client.stop_server, - nonexistent_server) - - @decorators.idempotent_id('6a8dc0c6-6cd4-4c0a-9f32-413881828091') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type=['negative']) - def test_pause_non_existent_server(self): - # pause a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.pause_server, - nonexistent_server) - - @decorators.idempotent_id('705b8e3a-e8a7-477c-a19b-6868fc24ac75') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type=['negative']) - def test_unpause_non_existent_server(self): - # unpause a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.unpause_server, - nonexistent_server) - - @decorators.idempotent_id('c8e639a7-ece8-42dd-a2e0-49615917ba4f') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type=['negative']) - def test_unpause_server_invalid_state(self): - # unpause an active server. - self.assertRaises(lib_exc.Conflict, - self.client.unpause_server, - self.server_id) - - @decorators.idempotent_id('d1f032d5-7b6e-48aa-b252-d5f16dd994ca') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type=['negative']) - def test_suspend_non_existent_server(self): - # suspend a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.suspend_server, - nonexistent_server) - - @decorators.idempotent_id('7f323206-05a9-4bf8-996b-dd5b2036501b') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type=['negative']) - def test_suspend_server_invalid_state(self): - # suspend a suspended server. - self.client.suspend_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, - 'SUSPENDED') - self.assertRaises(lib_exc.Conflict, - self.client.suspend_server, - self.server_id) - self.client.resume_server(self.server_id) - - @decorators.idempotent_id('221cd282-bddb-4837-a683-89c2487389b6') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type=['negative']) - def test_resume_non_existent_server(self): - # resume a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.resume_server, - nonexistent_server) - - @decorators.idempotent_id('ccb6294d-c4c9-498f-8a43-554c098bfadb') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type=['negative']) - def test_resume_server_invalid_state(self): - # resume an active server. - self.assertRaises(lib_exc.Conflict, - self.client.resume_server, - self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7dd919e7-413f-4198-bebb-35e2a01b13e9') - def test_get_console_output_of_non_existent_server(self): - # get the console output for a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.get_console_output, - nonexistent_server, length=10) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6f47992b-5144-4250-9f8b-f00aa33950f3') - def test_force_delete_nonexistent_server_id(self): - # force-delete a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.force_delete_server, - nonexistent_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9c6d38cc-fcfb-437a-85b9-7b788af8bf01') - def test_restore_nonexistent_server_id(self): - # restore-delete a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.restore_soft_deleted_server, - nonexistent_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7fcadfab-bd6a-4753-8db7-4a51e51aade9') - def test_restore_server_invalid_state(self): - # we can only restore-delete a server in 'soft-delete' state - self.assertRaises(lib_exc.Conflict, - self.client.restore_soft_deleted_server, - self.server_id) - - @decorators.idempotent_id('abca56e2-a892-48ea-b5e5-e07e69774816') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - @decorators.attr(type=['negative']) - def test_shelve_non_existent_server(self): - # shelve a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.shelve_server, - nonexistent_server) - - @decorators.idempotent_id('443e4f9b-e6bf-4389-b601-3a710f15fddd') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - @decorators.attr(type=['negative']) - def test_shelve_shelved_server(self): - # shelve a shelved server. - compute.shelve_server(self.client, self.server_id) - - server = self.client.show_server(self.server_id)['server'] - image_name = server['name'] + '-shelved' - params = {'name': image_name} - images = self.compute_images_client.list_images(**params)['images'] - self.assertEqual(1, len(images)) - self.assertEqual(image_name, images[0]['name']) - - self.assertRaises(lib_exc.Conflict, - self.client.shelve_server, - self.server_id) - - self.client.unshelve_server(self.server_id) - - @decorators.idempotent_id('23d23b37-afaf-40d7-aa5d-5726f82d8821') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - @decorators.attr(type=['negative']) - def test_unshelve_non_existent_server(self): - # unshelve a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.unshelve_server, - nonexistent_server) - - @decorators.idempotent_id('8f198ded-1cca-4228-9e65-c6b449c54880') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - @decorators.attr(type=['negative']) - def test_unshelve_server_invalid_state(self): - # unshelve an active server. - self.assertRaises(lib_exc.Conflict, - self.client.unshelve_server, - self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('74085be3-a370-4ca2-bc51-2d0e10e0f573') - @test.services('volume', 'image') - def test_create_server_from_non_bootable_volume(self): - # Create a volume - volume = self.create_volume() - - # Update volume bootable status to false - self.volumes_client.set_bootable_volume(volume['id'], - bootable=False) - - # Verify bootable flag was updated - nonbootable_vol = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual('false', nonbootable_vol['bootable']) - - # Block device mapping - bd_map = [{'boot_index': '0', - 'uuid': volume['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'delete_on_termination': False}] - - # Try creating a server from non-bootable volume - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - image_id='', - wait_until='ACTIVE', - block_device_mapping_v2=bd_map) - - -class ServersNegativeTestMultiTenantJSON(base.BaseV2ComputeTest): - - credentials = ['primary', 'alt'] - - def setUp(self): - super(ServersNegativeTestMultiTenantJSON, self).setUp() - try: - waiters.wait_for_server_status(self.servers_client, self.server_id, - 'ACTIVE') - except Exception: - self.__class__.server_id = self.rebuild_server(self.server_id) - - @classmethod - def setup_clients(cls): - super(ServersNegativeTestMultiTenantJSON, cls).setup_clients() - cls.alt_client = cls.os_alt.servers_client - - @classmethod - def resource_setup(cls): - super(ServersNegativeTestMultiTenantJSON, cls).resource_setup() - server = cls.create_test_server(wait_until='ACTIVE') - cls.server_id = server['id'] - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('543d84c1-dd2e-4c6d-8cb2-b9da0efaa384') - def test_update_server_of_another_tenant(self): - # Update name of a server that belongs to another tenant - - new_name = self.server_id + '_new' - self.assertRaises(lib_exc.NotFound, - self.alt_client.update_server, self.server_id, - name=new_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5c75009d-3eea-423e-bea3-61b09fd25f9c') - def test_delete_a_server_of_another_tenant(self): - # Delete a server that belongs to another tenant - self.assertRaises(lib_exc.NotFound, - self.alt_client.delete_server, - self.server_id) diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py deleted file mode 100644 index 6b625d935..000000000 --- a/tempest/api/compute/servers/test_virtual_interfaces.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr -import testtools - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest import test - -CONF = config.CONF - - -class VirtualInterfacesTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - # This test needs a network and a subnet - cls.set_network_resources(network=True, subnet=True) - super(VirtualInterfacesTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(VirtualInterfacesTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(VirtualInterfacesTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - @decorators.idempotent_id('96c4e2ef-5e4d-4d7f-87f5-fed6dca18016') - @test.services('network') - def test_list_virtual_interfaces(self): - # Positive test:Should be able to GET the virtual interfaces list - # for a given server_id - - if CONF.service_available.neutron: - # TODO(mriedem): After a microversion implements the API for - # neutron, a 400 should be a failure for nova-network and neutron. - with testtools.ExpectedException(exceptions.BadRequest): - self.client.list_virtual_interfaces(self.server['id']) - else: - output = self.client.list_virtual_interfaces(self.server['id']) - self.assertIsNotNone(output) - virt_ifaces = output - self.assertNotEmpty(virt_ifaces['virtual_interfaces'], - 'Expected virtual interfaces, got 0 ' - 'interfaces.') - for virt_iface in virt_ifaces['virtual_interfaces']: - mac_address = virt_iface['mac_address'] - self.assertTrue(netaddr.valid_mac(mac_address), - "Invalid mac address detected. mac address: %s" - % mac_address) diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py deleted file mode 100644 index 173784a40..000000000 --- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class VirtualInterfacesNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - # For this test no network resources are needed - cls.set_network_resources() - super(VirtualInterfacesNegativeTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(VirtualInterfacesNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('64ebd03c-1089-4306-93fa-60f5eb5c803c') - @test.services('network') - def test_list_virtual_interfaces_invalid_server_id(self): - # Negative test: Should not be able to GET virtual interfaces - # for an invalid server_id - invalid_server_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.list_virtual_interfaces, - invalid_server_id) diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py deleted file mode 100644 index 42e13bdef..000000000 --- a/tempest/api/compute/test_extensions.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -LOG = logging.getLogger(__name__) - - -class ExtensionsTestJSON(base.BaseV2ComputeTest): - - @decorators.idempotent_id('3bb27738-b759-4e0d-a5fa-37d7a6df07d1') - def test_list_extensions(self): - # List of all extensions - if not CONF.compute_feature_enabled.api_extensions: - raise self.skipException('There are not any extensions configured') - extensions = self.extensions_client.list_extensions()['extensions'] - ext = CONF.compute_feature_enabled.api_extensions[0] - - # Log extensions list - extension_list = map(lambda x: x['alias'], extensions) - LOG.debug("Nova extensions: %s", ','.join(extension_list)) - - if ext == 'all': - self.assertIn('Hosts', map(lambda x: x['name'], extensions)) - elif ext: - self.assertIn(ext, extension_list) - else: - raise self.skipException('There are not any extensions configured') - - @decorators.idempotent_id('05762f39-bdfa-4cdb-9b46-b78f8e78e2fd') - @test.requires_ext(extension='os-consoles', service='compute') - def test_get_extension(self): - # get the specified extensions - extension = self.extensions_client.show_extension('os-consoles') - self.assertEqual('os-consoles', extension['extension']['alias']) diff --git a/tempest/api/compute/test_networks.py b/tempest/api/compute/test_networks.py deleted file mode 100644 index b8c79d7ef..000000000 --- a/tempest/api/compute/test_networks.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class ComputeNetworksTest(base.BaseV2ComputeTest): - @classmethod - def skip_checks(cls): - super(ComputeNetworksTest, cls).skip_checks() - if CONF.service_available.neutron: - raise cls.skipException('nova-network is not available.') - - @classmethod - def setup_clients(cls): - super(ComputeNetworksTest, cls).setup_clients() - cls.client = cls.os_primary.compute_networks_client - - @decorators.idempotent_id('3fe07175-312e-49a5-a623-5f52eeada4c2') - def test_list_networks(self): - networks = self.client.list_networks()['networks'] - self.assertNotEmpty(networks, "No networks found.") diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py deleted file mode 100644 index 9d83ee19b..000000000 --- a/tempest/api/compute/test_quotas.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib import decorators -from tempest import test - - -class QuotasTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(QuotasTestJSON, cls).skip_checks() - if not test.is_extension_enabled('os-quota-sets', 'compute'): - msg = "quotas extension not enabled." - raise cls.skipException(msg) - - def setUp(self): - # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests. - self.useFixture(fixtures.LockFixture('compute_quotas')) - super(QuotasTestJSON, self).setUp() - - @classmethod - def setup_clients(cls): - super(QuotasTestJSON, cls).setup_clients() - cls.client = cls.quotas_client - - @classmethod - def resource_setup(cls): - super(QuotasTestJSON, cls).resource_setup() - cls.tenant_id = cls.client.tenant_id - cls.user_id = cls.client.user_id - cls.default_quota_set = set(('injected_file_content_bytes', - 'metadata_items', 'injected_files', - 'ram', 'floating_ips', - 'fixed_ips', 'key_pairs', - 'injected_file_path_bytes', - 'instances', 'security_group_rules', - 'cores', 'security_groups', - 'server_group_members', 'server_groups')) - - @decorators.idempotent_id('f1ef0a97-dbbb-4cca-adc5-c9fbc4f76107') - def test_get_quotas(self): - # User can get the quota set for it's tenant - expected_quota_set = self.default_quota_set | set(['id']) - quota_set = self.client.show_quota_set(self.tenant_id)['quota_set'] - self.assertEqual(quota_set['id'], self.tenant_id) - for quota in expected_quota_set: - self.assertIn(quota, quota_set.keys()) - - # get the quota set using user id - quota_set = self.client.show_quota_set( - self.tenant_id, user_id=self.user_id)['quota_set'] - self.assertEqual(quota_set['id'], self.tenant_id) - for quota in expected_quota_set: - self.assertIn(quota, quota_set.keys()) - - @decorators.idempotent_id('9bfecac7-b966-4f47-913f-1a9e2c12134a') - def test_get_default_quotas(self): - # User can get the default quota set for it's tenant - expected_quota_set = self.default_quota_set | set(['id']) - quota_set = (self.client.show_default_quota_set(self.tenant_id) - ['quota_set']) - self.assertEqual(quota_set['id'], self.tenant_id) - for quota in expected_quota_set: - self.assertIn(quota, quota_set.keys()) - - @decorators.idempotent_id('cd65d997-f7e4-4966-a7e9-d5001b674fdc') - def test_compare_tenant_quotas_with_default_quotas(self): - # Tenants are created with the default quota values - default_quota_set = \ - self.client.show_default_quota_set(self.tenant_id)['quota_set'] - tenant_quota_set = (self.client.show_quota_set(self.tenant_id) - ['quota_set']) - self.assertEqual(default_quota_set, tenant_quota_set) diff --git a/tempest/api/compute/test_tenant_networks.py b/tempest/api/compute/test_tenant_networks.py deleted file mode 100644 index 18c5d385d..000000000 --- a/tempest/api/compute/test_tenant_networks.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest import test - - -class ComputeTenantNetworksTest(base.BaseV2ComputeTest): - - @classmethod - def resource_setup(cls): - super(ComputeTenantNetworksTest, cls).resource_setup() - cls.client = cls.os_primary.tenant_networks_client - cls.network = cls.get_tenant_network() - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True) - super(ComputeTenantNetworksTest, cls).setup_credentials() - - @decorators.idempotent_id('edfea98e-bbe3-4c7a-9739-87b986baff26') - @test.services('network') - def test_list_show_tenant_networks(self): - # Fetch all networks that are visible to the tenant: this may include - # shared and external networks - tenant_networks = [ - n['id'] for n in self.client.list_tenant_networks()['networks'] - ] - self.assertIn(self.network['id'], tenant_networks, - "No tenant networks found.") - - net = self.client.show_tenant_network(self.network['id']) - self.assertEqual(self.network['id'], net['network']['id']) diff --git a/tempest/api/compute/test_versions.py b/tempest/api/compute/test_versions.py deleted file mode 100644 index 614155385..000000000 --- a/tempest/api/compute/test_versions.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest.lib import decorators - - -class TestVersions(base.BaseV2ComputeTest): - - @decorators.idempotent_id('6c0a0990-43b6-4529-9b61-5fd8daf7c55c') - @decorators.attr(type='smoke') - def test_list_api_versions(self): - """Test that a get of the unversioned url returns the choices doc. - - A key feature in OpenStack services is the idea that you can - GET / on the service and get a list of the versioned endpoints - that you can access. This comes back as a status 300 - request. It's important that this is available to API - consumers to discover the API they can use. - - """ - result = self.versions_client.list_versions() - versions = result['versions'] - # NOTE(sdague): at a later point we may want to loosen this - # up, but for now this should be true of all Novas deployed. - self.assertEqual(versions[0]['id'], 'v2.0', - "The first listed version should be v2.0") - - @decorators.idempotent_id('b953a29e-929c-4a8e-81be-ec3a7e03cb76') - @decorators.attr(type='smoke') - def test_get_version_details(self): - """Test individual version endpoints info works. - - In addition to the GET / version request, there is also a - version info document stored at the top of the versioned - endpoints. This provides access to details about that - endpoint, including min / max version if that implements - microversions. - - This test starts with the version list, iterates all the - returned endpoints, and fetches them. This will also ensure - that all the version links are followable constructs which - will help detect configuration issues when SSL termination - isn't done completely for a site. - - """ - result = self.versions_client.list_versions() - versions = result['versions'] - - # iterate through all the versions that are returned and - # attempt to get their version documents. - for version in versions: - links = [x for x in version['links'] if x['rel'] == 'self'] - self.assertEqual( - len(links), 1, - "There should only be 1 self link in %s" % version) - link = links[0] - # this is schema validated - result = self.versions_client.get_version_by_url(link['href']) - # ensure the new self link matches the old one - newlinks = [x for x in result['version']['links'] - if x['rel'] == 'self'] - self.assertEqual(links, newlinks) diff --git a/tempest/api/compute/volumes/__init__.py b/tempest/api/compute/volumes/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py deleted file mode 100644 index 502bc1b33..000000000 --- a/tempest/api/compute/volumes/test_attach_volume.py +++ /dev/null @@ -1,251 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common.utils.linux import remote_client -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class AttachVolumeTestJSON(base.BaseV2ComputeTest): - max_microversion = '2.19' - - @classmethod - def skip_checks(cls): - super(AttachVolumeTestJSON, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(AttachVolumeTestJSON, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - super(AttachVolumeTestJSON, cls).resource_setup() - cls.device = CONF.compute.volume_device_name - - def _create_server(self): - # Start a server and wait for it to become ready - server = self.create_test_server( - validatable=True, - wait_until='ACTIVE', - adminPass=self.image_ssh_password) - self.addCleanup(self.delete_server, server['id']) - # Record addresses so that we can ssh later - server['addresses'] = self.servers_client.list_addresses( - server['id'])['addresses'] - return server - - @decorators.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff') - def test_attach_detach_volume(self): - # Stop and Start a server with an attached volume, ensuring that - # the volume remains attached. - server = self._create_server() - - # NOTE(andreaf) Create one remote client used throughout the test. - if CONF.validation.run_validation: - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.image_ssh_user, - self.image_ssh_password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.servers_client) - # NOTE(andreaf) We need to ensure the ssh key has been - # injected in the guest before we power cycle - linux_client.validate_authentication() - - volume = self.create_volume() - attachment = self.attach_volume(server, volume, - device=('/dev/%s' % self.device)) - - self.servers_client.stop_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'SHUTOFF') - - self.servers_client.start_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - if CONF.validation.run_validation: - disks = linux_client.get_disks() - device_name_to_match = '\n' + self.device + ' ' - self.assertIn(device_name_to_match, disks) - - self.servers_client.detach_volume(server['id'], attachment['volumeId']) - waiters.wait_for_volume_resource_status( - self.volumes_client, attachment['volumeId'], 'available') - - self.servers_client.stop_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'SHUTOFF') - - self.servers_client.start_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - if CONF.validation.run_validation: - disks = linux_client.get_disks() - self.assertNotIn(device_name_to_match, disks) - - @decorators.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513') - def test_list_get_volume_attachments(self): - # List volume attachment of the server - server = self._create_server() - volume_1st = self.create_volume() - attachment_1st = self.attach_volume(server, volume_1st, - device=('/dev/%s' % self.device)) - body = self.servers_client.list_volume_attachments( - server['id'])['volumeAttachments'] - self.assertEqual(1, len(body)) - self.assertIn(attachment_1st, body) - - # Get volume attachment of the server - body = self.servers_client.show_volume_attachment( - server['id'], - attachment_1st['id'])['volumeAttachment'] - self.assertEqual(server['id'], body['serverId']) - self.assertEqual(volume_1st['id'], body['volumeId']) - self.assertEqual(attachment_1st['id'], body['id']) - - # attach one more volume to server - volume_2nd = self.create_volume() - attachment_2nd = self.attach_volume(server, volume_2nd) - body = self.servers_client.list_volume_attachments( - server['id'])['volumeAttachments'] - self.assertEqual(2, len(body)) - - for attachment in [attachment_1st, attachment_2nd]: - body = self.servers_client.show_volume_attachment( - server['id'], attachment['id'])['volumeAttachment'] - self.assertEqual(server['id'], body['serverId']) - self.assertEqual(attachment['volumeId'], body['volumeId']) - self.assertEqual(attachment['id'], body['id']) - - -class AttachVolumeShelveTestJSON(AttachVolumeTestJSON): - """Testing volume with shelved instance. - - This test checks the attaching and detaching volumes from - a shelved or shelved offload instance. - """ - - min_microversion = '2.20' - max_microversion = 'latest' - - def _count_volumes(self, server): - # Count number of volumes on an instance - volumes = 0 - if CONF.validation.run_validation: - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.image_ssh_user, - self.image_ssh_password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.servers_client) - - command = 'grep -c -E [vs]d.$ /proc/partitions' - volumes = int(linux_client.exec_command(command).strip()) - return volumes - - def _shelve_server(self, server): - # NOTE(andreaf) If we are going to shelve a server, we should - # check first whether the server is ssh-able. Otherwise we - # won't be able to distinguish failures introduced by shelve - # from pre-existing ones. Also it's good to wait for cloud-init - # to be done and sshd server to be running before shelving to - # avoid breaking the VM - if CONF.validation.run_validation: - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.image_ssh_user, - self.image_ssh_password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.servers_client) - linux_client.validate_authentication() - - # If validation went ok, or it was skipped, shelve the server - compute.shelve_server(self.servers_client, server['id']) - - def _unshelve_server_and_check_volumes(self, server, number_of_volumes): - # Unshelve the instance and check that there are expected volumes - self.servers_client.unshelve_server(server['id']) - waiters.wait_for_server_status(self.servers_client, - server['id'], - 'ACTIVE') - if CONF.validation.run_validation: - counted_volumes = self._count_volumes(server) - self.assertEqual(number_of_volumes, counted_volumes) - - @decorators.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - def test_attach_volume_shelved_or_offload_server(self): - # Create server, count number of volumes on it, shelve - # server and attach pre-created volume to shelved server - server = self._create_server() - volume = self.create_volume() - num_vol = self._count_volumes(server) - self._shelve_server(server) - attachment = self.attach_volume(server, volume, - device=('/dev/%s' % self.device), - check_reserved=True) - - # Unshelve the instance and check that attached volume exists - self._unshelve_server_and_check_volumes(server, num_vol + 1) - - # Get volume attachment of the server - volume_attachment = self.servers_client.show_volume_attachment( - server['id'], - attachment['id'])['volumeAttachment'] - self.assertEqual(server['id'], volume_attachment['serverId']) - self.assertEqual(attachment['id'], volume_attachment['id']) - # Check the mountpoint is not None after unshelve server even in - # case of shelved_offloaded. - self.assertIsNotNone(volume_attachment['device']) - - @decorators.idempotent_id('b54e86dd-a070-49c4-9c07-59ae6dae15aa') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - def test_detach_volume_shelved_or_offload_server(self): - # Count number of volumes on instance, shelve - # server and attach pre-created volume to shelved server - server = self._create_server() - volume = self.create_volume() - num_vol = self._count_volumes(server) - self._shelve_server(server) - - # Attach and then detach the volume - self.attach_volume(server, volume, device=('/dev/%s' % self.device), - check_reserved=True) - self.servers_client.detach_volume(server['id'], volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - # Unshelve the instance and check that we have the expected number of - # volume(s) - self._unshelve_server_and_check_volumes(server, num_vol) diff --git a/tempest/api/compute/volumes/test_attach_volume_negative.py b/tempest/api/compute/volumes/test_attach_volume_negative.py deleted file mode 100644 index eabb907ee..000000000 --- a/tempest/api/compute/volumes/test_attach_volume_negative.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class AttachVolumeNegativeTest(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(AttachVolumeNegativeTest, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @decorators.attr(type=['negative']) - @decorators.related_bug('1630783', status_code=500) - @decorators.idempotent_id('a313b5cd-fbd0-49cc-94de-870e99f763c7') - def test_delete_attached_volume(self): - server = self.create_test_server(wait_until='ACTIVE') - volume = self.create_volume() - - path = "/dev/%s" % CONF.compute.volume_device_name - self.attach_volume(server, volume, device=path) - - self.assertRaises(lib_exc.BadRequest, - self.delete_volume, volume['id']) diff --git a/tempest/api/compute/volumes/test_volume_snapshots.py b/tempest/api/compute/volumes/test_volume_snapshots.py deleted file mode 100644 index 0f436ebc7..000000000 --- a/tempest/api/compute/volumes/test_volume_snapshots.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2015 Fujitsu(fnst) Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -CONF = config.CONF - - -class VolumesSnapshotsTestJSON(base.BaseV2ComputeTest): - - # These tests will fail with a 404 starting from microversion 2.36. For - # more information, see: - # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(VolumesSnapshotsTestJSON, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(VolumesSnapshotsTestJSON, cls).setup_clients() - cls.volumes_client = cls.volumes_extensions_client - cls.snapshots_client = cls.snapshots_extensions_client - - @decorators.idempotent_id('cd4ec87d-7825-450d-8040-6e2068f2da8f') - @testtools.skipUnless(CONF.volume_feature_enabled.snapshot, - 'Cinder volume snapshots are disabled') - def test_volume_snapshot_create_get_list_delete(self): - volume = self.create_volume() - self.addCleanup(self.delete_volume, volume['id']) - - s_name = data_utils.rand_name(self.__class__.__name__ + '-Snapshot') - # Create snapshot - snapshot = self.snapshots_client.create_snapshot( - volume_id=volume['id'], - display_name=s_name)['snapshot'] - - def delete_snapshot(snapshot_id): - waiters.wait_for_volume_resource_status(self.snapshots_client, - snapshot_id, - 'available') - # Delete snapshot - self.snapshots_client.delete_snapshot(snapshot_id) - self.snapshots_client.wait_for_resource_deletion(snapshot_id) - - self.addCleanup(delete_snapshot, snapshot['id']) - self.assertEqual(volume['id'], snapshot['volumeId']) - # Get snapshot - fetched_snapshot = self.snapshots_client.show_snapshot( - snapshot['id'])['snapshot'] - self.assertEqual(s_name, fetched_snapshot['displayName']) - self.assertEqual(volume['id'], fetched_snapshot['volumeId']) - # Fetch all snapshots - snapshots = self.snapshots_client.list_snapshots()['snapshots'] - self.assertIn(snapshot['id'], map(lambda x: x['id'], snapshots)) diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py deleted file mode 100644 index 01cfb5f3d..000000000 --- a/tempest/api/compute/volumes/test_volumes_get.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from testtools import matchers - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -CONF = config.CONF - - -class VolumesGetTestJSON(base.BaseV2ComputeTest): - - # These tests will fail with a 404 starting from microversion 2.36. For - # more information, see: - # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(VolumesGetTestJSON, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(VolumesGetTestJSON, cls).setup_clients() - cls.volumes_client = cls.volumes_extensions_client - - @decorators.idempotent_id('f10f25eb-9775-4d9d-9cbe-1cf54dae9d5f') - def test_volume_create_get_delete(self): - # CREATE, GET, DELETE Volume - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - metadata = {'Type': 'work'} - # Create volume - volume = self.create_volume(size=CONF.volume.volume_size, - display_name=v_name, - metadata=metadata) - self.assertIn('id', volume) - self.assertIn('displayName', volume) - self.assertEqual(volume['displayName'], v_name, - "The created volume name is not equal " - "to the requested name") - self.assertIsNotNone(volume['id'], - "Field volume id is empty or not found.") - # GET Volume - fetched_volume = self.volumes_client.show_volume( - volume['id'])['volume'] - # Verification of details of fetched Volume - self.assertEqual(v_name, - fetched_volume['displayName'], - 'The fetched Volume is different ' - 'from the created Volume') - self.assertEqual(CONF.volume.volume_size, - fetched_volume['size'], - 'The fetched volume size is different ' - 'from the created Volume') - self.assertEqual(volume['id'], - fetched_volume['id'], - 'The fetched Volume is different ' - 'from the created Volume') - self.assertThat(fetched_volume['metadata'].items(), - matchers.ContainsAll(metadata.items()), - 'The fetched Volume metadata misses data ' - 'from the created Volume') diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py deleted file mode 100644 index b2aebe79b..000000000 --- a/tempest/api/compute/volumes/test_volumes_list.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesTestJSON(base.BaseV2ComputeTest): - # NOTE: This test creates a number of 1G volumes. To run successfully, - # ensure that the backing file for the volume group that Nova uses - # has space for at least 3 1G volumes! - # If you are running a Devstack environment, ensure that the - # VOLUME_BACKING_FILE_SIZE is at least 4G in your localrc - - # These tests will fail with a 404 starting from microversion 2.36. For - # more information, see: - # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(VolumesTestJSON, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(VolumesTestJSON, cls).setup_clients() - cls.client = cls.volumes_extensions_client - - @classmethod - def resource_setup(cls): - super(VolumesTestJSON, cls).resource_setup() - # Create 3 Volumes - cls.volume_list = [] - for _ in range(3): - metadata = {'Type': 'work'} - volume = cls.create_volume(metadata=metadata) - volume = cls.client.show_volume(volume['id'])['volume'] - cls.volume_list.append(volume) - - @decorators.idempotent_id('bc2dd1a0-15af-48e5-9990-f2e75a48325d') - def test_volume_list(self): - # Should return the list of Volumes - # Fetch all Volumes - fetched_list = self.client.list_volumes()['volumes'] - # Now check if all the Volumes created in setup are in fetched list - missing_volumes = [ - v for v in self.volume_list if v not in fetched_list - ] - - self.assertFalse(missing_volumes, - "Failed to find volume %s in fetched list" % - ', '.join(m_vol['displayName'] - for m_vol in missing_volumes)) - - @decorators.idempotent_id('bad0567a-5a4f-420b-851e-780b55bb867c') - def test_volume_list_with_details(self): - # Should return the list of Volumes with details - # Fetch all Volumes - fetched_list = self.client.list_volumes(detail=True)['volumes'] - # Now check if all the Volumes created in setup are in fetched list - missing_volumes = [ - v for v in self.volume_list if v not in fetched_list - ] - - self.assertFalse(missing_volumes, - "Failed to find volume %s in fetched list" % - ', '.join(m_vol['displayName'] - for m_vol in missing_volumes)) - - @decorators.idempotent_id('1048ed81-2baf-487a-b284-c0622b86e7b8') - def test_volume_list_param_limit(self): - # Return the list of volumes based on limit set - params = {'limit': 2} - fetched_vol_list = self.client.list_volumes(**params)['volumes'] - - self.assertEqual(len(fetched_vol_list), params['limit'], - "Failed to list volumes by limit set") - - @decorators.idempotent_id('33985568-4965-49d5-9bcc-0aa007ca5b7a') - def test_volume_list_with_detail_param_limit(self): - # Return the list of volumes with details based on limit set. - params = {'limit': 2} - fetched_vol_list = self.client.list_volumes(detail=True, - **params)['volumes'] - - self.assertEqual(len(fetched_vol_list), params['limit'], - "Failed to list volume details by limit set") - - @decorators.idempotent_id('51c22651-a074-4ea7-af0b-094f9331303e') - def test_volume_list_param_offset_and_limit(self): - # Return the list of volumes based on offset and limit set. - # get all volumes list - all_vol_list = self.client.list_volumes()['volumes'] - params = {'offset': 1, 'limit': 1} - fetched_vol_list = self.client.list_volumes(**params)['volumes'] - - # Validating length of the fetched volumes - self.assertEqual(len(fetched_vol_list), params['limit'], - "Failed to list volumes by offset and limit") - # Validating offset of fetched volume - for index, volume in enumerate(fetched_vol_list): - self.assertEqual(volume['id'], - all_vol_list[index + params['offset']]['id'], - "Failed to list volumes by offset and limit") - - @decorators.idempotent_id('06b6abc4-3f10-48e9-a7a1-3facc98f03e5') - def test_volume_list_with_detail_param_offset_and_limit(self): - # Return the list of volumes details based on offset and limit set. - # get all volumes list - all_vol_list = self.client.list_volumes(detail=True)['volumes'] - params = {'offset': 1, 'limit': 1} - fetched_vol_list = self.client.list_volumes(detail=True, - **params)['volumes'] - - # Validating length of the fetched volumes - self.assertEqual(len(fetched_vol_list), params['limit'], - "Failed to list volume details by offset and limit") - # Validating offset of fetched volume - for index, volume in enumerate(fetched_vol_list): - self.assertEqual(volume['id'], - all_vol_list[index + params['offset']]['id'], - "Failed to list volume details by " - "offset and limit") diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py deleted file mode 100644 index 87f7d8a49..000000000 --- a/tempest/api/compute/volumes/test_volumes_negative.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class VolumesNegativeTest(base.BaseV2ComputeTest): - - # These tests will fail with a 404 starting from microversion 2.36. For - # more information, see: - # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(VolumesNegativeTest, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(VolumesNegativeTest, cls).setup_clients() - cls.client = cls.volumes_extensions_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c03ea686-905b-41a2-8748-9635154b7c57') - def test_volume_get_nonexistent_volume_id(self): - # Negative: Should not be able to get details of nonexistent volume - # Creating a nonexistent volume id - # Trying to GET a non existent volume - self.assertRaises(lib_exc.NotFound, self.client.show_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('54a34226-d910-4b00-9ef8-8683e6c55846') - def test_volume_delete_nonexistent_volume_id(self): - # Negative: Should not be able to delete nonexistent Volume - # Creating nonexistent volume id - # Trying to DELETE a non existent volume - self.assertRaises(lib_exc.NotFound, self.client.delete_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5125ae14-152b-40a7-b3c5-eae15e9022ef') - def test_create_volume_with_invalid_size(self): - # Negative: Should not be able to create volume with invalid size - # in request - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - metadata = {'Type': 'work'} - self.assertRaises(lib_exc.BadRequest, self.client.create_volume, - size='#$%', display_name=v_name, metadata=metadata) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('131cb3a1-75cc-4d40-b4c3-1317f64719b0') - def test_create_volume_without_passing_size(self): - # Negative: Should not be able to create volume without passing size - # in request - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - metadata = {'Type': 'work'} - self.assertRaises(lib_exc.BadRequest, self.client.create_volume, - size='', display_name=v_name, metadata=metadata) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8cce995e-0a83-479a-b94d-e1e40b8a09d1') - def test_create_volume_with_size_zero(self): - # Negative: Should not be able to create volume with size zero - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - metadata = {'Type': 'work'} - self.assertRaises(lib_exc.BadRequest, self.client.create_volume, - size='0', display_name=v_name, metadata=metadata) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('62bab09a-4c03-4617-8cca-8572bc94af9b') - def test_get_volume_without_passing_volume_id(self): - # Negative: Should not be able to get volume when empty ID is passed - self.assertRaises(lib_exc.NotFound, self.client.show_volume, '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('62972737-124b-4513-b6cf-2f019f178494') - def test_delete_invalid_volume_id(self): - # Negative: Should not be able to delete volume when invalid ID is - # passed - self.assertRaises(lib_exc.NotFound, - self.client.delete_volume, - data_utils.rand_name('invalid')) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0d1417c5-4ae8-4c2c-adc5-5f0b864253e5') - def test_delete_volume_without_passing_volume_id(self): - # Negative: Should not be able to delete volume when empty ID is passed - self.assertRaises(lib_exc.NotFound, self.client.delete_volume, '') diff --git a/tempest/api/identity/__init__.py b/tempest/api/identity/__init__.py deleted file mode 100644 index 17efdcc37..000000000 --- a/tempest/api/identity/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging - -LOG = logging.getLogger(__name__) - - -# All identity tests -- single setup function -def setup_package(): - LOG.debug("Entering tempest.api.identity.setup_package") diff --git a/tempest/api/identity/admin/__init__.py b/tempest/api/identity/admin/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/identity/admin/v2/__init__.py b/tempest/api/identity/admin/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/identity/admin/v2/test_endpoints.py b/tempest/api/identity/admin/v2/test_endpoints.py deleted file mode 100644 index 59fc4d8c7..000000000 --- a/tempest/api/identity/admin/v2/test_endpoints.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class EndPointsTestJSON(base.BaseIdentityV2AdminTest): - - @classmethod - def resource_setup(cls): - super(EndPointsTestJSON, cls).resource_setup() - cls.service_ids = list() - s_name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - s_description = data_utils.rand_name('description') - service_data = cls.services_client.create_service( - name=s_name, type=s_type, - description=s_description)['OS-KSADM:service'] - cls.service_id = service_data['id'] - cls.service_ids.append(cls.service_id) - # Create endpoints so as to use for LIST and GET test cases - cls.setup_endpoints = list() - for _ in range(2): - region = data_utils.rand_name('region') - url = data_utils.rand_url() - endpoint = cls.endpoints_client.create_endpoint( - service_id=cls.service_id, - region=region, - publicurl=url, - adminurl=url, - internalurl=url)['endpoint'] - # list_endpoints() will return 'enabled' field - endpoint['enabled'] = True - cls.setup_endpoints.append(endpoint) - - @classmethod - def resource_cleanup(cls): - for e in cls.setup_endpoints: - cls.endpoints_client.delete_endpoint(e['id']) - for s in cls.service_ids: - cls.services_client.delete_service(s) - super(EndPointsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('11f590eb-59d8-4067-8b2b-980c7f387f51') - def test_list_endpoints(self): - # Get a list of endpoints - fetched_endpoints = self.endpoints_client.list_endpoints()['endpoints'] - # Asserting LIST endpoints - missing_endpoints =\ - [e for e in self.setup_endpoints if e not in fetched_endpoints] - self.assertEmpty(missing_endpoints, - "Failed to find endpoint %s in fetched list" % - ', '.join(str(e) for e in missing_endpoints)) - - @decorators.idempotent_id('9974530a-aa28-4362-8403-f06db02b26c1') - def test_create_list_delete_endpoint(self): - region = data_utils.rand_name('region') - url = data_utils.rand_url() - endpoint = self.endpoints_client.create_endpoint( - service_id=self.service_id, - region=region, - publicurl=url, - adminurl=url, - internalurl=url)['endpoint'] - # Asserting Create Endpoint response body - self.assertIn('id', endpoint) - self.assertEqual(region, endpoint['region']) - self.assertEqual(url, endpoint['publicurl']) - # Checking if created endpoint is present in the list of endpoints - fetched_endpoints = self.endpoints_client.list_endpoints()['endpoints'] - fetched_endpoints_id = [e['id'] for e in fetched_endpoints] - self.assertIn(endpoint['id'], fetched_endpoints_id) - # Deleting the endpoint created in this method - self.endpoints_client.delete_endpoint(endpoint['id']) - # Checking whether endpoint is deleted successfully - fetched_endpoints = self.endpoints_client.list_endpoints()['endpoints'] - fetched_endpoints_id = [e['id'] for e in fetched_endpoints] - self.assertNotIn(endpoint['id'], fetched_endpoints_id) diff --git a/tempest/api/identity/admin/v2/test_roles.py b/tempest/api/identity/admin/v2/test_roles.py deleted file mode 100644 index 124bb5f66..000000000 --- a/tempest/api/identity/admin/v2/test_roles.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - - -class RolesTestJSON(base.BaseIdentityV2AdminTest): - - @classmethod - def resource_setup(cls): - super(RolesTestJSON, cls).resource_setup() - cls.roles = list() - for _ in range(5): - role_name = data_utils.rand_name(name='role') - role = cls.roles_client.create_role(name=role_name)['role'] - cls.roles.append(role) - - @classmethod - def resource_cleanup(cls): - super(RolesTestJSON, cls).resource_cleanup() - for role in cls.roles: - cls.roles_client.delete_role(role['id']) - - def _get_role_params(self): - user = self.setup_test_user() - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - role = self.setup_test_role() - return (user, tenant, role) - - def assert_role_in_role_list(self, role, roles): - found = False - for user_role in roles: - if user_role['id'] == role['id']: - found = True - self.assertTrue(found, "assigned role was not in list") - - @decorators.idempotent_id('75d9593f-50b7-4fcf-bd64-e3fb4a278e23') - def test_list_roles(self): - """Return a list of all roles.""" - body = self.roles_client.list_roles()['roles'] - found = [role for role in body if role in self.roles] - self.assertNotEmpty(found) - self.assertEqual(len(found), len(self.roles)) - - @decorators.idempotent_id('c62d909d-6c21-48c0-ae40-0a0760e6db5e') - def test_role_create_delete(self): - """Role should be created, verified, and deleted.""" - role_name = data_utils.rand_name(name='role-test') - body = self.roles_client.create_role(name=role_name)['role'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role, body['id']) - self.assertEqual(role_name, body['name']) - - body = self.roles_client.list_roles()['roles'] - found = [role for role in body if role['name'] == role_name] - self.assertNotEmpty(found) - - body = self.roles_client.delete_role(found[0]['id']) - - body = self.roles_client.list_roles()['roles'] - found = [role for role in body if role['name'] == role_name] - self.assertEmpty(found) - - @decorators.idempotent_id('db6870bd-a6ed-43be-a9b1-2f10a5c9994f') - def test_get_role_by_id(self): - """Get a role by its id.""" - role = self.setup_test_role() - role_id = role['id'] - role_name = role['name'] - body = self.roles_client.show_role(role_id)['role'] - self.assertEqual(role_id, body['id']) - self.assertEqual(role_name, body['name']) - - @decorators.idempotent_id('0146f675-ffbd-4208-b3a4-60eb628dbc5e') - def test_assign_user_role(self): - """Assign a role to a user on a tenant.""" - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - roles = self.roles_client.list_user_roles_on_project( - tenant['id'], user['id'])['roles'] - self.assert_role_in_role_list(role, roles) - - @decorators.idempotent_id('f0b9292c-d3ba-4082-aa6c-440489beef69') - def test_remove_user_role(self): - """Remove a role assigned to a user on a tenant.""" - (user, tenant, role) = self._get_role_params() - user_role = self.roles_client.create_user_role_on_project( - tenant['id'], user['id'], role['id'])['role'] - self.roles_client.delete_role_from_user_on_project(tenant['id'], - user['id'], - user_role['id']) - - @decorators.idempotent_id('262e1e3e-ed71-4edd-a0e5-d64e83d66d05') - def test_list_user_roles(self): - """List roles assigned to a user on tenant.""" - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - roles = self.roles_client.list_user_roles_on_project( - tenant['id'], user['id'])['roles'] - self.assert_role_in_role_list(role, roles) diff --git a/tempest/api/identity/admin/v2/test_roles_negative.py b/tempest/api/identity/admin/v2/test_roles_negative.py deleted file mode 100644 index f3b7494c1..000000000 --- a/tempest/api/identity/admin/v2/test_roles_negative.py +++ /dev/null @@ -1,256 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class RolesNegativeTestJSON(base.BaseIdentityV2AdminTest): - - def _get_role_params(self): - user = self.setup_test_user() - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - role = self.setup_test_role() - return (user, tenant, role) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d5d5f1df-f8ca-4de0-b2ef-259c1cc67025') - def test_list_roles_by_unauthorized_user(self): - # Non-administrator user should not be able to list roles - self.assertRaises(lib_exc.Forbidden, - self.non_admin_roles_client.list_roles) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('11a3c7da-df6c-40c2-abc2-badd682edf9f') - def test_list_roles_request_without_token(self): - # Request to list roles without a valid token should fail - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, self.roles_client.list_roles) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c0b89e56-accc-4c73-85f8-9c0f866104c1') - def test_role_create_blank_name(self): - # Should not be able to create a role with a blank name - self.assertRaises(lib_exc.BadRequest, self.roles_client.create_role, - name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('585c8998-a8a4-4641-a5dd-abef7a8ced00') - def test_create_role_by_unauthorized_user(self): - # Non-administrator user should not be able to create role - role_name = data_utils.rand_name(name='role') - self.assertRaises(lib_exc.Forbidden, - self.non_admin_roles_client.create_role, - name=role_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a7edd17a-e34a-4aab-8bb7-fa6f498645b8') - def test_create_role_request_without_token(self): - # Request to create role without a valid token should fail - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - role_name = data_utils.rand_name(name='role') - self.assertRaises(lib_exc.Unauthorized, - self.roles_client.create_role, name=role_name) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c0cde2c8-81c1-4bb0-8fe2-cf615a3547a8') - def test_role_create_duplicate(self): - # Role names should be unique - role_name = data_utils.rand_name(name='role-dup') - body = self.roles_client.create_role(name=role_name)['role'] - role1_id = body.get('id') - self.addCleanup(self.roles_client.delete_role, role1_id) - self.assertRaises(lib_exc.Conflict, self.roles_client.create_role, - name=role_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('15347635-b5b1-4a87-a280-deb2bd6d865e') - def test_delete_role_by_unauthorized_user(self): - # Non-administrator user should not be able to delete role - role_name = data_utils.rand_name(name='role') - body = self.roles_client.create_role(name=role_name)['role'] - self.addCleanup(self.roles_client.delete_role, body['id']) - role_id = body.get('id') - self.assertRaises(lib_exc.Forbidden, - self.non_admin_roles_client.delete_role, role_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('44b60b20-70de-4dac-beaf-a3fc2650a16b') - def test_delete_role_request_without_token(self): - # Request to delete role without a valid token should fail - role_name = data_utils.rand_name(name='role') - body = self.roles_client.create_role(name=role_name)['role'] - self.addCleanup(self.roles_client.delete_role, body['id']) - role_id = body.get('id') - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.roles_client.delete_role, - role_id) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('38373691-8551-453a-b074-4260ad8298ef') - def test_delete_role_non_existent(self): - # Attempt to delete a non existent role should fail - non_existent_role = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, self.roles_client.delete_role, - non_existent_role) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('391df5cf-3ec3-46c9-bbe5-5cb58dd4dc41') - def test_assign_user_role_by_unauthorized_user(self): - # Non-administrator user should not be authorized to - # assign a role to user - (user, tenant, role) = self._get_role_params() - self.assertRaises( - lib_exc.Forbidden, - self.non_admin_roles_client.create_user_role_on_project, - tenant['id'], user['id'], role['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f0d2683c-5603-4aee-95d7-21420e87cfd8') - def test_assign_user_role_request_without_token(self): - # Request to assign a role to a user without a valid token - (user, tenant, role) = self._get_role_params() - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises( - lib_exc.Unauthorized, - self.roles_client.create_user_role_on_project, tenant['id'], - user['id'], role['id']) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('99b297f6-2b5d-47c7-97a9-8b6bb4f91042') - def test_assign_user_role_for_non_existent_role(self): - # Attempt to assign a non existent role to user should fail - (user, tenant, _) = self._get_role_params() - non_existent_role = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, - self.roles_client.create_user_role_on_project, - tenant['id'], user['id'], non_existent_role) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b2285aaa-9e76-4704-93a9-7a8acd0a6c8f') - def test_assign_user_role_for_non_existent_tenant(self): - # Attempt to assign a role on a non existent tenant should fail - (user, _, role) = self._get_role_params() - non_existent_tenant = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, - self.roles_client.create_user_role_on_project, - non_existent_tenant, user['id'], role['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5c3132cd-c4c8-4402-b5ea-71eb44e97793') - def test_assign_duplicate_user_role(self): - # Duplicate user role should not get assigned - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - self.assertRaises(lib_exc.Conflict, - self.roles_client.create_user_role_on_project, - tenant['id'], user['id'], role['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d0537987-0977-448f-a435-904c15de7298') - def test_remove_user_role_by_unauthorized_user(self): - # Non-administrator user should not be authorized to - # remove a user's role - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - self.assertRaises( - lib_exc.Forbidden, - self.non_admin_roles_client.delete_role_from_user_on_project, - tenant['id'], user['id'], role['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('cac81cf4-c1d2-47dc-90d3-f2b7eb572286') - def test_remove_user_role_request_without_token(self): - # Request to remove a user's role without a valid token - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.roles_client.delete_role_from_user_on_project, - tenant['id'], user['id'], role['id']) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ab32d759-cd16-41f1-a86e-44405fa9f6d2') - def test_remove_user_role_non_existent_role(self): - # Attempt to delete a non existent role from a user should fail - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - non_existent_role = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, - self.roles_client.delete_role_from_user_on_project, - tenant['id'], user['id'], non_existent_role) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('67a679ec-03dd-4551-bbfc-d1c93284f023') - def test_remove_user_role_non_existent_tenant(self): - # Attempt to remove a role from a non existent tenant should fail - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - non_existent_tenant = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, - self.roles_client.delete_role_from_user_on_project, - non_existent_tenant, user['id'], role['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7391ab4c-06f3-477a-a64a-c8e55ce89837') - def test_list_user_roles_by_unauthorized_user(self): - # Non-administrator user should not be authorized to list - # a user's roles - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - self.assertRaises( - lib_exc.Forbidden, - self.non_admin_roles_client.list_user_roles_on_project, - tenant['id'], user['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('682adfb2-fd5f-4b0a-a9ca-322e9bebb907') - def test_list_user_roles_request_without_token(self): - # Request to list user's roles without a valid token should fail - (user, tenant, _) = self._get_role_params() - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - try: - self.assertRaises(lib_exc.Unauthorized, - self.roles_client.list_user_roles_on_project, - tenant['id'], - user['id']) - finally: - self.client.auth_provider.clear_auth() diff --git a/tempest/api/identity/admin/v2/test_services.py b/tempest/api/identity/admin/v2/test_services.py deleted file mode 100644 index 634cf21f2..000000000 --- a/tempest/api/identity/admin/v2/test_services.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ServicesTestJSON(base.BaseIdentityV2AdminTest): - - def _del_service(self, service_id): - # Deleting the service created in this method - self.services_client.delete_service(service_id) - # Checking whether service is deleted successfully - self.assertRaises(lib_exc.NotFound, self.services_client.show_service, - service_id) - - @decorators.idempotent_id('84521085-c6e6-491c-9a08-ec9f70f90110') - def test_create_get_delete_service(self): - # GET Service - # Creating a Service - name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - description = data_utils.rand_name('description') - service_data = self.services_client.create_service( - name=name, type=s_type, - description=description)['OS-KSADM:service'] - self.assertIsNotNone(service_data['id']) - self.addCleanup(self._del_service, service_data['id']) - # Verifying response body of create service - self.assertIn('id', service_data) - self.assertIn('name', service_data) - self.assertEqual(name, service_data['name']) - self.assertIn('type', service_data) - self.assertEqual(s_type, service_data['type']) - self.assertIn('description', service_data) - self.assertEqual(description, service_data['description']) - # Get service - fetched_service = ( - self.services_client.show_service(service_data['id']) - ['OS-KSADM:service']) - # verifying the existence of service created - self.assertIn('id', fetched_service) - self.assertEqual(fetched_service['id'], service_data['id']) - self.assertIn('name', fetched_service) - self.assertEqual(fetched_service['name'], service_data['name']) - self.assertIn('type', fetched_service) - self.assertEqual(fetched_service['type'], service_data['type']) - self.assertIn('description', fetched_service) - self.assertEqual(fetched_service['description'], - service_data['description']) - - @decorators.idempotent_id('5d3252c8-e555-494b-a6c8-e11d7335da42') - def test_create_service_without_description(self): - # Create a service only with name and type - name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - service = self.services_client.create_service( - name=name, type=s_type)['OS-KSADM:service'] - self.assertIn('id', service) - self.addCleanup(self._del_service, service['id']) - self.assertIn('name', service) - self.assertEqual(name, service['name']) - self.assertIn('type', service) - self.assertEqual(s_type, service['type']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('34ea6489-012d-4a86-9038-1287cadd5eca') - def test_list_services(self): - # Create, List, Verify and Delete Services - services = [] - for _ in range(3): - name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - description = data_utils.rand_name('description') - - service = self.services_client.create_service( - name=name, type=s_type, - description=description)['OS-KSADM:service'] - services.append(service) - service_ids = [svc['id'] for svc in services] - - def delete_services(): - for service_id in service_ids: - self.services_client.delete_service(service_id) - - self.addCleanup(delete_services) - # List and Verify Services - body = self.services_client.list_services()['OS-KSADM:services'] - found = [serv for serv in body if serv['id'] in service_ids] - self.assertEqual(len(found), len(services), 'Services not found') diff --git a/tempest/api/identity/admin/v2/test_tenant_negative.py b/tempest/api/identity/admin/v2/test_tenant_negative.py deleted file mode 100644 index 49bb949cf..000000000 --- a/tempest/api/identity/admin/v2/test_tenant_negative.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class TenantsNegativeTestJSON(base.BaseIdentityV2AdminTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ca9bb202-63dd-4240-8a07-8ef9c19c04bb') - def test_list_tenants_by_unauthorized_user(self): - # Non-administrator user should not be able to list tenants - self.assertRaises(lib_exc.Forbidden, - self.non_admin_tenants_client.list_tenants) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('df33926c-1c96-4d8d-a762-79cc6b0c3cf4') - def test_list_tenant_request_without_token(self): - # Request to list tenants without a valid token should fail - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.tenants_client.list_tenants) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('162ba316-f18b-4987-8c0c-fd9140cd63ed') - def test_tenant_delete_by_unauthorized_user(self): - # Non-administrator user should not be able to delete a tenant - tenant = self.setup_test_tenant() - self.assertRaises(lib_exc.Forbidden, - self.non_admin_tenants_client.delete_tenant, - tenant['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e450db62-2e9d-418f-893a-54772d6386b1') - def test_tenant_delete_request_without_token(self): - # Request to delete a tenant without a valid token should fail - tenant = self.setup_test_tenant() - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.tenants_client.delete_tenant, - tenant['id']) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9c9a2aed-6e3c-467a-8f5c-89da9d1b516b') - def test_delete_non_existent_tenant(self): - # Attempt to delete a non existent tenant should fail - self.assertRaises(lib_exc.NotFound, self.tenants_client.delete_tenant, - data_utils.rand_uuid_hex()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('af16f44b-a849-46cb-9f13-a751c388f739') - def test_tenant_create_duplicate(self): - # Tenant names should be unique - tenant_name = data_utils.rand_name(name='tenant') - self.setup_test_tenant(name=tenant_name) - self.assertRaises(lib_exc.Conflict, self.tenants_client.create_tenant, - name=tenant_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d26b278a-6389-4702-8d6e-5980d80137e0') - def test_create_tenant_by_unauthorized_user(self): - # Non-administrator user should not be authorized to create a tenant - tenant_name = data_utils.rand_name(name='tenant') - self.assertRaises(lib_exc.Forbidden, - self.non_admin_tenants_client.create_tenant, - name=tenant_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a3ee9d7e-6920-4dd5-9321-d4b2b7f0a638') - def test_create_tenant_request_without_token(self): - # Create tenant request without a token should not be authorized - tenant_name = data_utils.rand_name(name='tenant') - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.tenants_client.create_tenant, - name=tenant_name) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5a2e4ca9-b0c0-486c-9c48-64a94fba2395') - def test_create_tenant_with_empty_name(self): - # Tenant name should not be empty - self.assertRaises(lib_exc.BadRequest, - self.tenants_client.create_tenant, - name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('2ff18d1e-dfe3-4359-9dc3-abf582c196b9') - def test_create_tenants_name_length_over_64(self): - # Tenant name length should not be greater than 64 characters - tenant_name = 'a' * 65 - self.assertRaises(lib_exc.BadRequest, - self.tenants_client.create_tenant, - name=tenant_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bd20dc2a-9557-4db7-b755-f48d952ad706') - def test_update_non_existent_tenant(self): - # Attempt to update a non existent tenant should fail - self.assertRaises(lib_exc.NotFound, self.tenants_client.update_tenant, - data_utils.rand_uuid_hex()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('41704dc5-c5f7-4f79-abfa-76e6fedc570b') - def test_tenant_update_by_unauthorized_user(self): - # Non-administrator user should not be able to update a tenant - tenant = self.setup_test_tenant() - self.assertRaises(lib_exc.Forbidden, - self.non_admin_tenants_client.update_tenant, - tenant['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7a421573-72c7-4c22-a98e-ce539219c657') - def test_tenant_update_request_without_token(self): - # Request to update a tenant without a valid token should fail - tenant = self.setup_test_tenant() - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.tenants_client.update_tenant, - tenant['id']) - self.client.auth_provider.clear_auth() diff --git a/tempest/api/identity/admin/v2/test_tenants.py b/tempest/api/identity/admin/v2/test_tenants.py deleted file mode 100644 index 0f955bf8f..000000000 --- a/tempest/api/identity/admin/v2/test_tenants.py +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class TenantsTestJSON(base.BaseIdentityV2AdminTest): - - @decorators.idempotent_id('16c6e05c-6112-4b0e-b83f-5e43f221b6b0') - def test_tenant_list_delete(self): - # Create several tenants and delete them - tenants = [] - for _ in range(3): - tenant = self.setup_test_tenant() - tenants.append(tenant) - tenant_ids = [tn['id'] for tn in tenants] - body = self.tenants_client.list_tenants()['tenants'] - found = [t for t in body if t['id'] in tenant_ids] - self.assertEqual(len(found), len(tenants), 'Tenants not created') - - for tenant in tenants: - self.tenants_client.delete_tenant(tenant['id']) - - body = self.tenants_client.list_tenants()['tenants'] - found = [tenant for tenant in body if tenant['id'] in tenant_ids] - self.assertEmpty(found, 'Tenants failed to delete') - - @decorators.idempotent_id('d25e9f24-1310-4d29-b61b-d91299c21d6d') - def test_tenant_create_with_description(self): - # Create tenant with a description - tenant_desc = data_utils.rand_name(name='desc') - tenant = self.setup_test_tenant(description=tenant_desc) - tenant_id = tenant['id'] - desc1 = tenant['description'] - self.assertEqual(desc1, tenant_desc, 'Description should have ' - 'been sent in response for create') - body = self.tenants_client.show_tenant(tenant_id)['tenant'] - desc2 = body['description'] - self.assertEqual(desc2, tenant_desc, 'Description does not appear' - 'to be set') - self.tenants_client.delete_tenant(tenant_id) - - @decorators.idempotent_id('670bdddc-1cd7-41c7-b8e2-751cfb67df50') - def test_tenant_create_enabled(self): - # Create a tenant that is enabled - tenant = self.setup_test_tenant(enabled=True) - tenant_id = tenant['id'] - en1 = tenant['enabled'] - self.assertTrue(en1, 'Enable should be True in response') - body = self.tenants_client.show_tenant(tenant_id)['tenant'] - en2 = body['enabled'] - self.assertTrue(en2, 'Enable should be True in lookup') - self.tenants_client.delete_tenant(tenant_id) - - @decorators.idempotent_id('3be22093-b30f-499d-b772-38340e5e16fb') - def test_tenant_create_not_enabled(self): - # Create a tenant that is not enabled - tenant = self.setup_test_tenant(enabled=False) - tenant_id = tenant['id'] - en1 = tenant['enabled'] - self.assertEqual('false', str(en1).lower(), - 'Enable should be False in response') - body = self.tenants_client.show_tenant(tenant_id)['tenant'] - en2 = body['enabled'] - self.assertEqual('false', str(en2).lower(), - 'Enable should be False in lookup') - self.tenants_client.delete_tenant(tenant_id) - - @decorators.idempotent_id('781f2266-d128-47f3-8bdb-f70970add238') - def test_tenant_update_name(self): - # Update name attribute of a tenant - t_name1 = data_utils.rand_name(name='tenant') - tenant = self.setup_test_tenant(name=t_name1) - t_id = tenant['id'] - resp1_name = tenant['name'] - - t_name2 = data_utils.rand_name(name='tenant2') - body = self.tenants_client.update_tenant(t_id, name=t_name2)['tenant'] - resp2_name = body['name'] - self.assertNotEqual(resp1_name, resp2_name) - - body = self.tenants_client.show_tenant(t_id)['tenant'] - resp3_name = body['name'] - - self.assertNotEqual(resp1_name, resp3_name) - self.assertEqual(t_name1, resp1_name) - self.assertEqual(resp2_name, resp3_name) - - self.tenants_client.delete_tenant(t_id) - - @decorators.idempotent_id('859fcfe1-3a03-41ef-86f9-b19a47d1cd87') - def test_tenant_update_desc(self): - # Update description attribute of a tenant - t_desc = data_utils.rand_name(name='desc') - tenant = self.setup_test_tenant(description=t_desc) - t_id = tenant['id'] - resp1_desc = tenant['description'] - - t_desc2 = data_utils.rand_name(name='desc2') - body = self.tenants_client.update_tenant(t_id, description=t_desc2) - updated_tenant = body['tenant'] - resp2_desc = updated_tenant['description'] - self.assertNotEqual(resp1_desc, resp2_desc) - - body = self.tenants_client.show_tenant(t_id)['tenant'] - resp3_desc = body['description'] - - self.assertNotEqual(resp1_desc, resp3_desc) - self.assertEqual(t_desc, resp1_desc) - self.assertEqual(resp2_desc, resp3_desc) - - self.tenants_client.delete_tenant(t_id) - - @decorators.idempotent_id('8fc8981f-f12d-4c66-9972-2bdcf2bc2e1a') - def test_tenant_update_enable(self): - # Update the enabled attribute of a tenant - t_en = False - tenant = self.setup_test_tenant(enabled=t_en) - t_id = tenant['id'] - resp1_en = tenant['enabled'] - - t_en2 = True - body = self.tenants_client.update_tenant(t_id, enabled=t_en2) - updated_tenant = body['tenant'] - resp2_en = updated_tenant['enabled'] - self.assertNotEqual(resp1_en, resp2_en) - - body = self.tenants_client.show_tenant(t_id)['tenant'] - resp3_en = body['enabled'] - - self.assertNotEqual(resp1_en, resp3_en) - self.assertEqual('false', str(resp1_en).lower()) - self.assertEqual(resp2_en, resp3_en) - - self.tenants_client.delete_tenant(t_id) diff --git a/tempest/api/identity/admin/v2/test_tokens.py b/tempest/api/identity/admin/v2/test_tokens.py deleted file mode 100644 index 6b30d23cc..000000000 --- a/tempest/api/identity/admin/v2/test_tokens.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class TokensTestJSON(base.BaseIdentityV2AdminTest): - - @decorators.idempotent_id('453ad4d5-e486-4b2f-be72-cffc8149e586') - def test_create_check_get_delete_token(self): - # get a token by username and password - user_name = data_utils.rand_name(name='user') - user_password = data_utils.rand_password() - # first:create a tenant - tenant = self.setup_test_tenant() - # second:create a user - user = self.create_test_user(name=user_name, - password=user_password, - tenantId=tenant['id'], - email='') - # then get a token for the user - body = self.token_client.auth(user_name, - user_password, - tenant['name']) - self.assertEqual(body['token']['tenant']['name'], - tenant['name']) - # Perform GET Token - token_id = body['token']['id'] - self.client.check_token_existence(token_id) - token_details = self.client.show_token(token_id)['access'] - self.assertEqual(token_id, token_details['token']['id']) - self.assertEqual(user['id'], token_details['user']['id']) - self.assertEqual(user_name, token_details['user']['name']) - self.assertEqual(tenant['name'], - token_details['token']['tenant']['name']) - # then delete the token - self.client.delete_token(token_id) - self.assertRaises(lib_exc.NotFound, - self.client.check_token_existence, - token_id) - - @decorators.idempotent_id('25ba82ee-8a32-4ceb-8f50-8b8c71e8765e') - def test_rescope_token(self): - """An unscoped token can be requested - - That token can be used to request a scoped token. - """ - - # Create a user. - user_name = data_utils.rand_name(name='user') - user_password = data_utils.rand_password() - tenant_id = None # No default tenant so will get unscoped token. - user = self.create_test_user(name=user_name, - password=user_password, - tenantId=tenant_id, - email='') - - # Create a couple tenants. - tenant1_name = data_utils.rand_name(name='tenant') - tenant1 = self.setup_test_tenant(name=tenant1_name) - - tenant2_name = data_utils.rand_name(name='tenant') - tenant2 = self.setup_test_tenant(name=tenant2_name) - - # Create a role - role = self.setup_test_role() - - # Grant the user the role on the tenants. - self.roles_client.create_user_role_on_project(tenant1['id'], - user['id'], - role['id']) - - self.roles_client.create_user_role_on_project(tenant2['id'], - user['id'], - role['id']) - - # Get an unscoped token. - body = self.token_client.auth(user_name, user_password) - - token_id = body['token']['id'] - - # Use the unscoped token to get a token scoped to tenant1 - body = self.token_client.auth_token(token_id, - tenant=tenant1_name) - - scoped_token_id = body['token']['id'] - - # Revoke the scoped token - self.client.delete_token(scoped_token_id) - - # Use the unscoped token to get a token scoped to tenant2 - body = self.token_client.auth_token(token_id, - tenant=tenant2_name) - - @decorators.idempotent_id('ca3ea6f7-ed08-4a61-adbd-96906456ad31') - def test_list_endpoints_for_token(self): - # get a token for the user - creds = self.os_primary.credentials - username = creds.username - password = creds.password - tenant_name = creds.tenant_name - token = self.token_client.auth(username, - password, - tenant_name)['token'] - endpoints = self.client.list_endpoints_for_token( - token['id'])['endpoints'] - self.assertIsInstance(endpoints, list) - # Store list of service names - service_names = [e['name'] for e in endpoints] - # Get the list of available services. - available_services = [s[0] for s in list( - CONF.service_available.items()) if s[1] is True] - # Verify that all available services are present. - for service in available_services: - self.assertIn(service, service_names) diff --git a/tempest/api/identity/admin/v2/test_tokens_negative.py b/tempest/api/identity/admin/v2/test_tokens_negative.py deleted file mode 100644 index eb3e365ec..000000000 --- a/tempest/api/identity/admin/v2/test_tokens_negative.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2017 AT&T Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class TokensAdminTestNegative(base.BaseIdentityV2AdminTest): - - credentials = ['primary', 'admin', 'alt'] - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a0a0a600-4292-4364-99c5-922c834fdf05') - def test_check_token_existence_negative(self): - creds = self.os_primary.credentials - creds_alt = self.os_alt.credentials - username = creds.username - password = creds.password - tenant_name = creds.tenant_name - alt_tenant_name = creds_alt.tenant_name - body = self.token_client.auth(username, password, tenant_name) - self.assertRaises(lib_exc.Unauthorized, - self.client.check_token_existence, - body['token']['id'], - belongsTo=alt_tenant_name) diff --git a/tempest/api/identity/admin/v2/test_users.py b/tempest/api/identity/admin/v2/test_users.py deleted file mode 100644 index 0d98af5fa..000000000 --- a/tempest/api/identity/admin/v2/test_users.py +++ /dev/null @@ -1,193 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from testtools import matchers - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class UsersTestJSON(base.BaseIdentityV2AdminTest): - - @classmethod - def resource_setup(cls): - super(UsersTestJSON, cls).resource_setup() - cls.alt_user = data_utils.rand_name('test_user') - cls.alt_email = cls.alt_user + '@testmail.tm' - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2d55a71e-da1d-4b43-9c03-d269fd93d905') - def test_create_user(self): - # Create a user - tenant = self.setup_test_tenant() - user = self.create_test_user(name=self.alt_user, tenantId=tenant['id']) - self.assertEqual(self.alt_user, user['name']) - - @decorators.idempotent_id('89d9fdb8-15c2-4304-a429-48715d0af33d') - def test_create_user_with_enabled(self): - # Create a user with enabled : False - tenant = self.setup_test_tenant() - name = data_utils.rand_name('test_user') - user = self.create_test_user(name=name, - tenantId=tenant['id'], - email=self.alt_email, - enabled=False) - self.assertEqual(name, user['name']) - self.assertEqual(False, user['enabled']) - self.assertEqual(self.alt_email, user['email']) - - @decorators.idempotent_id('39d05857-e8a5-4ed4-ba83-0b52d3ab97ee') - def test_update_user(self): - # Test case to check if updating of user attributes is successful. - tenant = self.setup_test_tenant() - user = self.create_test_user(tenantId=tenant['id']) - - # Updating user details with new values - u_name2 = data_utils.rand_name('user2') - u_email2 = u_name2 + '@testmail.tm' - update_user = self.users_client.update_user(user['id'], name=u_name2, - email=u_email2, - enabled=False)['user'] - self.assertEqual(u_name2, update_user['name']) - self.assertEqual(u_email2, update_user['email']) - self.assertEqual(False, update_user['enabled']) - # GET by id after updating - updated_user = self.users_client.show_user(user['id'])['user'] - # Assert response body of GET after updating - self.assertEqual(u_name2, updated_user['name']) - self.assertEqual(u_email2, updated_user['email']) - self.assertEqual(False, update_user['enabled']) - - @decorators.idempotent_id('29ed26f4-a74e-4425-9a85-fdb49fa269d2') - def test_delete_user(self): - # Delete a user - tenant = self.setup_test_tenant() - user = self.create_test_user(tenantId=tenant['id']) - self.users_client.delete_user(user['id']) - - @decorators.idempotent_id('aca696c3-d645-4f45-b728-63646045beb1') - def test_user_authentication(self): - # Valid user's token is authenticated - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - # Get a token - self.token_client.auth(user['name'], - password, - tenant['name']) - # Re-auth - self.token_client.auth(user['name'], - password, - tenant['name']) - - @decorators.idempotent_id('5d1fa498-4c2d-4732-a8fe-2b054598cfdd') - def test_authentication_request_without_token(self): - # Request for token authentication with a valid token in header - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.token_client.auth(user['name'], - password, - tenant['name']) - # Get the token of the current client - token = self.client.auth_provider.get_token() - # Delete the token from database - self.client.delete_token(token) - # Re-auth - self.token_client.auth(user['name'], - password, - tenant['name']) - self.client.auth_provider.clear_auth() - - @decorators.idempotent_id('a149c02e-e5e0-4b89-809e-7e8faf33ccda') - def test_get_users(self): - # Get a list of users and find the test user - user = self.setup_test_user() - users = self.users_client.list_users()['users'] - self.assertThat([u['name'] for u in users], - matchers.Contains(user['name']), - "Could not find %s" % user['name']) - - @decorators.idempotent_id('6e317209-383a-4bed-9f10-075b7c82c79a') - def test_list_users_for_tenant(self): - # Return a list of all users for a tenant - tenant = self.setup_test_tenant() - user_ids = list() - fetched_user_ids = list() - user1 = self.create_test_user(tenantId=tenant['id']) - user_ids.append(user1['id']) - user2 = self.create_test_user(tenantId=tenant['id']) - user_ids.append(user2['id']) - # List of users for the respective tenant ID - body = (self.tenants_client.list_tenant_users(tenant['id']) - ['users']) - for i in body: - fetched_user_ids.append(i['id']) - # verifying the user Id in the list - missing_users =\ - [user for user in user_ids if user not in fetched_user_ids] - self.assertEmpty(missing_users, - "Failed to find user %s in fetched list" % - ', '.join(m_user for m_user in missing_users)) - - @decorators.idempotent_id('a8b54974-40e1-41c0-b812-50fc90827971') - def test_list_users_with_roles_for_tenant(self): - # Return list of users on tenant when roles are assigned to users - user = self.setup_test_user() - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - role = self.setup_test_role() - # Assigning roles to two users - user_ids = list() - fetched_user_ids = list() - user_ids.append(user['id']) - role = self.roles_client.create_user_role_on_project( - tenant['id'], user['id'], role['id'])['role'] - - second_user = self.create_test_user(tenantId=tenant['id']) - user_ids.append(second_user['id']) - role = self.roles_client.create_user_role_on_project( - tenant['id'], second_user['id'], role['id'])['role'] - # List of users with roles for the respective tenant ID - body = (self.tenants_client.list_tenant_users(tenant['id'])['users']) - for i in body: - fetched_user_ids.append(i['id']) - # verifying the user Id in the list - missing_users = [missing_user for missing_user in user_ids - if missing_user not in fetched_user_ids] - self.assertEmpty(missing_users, - "Failed to find user %s in fetched list" % - ', '.join(m_user for m_user in missing_users)) - - @decorators.idempotent_id('1aeb25ac-6ec5-4d8b-97cb-7ac3567a989f') - def test_update_user_password(self): - # Test case to check if updating of user password is successful. - user = self.setup_test_user() - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - # Updating the user with new password - new_pass = data_utils.rand_password() - update_user = self.users_client.update_user_password( - user['id'], password=new_pass)['user'] - self.assertEqual(update_user['id'], user['id']) - # NOTE(morganfainberg): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure - # we are passing the second boundary. - time.sleep(1) - # Validate the updated password through getting a token. - body = self.token_client.auth(user['name'], new_pass, - tenant['name']) - self.assertIn('id', body['token']) diff --git a/tempest/api/identity/admin/v2/test_users_negative.py b/tempest/api/identity/admin/v2/test_users_negative.py deleted file mode 100644 index 4f47e41d8..000000000 --- a/tempest/api/identity/admin/v2/test_users_negative.py +++ /dev/null @@ -1,268 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class UsersNegativeTestJSON(base.BaseIdentityV2AdminTest): - - @classmethod - def resource_setup(cls): - super(UsersNegativeTestJSON, cls).resource_setup() - cls.alt_user = data_utils.rand_name('test_user') - cls.alt_password = data_utils.rand_password() - cls.alt_email = cls.alt_user + '@testmail.tm' - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('60a1f5fa-5744-4cdf-82bf-60b7de2d29a4') - def test_create_user_by_unauthorized_user(self): - # Non-administrator should not be authorized to create a user - tenant = self.setup_test_tenant() - self.assertRaises(lib_exc.Forbidden, - self.non_admin_users_client.create_user, - name=self.alt_user, password=self.alt_password, - tenantId=tenant['id'], - email=self.alt_email) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d80d0c2f-4514-4d1e-806d-0930dfc5a187') - def test_create_user_with_empty_name(self): - # User with an empty name should not be created - tenant = self.setup_test_tenant() - self.assertRaises(lib_exc.BadRequest, self.users_client.create_user, - name='', password=self.alt_password, - tenantId=tenant['id'], - email=self.alt_email) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7704b4f3-3b75-4b82-87cc-931d41c8f780') - def test_create_user_with_name_length_over_255(self): - # Length of user name filed should be restricted to 255 characters - tenant = self.setup_test_tenant() - self.assertRaises(lib_exc.BadRequest, self.users_client.create_user, - name='a' * 256, password=self.alt_password, - tenantId=tenant['id'], - email=self.alt_email) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('57ae8558-120c-4723-9308-3751474e7ecf') - def test_create_user_with_duplicate_name(self): - # Duplicate user should not be created - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.assertRaises(lib_exc.Conflict, self.users_client.create_user, - name=user['name'], - password=password, - tenantId=tenant['id'], - email=user['email']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0132cc22-7c4f-42e1-9e50-ac6aad31d59a') - def test_create_user_for_non_existent_tenant(self): - # Attempt to create a user in a non-existent tenant should fail - self.assertRaises(lib_exc.NotFound, self.users_client.create_user, - name=self.alt_user, - password=self.alt_password, - tenantId='49ffgg99999', - email=self.alt_email) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('55bbb103-d1ae-437b-989b-bcdf8175c1f4') - def test_create_user_request_without_a_token(self): - # Request to create a user without a valid token should fail - tenant = self.setup_test_tenant() - # Get the token of the current client - token = self.client.auth_provider.get_token() - # Delete the token from database - self.client.delete_token(token) - - # Unset the token to allow further tests to generate a new token - self.addCleanup(self.client.auth_provider.clear_auth) - - self.assertRaises(lib_exc.Unauthorized, self.users_client.create_user, - name=self.alt_user, password=self.alt_password, - tenantId=tenant['id'], - email=self.alt_email) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('23a2f3da-4a1a-41da-abdd-632328a861ad') - def test_create_user_with_enabled_non_bool(self): - # Attempt to create a user with valid enabled para should fail - tenant = self.setup_test_tenant() - name = data_utils.rand_name('test_user') - self.assertRaises(lib_exc.BadRequest, self.users_client.create_user, - name=name, password=self.alt_password, - tenantId=tenant['id'], - email=self.alt_email, enabled=3) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3d07e294-27a0-4144-b780-a2a1bf6fee19') - def test_update_user_for_non_existent_user(self): - # Attempt to update a user non-existent user should fail - user_name = data_utils.rand_name('user') - non_existent_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.users_client.update_user, - non_existent_id, name=user_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3cc2a64b-83aa-4b02-88f0-d6ab737c4466') - def test_update_user_request_without_a_token(self): - # Request to update a user without a valid token should fail - - # Get the token of the current client - token = self.client.auth_provider.get_token() - # Delete the token from database - self.client.delete_token(token) - - # Unset the token to allow further tests to generate a new token - self.addCleanup(self.client.auth_provider.clear_auth) - - self.assertRaises(lib_exc.Unauthorized, self.users_client.update_user, - self.alt_user) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('424868d5-18a7-43e1-8903-a64f95ee3aac') - def test_update_user_by_unauthorized_user(self): - # Non-administrator should not be authorized to update user - self.assertRaises(lib_exc.Forbidden, - self.non_admin_users_client.update_user, - self.alt_user) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d45195d5-33ed-41b9-a452-7d0d6a00f6e9') - def test_delete_users_by_unauthorized_user(self): - # Non-administrator user should not be authorized to delete a user - user = self.setup_test_user() - self.assertRaises(lib_exc.Forbidden, - self.non_admin_users_client.delete_user, - user['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7cc82f7e-9998-4f89-abae-23df36495867') - def test_delete_non_existent_user(self): - # Attempt to delete a non-existent user should fail - self.assertRaises(lib_exc.NotFound, self.users_client.delete_user, - 'junk12345123') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('57fe1df8-0aa7-46c0-ae9f-c2e785c7504a') - def test_delete_user_request_without_a_token(self): - # Request to delete a user without a valid token should fail - - # Get the token of the current client - token = self.client.auth_provider.get_token() - # Delete the token from database - self.client.delete_token(token) - - # Unset the token to allow further tests to generate a new token - self.addCleanup(self.client.auth_provider.clear_auth) - - self.assertRaises(lib_exc.Unauthorized, self.users_client.delete_user, - self.alt_user) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('593a4981-f6d4-460a-99a1-57a78bf20829') - def test_authentication_for_disabled_user(self): - # Disabled user's token should not get authenticated - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.disable_user(user['name']) - self.assertRaises(lib_exc.Unauthorized, self.token_client.auth, - user['name'], - password, - tenant['name']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('440a7a8d-9328-4b7b-83e0-d717010495e4') - def test_authentication_when_tenant_is_disabled(self): - # User's token for a disabled tenant should not be authenticated - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.disable_tenant(tenant['name']) - self.assertRaises(lib_exc.Unauthorized, self.token_client.auth, - user['name'], - password, - tenant['name']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('921f1ad6-7907-40b8-853f-637e7ee52178') - def test_authentication_with_invalid_tenant(self): - # User's token for an invalid tenant should not be authenticated - password = data_utils.rand_password() - user = self.setup_test_user(password) - self.assertRaises(lib_exc.Unauthorized, self.token_client.auth, - user['name'], - password, - 'junktenant1234') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bde9aecd-3b1c-4079-858f-beb5deaa5b5e') - def test_authentication_with_invalid_username(self): - # Non-existent user's token should not get authenticated - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.assertRaises(lib_exc.Unauthorized, self.token_client.auth, - 'junkuser123', password, tenant['name']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d5308b33-3574-43c3-8d87-1c090c5e1eca') - def test_authentication_with_invalid_password(self): - # User's token with invalid password should not be authenticated - user = self.setup_test_user() - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.assertRaises(lib_exc.Unauthorized, self.token_client.auth, - user['name'], 'junkpass1234', tenant['name']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('284192ce-fb7c-4909-a63b-9a502e0ddd11') - def test_get_users_by_unauthorized_user(self): - # Non-administrator user should not be authorized to get user list - self.assertRaises(lib_exc.Forbidden, - self.non_admin_users_client.list_users) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a73591ec-1903-4ffe-be42-282b39fefc9d') - def test_get_users_request_without_token(self): - # Request to get list of users without a valid token should fail - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - - # Unset the token to allow further tests to generate a new token - self.addCleanup(self.client.auth_provider.clear_auth) - - self.assertRaises(lib_exc.Unauthorized, self.users_client.list_users) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f5d39046-fc5f-425c-b29e-bac2632da28e') - def test_list_users_with_invalid_tenant(self): - # Should not be able to return a list of all - # users for a non-existent tenant - # Assign invalid tenant ids - invalid_id = list() - invalid_id.append(data_utils.rand_name('999')) - invalid_id.append('alpha') - invalid_id.append(data_utils.rand_name("dddd@#%%^$")) - invalid_id.append('!@#()$%^&*?<>{}[]') - # List the users with invalid tenant id - for invalid in invalid_id: - self.assertRaises(lib_exc.NotFound, - self.tenants_client.list_tenant_users, invalid) diff --git a/tempest/api/identity/admin/v3/__init__.py b/tempest/api/identity/admin/v3/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py deleted file mode 100644 index 15b20081e..000000000 --- a/tempest/api/identity/admin/v3/test_credentials.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -from oslo_serialization import jsonutils as json - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class CredentialsTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - super(CredentialsTestJSON, cls).resource_setup() - cls.projects = list() - cls.creds_list = [['project_id', 'user_id', 'id'], - ['access', 'secret']] - u_name = data_utils.rand_name('user') - u_desc = '%s description' % u_name - u_email = '%s@testmail.tm' % u_name - u_password = data_utils.rand_password() - for _ in range(2): - cls.project = cls.projects_client.create_project( - data_utils.rand_name('project'), - description=data_utils.rand_name('project-desc'))['project'] - cls.projects.append(cls.project['id']) - - cls.user_body = cls.users_client.create_user( - name=u_name, description=u_desc, password=u_password, - email=u_email, project_id=cls.projects[0])['user'] - - @classmethod - def resource_cleanup(cls): - cls.users_client.delete_user(cls.user_body['id']) - for p in cls.projects: - cls.projects_client.delete_project(p) - super(CredentialsTestJSON, cls).resource_cleanup() - - def _delete_credential(self, cred_id): - self.creds_client.delete_credential(cred_id) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('7cd59bf9-bda4-4c72-9467-d21cab278355') - def test_credentials_create_get_update_delete(self): - blob = '{"access": "%s", "secret": "%s"}' % ( - data_utils.rand_name('Access'), data_utils.rand_name('Secret')) - cred = self.creds_client.create_credential( - user_id=self.user_body['id'], project_id=self.projects[0], - blob=blob, type='ec2')['credential'] - self.addCleanup(self._delete_credential, cred['id']) - for value1 in self.creds_list[0]: - self.assertIn(value1, cred) - for value2 in self.creds_list[1]: - self.assertIn(value2, cred['blob']) - - new_keys = [data_utils.rand_name('NewAccess'), - data_utils.rand_name('NewSecret')] - blob = '{"access": "%s", "secret": "%s"}' % (new_keys[0], new_keys[1]) - update_body = self.creds_client.update_credential( - cred['id'], blob=blob, project_id=self.projects[1], - type='ec2')['credential'] - update_body['blob'] = json.loads(update_body['blob']) - self.assertEqual(cred['id'], update_body['id']) - self.assertEqual(self.projects[1], update_body['project_id']) - self.assertEqual(self.user_body['id'], update_body['user_id']) - self.assertEqual(update_body['blob']['access'], new_keys[0]) - self.assertEqual(update_body['blob']['secret'], new_keys[1]) - - get_body = self.creds_client.show_credential(cred['id'])['credential'] - get_body['blob'] = json.loads(get_body['blob']) - for value1 in self.creds_list[0]: - self.assertEqual(update_body[value1], - get_body[value1]) - for value2 in self.creds_list[1]: - self.assertEqual(update_body['blob'][value2], - get_body['blob'][value2]) - - @decorators.idempotent_id('13202c00-0021-42a1-88d4-81b44d448aab') - def test_credentials_list_delete(self): - created_cred_ids = list() - fetched_cred_ids = list() - - for _ in range(2): - blob = '{"access": "%s", "secret": "%s"}' % ( - data_utils.rand_name('Access'), data_utils.rand_name('Secret')) - cred = self.creds_client.create_credential( - user_id=self.user_body['id'], project_id=self.projects[0], - blob=blob, type='ec2')['credential'] - created_cred_ids.append(cred['id']) - self.addCleanup(self._delete_credential, cred['id']) - - creds = self.creds_client.list_credentials()['credentials'] - - for i in creds: - fetched_cred_ids.append(i['id']) - missing_creds = [c for c in created_cred_ids - if c not in fetched_cred_ids] - self.assertEmpty(missing_creds, - "Failed to find cred %s in fetched list" % - ', '.join(m_cred for m_cred in missing_creds)) diff --git a/tempest/api/identity/admin/v3/test_default_project_id.py b/tempest/api/identity/admin/v3/test_default_project_id.py deleted file mode 100644 index 302a0e541..000000000 --- a/tempest/api/identity/admin/v3/test_default_project_id.py +++ /dev/null @@ -1,85 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -from tempest.api.identity import base -from tempest import clients -from tempest import config -from tempest.lib import auth -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class TestDefaultProjectId (base.BaseIdentityV3AdminTest): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(TestDefaultProjectId, cls).setup_credentials() - - def _delete_domain(self, domain_id): - # It is necessary to disable the domain before deleting, - # or else it would result in unauthorized error - self.domains_client.update_domain(domain_id, enabled=False) - self.domains_client.delete_domain(domain_id) - - @decorators.idempotent_id('d6110661-6a71-49a7-a453-b5e26640ff6d') - def test_default_project_id(self): - # create a domain - dom_name = data_utils.rand_name('dom') - domain_body = self.domains_client.create_domain( - name=dom_name)['domain'] - dom_id = domain_body['id'] - self.addCleanup(self._delete_domain, dom_id) - - # create a project in the domain - proj_body = self.setup_test_project(domain_id=dom_id) - proj_id = proj_body['id'] - self.assertEqual(proj_body['domain_id'], dom_id, - "project " + proj_body['name'] + - "doesn't have domain id " + dom_id) - - # create a user in the domain, with the previous project as his - # default project - user_name = data_utils.rand_name('user') - user_body = self.users_client.create_user( - name=user_name, - password=user_name, - domain_id=dom_id, - default_project_id=proj_id)['user'] - user_id = user_body['id'] - self.addCleanup(self.users_client.delete_user, user_id) - self.assertEqual(user_body['domain_id'], dom_id, - "user " + user_name + - "doesn't have domain id " + dom_id) - - # get roles and find the admin role - admin_role = self.get_role_by_name(CONF.identity.admin_role) - admin_role_id = admin_role['id'] - - # grant the admin role to the user on his project - self.roles_client.create_user_role_on_project(proj_id, user_id, - admin_role_id) - - # create a new client with user's credentials (NOTE: unscoped token!) - creds = auth.KeystoneV3Credentials(username=user_name, - password=user_name, - user_domain_name=dom_name) - auth_provider = clients.get_auth_provider(creds) - creds = auth_provider.fill_credentials() - admin_client = clients.Manager(credentials=creds) - - # verify the user's token and see that it is scoped to the project - token, _ = admin_client.auth_provider.get_auth() - result = admin_client.identity_v3_client.show_token(token)['token'] - self.assertEqual(result['project']['domain']['id'], dom_id) - self.assertEqual(result['project']['id'], proj_id) diff --git a/tempest/api/identity/admin/v3/test_domain_configuration.py b/tempest/api/identity/admin/v3/test_domain_configuration.py deleted file mode 100644 index f7316970b..000000000 --- a/tempest/api/identity/admin/v3/test_domain_configuration.py +++ /dev/null @@ -1,184 +0,0 @@ -# Copyright 2017 AT&T Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class DomainConfigurationTestJSON(base.BaseIdentityV3AdminTest): - - custom_config = { - "identity": { - "driver": "ldap" - }, - "ldap": { - "url": "ldap://myldap.com:389/", - "user_tree_dn": "ou=Users,dc=my_new_root,dc=org" - } - } - - @classmethod - def setup_clients(cls): - super(DomainConfigurationTestJSON, cls).setup_clients() - cls.client = cls.domain_config_client - - @classmethod - def resource_setup(cls): - super(DomainConfigurationTestJSON, cls).resource_setup() - cls.group = cls.groups_client.create_group( - name=data_utils.rand_name('group'), - description=data_utils.rand_name('group-desc'))['group'] - - @classmethod - def resource_cleanup(cls): - cls.groups_client.delete_group(cls.group['id']) - super(DomainConfigurationTestJSON, cls).resource_cleanup() - - def _create_domain_and_config(self, config): - domain = self.setup_test_domain() - config = self.client.create_domain_config(domain['id'], **config)[ - 'config'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.client.delete_domain_config, domain['id']) - return domain, config - - @decorators.idempotent_id('11a02bf0-6f94-4380-b3b0-c8dc18fc0d22') - def test_show_default_group_config_and_options(self): - # The API supports only the identity and ldap groups. For the ldap - # group, a valid value is url or user_tree_dn. For the identity group, - # a valid value is driver. - - # Check that the default config has the identity and ldap groups. - config = self.client.show_default_config_settings()['config'] - self.assertIsInstance(config, dict) - self.assertIn('identity', config) - self.assertIn('ldap', config) - - # Check that the identity group is correct. - identity_config = self.client.show_default_group_config('identity')[ - 'config'] - - self.assertIsInstance(identity_config, dict) - self.assertIn('identity', identity_config) - self.assertIn('driver', identity_config['identity']) - self.assertIn('list_limit', identity_config['identity']) - - # Show each option for the default domain and identity group. - for config_opt_name in ['driver', 'list_limit']: - retrieved_config_opt = self.client.show_default_group_option( - 'identity', config_opt_name)['config'] - self.assertIn(config_opt_name, retrieved_config_opt) - - # Check that the ldap group is correct. - ldap_config = self.client.show_default_group_config('ldap')['config'] - - self.assertIsInstance(ldap_config, dict) - self.assertIn('ldap', ldap_config) - - # Several valid options exist for ldap group. - valid_options = ldap_config['ldap'].keys() - - # Show each option for the default domain and ldap group. - for config_opt_name in valid_options: - retrieved_config_opt = self.client.show_default_group_option( - 'ldap', config_opt_name)['config'] - self.assertIn(config_opt_name, retrieved_config_opt) - - @decorators.idempotent_id('9e3ff13c-f597-4f01-9377-d6c06c2a1477') - def test_create_domain_config_and_show_config_groups_and_options(self): - domain, created_config = self._create_domain_and_config( - self.custom_config) - - # Check that the entire configuration is correct. - self.assertEqual(self.custom_config, created_config) - - # Check that each configuration group is correct. - for group_name in self.custom_config.keys(): - group_cfg = self.client.show_domain_group_config( - domain['id'], group_name)['config'] - self.assertIn(group_name, group_cfg) - self.assertEqual(self.custom_config[group_name], - group_cfg[group_name]) - - # Check that each configuration option is correct. - for opt_name in self.custom_config[group_name].keys(): - group_opt = self.client.show_domain_group_option_config( - domain['id'], group_name, opt_name)['config'] - self.assertIn(opt_name, group_opt) - self.assertEqual(self.custom_config[group_name][opt_name], - group_opt[opt_name]) - - @decorators.idempotent_id('7161023e-5dd0-4612-9da0-1bac6ac30b63') - def test_create_update_and_delete_domain_config(self): - domain, created_config = self._create_domain_and_config( - self.custom_config) - - new_config = created_config - new_config['ldap']['url'] = data_utils.rand_url() - - # Check that the altered configuration is reflected in updated_config. - updated_config = self.client.update_domain_config( - domain['id'], **new_config)['config'] - self.assertEqual(new_config, updated_config) - - # Check that showing the domain config shows the altered configuration. - retrieved_config = self.client.show_domain_config(domain['id'])[ - 'config'] - self.assertEqual(new_config, retrieved_config) - - # Check that deleting a configuration works. - self.client.delete_domain_config(domain['id']) - self.assertRaises(lib_exc.NotFound, self.client.show_domain_config, - domain['id']) - - @decorators.idempotent_id('c7510fa2-6661-4170-9c6b-4783a80651e9') - def test_create_update_and_delete_domain_config_groups_and_opts(self): - domain, _ = self._create_domain_and_config(self.custom_config) - - # Check that updating configuration groups work. - new_driver = data_utils.rand_name('driver') - new_limit = data_utils.rand_int_id(0, 100) - new_group_config = {'identity': {'driver': new_driver, - 'list_limit': new_limit}} - - updated_config = self.client.update_domain_group_config( - domain['id'], 'identity', **new_group_config)['config'] - - self.assertEqual(new_driver, updated_config['identity']['driver']) - self.assertEqual(new_limit, updated_config['identity']['list_limit']) - - # Check that updating individual configuration group options work. - new_driver = data_utils.rand_name('driver') - - updated_config = self.client.update_domain_group_option_config( - domain['id'], 'identity', 'driver', driver=new_driver)['config'] - - self.assertEqual(new_driver, updated_config['identity']['driver']) - - # Check that deleting individual configuration group options work. - self.client.delete_domain_group_option_config( - domain['id'], 'identity', 'driver') - self.assertRaises(lib_exc.NotFound, - self.client.show_domain_group_option_config, - domain['id'], 'identity', 'driver') - - # Check that deleting configuration groups work. - self.client.delete_domain_group_config(domain['id'], 'identity') - self.assertRaises(lib_exc.NotFound, - self.client.show_domain_group_config, - domain['id'], 'identity') diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py deleted file mode 100644 index 9fe978c9d..000000000 --- a/tempest/api/identity/admin/v3/test_domains.py +++ /dev/null @@ -1,168 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class DomainsTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - super(DomainsTestJSON, cls).resource_setup() - # Create some test domains to be used during tests - # One of those domains will be disabled - cls.setup_domains = list() - for i in range(3): - domain = cls.create_domain(enabled=i < 2) - cls.setup_domains.append(domain) - - @classmethod - def resource_cleanup(cls): - for domain in cls.setup_domains: - cls._delete_domain(domain['id']) - super(DomainsTestJSON, cls).resource_cleanup() - - @classmethod - def _delete_domain(cls, domain_id): - # It is necessary to disable the domain before deleting, - # or else it would result in unauthorized error - cls.domains_client.update_domain(domain_id, enabled=False) - cls.domains_client.delete_domain(domain_id) - - @decorators.idempotent_id('8cf516ef-2114-48f1-907b-d32726c734d4') - def test_list_domains(self): - # Test to list domains - fetched_ids = list() - # List and Verify Domains - body = self.domains_client.list_domains()['domains'] - for d in body: - fetched_ids.append(d['id']) - missing_doms = [d for d in self.setup_domains - if d['id'] not in fetched_ids] - self.assertEmpty(missing_doms) - - @decorators.idempotent_id('c6aee07b-4981-440c-bb0b-eb598f58ffe9') - def test_list_domains_filter_by_name(self): - # List domains filtering by name - params = {'name': self.setup_domains[0]['name']} - fetched_domains = self.domains_client.list_domains( - **params)['domains'] - # Verify the filtered list is correct, domain names are unique - # so exactly one domain should be found with the provided name - self.assertEqual(1, len(fetched_domains)) - self.assertEqual(self.setup_domains[0]['name'], - fetched_domains[0]['name']) - - @decorators.idempotent_id('3fd19840-65c1-43f8-b48c-51bdd066dff9') - def test_list_domains_filter_by_enabled(self): - # List domains filtering by enabled domains - params = {'enabled': True} - fetched_domains = self.domains_client.list_domains( - **params)['domains'] - # Verify the filtered list is correct - self.assertIn(self.setup_domains[0], fetched_domains) - self.assertIn(self.setup_domains[1], fetched_domains) - for domain in fetched_domains: - self.assertEqual(True, domain['enabled']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f2f5b44a-82e8-4dad-8084-0661ea3b18cf') - def test_create_update_delete_domain(self): - # Create domain - d_name = data_utils.rand_name('domain') - d_desc = data_utils.rand_name('domain-desc') - domain = self.domains_client.create_domain( - name=d_name, description=d_desc)['domain'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self._delete_domain, domain['id']) - self.assertIn('id', domain) - self.assertIn('description', domain) - self.assertIn('name', domain) - self.assertIn('enabled', domain) - self.assertIn('links', domain) - self.assertIsNotNone(domain['id']) - self.assertEqual(d_name, domain['name']) - self.assertEqual(d_desc, domain['description']) - self.assertEqual(True, domain['enabled']) - # Update domain - new_desc = data_utils.rand_name('new-desc') - new_name = data_utils.rand_name('new-name') - updated_domain = self.domains_client.update_domain( - domain['id'], name=new_name, description=new_desc, - enabled=False)['domain'] - self.assertIn('id', updated_domain) - self.assertIn('description', updated_domain) - self.assertIn('name', updated_domain) - self.assertIn('enabled', updated_domain) - self.assertIn('links', updated_domain) - self.assertIsNotNone(updated_domain['id']) - self.assertEqual(new_name, updated_domain['name']) - self.assertEqual(new_desc, updated_domain['description']) - self.assertEqual(False, updated_domain['enabled']) - # Show domain - fetched_domain = self.domains_client.show_domain( - domain['id'])['domain'] - self.assertEqual(new_name, fetched_domain['name']) - self.assertEqual(new_desc, fetched_domain['description']) - self.assertEqual(False, fetched_domain['enabled']) - # Delete domain - self.domains_client.delete_domain(domain['id']) - body = self.domains_client.list_domains()['domains'] - domains_list = [d['id'] for d in body] - self.assertNotIn(domain['id'], domains_list) - - @decorators.idempotent_id('036df86e-bb5d-42c0-a7c2-66b9db3a6046') - def test_create_domain_with_disabled_status(self): - # Create domain with enabled status as false - d_name = data_utils.rand_name('domain') - d_desc = data_utils.rand_name('domain-desc') - domain = self.domains_client.create_domain( - name=d_name, description=d_desc, enabled=False)['domain'] - self.addCleanup(self.domains_client.delete_domain, domain['id']) - self.assertEqual(d_name, domain['name']) - self.assertFalse(domain['enabled']) - self.assertEqual(d_desc, domain['description']) - - @decorators.idempotent_id('2abf8764-309a-4fa9-bc58-201b799817ad') - def test_create_domain_without_description(self): - # Create domain only with name - d_name = data_utils.rand_name('domain') - domain = self.domains_client.create_domain(name=d_name)['domain'] - self.addCleanup(self._delete_domain, domain['id']) - self.assertIn('id', domain) - expected_data = {'name': d_name, 'enabled': True} - self.assertEqual('', domain['description']) - self.assertDictContainsSubset(expected_data, domain) - - -class DefaultDomainTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - cls.domain_id = CONF.identity.default_domain_id - super(DefaultDomainTestJSON, cls).resource_setup() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('17a5de24-e6a0-4e4a-a9ee-d85b6e5612b5') - def test_default_domain_exists(self): - domain = self.domains_client.show_domain(self.domain_id)['domain'] - - self.assertTrue(domain['enabled']) diff --git a/tempest/api/identity/admin/v3/test_domains_negative.py b/tempest/api/identity/admin/v3/test_domains_negative.py deleted file mode 100644 index 1a0b85181..000000000 --- a/tempest/api/identity/admin/v3/test_domains_negative.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2015 Red Hat Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class DomainsNegativeTestJSON(base.BaseIdentityV3AdminTest): - _interface = 'json' - - @decorators.attr(type=['negative', 'gate']) - @decorators.idempotent_id('1f3fbff5-4e44-400d-9ca1-d953f05f609b') - def test_delete_active_domain(self): - domain = self.create_domain() - domain_id = domain['id'] - - self.addCleanup(self.delete_domain, domain_id) - - # domain need to be disabled before deleting - self.assertRaises(lib_exc.Forbidden, self.domains_client.delete_domain, - domain_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9018461d-7d24-408d-b3fe-ae37e8cd5c9e') - def test_create_domain_with_empty_name(self): - # Domain name should not be empty - self.assertRaises(lib_exc.BadRequest, - self.domains_client.create_domain, name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('37b1bbf2-d664-4785-9a11-333438586eae') - def test_create_domain_with_name_length_over_64(self): - # Domain name length should not ne greater than 64 characters - d_name = 'a' * 65 - self.assertRaises(lib_exc.BadRequest, - self.domains_client.create_domain, - name=d_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('43781c07-764f-4cf2-a405-953c1916f605') - def test_delete_non_existent_domain(self): - # Attempt to delete a non existent domain should fail - self.assertRaises(lib_exc.NotFound, self.domains_client.delete_domain, - data_utils.rand_uuid_hex()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e6f9e4a2-4f36-4be8-bdbc-4e199ae29427') - def test_domain_create_duplicate(self): - domain_name = data_utils.rand_name('domain-dup') - domain = self.domains_client.create_domain(name=domain_name)['domain'] - domain_id = domain['id'] - self.addCleanup(self.delete_domain, domain_id) - # Domain name should be unique - self.assertRaises( - lib_exc.Conflict, self.domains_client.create_domain, - name=domain_name) diff --git a/tempest/api/identity/admin/v3/test_endpoint_groups.py b/tempest/api/identity/admin/v3/test_endpoint_groups.py deleted file mode 100644 index 49dbba198..000000000 --- a/tempest/api/identity/admin/v3/test_endpoint_groups.py +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class EndPointGroupsTest(base.BaseIdentityV3AdminTest): - - @classmethod - def setup_clients(cls): - super(EndPointGroupsTest, cls).setup_clients() - cls.client = cls.endpoint_groups_client - - @classmethod - def resource_setup(cls): - super(EndPointGroupsTest, cls).resource_setup() - cls.service_ids = list() - cls.endpoint_groups = list() - - # Create endpoint group so as to use it for LIST test - service_id = cls._create_service() - - name = data_utils.rand_name('service_group') - description = data_utils.rand_name('description') - filters = {'service_id': service_id} - - endpoint_group = cls.client.create_endpoint_group( - name=name, - description=description, - filters=filters)['endpoint_group'] - - cls.endpoint_groups.append(endpoint_group) - - @classmethod - def resource_cleanup(cls): - for e in cls.endpoint_groups: - cls.client.delete_endpoint_group(e['id']) - for s in cls.service_ids: - cls.services_client.delete_service(s) - super(EndPointGroupsTest, cls).resource_cleanup() - - @classmethod - def _create_service(cls): - s_name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - s_description = data_utils.rand_name('description') - service_data = ( - cls.services_client.create_service(name=s_name, - type=s_type, - description=s_description)) - - service_id = service_data['service']['id'] - cls.service_ids.append(service_id) - return service_id - - @decorators.idempotent_id('7c69e7a1-f865-402d-a2ea-44493017315a') - def test_create_list_show_check_delete_endpoint_group(self): - service_id = self._create_service() - name = data_utils.rand_name('service_group') - description = data_utils.rand_name('description') - filters = {'service_id': service_id} - - endpoint_group = self.client.create_endpoint_group( - name=name, - description=description, - filters=filters)['endpoint_group'] - - self.endpoint_groups.append(endpoint_group) - - # Asserting created endpoint group response body - self.assertIn('id', endpoint_group) - self.assertEqual(name, endpoint_group['name']) - self.assertEqual(description, endpoint_group['description']) - - # Checking if endpoint groups are present in the list of endpoints - # Note that there are two endpoint groups in the list, one created - # in the resource setup, one created in this test case. - fetched_endpoints = \ - self.client.list_endpoint_groups()['endpoint_groups'] - - missing_endpoints = \ - [e for e in self.endpoint_groups if e not in fetched_endpoints] - - # Asserting LIST endpoints - self.assertEmpty(missing_endpoints, - "Failed to find endpoint %s in fetched list" % - ', '.join(str(e) for e in missing_endpoints)) - - # Show endpoint group - fetched_endpoint = self.client.show_endpoint_group( - endpoint_group['id'])['endpoint_group'] - - # Asserting if the attributes of endpoint group are the same - self.assertEqual(service_id, - fetched_endpoint['filters']['service_id']) - for attr in ('id', 'name', 'description'): - self.assertEqual(endpoint_group[attr], fetched_endpoint[attr]) - - # Check endpoint group - self.client.check_endpoint_group(endpoint_group['id']) - - # Deleting the endpoint group created in this method - self.client.delete_endpoint_group(endpoint_group['id']) - self.endpoint_groups.remove(endpoint_group) - - # Checking whether endpoint group is deleted successfully - fetched_endpoints = \ - self.client.list_endpoint_groups()['endpoint_groups'] - fetched_endpoint_ids = [e['id'] for e in fetched_endpoints] - self.assertNotIn(endpoint_group['id'], fetched_endpoint_ids) - - @decorators.idempotent_id('51c8fc38-fa84-4e76-b5b6-6fc37770fb26') - def test_update_endpoint_group(self): - # Creating an endpoint group so as to check update endpoint group - # with new values - service1_id = self._create_service() - name = data_utils.rand_name('service_group') - description = data_utils.rand_name('description') - filters = {'service_id': service1_id} - - endpoint_group = self.client.create_endpoint_group( - name=name, - description=description, - filters=filters)['endpoint_group'] - self.endpoint_groups.append(endpoint_group) - - # Creating new attr values to update endpoint group - service2_id = self._create_service() - name2 = data_utils.rand_name('service_group2') - description2 = data_utils.rand_name('description2') - filters = {'service_id': service2_id} - - # Updating endpoint group with new attr values - updated_endpoint_group = self.client.update_endpoint_group( - endpoint_group['id'], - name=name2, - description=description2, - filters=filters)['endpoint_group'] - - self.assertEqual(name2, updated_endpoint_group['name']) - self.assertEqual(description2, updated_endpoint_group['description']) - self.assertEqual(service2_id, - updated_endpoint_group['filters']['service_id']) diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py deleted file mode 100644 index c9faa9aa5..000000000 --- a/tempest/api/identity/admin/v3/test_endpoints.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class EndPointsTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def setup_clients(cls): - super(EndPointsTestJSON, cls).setup_clients() - cls.client = cls.endpoints_client - - @classmethod - def resource_setup(cls): - super(EndPointsTestJSON, cls).resource_setup() - cls.service_ids = list() - - # Create endpoints so as to use for LIST and GET test cases - interfaces = ['public', 'internal'] - cls.setup_endpoint_ids = list() - for i in range(2): - cls._create_service() - region = data_utils.rand_name('region') - url = data_utils.rand_url() - endpoint = cls.client.create_endpoint( - service_id=cls.service_ids[i], interface=interfaces[i], - url=url, region=region, enabled=True)['endpoint'] - cls.setup_endpoint_ids.append(endpoint['id']) - - @classmethod - def _create_service(cls, s_name=None, s_type=None, s_description=None): - if s_name is None: - s_name = data_utils.rand_name('service') - if s_type is None: - s_type = data_utils.rand_name('type') - if s_description is None: - s_description = data_utils.rand_name('description') - service_data = ( - cls.services_client.create_service(name=s_name, type=s_type, - description=s_description)) - service = service_data['service'] - cls.service_ids.append(service['id']) - return service - - @classmethod - def resource_cleanup(cls): - for e in cls.setup_endpoint_ids: - cls.client.delete_endpoint(e) - for s in cls.service_ids: - cls.services_client.delete_service(s) - super(EndPointsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('c19ecf90-240e-4e23-9966-21cee3f6a618') - def test_list_endpoints(self): - # Get the list of all the endpoints. - fetched_endpoints = self.client.list_endpoints()['endpoints'] - fetched_endpoint_ids = [e['id'] for e in fetched_endpoints] - # Check that all the created endpoints are present in - # "fetched_endpoints". - missing_endpoints =\ - [e for e in self.setup_endpoint_ids - if e not in fetched_endpoint_ids] - self.assertEqual(0, len(missing_endpoints), - "Failed to find endpoint %s in fetched list" % - ', '.join(str(e) for e in missing_endpoints)) - - # Check that filtering endpoints by service_id works. - fetched_endpoints_for_service = self.client.list_endpoints( - service_id=self.service_ids[0])['endpoints'] - fetched_endpoints_for_alt_service = self.client.list_endpoints( - service_id=self.service_ids[1])['endpoints'] - - # Assert that both filters returned the correct result. - self.assertEqual(1, len(fetched_endpoints_for_service)) - self.assertEqual(1, len(fetched_endpoints_for_alt_service)) - self.assertEqual(set(self.setup_endpoint_ids), - set([fetched_endpoints_for_service[0]['id'], - fetched_endpoints_for_alt_service[0]['id']])) - - # Check that filtering endpoints by interface works. - fetched_public_endpoints = self.client.list_endpoints( - interface='public')['endpoints'] - fetched_internal_endpoints = self.client.list_endpoints( - interface='internal')['endpoints'] - - # Check that the expected endpoint_id is present per filter. [0] is - # public and [1] is internal. - self.assertIn(self.setup_endpoint_ids[0], - [e['id'] for e in fetched_public_endpoints]) - self.assertIn(self.setup_endpoint_ids[1], - [e['id'] for e in fetched_internal_endpoints]) - - @decorators.idempotent_id('0e2446d2-c1fd-461b-a729-b9e73e3e3b37') - def test_create_list_show_delete_endpoint(self): - region = data_utils.rand_name('region') - url = data_utils.rand_url() - interface = 'public' - endpoint = self.client.create_endpoint(service_id=self.service_ids[0], - interface=interface, - url=url, region=region, - enabled=True)['endpoint'] - - self.setup_endpoint_ids.append(endpoint['id']) - # Asserting Create Endpoint response body - self.assertIn('id', endpoint) - self.assertEqual(region, endpoint['region']) - self.assertEqual(url, endpoint['url']) - - # Checking if created endpoint is present in the list of endpoints - fetched_endpoints = self.client.list_endpoints()['endpoints'] - fetched_endpoints_id = [e['id'] for e in fetched_endpoints] - self.assertIn(endpoint['id'], fetched_endpoints_id) - - # Show endpoint - fetched_endpoint = ( - self.client.show_endpoint(endpoint['id'])['endpoint']) - # Asserting if the attributes of endpoint are the same - self.assertEqual(self.service_ids[0], fetched_endpoint['service_id']) - self.assertEqual(interface, fetched_endpoint['interface']) - self.assertEqual(url, fetched_endpoint['url']) - self.assertEqual(region, fetched_endpoint['region']) - self.assertEqual(True, fetched_endpoint['enabled']) - - # Deleting the endpoint created in this method - self.client.delete_endpoint(endpoint['id']) - self.setup_endpoint_ids.remove(endpoint['id']) - - # Checking whether endpoint is deleted successfully - fetched_endpoints = self.client.list_endpoints()['endpoints'] - fetched_endpoints_id = [e['id'] for e in fetched_endpoints] - self.assertNotIn(endpoint['id'], fetched_endpoints_id) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('37e8f15e-ee7c-4657-a1e7-f6b61e375eff') - def test_update_endpoint(self): - # Creating an endpoint so as to check update endpoint - # with new values - region1 = data_utils.rand_name('region') - url1 = data_utils.rand_url() - interface1 = 'public' - endpoint_for_update = ( - self.client.create_endpoint(service_id=self.service_ids[0], - interface=interface1, - url=url1, region=region1, - enabled=True)['endpoint']) - self.addCleanup(self.client.delete_endpoint, endpoint_for_update['id']) - # Creating service so as update endpoint with new service ID - s_name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - s_description = data_utils.rand_name('description') - service2 = self._create_service(s_name=s_name, s_type=s_type, - s_description=s_description) - # Updating endpoint with new values - region2 = data_utils.rand_name('region') - url2 = data_utils.rand_url() - interface2 = 'internal' - endpoint = self.client.update_endpoint(endpoint_for_update['id'], - service_id=service2['id'], - interface=interface2, - url=url2, region=region2, - enabled=False)['endpoint'] - # Asserting if the attributes of endpoint are updated - self.assertEqual(service2['id'], endpoint['service_id']) - self.assertEqual(interface2, endpoint['interface']) - self.assertEqual(url2, endpoint['url']) - self.assertEqual(region2, endpoint['region']) - self.assertEqual(False, endpoint['enabled']) diff --git a/tempest/api/identity/admin/v3/test_endpoints_negative.py b/tempest/api/identity/admin/v3/test_endpoints_negative.py deleted file mode 100644 index 70dd7b523..000000000 --- a/tempest/api/identity/admin/v3/test_endpoints_negative.py +++ /dev/null @@ -1,98 +0,0 @@ - -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class EndpointsNegativeTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def setup_clients(cls): - super(EndpointsNegativeTestJSON, cls).setup_clients() - cls.client = cls.endpoints_client - - @classmethod - def resource_setup(cls): - super(EndpointsNegativeTestJSON, cls).resource_setup() - cls.service_ids = list() - s_name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - s_description = data_utils.rand_name('description') - service_data = ( - cls.services_client.create_service(name=s_name, type=s_type, - description=s_description) - ['service']) - cls.service_id = service_data['id'] - cls.service_ids.append(cls.service_id) - - @classmethod - def resource_cleanup(cls): - for s in cls.service_ids: - cls.services_client.delete_service(s) - super(EndpointsNegativeTestJSON, cls).resource_cleanup() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ac6c137e-4d3d-448f-8c83-4f13d0942651') - def test_create_with_enabled_False(self): - # Enabled should be a boolean, not a string like 'False' - interface = 'public' - url = data_utils.rand_url() - region = data_utils.rand_name('region') - self.assertRaises(lib_exc.BadRequest, self.client.create_endpoint, - service_id=self.service_id, interface=interface, - url=url, region=region, enabled='False') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9c43181e-0627-484a-8c79-923e8a59598b') - def test_create_with_enabled_True(self): - # Enabled should be a boolean, not a string like 'True' - interface = 'public' - url = data_utils.rand_url() - region = data_utils.rand_name('region') - self.assertRaises(lib_exc.BadRequest, self.client.create_endpoint, - service_id=self.service_id, interface=interface, - url=url, region=region, enabled='True') - - def _assert_update_raises_bad_request(self, enabled): - - # Create an endpoint - region1 = data_utils.rand_name('region') - url1 = data_utils.rand_url() - interface1 = 'public' - endpoint_for_update = ( - self.client.create_endpoint(service_id=self.service_id, - interface=interface1, - url=url1, region=region1, - enabled=True)['endpoint']) - self.addCleanup(self.client.delete_endpoint, endpoint_for_update['id']) - - self.assertRaises(lib_exc.BadRequest, self.client.update_endpoint, - endpoint_for_update['id'], enabled=enabled) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('65e41f32-5eb7-498f-a92a-a6ccacf7439a') - def test_update_with_enabled_False(self): - # Enabled should be a boolean, not a string like 'False' - self._assert_update_raises_bad_request('False') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('faba3587-f066-4757-a48e-b4a3f01803bb') - def test_update_with_enabled_True(self): - # Enabled should be a boolean, not a string like 'True' - self._assert_update_raises_bad_request('True') diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py deleted file mode 100644 index 4bc987fbe..000000000 --- a/tempest/api/identity/admin/v3/test_groups.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class GroupsV3TestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - super(GroupsV3TestJSON, cls).resource_setup() - cls.domain = cls.create_domain() - - @classmethod - def resource_cleanup(cls): - # Cleanup the domains created in the setup - cls.domains_client.update_domain(cls.domain['id'], enabled=False) - cls.domains_client.delete_domain(cls.domain['id']) - super(GroupsV3TestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('2e80343b-6c81-4ac3-88c7-452f3e9d5129') - def test_group_create_update_get(self): - name = data_utils.rand_name('Group') - description = data_utils.rand_name('Description') - group = self.groups_client.create_group( - name=name, domain_id=self.domain['id'], - description=description)['group'] - self.addCleanup(self.groups_client.delete_group, group['id']) - self.assertEqual(group['name'], name) - self.assertEqual(group['description'], description) - - new_name = data_utils.rand_name('UpdateGroup') - new_desc = data_utils.rand_name('UpdateDescription') - updated_group = self.groups_client.update_group( - group['id'], name=new_name, description=new_desc)['group'] - self.assertEqual(updated_group['name'], new_name) - self.assertEqual(updated_group['description'], new_desc) - - new_group = self.groups_client.show_group(group['id'])['group'] - self.assertEqual(group['id'], new_group['id']) - self.assertEqual(new_name, new_group['name']) - self.assertEqual(new_desc, new_group['description']) - - @decorators.idempotent_id('b66eb441-b08a-4a6d-81ab-fef71baeb26c') - def test_group_update_with_few_fields(self): - name = data_utils.rand_name('Group') - old_description = data_utils.rand_name('Description') - group = self.groups_client.create_group( - name=name, domain_id=self.domain['id'], - description=old_description)['group'] - self.addCleanup(self.groups_client.delete_group, group['id']) - - new_name = data_utils.rand_name('UpdateGroup') - updated_group = self.groups_client.update_group( - group['id'], name=new_name)['group'] - self.assertEqual(new_name, updated_group['name']) - # Verify that 'description' is not being updated or deleted. - self.assertEqual(old_description, updated_group['description']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('1598521a-2f36-4606-8df9-30772bd51339') - def test_group_users_add_list_delete(self): - name = data_utils.rand_name('Group') - group = self.groups_client.create_group( - name=name, domain_id=self.domain['id'])['group'] - self.addCleanup(self.groups_client.delete_group, group['id']) - # add user into group - users = [] - for _ in range(3): - user = self.create_test_user() - users.append(user) - self.groups_client.add_group_user(group['id'], user['id']) - - # list users in group - group_users = self.groups_client.list_group_users(group['id'])['users'] - self.assertEqual(sorted(users, key=lambda k: k['name']), - sorted(group_users, key=lambda k: k['name'])) - # check and delete user in group - for user in users: - self.groups_client.check_group_user_existence( - group['id'], user['id']) - self.groups_client.delete_group_user(group['id'], user['id']) - group_users = self.groups_client.list_group_users(group['id'])['users'] - self.assertEqual(len(group_users), 0) - - @decorators.idempotent_id('64573281-d26a-4a52-b899-503cb0f4e4ec') - def test_list_user_groups(self): - # create a user - user = self.create_test_user() - # create two groups, and add user into them - groups = [] - for _ in range(2): - name = data_utils.rand_name('Group') - group = self.groups_client.create_group( - name=name, domain_id=self.domain['id'])['group'] - groups.append(group) - self.addCleanup(self.groups_client.delete_group, group['id']) - self.groups_client.add_group_user(group['id'], user['id']) - # list groups which user belongs to - user_groups = self.users_client.list_user_groups(user['id'])['groups'] - self.assertEqual(sorted(groups, key=lambda k: k['name']), - sorted(user_groups, key=lambda k: k['name'])) - self.assertEqual(2, len(user_groups)) - - @decorators.idempotent_id('cc9a57a5-a9ed-4f2d-a29f-4f979a06ec71') - def test_list_groups(self): - # Test to list groups - group_ids = list() - fetched_ids = list() - for _ in range(3): - name = data_utils.rand_name('Group') - description = data_utils.rand_name('Description') - group = self.groups_client.create_group( - name=name, domain_id=self.domain['id'], - description=description)['group'] - self.addCleanup(self.groups_client.delete_group, group['id']) - group_ids.append(group['id']) - # List and Verify Groups - body = self.groups_client.list_groups()['groups'] - for g in body: - fetched_ids.append(g['id']) - missing_groups = [g for g in group_ids if g not in fetched_ids] - self.assertEmpty(missing_groups) diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py deleted file mode 100644 index 49b658507..000000000 --- a/tempest/api/identity/admin/v3/test_inherits.py +++ /dev/null @@ -1,214 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class BaseInheritsV3Test(base.BaseIdentityV3AdminTest): - - @classmethod - def skip_checks(cls): - super(BaseInheritsV3Test, cls).skip_checks() - if not test.is_extension_enabled('OS-INHERIT', 'identity'): - raise cls.skipException("Inherits aren't enabled") - - @classmethod - def resource_setup(cls): - super(BaseInheritsV3Test, cls).resource_setup() - u_name = data_utils.rand_name('user-') - u_desc = '%s description' % u_name - u_email = '%s@testmail.tm' % u_name - u_password = data_utils.rand_name('pass-') - cls.domain = cls.create_domain() - cls.project = cls.projects_client.create_project( - data_utils.rand_name('project-'), - description=data_utils.rand_name('project-desc-'), - domain_id=cls.domain['id'])['project'] - cls.group = cls.groups_client.create_group( - name=data_utils.rand_name('group-'), project_id=cls.project['id'], - domain_id=cls.domain['id'])['group'] - cls.user = cls.users_client.create_user( - name=u_name, description=u_desc, password=u_password, - email=u_email, project_id=cls.project['id'], - domain_id=cls.domain['id'])['user'] - - @classmethod - def resource_cleanup(cls): - cls.groups_client.delete_group(cls.group['id']) - cls.users_client.delete_user(cls.user['id']) - cls.projects_client.delete_project(cls.project['id']) - cls.domains_client.update_domain(cls.domain['id'], enabled=False) - cls.domains_client.delete_domain(cls.domain['id']) - super(BaseInheritsV3Test, cls).resource_cleanup() - - def _list_assertions(self, body, fetched_role_ids, role_id): - self.assertEqual(len(body), 1) - self.assertIn(role_id, fetched_role_ids) - - -class InheritsV3TestJSON(BaseInheritsV3Test): - - @decorators.idempotent_id('4e6f0366-97c8-423c-b2be-41eae6ac91c8') - def test_inherit_assign_list_check_revoke_roles_on_domains_user(self): - # Create role - src_role = self.setup_test_role() - # Assign role on domains user - self.inherited_roles_client.create_inherited_role_on_domains_user( - self.domain['id'], self.user['id'], src_role['id']) - # list role on domains user - roles = self.inherited_roles_client.\ - list_inherited_project_role_for_user_on_domain( - self.domain['id'], self.user['id'])['roles'] - - fetched_role_ids = [i['id'] for i in roles] - self._list_assertions(roles, fetched_role_ids, - src_role['id']) - - # Check role on domains user - (self.inherited_roles_client. - check_user_inherited_project_role_on_domain( - self.domain['id'], self.user['id'], src_role['id'])) - # Revoke role from domains user. - self.inherited_roles_client.delete_inherited_role_from_user_on_domain( - self.domain['id'], self.user['id'], src_role['id']) - - @decorators.idempotent_id('c7a8dda2-be50-4fb4-9a9c-e830771078b1') - def test_inherit_assign_list_check_revoke_roles_on_domains_group(self): - # Create role - src_role = self.setup_test_role() - # Assign role on domains group - self.inherited_roles_client.create_inherited_role_on_domains_group( - self.domain['id'], self.group['id'], src_role['id']) - # List role on domains group - roles = self.inherited_roles_client.\ - list_inherited_project_role_for_group_on_domain( - self.domain['id'], self.group['id'])['roles'] - - fetched_role_ids = [i['id'] for i in roles] - self._list_assertions(roles, fetched_role_ids, - src_role['id']) - - # Check role on domains group - (self.inherited_roles_client. - check_group_inherited_project_role_on_domain( - self.domain['id'], self.group['id'], src_role['id'])) - # Revoke role from domains group - self.inherited_roles_client.delete_inherited_role_from_group_on_domain( - self.domain['id'], self.group['id'], src_role['id']) - - @decorators.idempotent_id('18b70e45-7687-4b72-8277-b8f1a47d7591') - def test_inherit_assign_check_revoke_roles_on_projects_user(self): - # Create role - src_role = self.setup_test_role() - # Assign role on projects user - self.inherited_roles_client.create_inherited_role_on_projects_user( - self.project['id'], self.user['id'], src_role['id']) - # Check role on projects user - (self.inherited_roles_client. - check_user_has_flag_on_inherited_to_project( - self.project['id'], self.user['id'], src_role['id'])) - # Revoke role from projects user - self.inherited_roles_client.delete_inherited_role_from_user_on_project( - self.project['id'], self.user['id'], src_role['id']) - - @decorators.idempotent_id('26021436-d5a4-4256-943c-ded01e0d4b45') - def test_inherit_assign_check_revoke_roles_on_projects_group(self): - # Create role - src_role = self.setup_test_role() - # Assign role on projects group - self.inherited_roles_client.create_inherited_role_on_projects_group( - self.project['id'], self.group['id'], src_role['id']) - # Check role on projects group - (self.inherited_roles_client. - check_group_has_flag_on_inherited_to_project( - self.project['id'], self.group['id'], src_role['id'])) - # Revoke role from projects group - (self.inherited_roles_client. - delete_inherited_role_from_group_on_project( - self.project['id'], self.group['id'], src_role['id'])) - - @decorators.idempotent_id('3acf666e-5354-42ac-8e17-8b68893bcd36') - def test_inherit_assign_list_revoke_user_roles_on_domain(self): - # Create role - src_role = self.setup_test_role() - - # Create a project hierarchy - leaf_project = self.setup_test_project(domain_id=self.domain['id'], - parent_id=self.project['id']) - - # Assign role on domain - self.inherited_roles_client.create_inherited_role_on_domains_user( - self.domain['id'], self.user['id'], src_role['id']) - - # List "effective" role assignments from user on the parent project - params = {'scope.project.id': self.project['id'], - 'user.id': self.user['id']} - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertNotEmpty(assignments) - - # List "effective" role assignments from user on the leaf project - params['scope.project.id'] = leaf_project['id'] - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertNotEmpty(assignments) - - # Revoke role from domain - self.inherited_roles_client.delete_inherited_role_from_user_on_domain( - self.domain['id'], self.user['id'], src_role['id']) - - # List "effective" role assignments from user on the parent project - # should return an empty list - params['scope.project.id'] = self.project['id'] - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEmpty(assignments) - - # List "effective" role assignments from user on the leaf project - # should return an empty list - params['scope.project.id'] = leaf_project['id'] - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEmpty(assignments) - - @decorators.idempotent_id('9f02ccd9-9b57-46b4-8f77-dd5a736f3a06') - def test_inherit_assign_list_revoke_user_roles_on_project_tree(self): - # Create role - src_role = self.setup_test_role() - - # Create a project hierarchy - leaf_project = self.setup_test_project(domain_id=self.domain['id'], - parent_id=self.project['id']) - - # Assign role on parent project - self.inherited_roles_client.create_inherited_role_on_projects_user( - self.project['id'], self.user['id'], src_role['id']) - - # List "effective" role assignments from user on the leaf project - params = {'scope.project.id': leaf_project['id'], - 'user.id': self.user['id']} - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertNotEmpty(assignments) - - # Revoke role from parent project - self.inherited_roles_client.delete_inherited_role_from_user_on_project( - self.project['id'], self.user['id'], src_role['id']) - - # List "effective" role assignments from user on the leaf project - # should return an empty list - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEmpty(assignments) diff --git a/tempest/api/identity/admin/v3/test_list_projects.py b/tempest/api/identity/admin/v3/test_list_projects.py deleted file mode 100644 index 7e70c14f8..000000000 --- a/tempest/api/identity/admin/v3/test_list_projects.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class ListProjectsTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - super(ListProjectsTestJSON, cls).resource_setup() - cls.project_ids = list() - # Create a domain - cls.domain = cls.create_domain() - # Create project with domain - cls.projects = list() - cls.p1_name = data_utils.rand_name('project') - cls.p1 = cls.projects_client.create_project( - cls.p1_name, enabled=False, - domain_id=cls.domain['id'])['project'] - cls.projects.append(cls.p1) - cls.project_ids.append(cls.p1['id']) - # Create default project - p2_name = data_utils.rand_name('project') - cls.p2 = cls.projects_client.create_project(p2_name)['project'] - cls.projects.append(cls.p2) - cls.project_ids.append(cls.p2['id']) - # Create a new project (p3) using p2 as parent project - p3_name = data_utils.rand_name('project') - cls.p3 = cls.projects_client.create_project( - p3_name, parent_id=cls.p2['id'])['project'] - cls.projects.append(cls.p3) - cls.project_ids.append(cls.p3['id']) - - @classmethod - def resource_cleanup(cls): - # Cleanup the projects created during setup in inverse order - for project in reversed(cls.projects): - cls.projects_client.delete_project(project['id']) - # Cleanup the domain created during setup - cls.domains_client.update_domain(cls.domain['id'], enabled=False) - cls.domains_client.delete_domain(cls.domain['id']) - super(ListProjectsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('1d830662-22ad-427c-8c3e-4ec854b0af44') - def test_list_projects(self): - # List projects - list_projects = self.projects_client.list_projects()['projects'] - - for p in self.project_ids: - show_project = self.projects_client.show_project(p)['project'] - self.assertIn(show_project, list_projects) - - @decorators.idempotent_id('fab13f3c-f6a6-4b9f-829b-d32fd44fdf10') - def test_list_projects_with_domains(self): - # List projects with domain - self._list_projects_with_params( - {'domain_id': self.domain['id']}, 'domain_id') - - @decorators.idempotent_id('0fe7a334-675a-4509-b00e-1c4b95d5dae8') - def test_list_projects_with_enabled(self): - # List the projects with enabled - self._list_projects_with_params({'enabled': False}, 'enabled') - - @decorators.idempotent_id('fa178524-4e6d-4925-907c-7ab9f42c7e26') - def test_list_projects_with_name(self): - # List projects with name - self._list_projects_with_params({'name': self.p1_name}, 'name') - - @decorators.idempotent_id('6edc66f5-2941-4a17-9526-4073311c1fac') - def test_list_projects_with_parent(self): - # List projects with parent - params = {'parent_id': self.p3['parent_id']} - fetched_projects = self.projects_client.list_projects( - params)['projects'] - self.assertNotEmpty(fetched_projects) - for project in fetched_projects: - self.assertEqual(self.p3['parent_id'], project['parent_id']) - - def _list_projects_with_params(self, params, key): - body = self.projects_client.list_projects(params)['projects'] - self.assertIn(self.p1[key], map(lambda x: x[key], body)) - self.assertNotIn(self.p2[key], map(lambda x: x[key], body)) diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py deleted file mode 100644 index 47a358068..000000000 --- a/tempest/api/identity/admin/v3/test_list_users.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class UsersV3TestJSON(base.BaseIdentityV3AdminTest): - - def _list_users_with_params(self, params, key, expected, not_expected): - # Helper method to list users filtered with params and - # assert the response based on expected and not_expected - # expected: user expected in the list response - # not_expected: user, which should not be present in list response - body = self.users_client.list_users(**params)['users'] - self.assertIn(expected[key], map(lambda x: x[key], body)) - self.assertNotIn(not_expected[key], - map(lambda x: x[key], body)) - - @classmethod - def resource_setup(cls): - super(UsersV3TestJSON, cls).resource_setup() - alt_user = data_utils.rand_name('test_user') - alt_password = data_utils.rand_password() - cls.alt_email = alt_user + '@testmail.tm' - # Create a domain - cls.domain = cls.create_domain() - # Create user with Domain - cls.users = list() - u1_name = data_utils.rand_name('test_user') - cls.domain_enabled_user = cls.users_client.create_user( - name=u1_name, password=alt_password, - email=cls.alt_email, domain_id=cls.domain['id'])['user'] - cls.users.append(cls.domain_enabled_user) - # Create default not enabled user - u2_name = data_utils.rand_name('test_user') - cls.non_domain_enabled_user = cls.users_client.create_user( - name=u2_name, password=alt_password, - email=cls.alt_email, enabled=False)['user'] - cls.users.append(cls.non_domain_enabled_user) - - @classmethod - def resource_cleanup(cls): - # Cleanup the users created during setup - for user in cls.users: - cls.users_client.delete_user(user['id']) - # Cleanup the domain created during setup - cls.domains_client.update_domain(cls.domain['id'], enabled=False) - cls.domains_client.delete_domain(cls.domain['id']) - super(UsersV3TestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('08f9aabb-dcfe-41d0-8172-82b5fa0bd73d') - def test_list_user_domains(self): - # List users with domain - params = {'domain_id': self.domain['id']} - self._list_users_with_params(params, 'domain_id', - self.domain_enabled_user, - self.non_domain_enabled_user) - - @decorators.idempotent_id('bff8bf2f-9408-4ef5-b63a-753c8c2124eb') - def test_list_users_with_not_enabled(self): - # List the users with not enabled - params = {'enabled': False} - self._list_users_with_params(params, 'enabled', - self.non_domain_enabled_user, - self.domain_enabled_user) - - @decorators.idempotent_id('c285bb37-7325-4c02-bff3-3da5d946d683') - def test_list_users_with_name(self): - # List users with name - params = {'name': self.domain_enabled_user['name']} - self._list_users_with_params(params, 'name', - self.domain_enabled_user, - self.non_domain_enabled_user) - - @decorators.idempotent_id('b30d4651-a2ea-4666-8551-0c0e49692635') - def test_list_users(self): - # List users - body = self.users_client.list_users()['users'] - fetched_ids = [u['id'] for u in body] - missing_users = [u['id'] for u in self.users - if u['id'] not in fetched_ids] - self.assertEmpty(missing_users, - "Failed to find user %s in fetched list" % - ', '.join(m_user for m_user in missing_users)) - - @decorators.idempotent_id('b4baa3ae-ac00-4b4e-9e27-80deaad7771f') - def test_get_user(self): - # Get a user detail - user = self.users_client.show_user(self.users[0]['id'])['user'] - self.assertEqual(self.users[0]['id'], user['id']) - self.assertEqual(self.users[0]['name'], user['name']) - self.assertEqual(self.alt_email, user['email']) - self.assertEqual(self.domain['id'], user['domain_id']) diff --git a/tempest/api/identity/admin/v3/test_oauth_consumers.py b/tempest/api/identity/admin/v3/test_oauth_consumers.py deleted file mode 100644 index f06fb8f5f..000000000 --- a/tempest/api/identity/admin/v3/test_oauth_consumers.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as exceptions - - -class OAUTHConsumersV3Test(base.BaseIdentityV3AdminTest): - - def _create_consumer(self): - """Creates a consumer with a random description.""" - description = data_utils.rand_name('test_create_consumer') - consumer = self.oauth_consumers_client.create_consumer( - description)['consumer'] - # cleans up created consumers after tests - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.oauth_consumers_client.delete_consumer, - consumer['id']) - return consumer - - @decorators.idempotent_id('c8307ea6-a86c-47fd-ae7b-5b3b2caca76d') - def test_create_and_show_consumer(self): - """Tests to make sure that a consumer with parameters is made""" - consumer = self._create_consumer() - # fetch created consumer from client - fetched_consumer = self.oauth_consumers_client.show_consumer( - consumer['id'])['consumer'] - # assert that the fetched consumer matches the created one and - # has all parameters - for key in ['description', 'id', 'links']: - self.assertEqual(consumer[key], fetched_consumer[key]) - - @decorators.idempotent_id('fdfa1b7f-2a31-4354-b2c7-f6ae20554f93') - def test_delete_consumer(self): - """Tests the delete function.""" - consumer = self._create_consumer() - # fetch consumer from client to confirm it exists - fetched_consumer = self.oauth_consumers_client.show_consumer( - consumer['id'])['consumer'] - self.assertEqual(consumer['id'], fetched_consumer['id']) - # delete existing consumer - self.oauth_consumers_client.delete_consumer(consumer['id']) - # check that consumer no longer exists - self.assertRaises(exceptions.NotFound, - self.oauth_consumers_client.show_consumer, - consumer['id']) - - @decorators.idempotent_id('080a9b1a-c009-47c0-9979-5305bf72e3dc') - def test_update_consumer(self): - """Tests the update functionality""" - # create a new consumer to update - consumer = self._create_consumer() - # create new description - new_description = data_utils.rand_name('test_update_consumer') - # update consumer - self.oauth_consumers_client.update_consumer(consumer['id'], - new_description) - # check that the same consumer now has the new description - updated_consumer = self.oauth_consumers_client.show_consumer( - consumer['id'])['consumer'] - self.assertEqual(new_description, updated_consumer['description']) - - @decorators.idempotent_id('09ca50de-78f2-4ffb-ac71-f2254036b2b8') - def test_list_consumers(self): - """Test for listing consumers""" - # create two consumers to populate list - new_consumer_one = self._create_consumer() - new_consumer_two = self._create_consumer() - # fetch the list of consumers - consumer_list = self.oauth_consumers_client \ - .list_consumers()['consumers'] - # add fetched consumer ids to a list - id_list = [consumer['id'] for consumer in consumer_list] - # check if created consumers are in the list - self.assertIn(new_consumer_one['id'], id_list) - self.assertIn(new_consumer_two['id'], id_list) diff --git a/tempest/api/identity/admin/v3/test_policies.py b/tempest/api/identity/admin/v3/test_policies.py deleted file mode 100644 index 960e2cb12..000000000 --- a/tempest/api/identity/admin/v3/test_policies.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class PoliciesTestJSON(base.BaseIdentityV3AdminTest): - - def _delete_policy(self, policy_id): - self.policies_client.delete_policy(policy_id) - - @decorators.idempotent_id('1a0ad286-2d06-4123-ab0d-728893a76201') - def test_list_policies(self): - # Test to list policies - policy_ids = list() - fetched_ids = list() - for _ in range(3): - blob = data_utils.rand_name('BlobName') - policy_type = data_utils.rand_name('PolicyType') - policy = self.policies_client.create_policy( - blob=blob, type=policy_type)['policy'] - # Delete the Policy at the end of this method - self.addCleanup(self._delete_policy, policy['id']) - policy_ids.append(policy['id']) - # List and Verify Policies - body = self.policies_client.list_policies()['policies'] - for p in body: - fetched_ids.append(p['id']) - missing_pols = [p for p in policy_ids if p not in fetched_ids] - self.assertEmpty(missing_pols) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('e544703a-2f03-4cf2-9b0f-350782fdb0d3') - def test_create_update_delete_policy(self): - # Test to update policy - blob = data_utils.rand_name('BlobName') - policy_type = data_utils.rand_name('PolicyType') - policy = self.policies_client.create_policy(blob=blob, - type=policy_type)['policy'] - self.addCleanup(self._delete_policy, policy['id']) - self.assertIn('id', policy) - self.assertIn('type', policy) - self.assertIn('blob', policy) - self.assertIsNotNone(policy['id']) - self.assertEqual(blob, policy['blob']) - self.assertEqual(policy_type, policy['type']) - # Update policy - update_type = data_utils.rand_name('UpdatedPolicyType') - data = self.policies_client.update_policy( - policy['id'], type=update_type)['policy'] - self.assertIn('type', data) - # Assertion for updated value with fetched value - fetched_policy = self.policies_client.show_policy( - policy['id'])['policy'] - self.assertIn('id', fetched_policy) - self.assertIn('blob', fetched_policy) - self.assertIn('type', fetched_policy) - self.assertEqual(fetched_policy['id'], policy['id']) - self.assertEqual(fetched_policy['blob'], policy['blob']) - self.assertEqual(update_type, fetched_policy['type']) diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py deleted file mode 100644 index 1b1d3f702..000000000 --- a/tempest/api/identity/admin/v3/test_projects.py +++ /dev/null @@ -1,207 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ProjectsTestJSON(base.BaseIdentityV3AdminTest): - - @decorators.idempotent_id('0ecf465c-0dc4-4532-ab53-91ffeb74d12d') - def test_project_create_with_description(self): - # Create project with a description - project_desc = data_utils.rand_name('desc') - project = self.setup_test_project(description=project_desc) - project_id = project['id'] - desc1 = project['description'] - self.assertEqual(desc1, project_desc, 'Description should have ' - 'been sent in response for create') - body = self.projects_client.show_project(project_id)['project'] - desc2 = body['description'] - self.assertEqual(desc2, project_desc, 'Description does not appear' - 'to be set') - - @decorators.idempotent_id('5f50fe07-8166-430b-a882-3b2ee0abe26f') - def test_project_create_with_domain(self): - # Create project with a domain - domain = self.setup_test_domain() - project_name = data_utils.rand_name('project') - project = self.setup_test_project( - name=project_name, domain_id=domain['id']) - project_id = project['id'] - self.assertEqual(project_name, project['name']) - self.assertEqual(domain['id'], project['domain_id']) - body = self.projects_client.show_project(project_id)['project'] - self.assertEqual(project_name, body['name']) - self.assertEqual(domain['id'], body['domain_id']) - - @decorators.idempotent_id('1854f9c0-70bc-4d11-a08a-1c789d339e3d') - def test_project_create_with_parent(self): - # Create root project without providing a parent_id - domain = self.setup_test_domain() - domain_id = domain['id'] - - root_project_name = data_utils.rand_name('root_project') - root_project = self.setup_test_project( - name=root_project_name, domain_id=domain_id) - - root_project_id = root_project['id'] - parent_id = root_project['parent_id'] - self.assertEqual(root_project_name, root_project['name']) - # If not provided, the parent_id must point to the top level - # project in the hierarchy, i.e. its domain - self.assertEqual(domain_id, parent_id) - - # Create a project using root_project_id as parent_id - project_name = data_utils.rand_name('project') - project = self.setup_test_project( - name=project_name, domain_id=domain_id, parent_id=root_project_id) - parent_id = project['parent_id'] - self.assertEqual(project_name, project['name']) - self.assertEqual(root_project_id, parent_id) - - @decorators.idempotent_id('a7eb9416-6f9b-4dbb-b71b-7f73aaef59d5') - def test_create_is_domain_project(self): - project = self.setup_test_project(domain_id=None, is_domain=True) - # To delete a domain, we need to disable it first - self.addCleanup(self.projects_client.update_project, project['id'], - enabled=False) - - # Check if the is_domain project is correctly returned by both - # project and domain APIs - projects_list = self.projects_client.list_projects( - params={'is_domain': True})['projects'] - self.assertIn(project, projects_list) - - # The domains API return different attributes for the entity, so we - # compare the entities IDs - domains_ids = [d['id'] for d in self.domains_client.list_domains()[ - 'domains']] - self.assertIn(project['id'], domains_ids) - - @decorators.idempotent_id('1f66dc76-50cc-4741-a200-af984509e480') - def test_project_create_enabled(self): - # Create a project that is enabled - project = self.setup_test_project(enabled=True) - project_id = project['id'] - en1 = project['enabled'] - self.assertTrue(en1, 'Enable should be True in response') - body = self.projects_client.show_project(project_id)['project'] - en2 = body['enabled'] - self.assertTrue(en2, 'Enable should be True in lookup') - - @decorators.idempotent_id('78f96a9c-e0e0-4ee6-a3ba-fbf6dfd03207') - def test_project_create_not_enabled(self): - # Create a project that is not enabled - project = self.setup_test_project(enabled=False) - en1 = project['enabled'] - self.assertEqual('false', str(en1).lower(), - 'Enable should be False in response') - body = self.projects_client.show_project(project['id'])['project'] - en2 = body['enabled'] - self.assertEqual('false', str(en2).lower(), - 'Enable should be False in lookup') - - @decorators.idempotent_id('f608f368-048c-496b-ad63-d286c26dab6b') - def test_project_update_name(self): - # Update name attribute of a project - p_name1 = data_utils.rand_name('project') - project = self.setup_test_project(name=p_name1) - - resp1_name = project['name'] - - p_name2 = data_utils.rand_name('project2') - body = self.projects_client.update_project(project['id'], - name=p_name2)['project'] - resp2_name = body['name'] - self.assertNotEqual(resp1_name, resp2_name) - - body = self.projects_client.show_project(project['id'])['project'] - resp3_name = body['name'] - - self.assertNotEqual(resp1_name, resp3_name) - self.assertEqual(p_name1, resp1_name) - self.assertEqual(resp2_name, resp3_name) - - @decorators.idempotent_id('f138b715-255e-4a7d-871d-351e1ef2e153') - def test_project_update_desc(self): - # Update description attribute of a project - p_desc = data_utils.rand_name('desc') - project = self.setup_test_project(description=p_desc) - resp1_desc = project['description'] - - p_desc2 = data_utils.rand_name('desc2') - body = self.projects_client.update_project( - project['id'], description=p_desc2)['project'] - resp2_desc = body['description'] - self.assertNotEqual(resp1_desc, resp2_desc) - - body = self.projects_client.show_project(project['id'])['project'] - resp3_desc = body['description'] - - self.assertNotEqual(resp1_desc, resp3_desc) - self.assertEqual(p_desc, resp1_desc) - self.assertEqual(resp2_desc, resp3_desc) - - @decorators.idempotent_id('b6b25683-c97f-474d-a595-55d410b68100') - def test_project_update_enable(self): - # Update the enabled attribute of a project - p_en = False - project = self.setup_test_project(enabled=p_en) - - resp1_en = project['enabled'] - - p_en2 = True - body = self.projects_client.update_project(project['id'], - enabled=p_en2)['project'] - resp2_en = body['enabled'] - self.assertNotEqual(resp1_en, resp2_en) - - body = self.projects_client.show_project(project['id'])['project'] - resp3_en = body['enabled'] - - self.assertNotEqual(resp1_en, resp3_en) - self.assertEqual('false', str(resp1_en).lower()) - self.assertEqual(resp2_en, resp3_en) - - @decorators.idempotent_id('59398d4a-5dc5-4f86-9a4c-c26cc804d6c6') - def test_associate_user_to_project(self): - # Associate a user to a project - # Create a Project - project = self.setup_test_project() - - # Create a User - u_name = data_utils.rand_name('user') - u_desc = u_name + 'description' - u_email = u_name + '@testmail.tm' - u_password = data_utils.rand_password() - user = self.users_client.create_user( - name=u_name, description=u_desc, password=u_password, - email=u_email, project_id=project['id'])['user'] - # Delete the User at the end of this method - self.addCleanup(self.users_client.delete_user, user['id']) - - # Get User To validate the user details - new_user_get = self.users_client.show_user(user['id'])['user'] - # Assert response body of GET - self.assertEqual(u_name, new_user_get['name']) - self.assertEqual(u_desc, new_user_get['description']) - self.assertEqual(project['id'], - new_user_get['project_id']) - self.assertEqual(u_email, new_user_get['email']) diff --git a/tempest/api/identity/admin/v3/test_projects_negative.py b/tempest/api/identity/admin/v3/test_projects_negative.py deleted file mode 100644 index 33a9c8cda..000000000 --- a/tempest/api/identity/admin/v3/test_projects_negative.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ProjectsNegativeTestJSON(base.BaseIdentityV3AdminTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('24c49279-45dd-4155-887a-cb738c2385aa') - def test_list_projects_by_unauthorized_user(self): - # Non-admin user should not be able to list projects - self.assertRaises(lib_exc.Forbidden, - self.non_admin_projects_client.list_projects) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('874c3e84-d174-4348-a16b-8c01f599561b') - def test_project_create_duplicate(self): - # Project names should be unique - project_name = data_utils.rand_name('project-dup') - self.setup_test_project(name=project_name) - - self.assertRaises(lib_exc.Conflict, - self.projects_client.create_project, project_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8fba9de2-3e1f-4e77-812a-60cb68f8df13') - def test_create_project_by_unauthorized_user(self): - # Non-admin user should not be authorized to create a project - project_name = data_utils.rand_name('project') - self.assertRaises( - lib_exc.Forbidden, self.non_admin_projects_client.create_project, - project_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7828db17-95e5-475b-9432-9a51b4aa79a9') - def test_create_project_with_empty_name(self): - # Project name should not be empty - self.assertRaises(lib_exc.BadRequest, - self.projects_client.create_project, name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('502b6ceb-b0c8-4422-bf53-f08fdb21e2f0') - def test_create_projects_name_length_over_64(self): - # Project name length should not be greater than 64 characters - project_name = 'a' * 65 - self.assertRaises(lib_exc.BadRequest, - self.projects_client.create_project, project_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8d68c012-89e0-4394-8d6b-ccd7196def97') - def test_project_delete_by_unauthorized_user(self): - # Non-admin user should not be able to delete a project - project = self.setup_test_project() - self.assertRaises( - lib_exc.Forbidden, self.non_admin_projects_client.delete_project, - project['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7965b581-60c1-43b7-8169-95d4ab7fc6fb') - def test_delete_non_existent_project(self): - # Attempt to delete a non existent project should fail - self.assertRaises(lib_exc.NotFound, - self.projects_client.delete_project, - data_utils.rand_uuid_hex()) diff --git a/tempest/api/identity/admin/v3/test_regions.py b/tempest/api/identity/admin/v3/test_regions.py deleted file mode 100644 index d00e40811..000000000 --- a/tempest/api/identity/admin/v3/test_regions.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - - -class RegionsTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def setup_clients(cls): - super(RegionsTestJSON, cls).setup_clients() - cls.client = cls.regions_client - - @classmethod - def resource_setup(cls): - super(RegionsTestJSON, cls).resource_setup() - cls.setup_regions = list() - for _ in range(2): - r_description = data_utils.rand_name('description') - region = cls.client.create_region( - description=r_description)['region'] - cls.setup_regions.append(region) - - @classmethod - def resource_cleanup(cls): - for r in cls.setup_regions: - cls.client.delete_region(r['id']) - super(RegionsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('56186092-82e4-43f2-b954-91013218ba42') - def test_create_update_get_delete_region(self): - # Create region - r_description = data_utils.rand_name('description') - region = self.client.create_region( - description=r_description, - parent_region_id=self.setup_regions[0]['id'])['region'] - # This test will delete the region as part of the validation - # procedure, so it needs a different cleanup method that - # would be useful in case the tests fails at any point before - # reaching the deletion part. - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.client.delete_region, region['id']) - self.assertEqual(r_description, region['description']) - self.assertEqual(self.setup_regions[0]['id'], - region['parent_region_id']) - # Update region with new description and parent ID - r_alt_description = data_utils.rand_name('description') - region = self.client.update_region( - region['id'], - description=r_alt_description, - parent_region_id=self.setup_regions[1]['id'])['region'] - self.assertEqual(r_alt_description, region['description']) - self.assertEqual(self.setup_regions[1]['id'], - region['parent_region_id']) - # Get the details of region - region = self.client.show_region(region['id'])['region'] - self.assertEqual(r_alt_description, region['description']) - self.assertEqual(self.setup_regions[1]['id'], - region['parent_region_id']) - # Delete the region - self.client.delete_region(region['id']) - body = self.client.list_regions()['regions'] - regions_list = [r['id'] for r in body] - self.assertNotIn(region['id'], regions_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2c12c5b5-efcf-4aa5-90c5-bff1ab0cdbe2') - def test_create_region_with_specific_id(self): - # Create a region with a specific id - r_region_id = data_utils.rand_uuid() - r_description = data_utils.rand_name('description') - region = self.client.create_region( - region_id=r_region_id, description=r_description)['region'] - self.addCleanup(self.client.delete_region, region['id']) - # Asserting Create Region with specific id response body - self.assertEqual(r_region_id, region['id']) - self.assertEqual(r_description, region['description']) - - @decorators.idempotent_id('d180bf99-544a-445c-ad0d-0c0d27663796') - def test_list_regions(self): - # Get a list of regions - fetched_regions = self.client.list_regions()['regions'] - missing_regions =\ - [e for e in self.setup_regions if e not in fetched_regions] - # Asserting List Regions response - self.assertEmpty(missing_regions, - "Failed to find region %s in fetched list" % - ', '.join(str(e) for e in missing_regions)) - - @decorators.idempotent_id('2d1057cb-bbde-413a-acdf-e2d265284542') - def test_list_regions_filter_by_parent_region_id(self): - # Add a sub-region to one of the existing test regions - r_description = data_utils.rand_name('description') - region = self.client.create_region( - description=r_description, - parent_region_id=self.setup_regions[0]['id'])['region'] - self.addCleanup(self.client.delete_region, region['id']) - # Get the list of regions filtering with the parent_region_id - params = {'parent_region_id': self.setup_regions[0]['id']} - fetched_regions = self.client.list_regions(params=params)['regions'] - # Asserting list regions response - self.assertIn(region, fetched_regions) - for r in fetched_regions: - self.assertEqual(self.setup_regions[0]['id'], - r['parent_region_id']) diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py deleted file mode 100644 index 6d42b2afa..000000000 --- a/tempest/api/identity/admin/v3/test_roles.py +++ /dev/null @@ -1,435 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class RolesV3TestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - super(RolesV3TestJSON, cls).resource_setup() - cls.roles = list() - for _ in range(3): - role_name = data_utils.rand_name(name='role') - role = cls.roles_client.create_role(name=role_name)['role'] - cls.roles.append(role) - cls.fetched_role_ids = list() - u_name = data_utils.rand_name('user') - u_desc = '%s description' % u_name - u_email = '%s@testmail.tm' % u_name - cls.u_password = data_utils.rand_password() - cls.domain = cls.create_domain() - cls.project = cls.projects_client.create_project( - data_utils.rand_name('project'), - description=data_utils.rand_name('project-desc'), - domain_id=cls.domain['id'])['project'] - cls.group_body = cls.groups_client.create_group( - name=data_utils.rand_name('Group'), project_id=cls.project['id'], - domain_id=cls.domain['id'])['group'] - cls.user_body = cls.users_client.create_user( - name=u_name, description=u_desc, password=cls.u_password, - email=u_email, project_id=cls.project['id'], - domain_id=cls.domain['id'])['user'] - cls.role = cls.roles_client.create_role( - name=data_utils.rand_name('Role'))['role'] - - @classmethod - def resource_cleanup(cls): - cls.roles_client.delete_role(cls.role['id']) - cls.groups_client.delete_group(cls.group_body['id']) - cls.users_client.delete_user(cls.user_body['id']) - cls.projects_client.delete_project(cls.project['id']) - # NOTE(harika-vakadi): It is necessary to disable the domain - # before deleting,or else it would result in unauthorized error - cls.domains_client.update_domain(cls.domain['id'], enabled=False) - cls.domains_client.delete_domain(cls.domain['id']) - for role in cls.roles: - cls.roles_client.delete_role(role['id']) - super(RolesV3TestJSON, cls).resource_cleanup() - - def _list_assertions(self, body, fetched_role_ids, role_id): - self.assertEqual(len(body), 1) - self.assertIn(role_id, fetched_role_ids) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('18afc6c0-46cf-4911-824e-9989cc056c3a') - def test_role_create_update_show_list(self): - r_name = data_utils.rand_name('Role') - role = self.roles_client.create_role(name=r_name)['role'] - self.addCleanup(self.roles_client.delete_role, role['id']) - self.assertIn('name', role) - self.assertEqual(role['name'], r_name) - - new_name = data_utils.rand_name('NewRole') - updated_role = self.roles_client.update_role(role['id'], - name=new_name)['role'] - self.assertIn('name', updated_role) - self.assertIn('id', updated_role) - self.assertIn('links', updated_role) - self.assertNotEqual(r_name, updated_role['name']) - - new_role = self.roles_client.show_role(role['id'])['role'] - self.assertEqual(new_name, new_role['name']) - self.assertEqual(updated_role['id'], new_role['id']) - - roles = self.roles_client.list_roles()['roles'] - self.assertIn(role['id'], [r['id'] for r in roles]) - - @decorators.idempotent_id('c6b80012-fe4a-498b-9ce8-eb391c05169f') - def test_grant_list_revoke_role_to_user_on_project(self): - self.roles_client.create_user_role_on_project(self.project['id'], - self.user_body['id'], - self.role['id']) - - roles = self.roles_client.list_user_roles_on_project( - self.project['id'], self.user_body['id'])['roles'] - - for i in roles: - self.fetched_role_ids.append(i['id']) - - self._list_assertions(roles, self.fetched_role_ids, - self.role['id']) - - self.roles_client.check_user_role_existence_on_project( - self.project['id'], self.user_body['id'], self.role['id']) - - self.roles_client.delete_role_from_user_on_project( - self.project['id'], self.user_body['id'], self.role['id']) - - @decorators.idempotent_id('6c9a2940-3625-43a3-ac02-5dcec62ef3bd') - def test_grant_list_revoke_role_to_user_on_domain(self): - self.roles_client.create_user_role_on_domain( - self.domain['id'], self.user_body['id'], self.role['id']) - - roles = self.roles_client.list_user_roles_on_domain( - self.domain['id'], self.user_body['id'])['roles'] - - for i in roles: - self.fetched_role_ids.append(i['id']) - - self._list_assertions(roles, self.fetched_role_ids, - self.role['id']) - - self.roles_client.check_user_role_existence_on_domain( - self.domain['id'], self.user_body['id'], self.role['id']) - - self.roles_client.delete_role_from_user_on_domain( - self.domain['id'], self.user_body['id'], self.role['id']) - - @decorators.idempotent_id('cbf11737-1904-4690-9613-97bcbb3df1c4') - def test_grant_list_revoke_role_to_group_on_project(self): - # Grant role to group on project - self.roles_client.create_group_role_on_project( - self.project['id'], self.group_body['id'], self.role['id']) - # List group roles on project - roles = self.roles_client.list_group_roles_on_project( - self.project['id'], self.group_body['id'])['roles'] - - for i in roles: - self.fetched_role_ids.append(i['id']) - - self._list_assertions(roles, self.fetched_role_ids, - self.role['id']) - # Add user to group, and insure user has role on project - self.groups_client.add_group_user(self.group_body['id'], - self.user_body['id']) - self.addCleanup(self.groups_client.delete_group_user, - self.group_body['id'], self.user_body['id']) - body = self.token.auth(user_id=self.user_body['id'], - password=self.u_password, - user_domain_name=self.domain['name'], - project_name=self.project['name'], - project_domain_name=self.domain['name']) - roles = body['token']['roles'] - self.assertEqual(len(roles), 1) - self.assertEqual(roles[0]['id'], self.role['id']) - - self.roles_client.check_role_from_group_on_project_existence( - self.project['id'], self.group_body['id'], self.role['id']) - - # Revoke role to group on project - self.roles_client.delete_role_from_group_on_project( - self.project['id'], self.group_body['id'], self.role['id']) - - @decorators.idempotent_id('4bf8a70b-e785-413a-ad53-9f91ce02faa7') - def test_grant_list_revoke_role_to_group_on_domain(self): - self.roles_client.create_group_role_on_domain( - self.domain['id'], self.group_body['id'], self.role['id']) - - roles = self.roles_client.list_group_roles_on_domain( - self.domain['id'], self.group_body['id'])['roles'] - - for i in roles: - self.fetched_role_ids.append(i['id']) - - self._list_assertions(roles, self.fetched_role_ids, - self.role['id']) - - self.roles_client.check_role_from_group_on_domain_existence( - self.domain['id'], self.group_body['id'], self.role['id']) - - self.roles_client.delete_role_from_group_on_domain( - self.domain['id'], self.group_body['id'], self.role['id']) - - @decorators.idempotent_id('f5654bcc-08c4-4f71-88fe-05d64e06de94') - def test_list_roles(self): - # Return a list of all roles - body = self.roles_client.list_roles()['roles'] - found = [role for role in body if role in self.roles] - self.assertEqual(len(found), len(self.roles)) - - def _create_implied_role(self, prior_role_id, implies_role_id, - ignore_not_found=False): - self.roles_client.create_role_inference_rule( - prior_role_id, implies_role_id) - if ignore_not_found: - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_inference_rule, - prior_role_id, - implies_role_id) - else: - self.addCleanup( - self.roles_client.delete_role_inference_rule, - prior_role_id, - implies_role_id) - - @decorators.idempotent_id('c90c316c-d706-4728-bcba-eb1912081b69') - def test_implied_roles_create_check_show_delete(self): - prior_role_id = self.roles[0]['id'] - implies_role_id = self.roles[1]['id'] - - # Create an inference rule from prior_role to implies_role - self._create_implied_role(prior_role_id, implies_role_id, - ignore_not_found=True) - - # Check if the inference rule exists - self.roles_client.check_role_inference_rule( - prior_role_id, implies_role_id) - - # Show the inference rule and check its elements - resp_body = self.roles_client.show_role_inference_rule( - prior_role_id, implies_role_id) - self.assertIn('role_inference', resp_body) - role_inference = resp_body['role_inference'] - for key1 in ['prior_role', 'implies']: - self.assertIn(key1, role_inference) - for key2 in ['id', 'links', 'name']: - self.assertIn(key2, role_inference[key1]) - - # Delete the inference rule - self.roles_client.delete_role_inference_rule( - prior_role_id, implies_role_id) - # Check if the inference rule no longer exists - self.assertRaises( - lib_exc.NotFound, - self.roles_client.show_role_inference_rule, - prior_role_id, - implies_role_id) - - @decorators.idempotent_id('dc6f5959-b74d-4e30-a9e5-a8255494ff00') - def test_roles_hierarchy(self): - # Create inference rule from "roles[0]" to "role[1]" - self._create_implied_role( - self.roles[0]['id'], self.roles[1]['id']) - - # Create inference rule from "roles[0]" to "role[2]" - self._create_implied_role( - self.roles[0]['id'], self.roles[2]['id']) - - # Create inference rule from "roles[2]" to "role" - self._create_implied_role( - self.roles[2]['id'], self.role['id']) - - # Listing inferences rules from "roles[2]" should only return "role" - rules = self.roles_client.list_role_inferences_rules( - self.roles[2]['id'])['role_inference'] - self.assertEqual(1, len(rules['implies'])) - self.assertEqual(self.role['id'], rules['implies'][0]['id']) - - # Listing inferences rules from "roles[0]" should return "roles[1]" and - # "roles[2]" (only direct rules are listed) - rules = self.roles_client.list_role_inferences_rules( - self.roles[0]['id'])['role_inference'] - implies_ids = [role['id'] for role in rules['implies']] - self.assertEqual(2, len(implies_ids)) - self.assertIn(self.roles[1]['id'], implies_ids) - self.assertIn(self.roles[2]['id'], implies_ids) - - @decorators.idempotent_id('c8828027-df48-4021-95df-b65b92c7429e') - def test_assignments_for_implied_roles_create_delete(self): - # Create a grant using "roles[0]" - self.roles_client.create_user_role_on_project( - self.project['id'], self.user_body['id'], self.roles[0]['id']) - self.addCleanup( - self.roles_client.delete_role_from_user_on_project, - self.project['id'], self.user_body['id'], self.roles[0]['id']) - - # Create an inference rule from "roles[0]" to "roles[1]" - self._create_implied_role(self.roles[0]['id'], self.roles[1]['id'], - ignore_not_found=True) - - # In the effective list of role assignments, both prior role and - # implied role should be present. This means that a user can - # authenticate using both roles (both roles will be present - # in the token). - params = {'scope.project.id': self.project['id'], - 'user.id': self.user_body['id']} - role_assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEqual(2, len(role_assignments)) - - roles_ids = [assignment['role']['id'] - for assignment in role_assignments] - self.assertIn(self.roles[0]['id'], roles_ids) - self.assertIn(self.roles[1]['id'], roles_ids) - - # After deleting the implied role, only the assignment with "roles[0]" - # should be present. - self.roles_client.delete_role_inference_rule( - self.roles[0]['id'], self.roles[1]['id']) - - role_assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEqual(1, len(role_assignments)) - - roles_ids = [assignment['role']['id'] - for assignment in role_assignments] - self.assertIn(self.roles[0]['id'], roles_ids) - - @decorators.idempotent_id('d92a41d2-5501-497a-84bb-6e294330e8f8') - def test_domain_roles_create_delete(self): - domain_role = self.roles_client.create_role( - name=data_utils.rand_name('domain_role'), - domain_id=self.domain['id'])['role'] - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role, - domain_role['id']) - - domain_roles = self.roles_client.list_roles( - domain_id=self.domain['id'])['roles'] - self.assertEqual(1, len(domain_roles)) - self.assertIn(domain_role, domain_roles) - - self.roles_client.delete_role(domain_role['id']) - domain_roles = self.roles_client.list_roles( - domain_id=self.domain['id'])['roles'] - self.assertEmpty(domain_roles) - - @decorators.idempotent_id('eb1e1c24-1bc4-4d47-9748-e127a1852c82') - def test_implied_domain_roles(self): - # Create two roles in the same domain - domain_role1 = self.setup_test_role(domain_id=self.domain['id']) - domain_role2 = self.setup_test_role(domain_id=self.domain['id']) - - # Check if we can create an inference rule from roles in the same - # domain - self._create_implied_role(domain_role1['id'], domain_role2['id']) - - # Create another role in a different domain - domain2 = self.setup_test_domain() - domain_role3 = self.setup_test_role(domain_id=domain2['id']) - - # Check if we can create cross domain implied roles - self._create_implied_role(domain_role1['id'], domain_role3['id']) - - # Finally, we also should be able to create an implied from a - # domain role to a global one - self._create_implied_role(domain_role1['id'], self.role['id']) - - if CONF.identity_feature_enabled.forbid_global_implied_dsr: - # The contrary is not true: we can't create an inference rule - # from a global role to a domain role - self.assertRaises( - lib_exc.Forbidden, - self.roles_client.create_role_inference_rule, - self.role['id'], - domain_role1['id']) - - @decorators.idempotent_id('3859df7e-5b78-4e4d-b10e-214c8953842a') - def test_assignments_for_domain_roles(self): - domain_role = self.setup_test_role(domain_id=self.domain['id']) - - # Create a grant using "domain_role" - self.roles_client.create_user_role_on_project( - self.project['id'], self.user_body['id'], domain_role['id']) - self.addCleanup( - self.roles_client.delete_role_from_user_on_project, - self.project['id'], self.user_body['id'], domain_role['id']) - - # NOTE(rodrigods): Regular roles would appear in the effective - # list of role assignments (meaning the role would be returned in - # a token) as a result from the grant above. This is not the case - # for domain roles, they should not appear in the effective role - # assignments list. - params = {'scope.project.id': self.project['id'], - 'user.id': self.user_body['id']} - role_assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEmpty(role_assignments) - - @decorators.idempotent_id('3748c316-c18f-4b08-997b-c60567bc6235') - def test_list_all_implied_roles(self): - # Create inference rule from "roles[0]" to "roles[1]" - self._create_implied_role( - self.roles[0]['id'], self.roles[1]['id']) - - # Create inference rule from "roles[0]" to "roles[2]" - self._create_implied_role( - self.roles[0]['id'], self.roles[2]['id']) - - # Create inference rule from "roles[2]" to "role" - self._create_implied_role( - self.roles[2]['id'], self.role['id']) - - rules = self.roles_client.list_all_role_inference_rules()[ - 'role_inferences'] - # Sort the rules by the number of inferences, since there should be 1 - # inference between "roles[2]" and "role" and 2 inferences for - # "roles[0]": between "roles[1]" and "roles[2]". - sorted_rules = sorted(rules, key=lambda r: len(r['implies'])) - - # Check that 2 sets of rules are returned. - self.assertEqual(2, len(sorted_rules)) - # Check that only 1 inference rule exists between "roles[2]" and "role" - self.assertEqual(1, len(sorted_rules[0]['implies'])) - # Check that 2 inference rules exist for "roles[0]": one between - # "roles[1]" and one between "roles[2]". - self.assertEqual(2, len(sorted_rules[1]['implies'])) - - # Check that "roles[2]" is the "prior_role" and that "role" is the - # "implies" role. - self.assertEqual(self.roles[2]['id'], - sorted_rules[0]['prior_role']['id']) - self.assertEqual(self.role['id'], - sorted_rules[0]['implies'][0]['id']) - - # Check that "roles[0]" is the "prior_role" and that "roles[1]" and - # "roles[2]" are the "implies" roles. - self.assertEqual(self.roles[0]['id'], - sorted_rules[1]['prior_role']['id']) - - implies_ids = [r['id'] for r in sorted_rules[1]['implies']] - self.assertIn(self.roles[1]['id'], implies_ids) - self.assertIn(self.roles[2]['id'], implies_ids) diff --git a/tempest/api/identity/admin/v3/test_services.py b/tempest/api/identity/admin/v3/test_services.py deleted file mode 100644 index 20c8a4456..000000000 --- a/tempest/api/identity/admin/v3/test_services.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ServicesTestJSON(base.BaseIdentityV3AdminTest): - - def _del_service(self, service_id): - # Used for deleting the services created in this class - self.services_client.delete_service(service_id) - # Checking whether service is deleted successfully - self.assertRaises(lib_exc.NotFound, self.services_client.show_service, - service_id) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('5193aad5-bcb7-411d-85b0-b3b61b96ef06') - def test_create_update_get_service(self): - # Creating a Service - name = data_utils.rand_name('service') - serv_type = data_utils.rand_name('type') - desc = data_utils.rand_name('description') - create_service = self.services_client.create_service( - type=serv_type, name=name, description=desc)['service'] - self.addCleanup(self._del_service, create_service['id']) - self.assertIsNotNone(create_service['id']) - - # Verifying response body of create service - expected_data = {'name': name, 'type': serv_type, 'description': desc} - self.assertDictContainsSubset(expected_data, create_service) - - # Update description - s_id = create_service['id'] - resp1_desc = create_service['description'] - s_desc2 = data_utils.rand_name('desc2') - update_service = self.services_client.update_service( - s_id, description=s_desc2)['service'] - resp2_desc = update_service['description'] - - self.assertNotEqual(resp1_desc, resp2_desc) - - # Get service - fetched_service = self.services_client.show_service(s_id)['service'] - resp3_desc = fetched_service['description'] - - self.assertEqual(resp2_desc, resp3_desc) - self.assertDictContainsSubset(update_service, fetched_service) - - @decorators.idempotent_id('d1dcb1a1-2b6b-4da8-bbb8-5532ef6e8269') - def test_create_service_without_description(self): - # Create a service only with name and type - name = data_utils.rand_name('service') - serv_type = data_utils.rand_name('type') - service = self.services_client.create_service( - type=serv_type, name=name)['service'] - self.addCleanup(self.services_client.delete_service, service['id']) - self.assertIn('id', service) - expected_data = {'name': name, 'type': serv_type} - self.assertDictContainsSubset(expected_data, service) - - @decorators.idempotent_id('e55908e8-360e-439e-8719-c3230a3e179e') - def test_list_services(self): - # Create, List, Verify and Delete Services - service_ids = list() - service_types = list() - for _ in range(3): - name = data_utils.rand_name(self.__class__.__name__ + '-Service') - serv_type = data_utils.rand_name(self.__class__.__name__ + '-Type') - create_service = self.services_client.create_service( - type=serv_type, name=name)['service'] - self.addCleanup(self.services_client.delete_service, - create_service['id']) - service_ids.append(create_service['id']) - service_types.append(serv_type) - - # List and Verify Services - services = self.services_client.list_services()['services'] - fetched_ids = [service['id'] for service in services] - found = [s for s in fetched_ids if s in service_ids] - self.assertEqual(len(found), len(service_ids)) - - # Check that filtering by service type works. - for serv_type in service_types: - fetched_services = self.services_client.list_services( - type=serv_type)['services'] - self.assertEqual(1, len(fetched_services)) - self.assertEqual(serv_type, fetched_services[0]['type']) diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py deleted file mode 100644 index 5c3cd2667..000000000 --- a/tempest/api/identity/admin/v3/test_tokens.py +++ /dev/null @@ -1,176 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class TokensV3TestJSON(base.BaseIdentityV3AdminTest): - - @decorators.idempotent_id('0f9f5a5f-d5cd-4a86-8a5b-c5ded151f212') - def test_tokens(self): - # Valid user's token is authenticated - # Create a User - u_name = data_utils.rand_name('user') - u_desc = '%s-description' % u_name - u_password = data_utils.rand_password() - user = self.create_test_user( - name=u_name, description=u_desc, password=u_password) - # Perform Authentication - resp = self.token.auth(user_id=user['id'], - password=u_password).response - subject_token = resp['x-subject-token'] - self.client.check_token_existence(subject_token) - # Perform GET Token - token_details = self.client.show_token(subject_token)['token'] - self.assertEqual(resp['x-subject-token'], subject_token) - self.assertEqual(token_details['user']['id'], user['id']) - self.assertEqual(token_details['user']['name'], u_name) - # Perform Delete Token - self.client.delete_token(subject_token) - self.assertRaises(lib_exc.NotFound, self.client.check_token_existence, - subject_token) - - @decorators.idempotent_id('565fa210-1da1-4563-999b-f7b5b67cf112') - def test_rescope_token(self): - """Rescope a token. - - An unscoped token can be requested, that token can be used to request a - scoped token. The scoped token can be revoked, and the original token - used to get a token in a different project. - - """ - - # Create a user. - user_password = data_utils.rand_password() - user = self.create_test_user(password=user_password) - - # Create a couple projects - project1_name = data_utils.rand_name(name='project') - project1 = self.setup_test_project(name=project1_name) - - project2_name = data_utils.rand_name(name='project') - project2 = self.setup_test_project(name=project2_name) - self.addCleanup(self.projects_client.delete_project, project2['id']) - - # Create a role - role = self.setup_test_role() - - # Grant the user the role on both projects. - self.roles_client.create_user_role_on_project(project1['id'], - user['id'], - role['id']) - - self.roles_client.create_user_role_on_project(project2['id'], - user['id'], - role['id']) - - # Get an unscoped token. - token_auth = self.token.auth(user_id=user['id'], - password=user_password) - - token_id = token_auth.response['x-subject-token'] - orig_expires_at = token_auth['token']['expires_at'] - orig_user = token_auth['token']['user'] - - self.assertIsInstance(token_auth['token']['expires_at'], six.text_type) - self.assertIsInstance(token_auth['token']['issued_at'], six.text_type) - self.assertEqual(['password'], token_auth['token']['methods']) - self.assertEqual(user['id'], token_auth['token']['user']['id']) - self.assertEqual(user['name'], token_auth['token']['user']['name']) - self.assertEqual(CONF.identity.default_domain_id, - token_auth['token']['user']['domain']['id']) - self.assertIsNotNone(token_auth['token']['user']['domain']['name']) - self.assertNotIn('catalog', token_auth['token']) - self.assertNotIn('project', token_auth['token']) - self.assertNotIn('roles', token_auth['token']) - - # Use the unscoped token to get a scoped token. - token_auth = self.token.auth( - token=token_id, - project_name=project1_name, - project_domain_id=CONF.identity.default_domain_id) - token1_id = token_auth.response['x-subject-token'] - - self.assertEqual(orig_expires_at, token_auth['token']['expires_at'], - 'Expiration time should match original token') - self.assertIsInstance(token_auth['token']['issued_at'], six.text_type) - self.assertEqual(set(['password', 'token']), - set(token_auth['token']['methods'])) - self.assertEqual(orig_user, token_auth['token']['user'], - 'User should match original token') - self.assertIsInstance(token_auth['token']['catalog'], list) - self.assertEqual(project1['id'], - token_auth['token']['project']['id']) - self.assertEqual(project1['name'], - token_auth['token']['project']['name']) - self.assertEqual(CONF.identity.default_domain_id, - token_auth['token']['project']['domain']['id']) - self.assertIsNotNone(token_auth['token']['project']['domain']['name']) - self.assertEqual(1, len(token_auth['token']['roles'])) - self.assertEqual(role['id'], token_auth['token']['roles'][0]['id']) - self.assertEqual(role['name'], token_auth['token']['roles'][0]['name']) - - # Revoke the unscoped token. - self.client.delete_token(token1_id) - - # Now get another scoped token using the unscoped token. - token_auth = self.token.auth( - token=token_id, - project_name=project2_name, - project_domain_id=CONF.identity.default_domain_id) - - self.assertEqual(project2['id'], - token_auth['token']['project']['id']) - self.assertEqual(project2['name'], - token_auth['token']['project']['name']) - - @decorators.idempotent_id('08ed85ce-2ba8-4864-b442-bcc61f16ae89') - def test_get_available_project_scopes(self): - manager_project_id = self.os_primary.credentials.project_id - admin_user_id = self.os_admin.credentials.user_id - admin_role_id = self.get_role_by_name(CONF.identity.admin_role)['id'] - - # Grant the user the role on both projects. - self.roles_client.create_user_role_on_project( - manager_project_id, admin_user_id, admin_role_id) - self.addCleanup( - self.roles_client.delete_role_from_user_on_project, - manager_project_id, admin_user_id, admin_role_id) - - assigned_project_ids = [self.os_admin.credentials.project_id, - manager_project_id] - - # Get available project scopes - available_projects =\ - self.client.list_auth_projects()['projects'] - - # create list to save fetched project's id - fetched_project_ids = [i['id'] for i in available_projects] - - # verifying the project ids in list - missing_project_ids = \ - [p for p in assigned_project_ids - if p not in fetched_project_ids] - self.assertEmpty(missing_project_ids, - "Failed to find project_id %s in fetched list" % - ', '.join(missing_project_ids)) diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py deleted file mode 100644 index 3e6a2de7a..000000000 --- a/tempest/api/identity/admin/v3/test_trusts.py +++ /dev/null @@ -1,289 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import datetime -import re - -from oslo_utils import timeutils - -from tempest.api.identity import base -from tempest import clients -from tempest.common import credentials_factory as common_creds -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class BaseTrustsV3Test(base.BaseIdentityV3AdminTest): - - def setUp(self): - super(BaseTrustsV3Test, self).setUp() - # Use alt_username as the trustee - if not CONF.identity_feature_enabled.trust: - raise self.skipException("Trusts aren't enabled") - - self.trust_id = None - - def tearDown(self): - if self.trust_id: - # Do the delete in tearDown not addCleanup - we want the test to - # fail in the event there is a bug which causes undeletable trusts - self.delete_trust() - super(BaseTrustsV3Test, self).tearDown() - - def create_trustor_and_roles(self): - # create a project that trusts will be granted on - trustor_project_name = data_utils.rand_name(name='project') - project = self.projects_client.create_project( - trustor_project_name, - domain_id=CONF.identity.default_domain_id)['project'] - self.trustor_project_id = project['id'] - self.assertIsNotNone(self.trustor_project_id) - - # Create a trustor User - trustor_username = data_utils.rand_name('user') - u_desc = trustor_username + 'description' - u_email = trustor_username + '@testmail.xx' - trustor_password = data_utils.rand_password() - user = self.users_client.create_user( - name=trustor_username, - description=u_desc, - password=trustor_password, - email=u_email, - project_id=self.trustor_project_id, - domain_id=CONF.identity.default_domain_id)['user'] - self.trustor_user_id = user['id'] - - # And two roles, one we'll delegate and one we won't - self.delegated_role = data_utils.rand_name('DelegatedRole') - self.not_delegated_role = data_utils.rand_name('NotDelegatedRole') - - role = self.roles_client.create_role(name=self.delegated_role)['role'] - self.delegated_role_id = role['id'] - - role = self.roles_client.create_role( - name=self.not_delegated_role)['role'] - self.not_delegated_role_id = role['id'] - - # Assign roles to trustor - self.roles_client.create_user_role_on_project( - self.trustor_project_id, - self.trustor_user_id, - self.delegated_role_id) - self.roles_client.create_user_role_on_project( - self.trustor_project_id, - self.trustor_user_id, - self.not_delegated_role_id) - - # Get trustee user ID, use the demo user - trustee_username = self.non_admin_client.user - self.trustee_user_id = self.get_user_by_name(trustee_username)['id'] - self.assertIsNotNone(self.trustee_user_id) - - # Initialize a new client with the trustor credentials - creds = common_creds.get_credentials( - identity_version='v3', - username=trustor_username, - password=trustor_password, - user_domain_id=CONF.identity.default_domain_id, - tenant_name=trustor_project_name, - project_domain_id=CONF.identity.default_domain_id, - domain_id=CONF.identity.default_domain_id) - os = clients.Manager(credentials=creds) - self.trustor_client = os.trusts_client - - def cleanup_user_and_roles(self): - if self.trustor_user_id: - self.users_client.delete_user(self.trustor_user_id) - if self.trustor_project_id: - self.projects_client.delete_project(self.trustor_project_id) - if self.delegated_role_id: - self.roles_client.delete_role(self.delegated_role_id) - if self.not_delegated_role_id: - self.roles_client.delete_role(self.not_delegated_role_id) - - def create_trust(self, impersonate=True, expires=None): - - trust_create = self.trustor_client.create_trust( - trustor_user_id=self.trustor_user_id, - trustee_user_id=self.trustee_user_id, - project_id=self.trustor_project_id, - roles=[{'name': self.delegated_role}], - impersonation=impersonate, - expires_at=expires)['trust'] - self.trust_id = trust_create['id'] - return trust_create - - def validate_trust(self, trust, impersonate=True, expires=None, - summary=False): - self.assertIsNotNone(trust['id']) - self.assertEqual(impersonate, trust['impersonation']) - if expires is not None: - # Omit microseconds component of the expiry time - trust_expires_at = re.sub(r'\.([0-9]){6}', '', trust['expires_at']) - self.assertEqual(expires, trust_expires_at) - else: - self.assertIsNone(trust['expires_at']) - self.assertEqual(self.trustor_user_id, trust['trustor_user_id']) - self.assertEqual(self.trustee_user_id, trust['trustee_user_id']) - self.assertIn('v3/OS-TRUST/trusts', trust['links']['self']) - self.assertEqual(self.trustor_project_id, trust['project_id']) - if not summary: - self.assertEqual(self.delegated_role, trust['roles'][0]['name']) - self.assertEqual(1, len(trust['roles'])) - - def show_trust(self): - trust_get = self.trustor_client.show_trust(self.trust_id)['trust'] - return trust_get - - def validate_role(self, role): - self.assertEqual(self.delegated_role_id, role['id']) - self.assertEqual(self.delegated_role, role['name']) - self.assertIn('v3/roles/%s' % self.delegated_role_id, - role['links']['self']) - self.assertNotEqual(self.not_delegated_role_id, role['id']) - self.assertNotEqual(self.not_delegated_role, role['name']) - self.assertNotIn('v3/roles/%s' % self.not_delegated_role_id, - role['links']['self']) - - def check_trust_roles(self): - # Check we find the delegated role - roles_get = self.trustor_client.list_trust_roles( - self.trust_id)['roles'] - self.assertEqual(1, len(roles_get)) - self.validate_role(roles_get[0]) - - role_get = self.trustor_client.show_trust_role( - self.trust_id, self.delegated_role_id)['role'] - self.validate_role(role_get) - - role_get = self.trustor_client.check_trust_role( - self.trust_id, self.delegated_role_id) - - # And that we don't find not_delegated_role - self.assertRaises(lib_exc.NotFound, - self.trustor_client.show_trust_role, - self.trust_id, - self.not_delegated_role_id) - - self.assertRaises(lib_exc.NotFound, - self.trustor_client.check_trust_role, - self.trust_id, - self.not_delegated_role_id) - - def delete_trust(self): - self.trustor_client.delete_trust(self.trust_id) - self.assertRaises(lib_exc.NotFound, - self.trustor_client.show_trust, - self.trust_id) - self.trust_id = None - - -class TrustsV3TestJSON(BaseTrustsV3Test): - - def setUp(self): - super(TrustsV3TestJSON, self).setUp() - self.create_trustor_and_roles() - self.addCleanup(self.cleanup_user_and_roles) - - @decorators.idempotent_id('5a0a91a4-baef-4a14-baba-59bf4d7fcace') - def test_trust_impersonate(self): - # Test case to check we can create, get and delete a trust - # updates are not supported for trusts - trust = self.create_trust() - self.validate_trust(trust) - - trust_get = self.show_trust() - self.validate_trust(trust_get) - - self.check_trust_roles() - - @decorators.idempotent_id('ed2a8779-a7ac-49dc-afd7-30f32f936ed2') - def test_trust_noimpersonate(self): - # Test case to check we can create, get and delete a trust - # with impersonation=False - trust = self.create_trust(impersonate=False) - self.validate_trust(trust, impersonate=False) - - trust_get = self.show_trust() - self.validate_trust(trust_get, impersonate=False) - - self.check_trust_roles() - - @decorators.idempotent_id('0ed14b66-cefd-4b5c-a964-65759453e292') - def test_trust_expire(self): - # Test case to check we can create, get and delete a trust - # with an expiry specified - expires_at = timeutils.utcnow() + datetime.timedelta(hours=1) - # NOTE(ylobankov) In some cases the expiry time may be rounded up - # because of microseconds. In fact, it depends on database and its - # version. At least MySQL 5.6.16 does this. - # For example, when creating a trust, we will set the expiry time of - # the trust to 2015-02-17T17:34:01.907051Z. However, if we make a GET - # request on the trust, the response will contain the time rounded up - # to 2015-02-17T17:34:02.000000Z. That is why we set microsecond to - # 0 when we invoke isoformat to avoid problems with rounding. - expires_at = expires_at.replace(microsecond=0) - # NOTE(ekhugen) Python datetime does not support military timezones - # since we used UTC we'll add the Z so our compare works. - expires_str = expires_at.isoformat() + 'Z' - - trust = self.create_trust(expires=expires_str) - self.validate_trust(trust, expires=expires_str) - - trust_get = self.show_trust() - - self.validate_trust(trust_get, expires=expires_str) - - self.check_trust_roles() - - @decorators.idempotent_id('3e48f95d-e660-4fa9-85e0-5a3d85594384') - def test_trust_expire_invalid(self): - # Test case to check we can check an invalid expiry time - # is rejected with the correct error - # with an expiry specified - expires_str = 'bad.123Z' - self.assertRaises(lib_exc.BadRequest, - self.create_trust, - expires=expires_str) - - @decorators.idempotent_id('6268b345-87ca-47c0-9ce3-37792b43403a') - def test_get_trusts_query(self): - self.create_trust() - trusts_get = self.trustor_client.list_trusts( - trustor_user_id=self.trustor_user_id)['trusts'] - self.assertEqual(1, len(trusts_get)) - self.validate_trust(trusts_get[0], summary=True) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('4773ebd5-ecbf-4255-b8d8-b63e6f72b65d') - def test_get_trusts_all(self): - - # Simple function that can be used for cleanup - def set_scope(auth_provider, scope): - auth_provider.scope = scope - - self.create_trust() - # Listing trusts can be done by trustor, by trustee, or without - # any filter if scoped to a project, so we must ensure token scope is - # project for this test. - original_scope = self.os_admin.auth_provider.scope - set_scope(self.os_admin.auth_provider, 'project') - self.addCleanup(set_scope, self.os_admin.auth_provider, original_scope) - trusts_get = self.trusts_client.list_trusts()['trusts'] - trusts = [t for t in trusts_get - if t['id'] == self.trust_id] - self.assertEqual(1, len(trusts)) - self.validate_trust(trusts[0], summary=True) diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py deleted file mode 100644 index 409d4f837..000000000 --- a/tempest/api/identity/admin/v3/test_users.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -import testtools - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -CONF = config.CONF - - -class UsersV3TestJSON(base.BaseIdentityV3AdminTest): - - @decorators.idempotent_id('b537d090-afb9-4519-b95d-270b0708e87e') - def test_user_update(self): - # Test case to check if updating of user attributes is successful. - # Creating first user - u_name = data_utils.rand_name('user') - u_desc = u_name + 'description' - u_email = u_name + '@testmail.tm' - u_password = data_utils.rand_password() - user = self.users_client.create_user( - name=u_name, description=u_desc, password=u_password, - email=u_email, enabled=False)['user'] - # Delete the User at the end of this method - self.addCleanup(self.users_client.delete_user, user['id']) - # Creating second project for updation - project = self.setup_test_project() - # Updating user details with new values - u_name2 = data_utils.rand_name('user2') - u_email2 = u_name2 + '@testmail.tm' - u_description2 = u_name2 + ' description' - update_user = self.users_client.update_user( - user['id'], name=u_name2, description=u_description2, - project_id=project['id'], - email=u_email2, enabled=False)['user'] - self.assertEqual(u_name2, update_user['name']) - self.assertEqual(u_description2, update_user['description']) - self.assertEqual(project['id'], - update_user['project_id']) - self.assertEqual(u_email2, update_user['email']) - self.assertEqual(False, update_user['enabled']) - # GET by id after updation - new_user_get = self.users_client.show_user(user['id'])['user'] - # Assert response body of GET after updation - self.assertEqual(u_name2, new_user_get['name']) - self.assertEqual(u_description2, new_user_get['description']) - self.assertEqual(project['id'], - new_user_get['project_id']) - self.assertEqual(u_email2, new_user_get['email']) - self.assertEqual(False, new_user_get['enabled']) - - @decorators.idempotent_id('2d223a0e-e457-4a70-9fb1-febe027a0ff9') - def test_update_user_password(self): - # Creating User to check password updation - u_name = data_utils.rand_name('user') - original_password = data_utils.rand_password() - user = self.users_client.create_user( - name=u_name, password=original_password)['user'] - # Delete the User at the end all test methods - self.addCleanup(self.users_client.delete_user, user['id']) - # Update user with new password - new_password = data_utils.rand_password() - self.users_client.update_user_password( - user['id'], password=new_password, - original_password=original_password) - # NOTE(morganfainberg): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure - # we are passing the second boundary. - time.sleep(1) - resp = self.token.auth(user_id=user['id'], - password=new_password).response - subject_token = resp['x-subject-token'] - # Perform GET Token to verify and confirm password is updated - token_details = self.client.show_token(subject_token)['token'] - self.assertEqual(token_details['user']['id'], user['id']) - self.assertEqual(token_details['user']['name'], u_name) - - @decorators.idempotent_id('a831e70c-e35b-430b-92ed-81ebbc5437b8') - def test_list_user_projects(self): - # List the projects that a user has access upon - assigned_project_ids = list() - fetched_project_ids = list() - u_project = self.setup_test_project() - # Create a user. - u_name = data_utils.rand_name('user') - u_desc = u_name + 'description' - u_email = u_name + '@testmail.tm' - u_password = data_utils.rand_password() - user_body = self.users_client.create_user( - name=u_name, description=u_desc, password=u_password, - email=u_email, enabled=False, project_id=u_project['id'])['user'] - # Delete the User at the end of this method - self.addCleanup(self.users_client.delete_user, user_body['id']) - # Creating Role - role_body = self.setup_test_role() - - user = self.users_client.show_user(user_body['id'])['user'] - role = self.roles_client.show_role(role_body['id'])['role'] - for _ in range(2): - # Creating project so as to assign role - project_body = self.setup_test_project() - project = self.projects_client.show_project( - project_body['id'])['project'] - # Assigning roles to user on project - self.roles_client.create_user_role_on_project(project['id'], - user['id'], - role['id']) - assigned_project_ids.append(project['id']) - body = self.users_client.list_user_projects(user['id'])['projects'] - for i in body: - fetched_project_ids.append(i['id']) - # verifying the project ids in list - missing_projects =\ - [p for p in assigned_project_ids - if p not in fetched_project_ids] - self.assertEmpty(missing_projects, - "Failed to find project %s in fetched list" % - ', '.join(m_project for m_project - in missing_projects)) - - @decorators.idempotent_id('c10dcd90-461d-4b16-8e23-4eb836c00644') - def test_get_user(self): - # Get a user detail - user = self.setup_test_user() - fetched_user = self.users_client.show_user(user['id'])['user'] - self.assertEqual(user['id'], fetched_user['id']) - - @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance, - 'Security compliance not available.') - @decorators.idempotent_id('568cd46c-ee6c-4ab4-a33a-d3791931979e') - def test_password_history_not_enforced_in_admin_reset(self): - old_password = self.os_primary.credentials.password - user_id = self.os_primary.credentials.user_id - - new_password = data_utils.rand_password() - self.users_client.update_user(user_id, password=new_password) - # To be safe, we add this cleanup to restore the original password in - # case something goes wrong before it is restored later. - self.addCleanup( - self.users_client.update_user, user_id, password=old_password) - - # Check authorization with new password - self.token.auth(user_id=user_id, password=new_password) - - if CONF.identity.user_unique_last_password_count > 1: - # The password history is not enforced via the admin reset route. - # We can set the same password. - self.users_client.update_user(user_id, password=new_password) - - # Restore original password - self.users_client.update_user(user_id, password=old_password) - # Check authorization with old password - self.token.auth(user_id=user_id, password=old_password) diff --git a/tempest/api/identity/admin/v3/test_users_negative.py b/tempest/api/identity/admin/v3/test_users_negative.py deleted file mode 100644 index 11dcdb03f..000000000 --- a/tempest/api/identity/admin/v3/test_users_negative.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class UsersNegativeTest(base.BaseIdentityV3AdminTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e75f006c-89cc-477b-874d-588e4eab4b17') - def test_create_user_for_non_existent_domain(self): - # Attempt to create a user in a non-existent domain should fail - u_name = data_utils.rand_name('user') - u_email = u_name + '@testmail.tm' - u_password = data_utils.rand_password() - self.assertRaises(lib_exc.NotFound, self.users_client.create_user, - name=u_name, password=u_password, - email=u_email, - domain_id=data_utils.rand_uuid_hex()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b3c9fccc-4134-46f5-b600-1da6fb0a3b1f') - def test_authentication_for_disabled_user(self): - # Attempt to authenticate for disabled user should fail - password = data_utils.rand_password() - user = self.setup_test_user(password) - self.disable_user(user['name'], user['domain_id']) - self.assertRaises(lib_exc.Unauthorized, self.token.auth, - username=user['name'], - password=password, - user_domain_id=CONF.identity.default_domain_id) diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py deleted file mode 100644 index 30d2a366a..000000000 --- a/tempest/api/identity/base.py +++ /dev/null @@ -1,287 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -import tempest.test - -CONF = config.CONF - - -class BaseIdentityTest(tempest.test.BaseTestCase): - - @classmethod - def setup_credentials(cls): - # Create no network resources for these test. - cls.set_network_resources() - super(BaseIdentityTest, cls).setup_credentials() - - @classmethod - def disable_user(cls, user_name): - user = cls.get_user_by_name(user_name) - cls.users_client.update_user_enabled(user['id'], enabled=False) - - @classmethod - def disable_tenant(cls, tenant_name): - tenant = cls.get_tenant_by_name(tenant_name) - cls.tenants_client.update_tenant(tenant['id'], enabled=False) - - @classmethod - def get_user_by_name(cls, name, domain_id=None): - if domain_id: - params = {'domain_id': domain_id} - users = cls.users_client.list_users(**params)['users'] - else: - users = cls.users_client.list_users()['users'] - user = [u for u in users if u['name'] == name] - if user: - return user[0] - - @classmethod - def get_tenant_by_name(cls, name): - try: - tenants = cls.tenants_client.list_tenants()['tenants'] - except AttributeError: - tenants = cls.projects_client.list_projects()['projects'] - tenant = [t for t in tenants if t['name'] == name] - if tenant: - return tenant[0] - - @classmethod - def get_role_by_name(cls, name): - roles = cls.roles_client.list_roles()['roles'] - role = [r for r in roles if r['name'] == name] - if role: - return role[0] - - def create_test_user(self, **kwargs): - if kwargs.get('password', None) is None: - kwargs['password'] = data_utils.rand_password() - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name('test_user') - if 'email' not in kwargs: - kwargs['email'] = kwargs['name'] + '@testmail.tm' - - user = self.users_client.create_user(**kwargs)['user'] - # Delete the user at the end of the test - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.users_client.delete_user, user['id']) - return user - - def setup_test_role(self, name=None, domain_id=None): - """Set up a test role.""" - params = {'name': name or data_utils.rand_name('test_role')} - if domain_id: - params['domain_id'] = domain_id - - role = self.roles_client.create_role(**params)['role'] - # Delete the role at the end of the test - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role, role['id']) - return role - - -class BaseIdentityV2Test(BaseIdentityTest): - - credentials = ['primary'] - - # identity v2 tests should obtain tokens and create accounts via v2 - # regardless of the configured CONF.identity.auth_version - identity_version = 'v2' - - @classmethod - def setup_clients(cls): - super(BaseIdentityV2Test, cls).setup_clients() - cls.non_admin_client = cls.os_primary.identity_public_client - cls.non_admin_token_client = cls.os_primary.token_client - cls.non_admin_tenants_client = cls.os_primary.tenants_public_client - cls.non_admin_users_client = cls.os_primary.users_public_client - - -class BaseIdentityV2AdminTest(BaseIdentityV2Test): - - credentials = ['primary', 'admin'] - - # NOTE(andreaf) Identity tests work with credentials, so it is safer - # for them to always use disposable credentials. Forcing dynamic creds - # on regular identity tests would be however to restrictive, since it - # would prevent any identity test from being executed against clouds where - # admin credentials are not available. - # Since All admin tests require admin credentials to be - # executed, so this will not impact the ability to execute tests. - force_tenant_isolation = True - - @classmethod - def skip_checks(cls): - super(BaseIdentityV2AdminTest, cls).skip_checks() - if not CONF.identity_feature_enabled.api_v2_admin: - raise cls.skipException('Identity v2 admin not available') - - @classmethod - def setup_clients(cls): - super(BaseIdentityV2AdminTest, cls).setup_clients() - cls.client = cls.os_admin.identity_client - cls.non_admin_client = cls.os_primary.identity_client - cls.token_client = cls.os_admin.token_client - cls.tenants_client = cls.os_admin.tenants_client - cls.non_admin_tenants_client = cls.os_primary.tenants_client - cls.roles_client = cls.os_admin.roles_client - cls.non_admin_roles_client = cls.os_primary.roles_client - cls.users_client = cls.os_admin.users_client - cls.non_admin_users_client = cls.os_primary.users_client - cls.services_client = cls.os_admin.identity_services_client - cls.endpoints_client = cls.os_admin.endpoints_client - - @classmethod - def resource_setup(cls): - super(BaseIdentityV2AdminTest, cls).resource_setup() - cls.projects_client = cls.tenants_client - - def setup_test_user(self, password=None): - """Set up a test user.""" - tenant = self.setup_test_tenant() - user = self.create_test_user(tenantId=tenant['id'], password=password) - return user - - def setup_test_tenant(self, **kwargs): - """Set up a test tenant.""" - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name('test_tenant') - if 'description' not in kwargs: - kwargs['description'] = data_utils.rand_name('desc') - tenant = self.projects_client.create_tenant(**kwargs)['tenant'] - # Delete the tenant at the end of the test - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.tenants_client.delete_tenant, tenant['id']) - return tenant - - -class BaseIdentityV3Test(BaseIdentityTest): - - credentials = ['primary'] - - # identity v3 tests should obtain tokens and create accounts via v3 - # regardless of the configured CONF.identity.auth_version - identity_version = 'v3' - - @classmethod - def setup_clients(cls): - super(BaseIdentityV3Test, cls).setup_clients() - cls.non_admin_client = cls.os_primary.identity_v3_client - cls.non_admin_users_client = cls.os_primary.users_v3_client - cls.non_admin_token = cls.os_primary.token_v3_client - cls.non_admin_projects_client = cls.os_primary.projects_client - cls.non_admin_catalog_client = cls.os_primary.catalog_client - cls.non_admin_versions_client =\ - cls.os_primary.identity_versions_v3_client - - -class BaseIdentityV3AdminTest(BaseIdentityV3Test): - - credentials = ['primary', 'admin'] - - # NOTE(andreaf) Identity tests work with credentials, so it is safer - # for them to always use disposable credentials. Forcing dynamic creds - # on regular identity tests would be however to restrictive, since it - # would prevent any identity test from being executed against clouds where - # admin credentials are not available. - # Since All admin tests require admin credentials to be - # executed, so this will not impact the ability to execute tests. - force_tenant_isolation = True - - @classmethod - def setup_clients(cls): - super(BaseIdentityV3AdminTest, cls).setup_clients() - cls.client = cls.os_admin.identity_v3_client - cls.domains_client = cls.os_admin.domains_client - cls.users_client = cls.os_admin.users_v3_client - cls.trusts_client = cls.os_admin.trusts_client - cls.roles_client = cls.os_admin.roles_v3_client - cls.inherited_roles_client = cls.os_admin.inherited_roles_client - cls.token = cls.os_admin.token_v3_client - cls.endpoints_client = cls.os_admin.endpoints_v3_client - cls.regions_client = cls.os_admin.regions_client - cls.services_client = cls.os_admin.identity_services_v3_client - cls.policies_client = cls.os_admin.policies_client - cls.creds_client = cls.os_admin.credentials_client - cls.groups_client = cls.os_admin.groups_client - cls.projects_client = cls.os_admin.projects_client - cls.role_assignments = cls.os_admin.role_assignments_client - cls.oauth_consumers_client = cls.os_admin.oauth_consumers_client - cls.oauth_token_client = cls.os_admin.oauth_token_client - cls.domain_config_client = cls.os_admin.domain_config_client - cls.endpoint_filter_client = cls.os_admin.endpoint_filter_client - cls.endpoint_groups_client = cls.os_admin.endpoint_groups_client - - if CONF.identity.admin_domain_scope: - # NOTE(andreaf) When keystone policy requires it, the identity - # admin clients for these tests shall use 'domain' scoped tokens. - # As the client manager is already created by the base class, - # we set the scope for the inner auth provider. - cls.os_admin.auth_provider.scope = 'domain' - - @classmethod - def disable_user(cls, user_name, domain_id=None): - user = cls.get_user_by_name(user_name, domain_id) - cls.users_client.update_user(user['id'], name=user_name, enabled=False) - - @classmethod - def create_domain(cls, **kwargs): - """Create a domain.""" - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name('test_domain') - if 'description' not in kwargs: - kwargs['description'] = data_utils.rand_name('desc') - domain = cls.domains_client.create_domain(**kwargs)['domain'] - return domain - - def delete_domain(self, domain_id): - # NOTE(mpavlase) It is necessary to disable the domain before deleting - # otherwise it raises Forbidden exception - self.domains_client.update_domain(domain_id, enabled=False) - self.domains_client.delete_domain(domain_id) - - def setup_test_user(self, password=None): - """Set up a test user.""" - project = self.setup_test_project() - user = self.create_test_user(project_id=project['id'], - password=password) - return user - - def setup_test_project(self, **kwargs): - """Set up a test project.""" - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name('test_project') - if 'description' not in kwargs: - kwargs['description'] = data_utils.rand_name('test_description') - project = self.projects_client.create_project(**kwargs)['project'] - # Delete the project at the end of the test - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.projects_client.delete_project, project['id']) - return project - - def setup_test_domain(self): - """Set up a test domain.""" - domain = self.create_domain() - # Delete the domain at the end of the test - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.delete_domain, domain['id']) - return domain diff --git a/tempest/api/identity/v2/__init__.py b/tempest/api/identity/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/identity/v2/test_api_discovery.py b/tempest/api/identity/v2/test_api_discovery.py deleted file mode 100644 index 5b9d38c48..000000000 --- a/tempest/api/identity/v2/test_api_discovery.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2015 OpenStack Foundation. -# Copyright 2015, Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib import decorators - - -class TestApiDiscovery(base.BaseIdentityV2Test): - """Tests for API discovery features.""" - - @decorators.attr(type='smoke') - @decorators.idempotent_id('ea889a68-a15f-4166-bfb1-c12456eae853') - def test_api_version_resources(self): - descr = self.non_admin_client.show_api_description()['version'] - expected_resources = ('id', 'links', 'media-types', 'status', - 'updated') - - keys = descr.keys() - for res in expected_resources: - self.assertIn(res, keys) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('007a0be0-78fe-4fdb-bbee-e9216cc17bb2') - def test_api_media_types(self): - descr = self.non_admin_client.show_api_description()['version'] - # Get MIME type bases and descriptions - media_types = [(media_type['base'], media_type['type']) for - media_type in descr['media-types']] - # These are supported for API version 2 - supported_types = [('application/json', - 'application/vnd.openstack.identity-v2.0+json')] - - # Check if supported types exist in response body - for s_type in supported_types: - self.assertIn(s_type, media_types) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('77fd6be0-8801-48e6-b9bf-38cdd2f253ec') - def test_api_version_statuses(self): - descr = self.non_admin_client.show_api_description()['version'] - status = descr['status'].lower() - supported_statuses = ['current', 'stable', 'experimental', - 'supported', 'deprecated'] - - self.assertIn(status, supported_statuses) diff --git a/tempest/api/identity/v2/test_ec2_credentials.py b/tempest/api/identity/v2/test_ec2_credentials.py deleted file mode 100644 index 599b784d6..000000000 --- a/tempest/api/identity/v2/test_ec2_credentials.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class EC2CredentialsTest(base.BaseIdentityV2Test): - - @classmethod - def skip_checks(cls): - super(EC2CredentialsTest, cls).skip_checks() - if not test.is_extension_enabled('OS-EC2', 'identity'): - msg = "OS-EC2 identity extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(EC2CredentialsTest, cls).resource_setup() - cls.creds = cls.os_primary.credentials - - @decorators.idempotent_id('b580fab9-7ae9-46e8-8138-417260cb6f9f') - def test_create_ec2_credential(self): - """Create user ec2 credential.""" - resp = self.non_admin_users_client.create_user_ec2_credential( - self.creds.user_id, - tenant_id=self.creds.tenant_id)["credential"] - access = resp['access'] - self.addCleanup( - self.non_admin_users_client.delete_user_ec2_credential, - self.creds.user_id, access) - self.assertNotEmpty(resp['access']) - self.assertNotEmpty(resp['secret']) - self.assertEqual(self.creds.user_id, resp['user_id']) - self.assertEqual(self.creds.tenant_id, resp['tenant_id']) - - @decorators.idempotent_id('9e2ea42f-0a4f-468c-a768-51859ce492e0') - def test_list_ec2_credentials(self): - """Get the list of user ec2 credentials.""" - created_creds = [] - # create first ec2 credentials - creds1 = self.non_admin_users_client.create_user_ec2_credential( - self.creds.user_id, - tenant_id=self.creds.tenant_id)["credential"] - created_creds.append(creds1['access']) - # create second ec2 credentials - creds2 = self.non_admin_users_client.create_user_ec2_credential( - self.creds.user_id, - tenant_id=self.creds.tenant_id)["credential"] - created_creds.append(creds2['access']) - # add credentials to be cleaned up - self.addCleanup( - self.non_admin_users_client.delete_user_ec2_credential, - self.creds.user_id, creds1['access']) - self.addCleanup( - self.non_admin_users_client.delete_user_ec2_credential, - self.creds.user_id, creds2['access']) - # get the list of user ec2 credentials - resp = self.non_admin_users_client.list_user_ec2_credentials( - self.creds.user_id)["credentials"] - fetched_creds = [cred['access'] for cred in resp] - # created credentials should be in a fetched list - missing = [cred for cred in created_creds - if cred not in fetched_creds] - self.assertEmpty(missing, - "Failed to find ec2_credentials %s in fetched list" % - ', '.join(cred for cred in missing)) - - @decorators.idempotent_id('cb284075-b613-440d-83ca-fe0b33b3c2b8') - def test_show_ec2_credential(self): - """Get the definite user ec2 credential.""" - resp = self.non_admin_users_client.create_user_ec2_credential( - self.creds.user_id, - tenant_id=self.creds.tenant_id)["credential"] - self.addCleanup( - self.non_admin_users_client.delete_user_ec2_credential, - self.creds.user_id, resp['access']) - - ec2_creds = self.non_admin_users_client.show_user_ec2_credential( - self.creds.user_id, resp['access'] - )["credential"] - for key in ['access', 'secret', 'user_id', 'tenant_id']: - self.assertEqual(ec2_creds[key], resp[key]) - - @decorators.idempotent_id('6aba0d4c-b76b-4e46-aa42-add79bc1551d') - def test_delete_ec2_credential(self): - """Delete user ec2 credential.""" - resp = self.non_admin_users_client.create_user_ec2_credential( - self.creds.user_id, - tenant_id=self.creds.tenant_id)["credential"] - access = resp['access'] - self.non_admin_users_client.delete_user_ec2_credential( - self.creds.user_id, access) - self.assertRaises( - lib_exc.NotFound, - self.non_admin_users_client.show_user_ec2_credential, - self.creds.user_id, - access) diff --git a/tempest/api/identity/v2/test_extension.py b/tempest/api/identity/v2/test_extension.py deleted file mode 100644 index c538c142c..000000000 --- a/tempest/api/identity/v2/test_extension.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2014 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib import decorators - - -class ExtensionTestJSON(base.BaseIdentityV2Test): - - @decorators.idempotent_id('85f3f661-f54c-4d48-b563-72ae952b9383') - def test_list_extensions(self): - # List all the extensions - body = self.non_admin_client.list_extensions()['extensions']['values'] - self.assertNotEmpty(body) - keys = ['name', 'updated', 'alias', 'links', - 'namespace', 'description'] - for value in body: - for key in keys: - self.assertIn(key, value) diff --git a/tempest/api/identity/v2/test_tenants.py b/tempest/api/identity/v2/test_tenants.py deleted file mode 100644 index b2a6d13c3..000000000 --- a/tempest/api/identity/v2/test_tenants.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class IdentityTenantsTest(base.BaseIdentityV2Test): - - credentials = ['primary', 'alt'] - - @decorators.idempotent_id('ecae2459-243d-4ba1-ad02-65f15dc82b78') - def test_list_tenants_returns_only_authorized_tenants(self): - alt_tenant_name = self.os_alt.credentials.tenant_name - resp = self.non_admin_tenants_client.list_tenants() - - # check that user can see only that tenants that he presents in so user - # can successfully authenticate using his credentials and tenant name - # from received tenants list - for tenant in resp['tenants']: - body = self.non_admin_token_client.auth( - self.os_primary.credentials.username, - self.os_primary.credentials.password, - tenant['name']) - self.assertNotEmpty(body['token']['id']) - self.assertEqual(body['token']['tenant']['id'], tenant['id']) - self.assertEqual(body['token']['tenant']['name'], tenant['name']) - self.assertEqual( - body['user']['id'], self.os_primary.credentials.user_id) - - # check that user cannot log in to alt user's tenant - self.assertRaises( - lib_exc.Unauthorized, - self.non_admin_token_client.auth, - self.os_primary.credentials.username, - self.os_primary.credentials.password, - alt_tenant_name) diff --git a/tempest/api/identity/v2/test_tokens.py b/tempest/api/identity/v2/test_tokens.py deleted file mode 100644 index 64b81c229..000000000 --- a/tempest/api/identity/v2/test_tokens.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_utils import timeutils -import six -from tempest.api.identity import base -from tempest.lib import decorators - - -class TokensTest(base.BaseIdentityV2Test): - - @decorators.idempotent_id('65ae3b78-91ff-467b-a705-f6678863b8ec') - def test_create_token(self): - - token_client = self.non_admin_token_client - - # get a token for the user - creds = self.os_primary.credentials - username = creds.username - password = creds.password - tenant_name = creds.tenant_name - - body = token_client.auth(username, password, tenant_name) - - self.assertNotEmpty(body['token']['id']) - self.assertIsInstance(body['token']['id'], six.string_types) - - now = timeutils.utcnow() - expires_at = timeutils.normalize_time( - timeutils.parse_isotime(body['token']['expires'])) - self.assertGreater(expires_at, now) - - self.assertEqual(body['token']['tenant']['id'], - creds.tenant_id) - self.assertEqual(body['token']['tenant']['name'], - tenant_name) - - self.assertEqual(body['user']['id'], creds.user_id) diff --git a/tempest/api/identity/v2/test_users.py b/tempest/api/identity/v2/test_users.py deleted file mode 100644 index 9c77fff51..000000000 --- a/tempest/api/identity/v2/test_users.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - - -CONF = config.CONF - - -class IdentityUsersTest(base.BaseIdentityV2Test): - - @classmethod - def resource_setup(cls): - super(IdentityUsersTest, cls).resource_setup() - cls.creds = cls.os_primary.credentials - cls.username = cls.creds.username - cls.password = cls.creds.password - cls.tenant_name = cls.creds.tenant_name - - def _update_password(self, user_id, original_password, password): - self.non_admin_users_client.update_user_own_password( - user_id, password=password, original_password=original_password) - - # NOTE(morganfainberg): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure - # we are passing the second boundary. - time.sleep(1) - - # check authorization with new password - self.non_admin_token_client.auth(self.username, - password, - self.tenant_name) - - # Reset auth to get a new token with the new password - self.non_admin_users_client.auth_provider.clear_auth() - self.non_admin_users_client.auth_provider.credentials.password = ( - password) - - def _restore_password(self, user_id, old_pass, new_pass): - if CONF.identity_feature_enabled.security_compliance: - # First we need to clear the password history - unique_count = CONF.identity.user_unique_last_password_count - for _ in range(unique_count): - random_pass = data_utils.rand_password() - self._update_password( - user_id, original_password=new_pass, password=random_pass) - new_pass = random_pass - - self._update_password( - user_id, original_password=new_pass, password=old_pass) - # Reset auth again to verify the password restore does work. - # Clear auth restores the original credentials and deletes - # cached auth data - self.non_admin_users_client.auth_provider.clear_auth() - # NOTE(lbragstad): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure we - # are passing the second boundary before attempting to - # authenticate. - time.sleep(1) - self.non_admin_users_client.auth_provider.set_auth() - - @decorators.idempotent_id('165859c9-277f-4124-9479-a7d1627b0ca7') - def test_user_update_own_password(self): - old_pass = self.creds.password - old_token = self.non_admin_users_client.token - new_pass = data_utils.rand_password() - user_id = self.creds.user_id - - # to change password back. important for allow_tenant_isolation = false - self.addCleanup(self._restore_password, user_id, old_pass, new_pass) - - # user updates own password - self._update_password( - user_id, original_password=old_pass, password=new_pass) - - # authorize with old token should lead to Unauthorized - self.assertRaises(exceptions.Unauthorized, - self.non_admin_token_client.auth_token, - old_token) - - # authorize with old password should lead to Unauthorized - self.assertRaises(exceptions.Unauthorized, - self.non_admin_token_client.auth, - self.username, - old_pass, - self.tenant_name) diff --git a/tempest/api/identity/v3/__init__.py b/tempest/api/identity/v3/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/identity/v3/test_api_discovery.py b/tempest/api/identity/v3/test_api_discovery.py deleted file mode 100644 index c04c21bc9..000000000 --- a/tempest/api/identity/v3/test_api_discovery.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2015 OpenStack Foundation. -# Copyright 2015, Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib import decorators - - -class TestApiDiscovery(base.BaseIdentityV3Test): - """Tests for API discovery features.""" - - @decorators.idempotent_id('721f480f-35b6-46c7-846e-047e6acea0dc') - @decorators.attr(type='smoke') - def test_list_api_versions(self): - # NOTE: Actually this API doesn't depend on v3 API at all, because - # the API operation is "GET /" without v3's endpoint. The reason of - # this test path is just v3 API is CURRENT on Keystone side. - versions = self.non_admin_versions_client.list_versions() - expected_resources = ('id', 'links', 'media-types', 'status', - 'updated') - - for version in versions['versions']["values"]: - for res in expected_resources: - self.assertIn(res, version) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('b9232f5e-d9e5-4d97-b96c-28d3db4de1bd') - def test_api_version_resources(self): - descr = self.non_admin_client.show_api_description()['version'] - expected_resources = ('id', 'links', 'media-types', 'status', - 'updated') - - keys = descr.keys() - for res in expected_resources: - self.assertIn(res, keys) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('657c1970-4722-4189-8831-7325f3bc4265') - def test_api_media_types(self): - descr = self.non_admin_client.show_api_description()['version'] - # Get MIME type bases and descriptions - media_types = [(media_type['base'], media_type['type']) for - media_type in descr['media-types']] - # These are supported for API version 2 - supported_types = [('application/json', - 'application/vnd.openstack.identity-v3+json')] - - # Check if supported types exist in response body - for s_type in supported_types: - self.assertIn(s_type, media_types) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('8879a470-abfb-47bb-bb8d-5a7fd279ad1e') - def test_api_version_statuses(self): - descr = self.non_admin_client.show_api_description()['version'] - status = descr['status'].lower() - supported_statuses = ['current', 'stable', 'experimental', - 'supported', 'deprecated'] - - self.assertIn(status, supported_statuses) diff --git a/tempest/api/identity/v3/test_catalog.py b/tempest/api/identity/v3/test_catalog.py deleted file mode 100755 index deec2dcf1..000000000 --- a/tempest/api/identity/v3/test_catalog.py +++ /dev/null @@ -1,41 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest import config -from tempest.lib import decorators - - -CONF = config.CONF - - -class IdentityCatalogTest(base.BaseIdentityV3Test): - - @decorators.idempotent_id('56b57ced-22b8-4127-9b8a-565dfb0207e2') - def test_catalog_standardization(self): - # http://git.openstack.org/cgit/openstack/service-types-authority - # /tree/service-types.yaml - standard_service_values = [{'name': 'keystone', 'type': 'identity'}, - {'name': 'nova', 'type': 'compute'}, - {'name': 'glance', 'type': 'image'}, - {'name': 'swift', 'type': 'object-store'}] - # next, we need to GET the catalog using the catalog client - catalog = self.non_admin_catalog_client.show_catalog()['catalog'] - # get list of the service types present in the catalog - catalog_services = [] - for service in catalog: - catalog_services.append(service['type']) - for service in standard_service_values: - # if service enabled, check if it has a standard typevalue - if service['name'] == 'keystone' or\ - getattr(CONF.service_available, service['name']): - self.assertIn(service['type'], catalog_services) diff --git a/tempest/api/identity/v3/test_projects.py b/tempest/api/identity/v3/test_projects.py deleted file mode 100644 index 0ae35eada..000000000 --- a/tempest/api/identity/v3/test_projects.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.identity import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class IdentityV3ProjectsTest(base.BaseIdentityV3Test): - - credentials = ['primary', 'alt'] - - @decorators.idempotent_id('86128d46-e170-4644-866a-cc487f699e1d') - def test_list_projects_returns_only_authorized_projects(self): - alt_project_name =\ - self.os_alt.credentials.project_name - resp = self.non_admin_users_client.list_user_projects( - self.os_primary.credentials.user_id) - - # check that user can see only that projects that he presents in so - # user can successfully authenticate using his credentials and - # project name from received projects list - for project in resp['projects']: - # 'user_domain_id' needs to be specified otherwise tempest.lib - # assumes it to be 'default' - token_id, body = self.non_admin_token.get_token( - username=self.os_primary.credentials.username, - user_domain_id=self.os_primary.credentials.user_domain_id, - password=self.os_primary.credentials.password, - project_name=project['name'], - project_domain_id=project['domain_id'], - auth_data=True) - self.assertNotEmpty(token_id) - self.assertEqual(body['project']['id'], project['id']) - self.assertEqual(body['project']['name'], project['name']) - self.assertEqual( - body['user']['id'], self.os_primary.credentials.user_id) - - # check that user cannot log in to alt user's project - self.assertRaises( - lib_exc.Unauthorized, - self.non_admin_token.get_token, - username=self.os_primary.credentials.username, - user_domain_id=self.os_primary.credentials.user_domain_id, - password=self.os_primary.credentials.password, - project_name=alt_project_name, - project_domain_id=project['domain_id']) diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py deleted file mode 100644 index 4c72d828f..000000000 --- a/tempest/api/identity/v3/test_tokens.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_utils import timeutils -import six - -from tempest.api.identity import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class TokensV3Test(base.BaseIdentityV3Test): - - @decorators.idempotent_id('a9512ac3-3909-48a4-b395-11f438e16260') - def test_validate_token(self): - creds = self.os_primary.credentials - user_id = creds.user_id - username = creds.username - password = creds.password - user_domain_id = creds.user_domain_id - # GET and validate token - subject_token, token_body = self.non_admin_token.get_token( - user_id=user_id, - username=username, - user_domain_id=user_domain_id, - password=password, - auth_data=True) - authenticated_token = self.non_admin_client.show_token( - subject_token)['token'] - # sanity checking to make sure they are indeed the same token - self.assertEqual(authenticated_token, token_body) - # test to see if token has been properly authenticated - self.assertEqual(authenticated_token['user']['id'], user_id) - self.assertEqual(authenticated_token['user']['name'], username) - self.non_admin_client.delete_token(subject_token) - self.assertRaises( - lib_exc.NotFound, self.non_admin_client.show_token, subject_token) - - @decorators.idempotent_id('6f8e4436-fc96-4282-8122-e41df57197a9') - def test_create_token(self): - - creds = self.os_primary.credentials - user_id = creds.user_id - username = creds.username - password = creds.password - user_domain_id = creds.user_domain_id - - # 'user_domain_id' needs to be specified otherwise tempest.lib assumes - # it to be 'default' - token_id, resp = self.non_admin_token.get_token( - user_id=user_id, - username=username, - user_domain_id=user_domain_id, - password=password, - auth_data=True) - - self.assertNotEmpty(token_id) - self.assertIsInstance(token_id, six.string_types) - - now = timeutils.utcnow() - expires_at = timeutils.normalize_time( - timeutils.parse_isotime(resp['expires_at'])) - self.assertGreater(resp['expires_at'], - resp['issued_at']) - self.assertGreater(expires_at, now) - - subject_id = resp['user']['id'] - if user_id: - self.assertEqual(subject_id, user_id) - else: - # Expect a user ID, but don't know what it will be. - self.assertIsNotNone(subject_id, 'Expected user ID in token.') - - subject_name = resp['user']['name'] - if username: - self.assertEqual(subject_name, username) - else: - # Expect a user name, but don't know what it will be. - self.assertIsNotNone(subject_name, 'Expected user name in token.') - - self.assertEqual(resp['methods'][0], 'password') diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py deleted file mode 100644 index 1f099df49..000000000 --- a/tempest/api/identity/v3/test_users.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -import testtools - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - - -CONF = config.CONF - - -class IdentityV3UsersTest(base.BaseIdentityV3Test): - - @classmethod - def resource_setup(cls): - super(IdentityV3UsersTest, cls).resource_setup() - cls.creds = cls.os_primary.credentials - cls.user_id = cls.creds.user_id - - def _update_password(self, original_password, password): - self.non_admin_users_client.update_user_password( - self.user_id, - password=password, - original_password=original_password) - - # NOTE(morganfainberg): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure - # we are passing the second boundary. - time.sleep(1) - - # check authorization with new password - self.non_admin_token.auth(user_id=self.user_id, password=password) - - # Reset auth to get a new token with the new password - self.non_admin_users_client.auth_provider.clear_auth() - self.non_admin_users_client.auth_provider.credentials.password = ( - password) - - def _restore_password(self, old_pass, new_pass): - if CONF.identity_feature_enabled.security_compliance: - # First we need to clear the password history - unique_count = CONF.identity.user_unique_last_password_count - for _ in range(unique_count): - random_pass = data_utils.rand_password() - self._update_password( - original_password=new_pass, password=random_pass) - new_pass = random_pass - - self._update_password(original_password=new_pass, password=old_pass) - # Reset auth again to verify the password restore does work. - # Clear auth restores the original credentials and deletes - # cached auth data - self.non_admin_users_client.auth_provider.clear_auth() - # NOTE(lbragstad): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure we - # are passing the second boundary before attempting to - # authenticate. - time.sleep(1) - self.non_admin_users_client.auth_provider.set_auth() - - @decorators.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27') - def test_user_update_own_password(self): - old_pass = self.creds.password - old_token = self.non_admin_client.token - new_pass = data_utils.rand_password() - - # to change password back. important for allow_tenant_isolation = false - self.addCleanup(self._restore_password, old_pass, new_pass) - - # user updates own password - self._update_password(original_password=old_pass, password=new_pass) - - # authorize with old token should lead to IdentityError (404 code) - self.assertRaises(exceptions.IdentityError, - self.non_admin_token.auth, - token=old_token) - - # authorize with old password should lead to Unauthorized - self.assertRaises(exceptions.Unauthorized, - self.non_admin_token.auth, - user_id=self.user_id, - password=old_pass) - - @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance, - 'Security compliance not available.') - @decorators.idempotent_id('941784ee-5342-4571-959b-b80dd2cea516') - def test_password_history_check_self_service_api(self): - old_pass = self.creds.password - new_pass1 = data_utils.rand_password() - new_pass2 = data_utils.rand_password() - - self.addCleanup(self._restore_password, old_pass, new_pass2) - - # Update password - self._update_password(original_password=old_pass, password=new_pass1) - - if CONF.identity.user_unique_last_password_count > 1: - # Can not reuse a previously set password - self.assertRaises(exceptions.BadRequest, - self.non_admin_users_client.update_user_password, - self.user_id, - password=new_pass1, - original_password=new_pass1) - - self.assertRaises(exceptions.BadRequest, - self.non_admin_users_client.update_user_password, - self.user_id, - password=old_pass, - original_password=new_pass1) - - # A different password can be set - self._update_password(original_password=new_pass1, password=new_pass2) - - @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance, - 'Security compliance not available.') - @decorators.idempotent_id('a7ad8bbf-2cff-4520-8c1d-96332e151658') - def test_user_account_lockout(self): - password = self.creds.password - - # First, we login using the correct credentials - self.non_admin_token.auth(user_id=self.user_id, password=password) - - # Lock user account by using the wrong password to login - bad_password = data_utils.rand_password() - for _ in range(CONF.identity.user_lockout_failure_attempts): - self.assertRaises(exceptions.Unauthorized, - self.non_admin_token.auth, - user_id=self.user_id, - password=bad_password) - - # The user account must be locked, so now it is not possible to login - # even using the correct password - self.assertRaises(exceptions.Unauthorized, - self.non_admin_token.auth, - user_id=self.user_id, - password=password) - - # If we wait the required time, the user account will be unlocked - time.sleep(CONF.identity.user_lockout_duration + 1) - self.non_admin_token.auth(user_id=self.user_id, password=password) diff --git a/tempest/api/image/__init__.py b/tempest/api/image/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py deleted file mode 100644 index 70ba2feca..000000000 --- a/tempest/api/image/base.py +++ /dev/null @@ -1,211 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - -from tempest.common import image as common_image -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -import tempest.test - -CONF = config.CONF - - -class BaseImageTest(tempest.test.BaseTestCase): - """Base test class for Image API tests.""" - - credentials = ['primary'] - - @classmethod - def skip_checks(cls): - super(BaseImageTest, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(BaseImageTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(BaseImageTest, cls).resource_setup() - cls.created_images = [] - - @classmethod - def resource_cleanup(cls): - for image_id in cls.created_images: - test_utils.call_and_ignore_notfound_exc( - cls.client.delete_image, image_id) - - for image_id in cls.created_images: - cls.client.wait_for_resource_deletion(image_id) - super(BaseImageTest, cls).resource_cleanup() - - @classmethod - def create_image(cls, data=None, **kwargs): - """Wrapper that returns a test image.""" - - if 'name' not in kwargs: - name = data_utils.rand_name(cls.__name__ + "-image") - kwargs['name'] = name - - params = cls._get_create_params(**kwargs) - if data: - # NOTE: On glance v1 API, the data should be passed on - # a header. Then here handles the data separately. - params['data'] = data - - image = cls.client.create_image(**params) - # Image objects returned by the v1 client have the image - # data inside a dict that is keyed against 'image'. - if 'image' in image: - image = image['image'] - cls.created_images.append(image['id']) - return image - - @classmethod - def _get_create_params(cls, **kwargs): - return kwargs - - -class BaseV1ImageTest(BaseImageTest): - - @classmethod - def skip_checks(cls): - super(BaseV1ImageTest, cls).skip_checks() - if not CONF.image_feature_enabled.api_v1: - msg = "Glance API v1 not supported" - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(BaseV1ImageTest, cls).setup_clients() - cls.client = cls.os_primary.image_client - - @classmethod - def _get_create_params(cls, **kwargs): - return {'headers': common_image.image_meta_to_headers(**kwargs)} - - -class BaseV1ImageMembersTest(BaseV1ImageTest): - - credentials = ['primary', 'alt'] - - @classmethod - def setup_clients(cls): - super(BaseV1ImageMembersTest, cls).setup_clients() - cls.image_member_client = cls.os_primary.image_member_client - cls.alt_image_member_client = cls.os_alt.image_member_client - cls.alt_img_cli = cls.os_alt.image_client - - @classmethod - def resource_setup(cls): - super(BaseV1ImageMembersTest, cls).resource_setup() - cls.alt_tenant_id = cls.alt_image_member_client.tenant_id - - def _create_image(self): - image_file = six.BytesIO(data_utils.random_bytes()) - image = self.create_image(container_format='bare', - disk_format='raw', - is_public=False, - data=image_file) - return image['id'] - - -class BaseV2ImageTest(BaseImageTest): - - @classmethod - def skip_checks(cls): - super(BaseV2ImageTest, cls).skip_checks() - if not CONF.image_feature_enabled.api_v2: - msg = "Glance API v2 not supported" - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(BaseV2ImageTest, cls).setup_clients() - cls.client = cls.os_primary.image_client_v2 - cls.namespaces_client = cls.os_primary.namespaces_client - cls.resource_types_client = cls.os_primary.resource_types_client - cls.namespace_properties_client =\ - cls.os_primary.namespace_properties_client - cls.namespace_objects_client = cls.os_primary.namespace_objects_client - cls.namespace_tags_client = cls.os_primary.namespace_tags_client - cls.schemas_client = cls.os_primary.schemas_client - cls.versions_client = cls.os_primary.image_versions_client - - def create_namespace(cls, namespace_name=None, visibility='public', - description='Tempest', protected=False, - **kwargs): - if not namespace_name: - namespace_name = data_utils.rand_name('test-ns') - kwargs.setdefault('display_name', namespace_name) - namespace = cls.namespaces_client.create_namespace( - namespace=namespace_name, visibility=visibility, - description=description, protected=protected, **kwargs) - cls.addCleanup(cls.namespaces_client.delete_namespace, namespace_name) - return namespace - - -class BaseV2MemberImageTest(BaseV2ImageTest): - - credentials = ['primary', 'alt'] - - @classmethod - def setup_clients(cls): - super(BaseV2MemberImageTest, cls).setup_clients() - cls.image_member_client = cls.os_primary.image_member_client_v2 - cls.alt_image_member_client = cls.os_alt.image_member_client_v2 - cls.alt_img_client = cls.os_alt.image_client_v2 - - @classmethod - def resource_setup(cls): - super(BaseV2MemberImageTest, cls).resource_setup() - cls.alt_tenant_id = cls.alt_image_member_client.tenant_id - - def _list_image_ids_as_alt(self): - image_list = self.alt_img_client.list_images()['images'] - image_ids = map(lambda x: x['id'], image_list) - return image_ids - - def _create_image(self): - name = data_utils.rand_name(self.__class__.__name__ + '-image') - image = self.client.create_image(name=name, - container_format='bare', - disk_format='raw') - self.addCleanup(self.client.delete_image, image['id']) - return image['id'] - - -class BaseV1ImageAdminTest(BaseImageTest): - credentials = ['admin', 'primary'] - - @classmethod - def setup_clients(cls): - super(BaseV1ImageAdminTest, cls).setup_clients() - cls.client = cls.os_primary.image_client - cls.admin_client = cls.os_admin.image_client - - -class BaseV2ImageAdminTest(BaseImageTest): - credentials = ['admin', 'primary'] - - @classmethod - def setup_clients(cls): - super(BaseV2ImageAdminTest, cls).setup_clients() - cls.client = cls.os_primary.image_client_v2 - cls.admin_client = cls.os_admin.image_client_v2 diff --git a/tempest/api/image/v1/__init__.py b/tempest/api/image/v1/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py deleted file mode 100644 index bf2e510ed..000000000 --- a/tempest/api/image/v1/test_image_members.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.api.image import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImageMembersTest(base.BaseV1ImageMembersTest): - - @decorators.idempotent_id('1d6ef640-3a20-4c84-8710-d95828fdb6ad') - def test_add_image_member(self): - image = self._create_image() - self.image_member_client.create_image_member(image, self.alt_tenant_id) - body = self.image_member_client.list_image_members(image) - members = body['members'] - members = [member['member_id'] for member in members] - self.assertIn(self.alt_tenant_id, members) - # get image as alt user - self.alt_img_cli.show_image(image) - - @decorators.idempotent_id('6a5328a5-80e8-4b82-bd32-6c061f128da9') - def test_get_shared_images(self): - image = self._create_image() - self.image_member_client.create_image_member(image, self.alt_tenant_id) - share_image = self._create_image() - self.image_member_client.create_image_member(share_image, - self.alt_tenant_id) - body = self.image_member_client.list_shared_images( - self.alt_tenant_id) - images = body['shared_images'] - images = [img['image_id'] for img in images] - self.assertIn(share_image, images) - self.assertIn(image, images) - - @decorators.idempotent_id('a76a3191-8948-4b44-a9d6-4053e5f2b138') - def test_remove_member(self): - image_id = self._create_image() - self.image_member_client.create_image_member(image_id, - self.alt_tenant_id) - self.image_member_client.delete_image_member(image_id, - self.alt_tenant_id) - body = self.image_member_client.list_image_members(image_id) - members = body['members'] - self.assertEmpty(members) - self.assertRaises( - lib_exc.NotFound, self.alt_img_cli.show_image, image_id) diff --git a/tempest/api/image/v1/test_image_members_negative.py b/tempest/api/image/v1/test_image_members_negative.py deleted file mode 100644 index 2748bd54e..000000000 --- a/tempest/api/image/v1/test_image_members_negative.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImageMembersNegativeTest(base.BaseV1ImageMembersTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('147a9536-18e3-45da-91ea-b037a028f364') - def test_add_member_with_non_existing_image(self): - # Add member with non existing image. - non_exist_image = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.image_member_client.create_image_member, - non_exist_image, self.alt_tenant_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e1559f05-b667-4f1b-a7af-518b52dc0c0f') - def test_delete_member_with_non_existing_image(self): - # Delete member with non existing image. - non_exist_image = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.image_member_client.delete_image_member, - non_exist_image, self.alt_tenant_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f5720333-dd69-4194-bb76-d2f048addd56') - def test_delete_member_with_non_existing_tenant(self): - # Delete member with non existing tenant. - image_id = self._create_image() - non_exist_tenant = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, - self.image_member_client.delete_image_member, - image_id, non_exist_tenant) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f25f89e4-0b6c-453b-a853-1f80b9d7ef26') - def test_get_image_without_membership(self): - # Image is hidden from another tenants. - image_id = self._create_image() - self.assertRaises(lib_exc.NotFound, - self.alt_img_cli.show_image, - image_id) diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py deleted file mode 100644 index 76723f496..000000000 --- a/tempest/api/image/v1/test_images.py +++ /dev/null @@ -1,330 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - -from tempest.api.image import base -from tempest.common import image as common_image -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -def get_container_and_disk_format(): - a_formats = ['ami', 'ari', 'aki'] - - container_format = CONF.image.container_formats[0] - - # In v1, If container_format is one of ['ami', 'ari', 'aki'], then - # disk_format must be same with container_format. - # If they are of different item sequence in tempest.conf, such as: - # container_formats = ami,ari,aki,bare - # disk_formats = ari,ami,aki,vhd - # we can select one in disk_format list that is same with container_format. - if container_format in a_formats: - if container_format in CONF.image.disk_formats: - disk_format = container_format - else: - msg = ("The container format and the disk format don't match. " - "Container format: %(container)s, Disk format: %(disk)s." % - {'container': container_format, 'disk': - CONF.image.disk_formats}) - raise exceptions.InvalidConfiguration(msg) - else: - disk_format = CONF.image.disk_formats[0] - - return container_format, disk_format - - -class CreateRegisterImagesTest(base.BaseV1ImageTest): - """Here we test the registration and creation of images.""" - - @decorators.idempotent_id('3027f8e6-3492-4a11-8575-c3293017af4d') - def test_register_then_upload(self): - # Register, then upload an image - properties = {'prop1': 'val1'} - container_format, disk_format = get_container_and_disk_format() - image = self.create_image(name='New Name', - container_format=container_format, - disk_format=disk_format, - is_public=False, - properties=properties) - self.assertEqual('New Name', image.get('name')) - self.assertFalse(image.get('is_public')) - self.assertEqual('queued', image.get('status')) - for key, val in properties.items(): - self.assertEqual(val, image.get('properties')[key]) - - # Now try uploading an image file - image_file = six.BytesIO(data_utils.random_bytes()) - body = self.client.update_image(image['id'], data=image_file)['image'] - self.assertIn('size', body) - self.assertEqual(1024, body.get('size')) - - @decorators.idempotent_id('69da74d9-68a9-404b-9664-ff7164ccb0f5') - def test_register_remote_image(self): - # Register a new remote image - container_format, disk_format = get_container_and_disk_format() - body = self.create_image(name='New Remote Image', - container_format=container_format, - disk_format=disk_format, is_public=False, - location=CONF.image.http_image, - properties={'key1': 'value1', - 'key2': 'value2'}) - self.assertEqual('New Remote Image', body.get('name')) - self.assertFalse(body.get('is_public')) - self.assertEqual('active', body.get('status')) - properties = body.get('properties') - self.assertEqual(properties['key1'], 'value1') - self.assertEqual(properties['key2'], 'value2') - - @decorators.idempotent_id('6d0e13a7-515b-460c-b91f-9f4793f09816') - def test_register_http_image(self): - container_format, disk_format = get_container_and_disk_format() - image = self.create_image(name='New Http Image', - container_format=container_format, - disk_format=disk_format, is_public=False, - copy_from=CONF.image.http_image) - self.assertEqual('New Http Image', image.get('name')) - self.assertFalse(image.get('is_public')) - waiters.wait_for_image_status(self.client, image['id'], 'active') - self.client.show_image(image['id']) - - @decorators.idempotent_id('05b19d55-140c-40d0-b36b-fafd774d421b') - def test_register_image_with_min_ram(self): - # Register an image with min ram - container_format, disk_format = get_container_and_disk_format() - properties = {'prop1': 'val1'} - body = self.create_image(name='New_image_with_min_ram', - container_format=container_format, - disk_format=disk_format, - is_public=False, - min_ram=40, - properties=properties) - self.assertEqual('New_image_with_min_ram', body.get('name')) - self.assertFalse(body.get('is_public')) - self.assertEqual('queued', body.get('status')) - self.assertEqual(40, body.get('min_ram')) - for key, val in properties.items(): - self.assertEqual(val, body.get('properties')[key]) - self.client.delete_image(body['id']) - - -class ListImagesTest(base.BaseV1ImageTest): - """Here we test the listing of image information""" - - @classmethod - def skip_checks(cls): - super(ListImagesTest, cls).skip_checks() - if (len(CONF.image.container_formats) < 2 - or len(CONF.image.disk_formats) < 2): - skip_msg = ("%s skipped as multiple container formats " - "or disk formats are not available." % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def resource_setup(cls): - super(ListImagesTest, cls).resource_setup() - # We add a few images here to test the listing functionality of - # the images API - a_formats = ['ami', 'ari', 'aki'] - - (cls.container_format, - container_format_alt) = CONF.image.container_formats[:2] - cls.disk_format, cls.disk_format_alt = CONF.image.disk_formats[:2] - if cls.container_format in a_formats: - cls.disk_format = cls.container_format - if container_format_alt in a_formats: - cls.disk_format_alt = container_format_alt - - img1 = cls._create_remote_image('one', cls.container_format, - cls.disk_format) - img2 = cls._create_remote_image('two', container_format_alt, - cls.disk_format_alt) - img3 = cls._create_remote_image('dup', cls.container_format, - cls.disk_format) - img4 = cls._create_remote_image('dup', cls.container_format, - cls.disk_format) - img5 = cls._create_standard_image('1', container_format_alt, - cls.disk_format_alt, 42) - img6 = cls._create_standard_image('2', container_format_alt, - cls.disk_format_alt, 142) - img7 = cls._create_standard_image('33', cls.container_format, - cls.disk_format, 142) - img8 = cls._create_standard_image('33', cls.container_format, - cls.disk_format, 142) - cls.created_set = set(cls.created_images) - # same container format - cls.same_container_format_set = set((img1, img3, img4, img7, img8)) - # same disk format - cls.same_disk_format_set = set((img2, img5, img6)) - - # 1x with size 42 - cls.size42_set = set((img5,)) - # 3x with size 142 - cls.size142_set = set((img6, img7, img8,)) - # dup named - cls.dup_set = set((img3, img4)) - - @classmethod - def _create_remote_image(cls, name, container_format, disk_format): - """Create a new remote image and return newly-registered image-id""" - - name = 'New Remote Image %s' % name - location = CONF.image.http_image - image = cls.create_image(name=name, - container_format=container_format, - disk_format=disk_format, - is_public=False, - location=location) - return image['id'] - - @classmethod - def _create_standard_image(cls, name, container_format, - disk_format, size): - """Create a new standard image and return newly-registered image-id - - Note that the size of the new image is a random number between - 1024 and 4096 - """ - image_file = six.BytesIO(data_utils.random_bytes(size)) - name = 'New Standard Image %s' % name - image = cls.create_image(name=name, - container_format=container_format, - disk_format=disk_format, - is_public=False, data=image_file) - return image['id'] - - @decorators.idempotent_id('246178ab-3b33-4212-9a4b-a7fe8261794d') - def test_index_no_params(self): - # Simple test to see all fixture images returned - images_list = self.client.list_images()['images'] - image_list = [image['id'] for image in images_list] - for image_id in self.created_images: - self.assertIn(image_id, image_list) - - @decorators.idempotent_id('f1755589-63d6-4468-b098-589820eb4031') - def test_index_disk_format(self): - images_list = self.client.list_images( - disk_format=self.disk_format_alt)['images'] - for image in images_list: - self.assertEqual(image['disk_format'], self.disk_format_alt) - result_set = set(map(lambda x: x['id'], images_list)) - self.assertTrue(self.same_disk_format_set <= result_set) - self.assertFalse(self.created_set - self.same_disk_format_set - <= result_set) - - @decorators.idempotent_id('2143655d-96d9-4bec-9188-8674206b4b3b') - def test_index_container_format(self): - images_list = self.client.list_images( - container_format=self.container_format)['images'] - for image in images_list: - self.assertEqual(image['container_format'], self.container_format) - result_set = set(map(lambda x: x['id'], images_list)) - self.assertTrue(self.same_container_format_set <= result_set) - self.assertFalse(self.created_set - self.same_container_format_set - <= result_set) - - @decorators.idempotent_id('feb32ac6-22bb-4a16-afd8-9454bb714b14') - def test_index_max_size(self): - images_list = self.client.list_images(size_max=42)['images'] - for image in images_list: - self.assertLessEqual(image['size'], 42) - result_set = set(map(lambda x: x['id'], images_list)) - self.assertTrue(self.size42_set <= result_set) - self.assertFalse(self.created_set - self.size42_set <= result_set) - - @decorators.idempotent_id('6ffc16d0-4cbf-4401-95c8-4ac63eac34d8') - def test_index_min_size(self): - images_list = self.client.list_images(size_min=142)['images'] - for image in images_list: - self.assertGreaterEqual(image['size'], 142) - result_set = set(map(lambda x: x['id'], images_list)) - self.assertTrue(self.size142_set <= result_set) - self.assertFalse(self.size42_set <= result_set) - - @decorators.idempotent_id('e5dc26d9-9aa2-48dd-bda5-748e1445da98') - def test_index_status_active_detail(self): - images_list = self.client.list_images(detail=True, - status='active', - sort_key='size', - sort_dir='desc')['images'] - top_size = images_list[0]['size'] # We have non-zero sized images - for image in images_list: - size = image['size'] - self.assertLessEqual(size, top_size) - top_size = size - self.assertEqual(image['status'], 'active') - - @decorators.idempotent_id('097af10a-bae8-4342-bff4-edf89969ed2a') - def test_index_name(self): - images_list = self.client.list_images( - detail=True, - name='New Remote Image dup')['images'] - result_set = set(map(lambda x: x['id'], images_list)) - for image in images_list: - self.assertEqual(image['name'], 'New Remote Image dup') - self.assertTrue(self.dup_set <= result_set) - self.assertFalse(self.created_set - self.dup_set <= result_set) - - -class UpdateImageMetaTest(base.BaseV1ImageTest): - @classmethod - def resource_setup(cls): - super(UpdateImageMetaTest, cls).resource_setup() - container_format, disk_format = get_container_and_disk_format() - cls.image_id = cls._create_standard_image('1', container_format, - disk_format, 42) - - @classmethod - def _create_standard_image(cls, name, container_format, - disk_format, size): - """Create a new standard image and return newly-registered image-id""" - - image_file = six.BytesIO(data_utils.random_bytes(size)) - name = 'New Standard Image %s' % name - image = cls.create_image(name=name, - container_format=container_format, - disk_format=disk_format, - is_public=False, data=image_file, - properties={'key1': 'value1'}) - return image['id'] - - @decorators.idempotent_id('01752c1c-0275-4de3-9e5b-876e44541928') - def test_list_image_metadata(self): - # All metadata key/value pairs for an image should be returned - resp = self.client.check_image(self.image_id) - resp_metadata = common_image.get_image_meta_from_headers(resp) - expected = {'key1': 'value1'} - self.assertEqual(expected, resp_metadata['properties']) - - @decorators.idempotent_id('d6d7649c-08ce-440d-9ea7-e3dda552f33c') - def test_update_image_metadata(self): - # The metadata for the image should match the updated values - req_metadata = {'key1': 'alt1', 'key2': 'value2'} - resp = self.client.check_image(self.image_id) - metadata = common_image.get_image_meta_from_headers(resp) - self.assertEqual(metadata['properties'], {'key1': 'value1'}) - metadata['properties'].update(req_metadata) - headers = common_image.image_meta_to_headers( - properties=metadata['properties']) - self.client.update_image(self.image_id, headers=headers) - resp = self.client.check_image(self.image_id) - resp_metadata = common_image.get_image_meta_from_headers(resp) - self.assertEqual(req_metadata, resp_metadata['properties']) diff --git a/tempest/api/image/v1/test_images_negative.py b/tempest/api/image/v1/test_images_negative.py deleted file mode 100644 index 690b8da71..000000000 --- a/tempest/api/image/v1/test_images_negative.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class CreateDeleteImagesNegativeTest(base.BaseV1ImageTest): - """Here are negative tests for the deletion and creation of images.""" - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('036ede36-6160-4463-8c01-c781eee6369d') - def test_register_with_invalid_container_format(self): - # Negative tests for invalid data supplied to POST /images - self.assertRaises(lib_exc.BadRequest, self.client.create_image, - headers={'x-image-meta-name': 'test', - 'x-image-meta-container_format': 'wrong', - 'x-image-meta-disk_format': 'vhd'}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('993face5-921d-4e84-aabf-c1bba4234a67') - def test_register_with_invalid_disk_format(self): - self.assertRaises(lib_exc.BadRequest, self.client.create_image, - headers={'x-image-meta-name': 'test', - 'x-image-meta-container_format': 'bare', - 'x-image-meta-disk_format': 'wrong'}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ec652588-7e3c-4b67-a2f2-0fa96f57c8fc') - def test_delete_non_existent_image(self): - # Return an error while trying to delete a non-existent image - - non_existent_image_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - non_existent_image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('04f72aa3-fcec-45a3-81a3-308ef7cc82bc') - def test_delete_image_blank_id(self): - # Return an error while trying to delete an image with blank Id - self.assertRaises(lib_exc.NotFound, self.client.delete_image, '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('950e5054-a3c7-4dee-ada5-e576f1087abd') - def test_delete_image_non_hex_string_id(self): - # Return an error while trying to delete an image with non hex id - invalid_image_id = data_utils.rand_uuid()[:-1] + "j" - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - invalid_image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4ed757cd-450c-44b1-9fd1-c819748c650d') - def test_delete_image_negative_image_id(self): - # Return an error while trying to delete an image with negative id - self.assertRaises(lib_exc.NotFound, self.client.delete_image, -1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a4a448ab-3db2-4d2d-b9b2-6a1271241dfe') - def test_delete_image_id_over_character_limit(self): - # Return an error while trying to delete image with id over limit - overlimit_image_id = data_utils.rand_uuid() + "1" - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - overlimit_image_id) diff --git a/tempest/api/image/v2/__init__.py b/tempest/api/image/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py deleted file mode 100644 index 2e68efd67..000000000 --- a/tempest/api/image/v2/test_images.py +++ /dev/null @@ -1,390 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# Copyright 2013 IBM Corp -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import random - -import six - -import testtools - -from oslo_log import log as logging -from tempest.api.image import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class BasicOperationsImagesTest(base.BaseV2ImageTest): - """Here we test the basic operations of images""" - - @decorators.attr(type='smoke') - @decorators.idempotent_id('139b765e-7f3d-4b3d-8b37-3ca3876ee318') - def test_register_upload_get_image_file(self): - """Here we test these functionalities - - Register image, upload the image file, get image and get image - file api's - """ - - uuid = '00000000-1111-2222-3333-444455556666' - image_name = data_utils.rand_name('image') - container_format = CONF.image.container_formats[0] - disk_format = CONF.image.disk_formats[0] - image = self.create_image(name=image_name, - container_format=container_format, - disk_format=disk_format, - visibility='private', - ramdisk_id=uuid) - self.assertIn('name', image) - self.assertEqual(image_name, image['name']) - self.assertIn('visibility', image) - self.assertEqual('private', image['visibility']) - self.assertIn('status', image) - self.assertEqual('queued', image['status']) - - # Now try uploading an image file - file_content = data_utils.random_bytes() - image_file = six.BytesIO(file_content) - self.client.store_image_file(image['id'], image_file) - - # Now try to get image details - body = self.client.show_image(image['id']) - self.assertEqual(image['id'], body['id']) - self.assertEqual(image_name, body['name']) - self.assertEqual(uuid, body['ramdisk_id']) - self.assertIn('size', body) - self.assertEqual(1024, body.get('size')) - - # Now try get image file - body = self.client.show_image_file(image['id']) - self.assertEqual(file_content, body.data) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f848bb94-1c6e-45a4-8726-39e3a5b23535') - def test_delete_image(self): - # Deletes an image by image_id - - # Create image - image_name = data_utils.rand_name('image') - container_format = CONF.image.container_formats[0] - disk_format = CONF.image.disk_formats[0] - image = self.create_image(name=image_name, - container_format=container_format, - disk_format=disk_format, - visibility='private') - # Delete Image - self.client.delete_image(image['id']) - self.client.wait_for_resource_deletion(image['id']) - - # Verifying deletion - images = self.client.list_images()['images'] - images_id = [item['id'] for item in images] - self.assertNotIn(image['id'], images_id) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f66891a7-a35c-41a8-b590-a065c2a1caa6') - def test_update_image(self): - # Updates an image by image_id - - # Create image - image_name = data_utils.rand_name('image') - container_format = CONF.image.container_formats[0] - disk_format = CONF.image.disk_formats[0] - image = self.create_image(name=image_name, - container_format=container_format, - disk_format=disk_format, - visibility='private') - self.assertEqual('queued', image['status']) - - # Now try uploading an image file - image_file = six.BytesIO(data_utils.random_bytes()) - self.client.store_image_file(image['id'], image_file) - - # Update Image - new_image_name = data_utils.rand_name('new-image') - body = self.client.update_image(image['id'], [ - dict(replace='/name', value=new_image_name)]) - - # Verifying updating - - body = self.client.show_image(image['id']) - self.assertEqual(image['id'], body['id']) - self.assertEqual(new_image_name, body['name']) - - @testtools.skipUnless(CONF.image_feature_enabled.deactivate_image, - 'deactivate-image is not available.') - @decorators.idempotent_id('951ebe01-969f-4ea9-9898-8a3f1f442ab0') - def test_deactivate_reactivate_image(self): - # Create image - image_name = data_utils.rand_name('image') - image = self.create_image(name=image_name, - container_format='bare', - disk_format='raw', - visibility='private') - - # Upload an image file - content = data_utils.random_bytes() - image_file = six.BytesIO(content) - self.client.store_image_file(image['id'], image_file) - - # Deactivate image - self.client.deactivate_image(image['id']) - body = self.client.show_image(image['id']) - self.assertEqual("deactivated", body['status']) - - # User unable to download deactivated image - self.assertRaises(lib_exc.Forbidden, self.client.show_image_file, - image['id']) - - # Reactivate image - self.client.reactivate_image(image['id']) - body = self.client.show_image(image['id']) - self.assertEqual("active", body['status']) - - # User able to download image after reactivation - body = self.client.show_image_file(image['id']) - self.assertEqual(content, body.data) - - -class ListUserImagesTest(base.BaseV2ImageTest): - """Here we test the listing of image information""" - - @classmethod - def resource_setup(cls): - super(ListUserImagesTest, cls).resource_setup() - # We add a few images here to test the listing functionality of - # the images API - container_fmts = CONF.image.container_formats - disk_fmts = CONF.image.disk_formats - all_pairs = [(container_fmt, disk_fmt) - for container_fmt in container_fmts - for disk_fmt in disk_fmts] - - for (container_fmt, disk_fmt) in all_pairs[:6]: - LOG.debug("Creating an image" - "(Container format: %s, Disk format: %s).", - container_fmt, disk_fmt) - cls._create_standard_image(container_fmt, disk_fmt) - - @classmethod - def _create_standard_image(cls, container_format, disk_format): - """Create a new standard image and return the newly-registered image-id - - Note that the size of the new image is a random number between - 1024 and 4096 - """ - size = random.randint(1024, 4096) - image_file = six.BytesIO(data_utils.random_bytes(size)) - tags = [data_utils.rand_name('tag'), data_utils.rand_name('tag')] - image = cls.create_image(container_format=container_format, - disk_format=disk_format, - visibility='private', - tags=tags) - cls.client.store_image_file(image['id'], data=image_file) - # Keep the data of one test image so it can be used to filter lists - cls.test_data = image - - return image['id'] - - def _list_by_param_value_and_assert(self, params): - """Perform list action with given params and validates result.""" - # Retrieve the list of images that meet the filter - images_list = self.client.list_images(params=params)['images'] - # Validating params of fetched images - msg = 'No images were found that met the filter criteria.' - self.assertNotEmpty(images_list, msg) - for image in images_list: - for key in params: - msg = "Failed to list images by %s" % key - self.assertEqual(params[key], image[key], msg) - - def _list_sorted_by_image_size_and_assert(self, params, desc=False): - """Validate an image list that has been sorted by size - - Perform list action with given params and validates the results are - sorted by image size in either ascending or descending order. - """ - # Retrieve the list of images that meet the filter - images_list = self.client.list_images(params=params)['images'] - # Validate that the list was fetched sorted accordingly - msg = 'No images were found that met the filter criteria.' - self.assertNotEmpty(images_list, msg) - sorted_list = [image['size'] for image in images_list] - msg = 'The list of images was not sorted correctly.' - self.assertEqual(sorted(sorted_list, reverse=desc), sorted_list, msg) - - @decorators.idempotent_id('1e341d7a-90a9-494c-b143-2cdf2aeb6aee') - def test_list_no_params(self): - # Simple test to see all fixture images returned - images_list = self.client.list_images()['images'] - image_list = [image['id'] for image in images_list] - - for image in self.created_images: - self.assertIn(image, image_list) - - @decorators.idempotent_id('9959ca1d-1aa7-4b7a-a1ea-0fff0499b37e') - def test_list_images_param_container_format(self): - # Test to get all images with a specific container_format - params = {"container_format": self.test_data['container_format']} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('4a4735a7-f22f-49b6-b0d9-66e1ef7453eb') - def test_list_images_param_disk_format(self): - # Test to get all images with disk_format = raw - params = {"disk_format": "raw"} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('7a95bb92-d99e-4b12-9718-7bc6ab73e6d2') - def test_list_images_param_visibility(self): - # Test to get all images with visibility = private - params = {"visibility": "private"} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('cf1b9a48-8340-480e-af7b-fe7e17690876') - def test_list_images_param_size(self): - # Test to get all images by size - image_id = self.created_images[0] - # Get image metadata - image = self.client.show_image(image_id) - - params = {"size": image['size']} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('4ad8c157-971a-4ba8-aa84-ed61154b1e7f') - def test_list_images_param_min_max_size(self): - # Test to get all images with size between 2000 to 3000 - image_id = self.created_images[0] - # Get image metadata - image = self.client.show_image(image_id) - - size = image['size'] - params = {"size_min": size - 500, "size_max": size + 500} - images_list = self.client.list_images(params=params)['images'] - image_size_list = map(lambda x: x['size'], images_list) - - for image_size in image_size_list: - self.assertGreaterEqual(image_size, params['size_min'], - "Failed to get images by size_min") - self.assertLessEqual(image_size, params['size_max'], - "Failed to get images by size_max") - - @decorators.idempotent_id('7fc9e369-0f58-4d05-9aa5-0969e2d59d15') - def test_list_images_param_status(self): - # Test to get all active images - params = {"status": "active"} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('e914a891-3cc8-4b40-ad32-e0a39ffbddbb') - def test_list_images_param_limit(self): - # Test to get images by limit - params = {"limit": 1} - images_list = self.client.list_images(params=params)['images'] - - self.assertEqual(len(images_list), params['limit'], - "Failed to get images by limit") - - @decorators.idempotent_id('e9a44b91-31c8-4b40-a332-e0a39ffb4dbb') - def test_list_image_param_owner(self): - # Test to get images by owner - image_id = self.created_images[0] - # Get image metadata - image = self.client.show_image(image_id) - - params = {"owner": image['owner']} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('55c8f5f5-bfed-409d-a6d5-4caeda985d7b') - def test_list_images_param_name(self): - # Test to get images by name - params = {'name': self.test_data['name']} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('aa8ac4df-cff9-418b-8d0f-dd9c67b072c9') - def test_list_images_param_tag(self): - # Test to get images matching a tag - params = {'tag': self.test_data['tags'][0]} - images_list = self.client.list_images(params=params)['images'] - # Validating properties of fetched images - self.assertNotEmpty(images_list) - for image in images_list: - msg = ("The image {image_name} does not have the expected tag " - "{expected_tag} among its tags: {observerd_tags}." - .format(image_name=image['name'], - expected_tag=self.test_data['tags'][0], - observerd_tags=image['tags'])) - self.assertIn(self.test_data['tags'][0], image['tags'], msg) - - @decorators.idempotent_id('eeadce49-04e0-43b7-aec7-52535d903e7a') - def test_list_images_param_sort(self): - params = {'sort': 'size:desc'} - self._list_sorted_by_image_size_and_assert(params, desc=True) - - @decorators.idempotent_id('9faaa0c2-c3a5-43e1-8f61-61c54b409a49') - def test_list_images_param_sort_key_dir(self): - params = {'sort_key': 'size', 'sort_dir': 'desc'} - self._list_sorted_by_image_size_and_assert(params, desc=True) - - @decorators.idempotent_id('622b925c-479f-4736-860d-adeaf13bc371') - def test_get_image_schema(self): - # Test to get image schema - schema = "image" - body = self.schemas_client.show_schema(schema) - self.assertEqual("image", body['name']) - - @decorators.idempotent_id('25c8d7b2-df21-460f-87ac-93130bcdc684') - def test_get_images_schema(self): - # Test to get images schema - schema = "images" - body = self.schemas_client.show_schema(schema) - self.assertEqual("images", body['name']) - - -class ListSharedImagesTest(base.BaseV2ImageTest): - """Here we test the listing of a shared image information""" - - credentials = ['primary', 'alt'] - - @classmethod - def setup_clients(cls): - super(ListSharedImagesTest, cls).setup_clients() - cls.image_member_client = cls.os_primary.image_member_client_v2 - cls.alt_img_client = cls.os_alt.image_client_v2 - - @decorators.idempotent_id('3fa50be4-8e38-4c02-a8db-7811bb780122') - def test_list_images_param_member_status(self): - # Create an image to be shared using default visibility - image_file = six.BytesIO(data_utils.random_bytes(2048)) - container_format = CONF.image.container_formats[0] - disk_format = CONF.image.disk_formats[0] - image = self.create_image(container_format=container_format, - disk_format=disk_format) - self.client.store_image_file(image['id'], data=image_file) - - # Share the image created with the alt user - self.image_member_client.create_image_member( - image_id=image['id'], member=self.alt_img_client.tenant_id) - - # As an image consumer you need to provide the member_status parameter - # along with the visibility=shared parameter in order for it to show - # results - params = {'member_status': 'pending', 'visibility': 'shared'} - fetched_images = self.alt_img_client.list_images(params)['images'] - self.assertEqual(1, len(fetched_images)) - self.assertEqual(image['id'], fetched_images[0]['id']) diff --git a/tempest/api/image/v2/test_images_member.py b/tempest/api/image/v2/test_images_member.py deleted file mode 100644 index 02087802c..000000000 --- a/tempest/api/image/v2/test_images_member.py +++ /dev/null @@ -1,98 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib import decorators - - -class ImagesMemberTest(base.BaseV2MemberImageTest): - - @decorators.idempotent_id('5934c6ea-27dc-4d6e-9421-eeb5e045494a') - def test_image_share_accept(self): - image_id = self._create_image() - member = self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.addCleanup(self.image_member_client.delete_image_member, - image_id, self.alt_tenant_id) - self.assertEqual(member['member_id'], self.alt_tenant_id) - self.assertEqual(member['image_id'], image_id) - self.assertEqual(member['status'], 'pending') - self.assertNotIn(image_id, self._list_image_ids_as_alt()) - self.alt_image_member_client.update_image_member(image_id, - self.alt_tenant_id, - status='accepted') - self.assertIn(image_id, self._list_image_ids_as_alt()) - body = self.image_member_client.list_image_members(image_id) - members = body['members'] - member = members[0] - self.assertEqual(len(members), 1, str(members)) - self.assertEqual(member['member_id'], self.alt_tenant_id) - self.assertEqual(member['image_id'], image_id) - self.assertEqual(member['status'], 'accepted') - - @decorators.idempotent_id('d9e83e5f-3524-4b38-a900-22abcb26e90e') - def test_image_share_reject(self): - image_id = self._create_image() - member = self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.addCleanup(self.image_member_client.delete_image_member, - image_id, self.alt_tenant_id) - self.assertEqual(member['member_id'], self.alt_tenant_id) - self.assertEqual(member['image_id'], image_id) - self.assertEqual(member['status'], 'pending') - self.assertNotIn(image_id, self._list_image_ids_as_alt()) - self.alt_image_member_client.update_image_member(image_id, - self.alt_tenant_id, - status='rejected') - self.assertNotIn(image_id, self._list_image_ids_as_alt()) - - @decorators.idempotent_id('a6ee18b9-4378-465e-9ad9-9a6de58a3287') - def test_get_image_member(self): - image_id = self._create_image() - self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.addCleanup(self.image_member_client.delete_image_member, - image_id, self.alt_tenant_id) - self.alt_image_member_client.update_image_member(image_id, - self.alt_tenant_id, - status='accepted') - - self.assertIn(image_id, self._list_image_ids_as_alt()) - member = self.image_member_client.show_image_member( - image_id, self.alt_tenant_id) - self.assertEqual(self.alt_tenant_id, member['member_id']) - self.assertEqual(image_id, member['image_id']) - self.assertEqual('accepted', member['status']) - - @decorators.idempotent_id('72989bc7-2268-48ed-af22-8821e835c914') - def test_remove_image_member(self): - image_id = self._create_image() - self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.alt_image_member_client.update_image_member(image_id, - self.alt_tenant_id, - status='accepted') - - self.assertIn(image_id, self._list_image_ids_as_alt()) - self.image_member_client.delete_image_member(image_id, - self.alt_tenant_id) - self.assertNotIn(image_id, self._list_image_ids_as_alt()) - - @decorators.idempotent_id('634dcc3f-f6e2-4409-b8fd-354a0bb25d83') - def test_get_image_member_schema(self): - body = self.schemas_client.show_schema("member") - self.assertEqual("member", body['name']) - - @decorators.idempotent_id('6ae916ef-1052-4e11-8d36-b3ae14853cbb') - def test_get_image_members_schema(self): - body = self.schemas_client.show_schema("members") - self.assertEqual("members", body['name']) diff --git a/tempest/api/image/v2/test_images_member_negative.py b/tempest/api/image/v2/test_images_member_negative.py deleted file mode 100644 index caa90f9f3..000000000 --- a/tempest/api/image/v2/test_images_member_negative.py +++ /dev/null @@ -1,43 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImagesMemberNegativeTest(base.BaseV2MemberImageTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b79efb37-820d-4cf0-b54c-308b00cf842c') - def test_image_share_invalid_status(self): - image_id = self._create_image() - member = self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.assertEqual(member['status'], 'pending') - self.assertRaises(lib_exc.BadRequest, - self.alt_image_member_client.update_image_member, - image_id, self.alt_tenant_id, - status='notavalidstatus') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('27002f74-109e-4a37-acd0-f91cd4597967') - def test_image_share_owner_cannot_accept(self): - image_id = self._create_image() - member = self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.assertEqual(member['status'], 'pending') - self.assertNotIn(image_id, self._list_image_ids_as_alt()) - self.assertRaises(lib_exc.Forbidden, - self.image_member_client.update_image_member, - image_id, self.alt_tenant_id, status='accepted') - self.assertNotIn(image_id, self._list_image_ids_as_alt()) diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_objects.py b/tempest/api/image/v2/test_images_metadefs_namespace_objects.py deleted file mode 100644 index 80f811211..000000000 --- a/tempest/api/image/v2/test_images_metadefs_namespace_objects.py +++ /dev/null @@ -1,73 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - - -class MetadataNamespaceObjectsTest(base.BaseV2ImageTest): - """Test the Metadata definition namespace objects basic functionality""" - - def _create_namespace_object(self, namespace): - object_name = data_utils.rand_name(self.__class__.__name__ + '-object') - namespace_object = self.namespace_objects_client.\ - create_namespace_object(namespace['namespace'], name=object_name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.namespace_objects_client.delete_namespace_object, - namespace['namespace'], object_name) - return namespace_object - - @decorators.idempotent_id('b1a3775e-3b5c-4f6a-a3b4-1ba3574ae718') - def test_create_update_delete_meta_namespace_objects(self): - # Create a namespace - namespace = self.create_namespace() - # Create a namespace object - body = self._create_namespace_object(namespace) - # Update a namespace object - up_object_name = data_utils.rand_name('update-object') - body = self.namespace_objects_client.update_namespace_object( - namespace['namespace'], body['name'], - name=up_object_name) - self.assertEqual(up_object_name, body['name']) - # Delete a namespace object - self.namespace_objects_client.delete_namespace_object( - namespace['namespace'], up_object_name) - # List namespace objects and validate deletion - namespace_objects = [ - namespace_object['name'] for namespace_object in - self.namespace_objects_client.list_namespace_objects( - namespace['namespace'])['objects']] - self.assertNotIn(up_object_name, namespace_objects) - - @decorators.idempotent_id('a2a3615e-3b5c-3f6a-a2b1-1ba3574ae738') - def test_list_meta_namespace_objects(self): - # Create a namespace object - namespace = self.create_namespace() - meta_namespace_object = self._create_namespace_object(namespace) - # List namespace objects - namespace_objects = [ - namespace_object['name'] for namespace_object in - self.namespace_objects_client.list_namespace_objects( - namespace['namespace'])['objects']] - self.assertIn(meta_namespace_object['name'], namespace_objects) - - @decorators.idempotent_id('b1a3674e-3b4c-3f6a-a3b4-1ba3573ca768') - def test_show_meta_namespace_objects(self): - # Create a namespace object - namespace = self.create_namespace() - namespace_object = self._create_namespace_object(namespace) - # Show a namespace object - body = self.namespace_objects_client.show_namespace_object( - namespace['namespace'], namespace_object['name']) - self.assertEqual(namespace_object['name'], body['name']) diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_properties.py b/tempest/api/image/v2/test_images_metadefs_namespace_properties.py deleted file mode 100644 index ed91726e0..000000000 --- a/tempest/api/image/v2/test_images_metadefs_namespace_properties.py +++ /dev/null @@ -1,57 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class MetadataNamespacePropertiesTest(base.BaseV2ImageTest): - """Test the Metadata definition namespace property basic functionality""" - - @decorators.idempotent_id('b1a3765e-3a5d-4f6d-a3a7-3ca3476ae768') - def test_basic_meta_def_namespace_property(self): - # Get the available resource types and use one resource_type - body = self.resource_types_client.list_resource_types() - resource_name = body['resource_types'][0]['name'] - enum = ["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"] - # Create a namespace - namespace = self.create_namespace() - # Create resource type association - body = self.resource_types_client.create_resource_type_association( - namespace['namespace'], name=resource_name) - # Create a property - property_title = data_utils.rand_name('property') - body = self.namespace_properties_client.create_namespace_property( - namespace=namespace['namespace'], title=property_title, - name=resource_name, type="string", enum=enum) - self.assertEqual(property_title, body['title']) - # Show namespace property - body = self.namespace_properties_client.show_namespace_properties( - namespace['namespace'], resource_name) - self.assertEqual(resource_name, body['name']) - # Update namespace property - update_property_title = data_utils.rand_name('update-property') - body = self.namespace_properties_client.update_namespace_properties( - namespace['namespace'], resource_name, - title=update_property_title, type="string", - enum=enum, name=resource_name) - self.assertEqual(update_property_title, body['title']) - # Delete namespace property - self.namespace_properties_client.delete_namespace_property( - namespace['namespace'], resource_name) - # List namespace properties and validate deletion - namespace_property = [ - namespace_property['title'] for namespace_property in - self.namespace_properties_client.list_namespace_properties( - namespace['namespace'])['properties']] - self.assertNotIn(update_property_title, namespace_property) diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_tags.py b/tempest/api/image/v2/test_images_metadefs_namespace_tags.py deleted file mode 100644 index 69bebfe30..000000000 --- a/tempest/api/image/v2/test_images_metadefs_namespace_tags.py +++ /dev/null @@ -1,90 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - - -class MetadataNamespaceTagsTest(base.BaseV2ImageTest): - """Test the Metadata definition namespace tags basic functionality""" - - tags = [ - { - "name": "sample-tag1" - }, - { - "name": "sample-tag2" - }, - { - "name": "sample-tag3" - } - ] - tag_list = ["sample-tag1", "sample-tag2", "sample-tag3"] - - def _create_namespace_tags(self, namespace): - # Create a namespace - namespace_tags = self.namespace_tags_client.create_namespace_tags( - namespace['namespace'], tags=self.tags) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.namespace_tags_client.delete_namespace_tags, - namespace['namespace']) - return namespace_tags - - @decorators.idempotent_id('a2a3765e-3a6d-4f6d-a3a7-3cc3476aa876') - def test_create_list_delete_namespace_tags(self): - # Create a namespace - namespace = self.create_namespace() - self._create_namespace_tags(namespace) - # List namespace tags - body = self.namespace_tags_client.list_namespace_tags( - namespace['namespace']) - self.assertTrue(3, len(body['tags'])) - self.assertIn(body['tags'][0]['name'], self.tag_list) - self.assertIn(body['tags'][1]['name'], self.tag_list) - self.assertIn(body['tags'][2]['name'], self.tag_list) - # Delete all tag definitions - self.namespace_tags_client.delete_namespace_tags( - namespace['namespace']) - body = self.namespace_tags_client.list_namespace_tags( - namespace['namespace']) - self.assertEmpty(body['tags']) - - @decorators.idempotent_id('a2a3765e-1a2c-3f6d-a3a7-3cc3466ab875') - def test_create_update_delete_tag(self): - # Create a namespace - namespace = self.create_namespace() - self._create_namespace_tags(namespace) - # Create a tag - tag_name = data_utils.rand_name('tag_name') - self.namespace_tags_client.create_namespace_tag( - namespace=namespace['namespace'], tag_name=tag_name) - - body = self.namespace_tags_client.show_namespace_tag( - namespace['namespace'], tag_name) - self.assertEqual(tag_name, body['name']) - # Update tag definition - update_tag_definition = data_utils.rand_name('update-tag') - body = self.namespace_tags_client.update_namespace_tag( - namespace['namespace'], tag_name=tag_name, - name=update_tag_definition) - self.assertEqual(update_tag_definition, body['name']) - # Delete tag definition - self.namespace_tags_client.delete_namespace_tag( - namespace['namespace'], update_tag_definition) - # List namespace tags and validate deletion - namespace_tags = [ - namespace_tag['name'] for namespace_tag in - self.namespace_tags_client.list_namespace_tags( - namespace['namespace'])['tags']] - self.assertNotIn(update_tag_definition, namespace_tags) diff --git a/tempest/api/image/v2/test_images_metadefs_namespaces.py b/tempest/api/image/v2/test_images_metadefs_namespaces.py deleted file mode 100644 index f71b16c4e..000000000 --- a/tempest/api/image/v2/test_images_metadefs_namespaces.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class MetadataNamespacesTest(base.BaseV2ImageTest): - """Test the Metadata definition Namespaces basic functionality""" - - @decorators.idempotent_id('319b765e-7f3d-4b3d-8b37-3ca3876ee768') - def test_basic_metadata_definition_namespaces(self): - # get the available resource types and use one resource_type - body = self.resource_types_client.list_resource_types() - resource_name = body['resource_types'][0]['name'] - name = [{'name': resource_name}] - namespace_name = data_utils.rand_name('namespace') - # create the metadef namespace - body = self.namespaces_client.create_namespace( - namespace=namespace_name, - visibility='public', - description='Tempest', - display_name=namespace_name, - resource_type_associations=name, - protected=True) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self._cleanup_namespace, namespace_name) - # list namespaces - bodys = self.namespaces_client.list_namespaces()['namespaces'] - body = [namespace['namespace'] for namespace in bodys] - self.assertIn(namespace_name, body) - # get namespace details - body = self.namespaces_client.show_namespace(namespace_name) - self.assertEqual(namespace_name, body['namespace']) - self.assertEqual('public', body['visibility']) - # unable to delete protected namespace - self.assertRaises(lib_exc.Forbidden, - self.namespaces_client.delete_namespace, - namespace_name) - # update the visibility to private and protected to False - body = self.namespaces_client.update_namespace( - namespace=namespace_name, - description='Tempest', - visibility='private', - display_name=namespace_name, - protected=False) - self.assertEqual('private', body['visibility']) - self.assertEqual(False, body['protected']) - # now able to delete the non-protected namespace - self.namespaces_client.delete_namespace(namespace_name) - - def _cleanup_namespace(self, namespace_name): - body = self.namespaces_client.show_namespace(namespace_name) - self.assertEqual(namespace_name, body['namespace']) - body = self.namespaces_client.update_namespace( - namespace=namespace_name, - description='Tempest', - visibility='private', - display_name=namespace_name, - protected=False) - self.namespaces_client.delete_namespace(namespace_name) diff --git a/tempest/api/image/v2/test_images_metadefs_resource_types.py b/tempest/api/image/v2/test_images_metadefs_resource_types.py deleted file mode 100644 index c60b3f716..000000000 --- a/tempest/api/image/v2/test_images_metadefs_resource_types.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2016 Ericsson India Global Services Private Limited -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib import decorators - - -class MetadataResourceTypesTest(base.BaseV2ImageTest): - """Test the Metadata definition resource types basic functionality""" - - @decorators.idempotent_id('6f358a4e-5ef0-11e6-a795-080027d0d606') - def test_basic_meta_def_resource_type_association(self): - # Get the available resource types and use one resource_type - body = self.resource_types_client.list_resource_types() - resource_name = body['resource_types'][0]['name'] - # Create a namespace - namespace = self.create_namespace() - # Create resource type association - body = self.resource_types_client.create_resource_type_association( - namespace['namespace'], name=resource_name) - self.assertEqual(body['name'], resource_name) - # NOTE(raiesmh08): Here intentionally I have not added addcleanup - # method for resource type dissociation because its a metadata add and - # being cleaned as soon as namespace is cleaned at test case level. - # When namespace cleans, resource type association will automatically - # clean without any error or dependency. - - # List resource type associations and validate creation - rs_type_associations = [ - rs_type_association['name'] for rs_type_association in - self.resource_types_client.list_resource_type_association( - namespace['namespace'])['resource_type_associations']] - self.assertIn(resource_name, rs_type_associations) - # Delete resource type association - self.resource_types_client.delete_resource_type_association( - namespace['namespace'], resource_name) - # List resource type associations and validate deletion - rs_type_associations = [ - rs_type_association['name'] for rs_type_association in - self.resource_types_client.list_resource_type_association( - namespace['namespace'])['resource_type_associations']] - self.assertNotIn(resource_name, rs_type_associations) diff --git a/tempest/api/image/v2/test_images_metadefs_schema.py b/tempest/api/image/v2/test_images_metadefs_schema.py deleted file mode 100644 index 95cc31079..000000000 --- a/tempest/api/image/v2/test_images_metadefs_schema.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2016 EasyStack. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib import decorators - - -class MetadataSchemaTest(base.BaseV2ImageTest): - """Test to get metadata schema""" - - @decorators.idempotent_id('e9e44891-3cb8-3b40-a532-e0a39fea3dab') - def test_get_metadata_namespace_schema(self): - # Test to get namespace schema - body = self.schemas_client.show_schema("metadefs/namespace") - self.assertEqual("namespace", body['name']) - - @decorators.idempotent_id('ffe44891-678b-3ba0-a3e2-e0a3967b3aeb') - def test_get_metadata_namespaces_schema(self): - # Test to get namespaces schema - body = self.schemas_client.show_schema("metadefs/namespaces") - self.assertEqual("namespaces", body['name']) - - @decorators.idempotent_id('fde34891-678b-3b40-ae32-e0a3e67b6beb') - def test_get_metadata_resource_type_schema(self): - # Test to get resource_type schema - body = self.schemas_client.show_schema("metadefs/resource_type") - self.assertEqual("resource_type_association", body['name']) - - @decorators.idempotent_id('dfe4a891-b38b-3bf0-a3b2-e03ee67b3a3a') - def test_get_metadata_resources_types_schema(self): - # Test to get resource_types schema - body = self.schemas_client.show_schema("metadefs/resource_types") - self.assertEqual("resource_type_associations", body['name']) - - @decorators.idempotent_id('dff4a891-b38b-3bf0-a3b2-e03ee67b3a3b') - def test_get_metadata_object_schema(self): - # Test to get object schema - body = self.schemas_client.show_schema("metadefs/object") - self.assertEqual("object", body['name']) - - @decorators.idempotent_id('dee4a891-b38b-3bf0-a3b2-e03ee67b3a3c') - def test_get_metadata_objects_schema(self): - # Test to get objects schema - body = self.schemas_client.show_schema("metadefs/objects") - self.assertEqual("objects", body['name']) - - @decorators.idempotent_id('dae4a891-b38b-3bf0-a3b2-e03ee67b3a3d') - def test_get_metadata_property_schema(self): - # Test to get property schema - body = self.schemas_client.show_schema("metadefs/property") - self.assertEqual("property", body['name']) - - @decorators.idempotent_id('dce4a891-b38b-3bf0-a3b2-e03ee67b3a3e') - def test_get_metadata_properties_schema(self): - # Test to get properties schema - body = self.schemas_client.show_schema("metadefs/properties") - self.assertEqual("properties", body['name']) - - @decorators.idempotent_id('dde4a891-b38b-3bf0-a3b2-e03ee67b3a3e') - def test_get_metadata_tag_schema(self): - # Test to get tag schema - body = self.schemas_client.show_schema("metadefs/tag") - self.assertEqual("tag", body['name']) - - @decorators.idempotent_id('cde4a891-b38b-3bf0-a3b2-e03ee67b3a3a') - def test_get_metadata_tags_schema(self): - # Test to get tags schema - body = self.schemas_client.show_schema("metadefs/tags") - self.assertEqual("tags", body['name']) diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py deleted file mode 100644 index b4baf05d3..000000000 --- a/tempest/api/image/v2/test_images_negative.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImagesNegativeTest(base.BaseV2ImageTest): - - """here we have -ve tests for show_image and delete_image api - - Tests - ** get non-existent image - ** get image with image_id=NULL - ** get the deleted image - ** delete non-existent image - ** delete image with image_id=NULL - ** delete the deleted image - """ - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('668743d5-08ad-4480-b2b8-15da34f81d9f') - def test_get_non_existent_image(self): - # get the non-existent image - non_existent_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.show_image, - non_existent_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ef45000d-0a72-4781-866d-4cb7bf2562ad') - def test_get_image_null_id(self): - # get image with image_id = NULL - image_id = "" - self.assertRaises(lib_exc.NotFound, self.client.show_image, image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e57fc127-7ba0-4693-92d7-1d8a05ebcba9') - def test_get_delete_deleted_image(self): - # get and delete the deleted image - # create and delete image - image = self.client.create_image(name='test', - container_format='bare', - disk_format='raw') - self.client.delete_image(image['id']) - self.client.wait_for_resource_deletion(image['id']) - - # get the deleted image - self.assertRaises(lib_exc.NotFound, - self.client.show_image, image['id']) - - # delete the deleted image - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - image['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6fe40f1c-57bd-4918-89cc-8500f850f3de') - def test_delete_non_existing_image(self): - # delete non-existent image - non_existent_image_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - non_existent_image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('32248db1-ab88-4821-9604-c7c369f1f88c') - def test_delete_image_null_id(self): - # delete image with image_id=NULL - image_id = "" - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('292bd310-369b-41c7-a7a3-10276ef76753') - def test_register_with_invalid_container_format(self): - # Negative tests for invalid data supplied to POST /images - self.assertRaises(lib_exc.BadRequest, self.client.create_image, - name='test', container_format='wrong', - disk_format='vhd') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('70c6040c-5a97-4111-9e13-e73665264ce1') - def test_register_with_invalid_disk_format(self): - self.assertRaises(lib_exc.BadRequest, self.client.create_image, - name='test', container_format='bare', - disk_format='wrong') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ab980a34-8410-40eb-872b-f264752f46e5') - def test_delete_protected_image(self): - # Create a protected image - image = self.create_image(protected=True) - self.addCleanup(self.client.update_image, image['id'], - [dict(replace="/protected", value=False)]) - - # Try deleting the protected image - self.assertRaises(lib_exc.Forbidden, - self.client.delete_image, - image['id']) diff --git a/tempest/api/image/v2/test_images_tags.py b/tempest/api/image/v2/test_images_tags.py deleted file mode 100644 index 601826ee4..000000000 --- a/tempest/api/image/v2/test_images_tags.py +++ /dev/null @@ -1,38 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class ImagesTagsTest(base.BaseV2ImageTest): - - @decorators.idempotent_id('10407036-6059-4f95-a2cd-cbbbee7ed329') - def test_update_delete_tags_for_image(self): - image = self.create_image(container_format='bare', - disk_format='raw', - visibility='private') - tag = data_utils.rand_name('tag') - self.addCleanup(self.client.delete_image, image['id']) - - # Creating image tag and verify it. - self.client.add_image_tag(image['id'], tag) - body = self.client.show_image(image['id']) - self.assertIn(tag, body['tags']) - - # Deleting image tag and verify it. - self.client.delete_image_tag(image['id'], tag) - body = self.client.show_image(image['id']) - self.assertNotIn(tag, body['tags']) diff --git a/tempest/api/image/v2/test_images_tags_negative.py b/tempest/api/image/v2/test_images_tags_negative.py deleted file mode 100644 index 440fa3688..000000000 --- a/tempest/api/image/v2/test_images_tags_negative.py +++ /dev/null @@ -1,43 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImagesTagsNegativeTest(base.BaseV2ImageTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8cd30f82-6f9a-4c6e-8034-c1b51fba43d9') - def test_update_tags_for_non_existing_image(self): - # Update tag with non existing image. - tag = data_utils.rand_name('tag') - non_exist_image = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.add_image_tag, - non_exist_image, tag) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('39c023a2-325a-433a-9eea-649bf1414b19') - def test_delete_non_existing_tag(self): - # Delete non existing tag. - image = self.create_image(container_format='bare', - disk_format='raw', - visibility='private' - ) - tag = data_utils.rand_name('non-exist-tag') - self.addCleanup(self.client.delete_image, image['id']) - self.assertRaises(lib_exc.NotFound, self.client.delete_image_tag, - image['id'], tag) diff --git a/tempest/api/image/v2/test_versions.py b/tempest/api/image/v2/test_versions.py deleted file mode 100644 index 84f10685c..000000000 --- a/tempest/api/image/v2/test_versions.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2017 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.image import base -from tempest.lib import decorators - - -class VersionsTest(base.BaseV2ImageTest): - - @decorators.idempotent_id('659ea30a-a17c-4317-832c-0f68ed23c31d') - @decorators.attr(type='smoke') - def test_list_versions(self): - versions = self.versions_client.list_versions()['versions'] - expected_resources = ('id', 'links', 'status') - - for version in versions: - for res in expected_resources: - self.assertIn(res, version) diff --git a/tempest/api/network/__init__.py b/tempest/api/network/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/network/admin/__init__.py b/tempest/api/network/admin/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py deleted file mode 100644 index 7304db92b..000000000 --- a/tempest/api/network/admin/test_agent_management.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib import decorators -from tempest import test - - -class AgentManagementTestJSON(base.BaseAdminNetworkTest): - - @classmethod - def skip_checks(cls): - super(AgentManagementTestJSON, cls).skip_checks() - if not test.is_extension_enabled('agent', 'network'): - msg = "agent extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(AgentManagementTestJSON, cls).resource_setup() - body = cls.admin_agents_client.list_agents() - agents = body['agents'] - cls.agent = agents[0] - - @decorators.idempotent_id('9c80f04d-11f3-44a4-8738-ed2f879b0ff4') - def test_list_agent(self): - body = self.admin_agents_client.list_agents() - agents = body['agents'] - # Hearthbeats must be excluded from comparison - self.agent.pop('heartbeat_timestamp', None) - self.agent.pop('configurations', None) - for agent in agents: - agent.pop('heartbeat_timestamp', None) - agent.pop('configurations', None) - self.assertIn(self.agent, agents) - - @decorators.idempotent_id('e335be47-b9a1-46fd-be30-0874c0b751e6') - def test_list_agents_non_admin(self): - body = self.agents_client.list_agents() - self.assertEmpty(body["agents"]) - - @decorators.idempotent_id('869bc8e8-0fda-4a30-9b71-f8a7cf58ca9f') - def test_show_agent(self): - body = self.admin_agents_client.show_agent(self.agent['id']) - agent = body['agent'] - self.assertEqual(agent['id'], self.agent['id']) - - @decorators.idempotent_id('371dfc5b-55b9-4cb5-ac82-c40eadaac941') - def test_update_agent_status(self): - origin_status = self.agent['admin_state_up'] - # Try to update the 'admin_state_up' to the original - # one to avoid the negative effect. - agent_status = {'admin_state_up': origin_status} - body = self.admin_agents_client.update_agent(agent_id=self.agent['id'], - agent=agent_status) - updated_status = body['agent']['admin_state_up'] - self.assertEqual(origin_status, updated_status) - - @decorators.idempotent_id('68a94a14-1243-46e6-83bf-157627e31556') - def test_update_agent_description(self): - self.useFixture(fixtures.LockFixture('agent_description')) - description = 'description for update agent.' - agent_description = {'description': description} - body = self.admin_agents_client.update_agent(agent_id=self.agent['id'], - agent=agent_description) - self.addCleanup(self._restore_agent) - updated_description = body['agent']['description'] - self.assertEqual(updated_description, description) - - def _restore_agent(self): - """Restore the agent description after update test""" - - description = self.agent['description'] or '' - origin_agent = {'description': description} - self.admin_agents_client.update_agent(agent_id=self.agent['id'], - agent=origin_agent) diff --git a/tempest/api/network/admin/test_dhcp_agent_scheduler.py b/tempest/api/network/admin/test_dhcp_agent_scheduler.py deleted file mode 100644 index 485c8f5ed..000000000 --- a/tempest/api/network/admin/test_dhcp_agent_scheduler.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest.lib import decorators -from tempest import test - - -class DHCPAgentSchedulersTestJSON(base.BaseAdminNetworkTest): - - @classmethod - def skip_checks(cls): - super(DHCPAgentSchedulersTestJSON, cls).skip_checks() - if not test.is_extension_enabled('dhcp_agent_scheduler', 'network'): - msg = "dhcp_agent_scheduler extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(DHCPAgentSchedulersTestJSON, cls).resource_setup() - # Create a network and make sure it will be hosted by a - # dhcp agent: this is done by creating a regular port - cls.network = cls.create_network() - cls.create_subnet(cls.network) - cls.port = cls.create_port(cls.network) - - @decorators.idempotent_id('5032b1fe-eb42-4a64-8f3b-6e189d8b5c7d') - def test_list_dhcp_agent_hosting_network(self): - self.admin_networks_client.list_dhcp_agents_on_hosting_network( - self.network['id']) - - @decorators.idempotent_id('30c48f98-e45d-4ffb-841c-b8aad57c7587') - def test_list_networks_hosted_by_one_dhcp(self): - body = self.admin_networks_client.list_dhcp_agents_on_hosting_network( - self.network['id']) - agents = body['agents'] - self.assertNotEmpty(agents, "no dhcp agent") - agent = agents[0] - self.assertTrue(self._check_network_in_dhcp_agent( - self.network['id'], agent)) - - def _check_network_in_dhcp_agent(self, network_id, agent): - network_ids = [] - body = self.admin_agents_client.list_networks_hosted_by_one_dhcp_agent( - agent['id']) - networks = body['networks'] - for network in networks: - network_ids.append(network['id']) - return network_id in network_ids - - @decorators.idempotent_id('a0856713-6549-470c-a656-e97c8df9a14d') - def test_add_remove_network_from_dhcp_agent(self): - # The agent is now bound to the network, we can free the port - self.ports_client.delete_port(self.port['id']) - self.ports.remove(self.port) - agent = dict() - agent['agent_type'] = None - body = self.admin_agents_client.list_agents() - agents = body['agents'] - for a in agents: - if a['agent_type'] == 'DHCP agent': - agent = a - break - self.assertEqual(agent['agent_type'], 'DHCP agent', 'Could not find ' - 'DHCP agent in agent list though dhcp_agent_scheduler' - ' is enabled.') - network = self.create_network() - network_id = network['id'] - if self._check_network_in_dhcp_agent(network_id, agent): - self._remove_network_from_dhcp_agent(network_id, agent) - self._add_dhcp_agent_to_network(network_id, agent) - else: - self._add_dhcp_agent_to_network(network_id, agent) - self._remove_network_from_dhcp_agent(network_id, agent) - - def _remove_network_from_dhcp_agent(self, network_id, agent): - self.admin_agents_client.delete_network_from_dhcp_agent( - agent_id=agent['id'], - network_id=network_id) - self.assertFalse(self._check_network_in_dhcp_agent( - network_id, agent)) - - def _add_dhcp_agent_to_network(self, network_id, agent): - self.admin_agents_client.add_dhcp_agent_to_network( - agent['id'], network_id=network_id) - self.assertTrue(self._check_network_in_dhcp_agent( - network_id, agent)) diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py deleted file mode 100644 index 4d41e3354..000000000 --- a/tempest/api/network/admin/test_external_network_extension.py +++ /dev/null @@ -1,134 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ExternalNetworksTestJSON(base.BaseAdminNetworkTest): - - @classmethod - def resource_setup(cls): - super(ExternalNetworksTestJSON, cls).resource_setup() - cls.network = cls.create_network() - - def _create_network(self, external=True): - post_body = {'name': data_utils.rand_name('network-')} - if external: - post_body['router:external'] = external - body = self.admin_networks_client.create_network(**post_body) - network = body['network'] - self.addCleanup( - self.admin_networks_client.delete_network, network['id']) - return network - - @decorators.idempotent_id('462be770-b310-4df9-9c42-773217e4c8b1') - def test_create_external_network(self): - # Create a network as an admin user specifying the - # external network extension attribute - ext_network = self._create_network() - # Verifies router:external parameter - self.assertIsNotNone(ext_network['id']) - self.assertTrue(ext_network['router:external']) - - @decorators.idempotent_id('4db5417a-e11c-474d-a361-af00ebef57c5') - def test_update_external_network(self): - # Update a network as an admin user specifying the - # external network extension attribute - network = self._create_network(external=False) - self.assertFalse(network.get('router:external', False)) - update_body = {'router:external': True} - body = self.admin_networks_client.update_network(network['id'], - **update_body) - updated_network = body['network'] - # Verify that router:external parameter was updated - self.assertTrue(updated_network['router:external']) - - @decorators.idempotent_id('39be4c9b-a57e-4ff9-b7c7-b218e209dfcc') - def test_list_external_networks(self): - # Create external_net - external_network = self._create_network() - # List networks as a normal user and confirm the external - # network extension attribute is returned for those networks - # that were created as external - body = self.networks_client.list_networks() - networks_list = [net['id'] for net in body['networks']] - self.assertIn(external_network['id'], networks_list) - self.assertIn(self.network['id'], networks_list) - for net in body['networks']: - if net['id'] == self.network['id']: - self.assertFalse(net['router:external']) - elif net['id'] == external_network['id']: - self.assertTrue(net['router:external']) - - @decorators.idempotent_id('2ac50ab2-7ebd-4e27-b3ce-a9e399faaea2') - def test_show_external_networks_attribute(self): - # Create external_net - external_network = self._create_network() - # Show an external network as a normal user and confirm the - # external network extension attribute is returned. - body = self.networks_client.show_network(external_network['id']) - show_ext_net = body['network'] - self.assertEqual(external_network['name'], show_ext_net['name']) - self.assertEqual(external_network['id'], show_ext_net['id']) - self.assertTrue(show_ext_net['router:external']) - body = self.networks_client.show_network(self.network['id']) - show_net = body['network'] - # Verify with show that router:external is False for network - self.assertEqual(self.network['name'], show_net['name']) - self.assertEqual(self.network['id'], show_net['id']) - self.assertFalse(show_net['router:external']) - - @decorators.idempotent_id('82068503-2cf2-4ed4-b3be-ecb89432e4bb') - @testtools.skipUnless(CONF.network_feature_enabled.floating_ips, - 'Floating ips are not availabled') - def test_delete_external_networks_with_floating_ip(self): - # Verifies external network can be deleted while still holding - # (unassociated) floating IPs - - body = self.admin_networks_client.create_network( - **{'router:external': True}) - external_network = body['network'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.admin_networks_client.delete_network, - external_network['id']) - subnet = self.create_subnet( - external_network, client=self.admin_subnets_client, - enable_dhcp=False) - body = self.admin_floating_ips_client.create_floatingip( - floating_network_id=external_network['id']) - created_floating_ip = body['floatingip'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.admin_floating_ips_client.delete_floatingip, - created_floating_ip['id']) - floatingip_list = self.admin_floating_ips_client.list_floatingips( - network=external_network['id']) - self.assertIn(created_floating_ip['id'], - (f['id'] for f in floatingip_list['floatingips'])) - self.admin_networks_client.delete_network(external_network['id']) - # Verifies floating ip is deleted - floatingip_list = self.admin_floating_ips_client.list_floatingips() - self.assertNotIn(created_floating_ip['id'], - (f['id'] for f in floatingip_list['floatingips'])) - # Verifies subnet is deleted - subnet_list = self.admin_subnets_client.list_subnets() - self.assertNotIn(subnet['id'], - (s['id'] for s in subnet_list)) - # Removes subnet from the cleanup list - self.subnets.remove(subnet) diff --git a/tempest/api/network/admin/test_external_networks_negative.py b/tempest/api/network/admin/test_external_networks_negative.py deleted file mode 100644 index 0709d2ade..000000000 --- a/tempest/api/network/admin/test_external_networks_negative.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import testtools - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ExternalNetworksAdminNegativeTestJSON(base.BaseAdminNetworkTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d402ae6c-0be0-4d8e-833b-a738895d98d0') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_create_port_with_precreated_floatingip_as_fixed_ip(self): - # NOTE: External networks can be used to create both floating-ip as - # well as instance-ip. So, creating an instance-ip with a value of a - # pre-created floating-ip should be denied. - - # create a floating ip - body = self.admin_floating_ips_client.create_floatingip( - floating_network_id=CONF.network.public_network_id) - created_floating_ip = body['floatingip'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.admin_floating_ips_client.delete_floatingip, - created_floating_ip['id']) - floating_ip_address = created_floating_ip['floating_ip_address'] - self.assertIsNotNone(floating_ip_address) - - # use the same value of floatingip as fixed-ip to create_port() - fixed_ips = [{'ip_address': floating_ip_address}] - - # create a port which will internally create an instance-ip - self.assertRaises(lib_exc.Conflict, - self.admin_ports_client.create_port, - network_id=CONF.network.public_network_id, - fixed_ips=fixed_ips) diff --git a/tempest/api/network/admin/test_floating_ips_admin_actions.py b/tempest/api/network/admin/test_floating_ips_admin_actions.py deleted file mode 100644 index 7ee819ea7..000000000 --- a/tempest/api/network/admin/test_floating_ips_admin_actions.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class FloatingIPAdminTestJSON(base.BaseAdminNetworkTest): - force_tenant_isolation = True - credentials = ['primary', 'alt', 'admin'] - - @classmethod - def skip_checks(cls): - super(FloatingIPAdminTestJSON, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - if not CONF.network.public_network_id: - msg = "The public_network_id option must be specified." - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_clients(cls): - super(FloatingIPAdminTestJSON, cls).setup_clients() - cls.alt_floating_ips_client = cls.os_alt.floating_ips_client - - @classmethod - def resource_setup(cls): - super(FloatingIPAdminTestJSON, cls).resource_setup() - cls.ext_net_id = CONF.network.public_network_id - cls.floating_ip = cls.create_floatingip(cls.ext_net_id) - cls.network = cls.create_network() - subnet = cls.create_subnet(cls.network) - router = cls.create_router(external_network_id=cls.ext_net_id) - cls.create_router_interface(router['id'], subnet['id']) - cls.port = cls.create_port(cls.network) - - @decorators.idempotent_id('64f2100b-5471-4ded-b46c-ddeeeb4f231b') - def test_list_floating_ips_from_admin_and_nonadmin(self): - # Create floating ip from admin user - floating_ip_admin = self.admin_floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id) - self.addCleanup(self.admin_floating_ips_client.delete_floatingip, - floating_ip_admin['floatingip']['id']) - # Create floating ip from alt user - body = self.alt_floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id) - floating_ip_alt = body['floatingip'] - self.addCleanup(self.alt_floating_ips_client.delete_floatingip, - floating_ip_alt['id']) - # List floating ips from admin - body = self.admin_floating_ips_client.list_floatingips() - floating_ip_ids_admin = [f['id'] for f in body['floatingips']] - # Check that admin sees all floating ips - self.assertIn(self.floating_ip['id'], floating_ip_ids_admin) - self.assertIn(floating_ip_admin['floatingip']['id'], - floating_ip_ids_admin) - self.assertIn(floating_ip_alt['id'], floating_ip_ids_admin) - # List floating ips from nonadmin - body = self.floating_ips_client.list_floatingips() - floating_ip_ids = [f['id'] for f in body['floatingips']] - # Check that nonadmin user doesn't see floating ip created from admin - # and floating ip that is created in another project (alt user) - self.assertIn(self.floating_ip['id'], floating_ip_ids) - self.assertNotIn(floating_ip_admin['floatingip']['id'], - floating_ip_ids) - self.assertNotIn(floating_ip_alt['id'], floating_ip_ids) - - @decorators.idempotent_id('32727cc3-abe2-4485-a16e-48f2d54c14f2') - def test_create_list_show_floating_ip_with_tenant_id_by_admin(self): - # Creates a floating IP - body = self.admin_floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id, - tenant_id=self.network['tenant_id'], - port_id=self.port['id']) - created_floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - created_floating_ip['id']) - self.assertIsNotNone(created_floating_ip['id']) - self.assertIsNotNone(created_floating_ip['tenant_id']) - self.assertIsNotNone(created_floating_ip['floating_ip_address']) - self.assertEqual(created_floating_ip['port_id'], self.port['id']) - self.assertEqual(created_floating_ip['floating_network_id'], - self.ext_net_id) - port = self.port['fixed_ips'] - self.assertEqual(created_floating_ip['fixed_ip_address'], - port[0]['ip_address']) - # Verifies the details of a floating_ip - floating_ip = self.admin_floating_ips_client.show_floatingip( - created_floating_ip['id']) - shown_floating_ip = floating_ip['floatingip'] - self.assertEqual(shown_floating_ip['id'], created_floating_ip['id']) - self.assertEqual(shown_floating_ip['floating_network_id'], - self.ext_net_id) - self.assertEqual(shown_floating_ip['tenant_id'], - self.network['tenant_id']) - self.assertEqual(shown_floating_ip['floating_ip_address'], - created_floating_ip['floating_ip_address']) - self.assertEqual(shown_floating_ip['port_id'], self.port['id']) - # Verify the floating ip exists in the list of all floating_ips - floating_ips = self.admin_floating_ips_client.list_floatingips() - floatingip_id_list = [f['id'] for f in floating_ips['floatingips']] - self.assertIn(created_floating_ip['id'], floatingip_id_list) diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py deleted file mode 100644 index 85b2472e8..000000000 --- a/tempest/api/network/admin/test_l3_agent_scheduler.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest import test - -CONF = config.CONF -AGENT_TYPE = 'L3 agent' -AGENT_MODES = ( - 'legacy', - 'dvr_snat' -) - - -class L3AgentSchedulerTestJSON(base.BaseAdminNetworkTest): - """Tests the following operations in the Neutron API: - - List routers that the given L3 agent is hosting. - List L3 agents hosting the given router. - Add and Remove Router to L3 agent - - v2.0 of the Neutron API is assumed. - - The l3_agent_scheduler extension is required for these tests. - """ - - @classmethod - def skip_checks(cls): - super(L3AgentSchedulerTestJSON, cls).skip_checks() - if not test.is_extension_enabled('l3_agent_scheduler', 'network'): - msg = "L3 Agent Scheduler Extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(L3AgentSchedulerTestJSON, cls).resource_setup() - agents = cls.admin_agents_client.list_agents( - agent_type=AGENT_TYPE)['agents'] - for agent in agents: - if agent['configurations']['agent_mode'] in AGENT_MODES: - cls.agent = agent - break - else: - msg = "L3 Agent Scheduler enabled in conf, but L3 Agent not found" - raise exceptions.InvalidConfiguration(msg) - cls.router = cls.create_router() - - @decorators.idempotent_id('b7ce6e89-e837-4ded-9b78-9ed3c9c6a45a') - def test_list_routers_on_l3_agent(self): - self.admin_agents_client.list_routers_on_l3_agent(self.agent['id']) - - @decorators.idempotent_id('9464e5e7-8625-49c3-8fd1-89c52be59d66') - def test_add_list_remove_router_on_l3_agent(self): - l3_agent_ids = list() - self.admin_agents_client.create_router_on_l3_agent( - self.agent['id'], - router_id=self.router['id']) - body = ( - self.admin_routers_client.list_l3_agents_hosting_router( - self.router['id'])) - for agent in body['agents']: - l3_agent_ids.append(agent['id']) - self.assertIn('agent_type', agent) - self.assertEqual('L3 agent', agent['agent_type']) - self.assertIn(self.agent['id'], l3_agent_ids) - body = self.admin_agents_client.delete_router_from_l3_agent( - self.agent['id'], - self.router['id']) - # NOTE(afazekas): The deletion not asserted, because neutron - # is not forbidden to reschedule the router to the same agent diff --git a/tempest/api/network/admin/test_metering_extensions.py b/tempest/api/network/admin/test_metering_extensions.py deleted file mode 100644 index 21a7ab4ea..000000000 --- a/tempest/api/network/admin/test_metering_extensions.py +++ /dev/null @@ -1,168 +0,0 @@ -# Copyright (C) 2014 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class MeteringTestJSON(base.BaseAdminNetworkTest): - """Tests the following operations in the Neutron API: - - List, Show, Create, Delete Metering labels - List, Show, Create, Delete Metering labels rules - """ - - @classmethod - def skip_checks(cls): - super(MeteringTestJSON, cls).skip_checks() - if not test.is_extension_enabled('metering', 'network'): - msg = "metering extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(MeteringTestJSON, cls).resource_setup() - description = "metering label created by tempest" - name = data_utils.rand_name("metering-label") - cls.metering_label = cls.create_metering_label(name, description) - remote_ip_prefix = ("10.0.0.0/24" if cls._ip_version == 4 - else "fd02::/64") - direction = "ingress" - cls.metering_label_rule = cls.create_metering_label_rule( - remote_ip_prefix, direction, - metering_label_id=cls.metering_label['id']) - - @classmethod - def create_metering_label(cls, name, description): - """Wrapper utility that returns a test metering label.""" - body = cls.admin_metering_labels_client.create_metering_label( - description=description, - name=name) - metering_label = body['metering_label'] - cls.metering_labels.append(metering_label) - return metering_label - - @classmethod - def create_metering_label_rule(cls, remote_ip_prefix, direction, - metering_label_id): - """Wrapper utility that returns a test metering label rule.""" - client = cls.admin_metering_label_rules_client - body = client.create_metering_label_rule( - remote_ip_prefix=remote_ip_prefix, direction=direction, - metering_label_id=metering_label_id) - metering_label_rule = body['metering_label_rule'] - cls.metering_label_rules.append(metering_label_rule) - return metering_label_rule - - def _delete_metering_label(self, metering_label_id): - # Deletes a label and verifies if it is deleted or not - self.admin_metering_labels_client.delete_metering_label( - metering_label_id) - # Asserting that the label is not found in list after deletion - labels = self.admin_metering_labels_client.list_metering_labels( - id=metering_label_id) - self.assertEmpty(labels['metering_labels']) - - def _delete_metering_label_rule(self, metering_label_rule_id): - client = self.admin_metering_label_rules_client - # Deletes a rule and verifies if it is deleted or not - client.delete_metering_label_rule(metering_label_rule_id) - # Asserting that the rule is not found in list after deletion - rules = client.list_metering_label_rules(id=metering_label_rule_id) - self.assertEqual(len(rules['metering_label_rules']), 0) - - @decorators.idempotent_id('e2fb2f8c-45bf-429a-9f17-171c70444612') - def test_list_metering_labels(self): - # Verify label filtering - body = self.admin_metering_labels_client.list_metering_labels(id=33) - metering_labels = body['metering_labels'] - self.assertEmpty(metering_labels) - - @decorators.idempotent_id('ec8e15ff-95d0-433b-b8a6-b466bddb1e50') - def test_create_delete_metering_label_with_filters(self): - # Creates a label - name = data_utils.rand_name('metering-label-') - description = "label created by tempest" - body = self.admin_metering_labels_client.create_metering_label( - name=name, description=description) - metering_label = body['metering_label'] - self.addCleanup(self._delete_metering_label, - metering_label['id']) - # Assert whether created labels are found in labels list or fail - # if created labels are not found in labels list - labels = (self.admin_metering_labels_client.list_metering_labels( - id=metering_label['id'])) - self.assertEqual(len(labels['metering_labels']), 1) - - @decorators.idempotent_id('30abb445-0eea-472e-bd02-8649f54a5968') - def test_show_metering_label(self): - # Verifies the details of a label - body = self.admin_metering_labels_client.show_metering_label( - self.metering_label['id']) - metering_label = body['metering_label'] - self.assertEqual(self.metering_label['id'], metering_label['id']) - self.assertEqual(self.metering_label['tenant_id'], - metering_label['tenant_id']) - self.assertEqual(self.metering_label['name'], metering_label['name']) - self.assertEqual(self.metering_label['description'], - metering_label['description']) - - @decorators.idempotent_id('cc832399-6681-493b-9d79-0202831a1281') - def test_list_metering_label_rules(self): - client = self.admin_metering_label_rules_client - # Verify rule filtering - body = client.list_metering_label_rules(id=33) - metering_label_rules = body['metering_label_rules'] - self.assertEmpty(metering_label_rules) - - @decorators.idempotent_id('f4d547cd-3aee-408f-bf36-454f8825e045') - def test_create_delete_metering_label_rule_with_filters(self): - # Creates a rule - remote_ip_prefix = ("10.0.1.0/24" if self._ip_version == 4 - else "fd03::/64") - client = self.admin_metering_label_rules_client - body = (client.create_metering_label_rule( - remote_ip_prefix=remote_ip_prefix, - direction="ingress", - metering_label_id=self.metering_label['id'])) - metering_label_rule = body['metering_label_rule'] - self.addCleanup(self._delete_metering_label_rule, - metering_label_rule['id']) - # Assert whether created rules are found in rules list or fail - # if created rules are not found in rules list - rules = client.list_metering_label_rules(id=metering_label_rule['id']) - self.assertEqual(len(rules['metering_label_rules']), 1) - - @decorators.idempotent_id('b7354489-96ea-41f3-9452-bace120fb4a7') - def test_show_metering_label_rule(self): - # Verifies the details of a rule - client = self.admin_metering_label_rules_client - body = (client.show_metering_label_rule( - self.metering_label_rule['id'])) - metering_label_rule = body['metering_label_rule'] - self.assertEqual(self.metering_label_rule['id'], - metering_label_rule['id']) - self.assertEqual(self.metering_label_rule['remote_ip_prefix'], - metering_label_rule['remote_ip_prefix']) - self.assertEqual(self.metering_label_rule['direction'], - metering_label_rule['direction']) - self.assertEqual(self.metering_label_rule['metering_label_id'], - metering_label_rule['metering_label_id']) - self.assertFalse(metering_label_rule['excluded']) - - -class MeteringIpV6TestJSON(MeteringTestJSON): - _ip_version = 6 diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py deleted file mode 100644 index 21688d242..000000000 --- a/tempest/api/network/admin/test_negative_quotas.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2015 Cloudwatt -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class QuotasNegativeTest(base.BaseAdminNetworkTest): - """Tests the following operations in the Neutron API: - - set network quota and exceed this quota - - v2.0 of the API is assumed. - It is also assumed that the per-project quota extension API is configured - in /etc/neutron/neutron.conf as follows: - - quota_driver = neutron.db.quota_db.DbQuotaDriver - """ - force_tenant_isolation = True - - @classmethod - def skip_checks(cls): - super(QuotasNegativeTest, cls).skip_checks() - if not test.is_extension_enabled('quotas', 'network'): - msg = "quotas extension not enabled." - raise cls.skipException(msg) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('644f4e1b-1bf9-4af0-9fd8-eb56ac0f51cf') - def test_network_quota_exceeding(self): - # Set the network quota to two - self.admin_quotas_client.update_quotas(self.networks_client.tenant_id, - network=2) - self.addCleanup(self.admin_quotas_client.reset_quotas, - self.networks_client.tenant_id) - - # Create two networks - n1 = self.networks_client.create_network() - self.addCleanup(self.networks_client.delete_network, - n1['network']['id']) - n2 = self.networks_client.create_network() - self.addCleanup(self.networks_client.delete_network, - n2['network']['id']) - - # Try to create a third network while the quota is two - with self.assertRaisesRegex( - lib_exc.Conflict, - "Quota exceeded for resources: \['network'\].*"): - n3 = self.networks_client.create_network() - self.addCleanup(self.networks_client.delete_network, - n3['network']['id']) diff --git a/tempest/api/network/admin/test_ports.py b/tempest/api/network/admin/test_ports.py deleted file mode 100644 index 807994b9f..000000000 --- a/tempest/api/network/admin/test_ports.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import socket - -from tempest.api.network import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest): - - @classmethod - def resource_setup(cls): - super(PortsAdminExtendedAttrsTestJSON, cls).resource_setup() - cls.network = cls.create_network() - cls.host_id = socket.gethostname() - - @decorators.idempotent_id('8e8569c1-9ac7-44db-8bc1-f5fb2814f29b') - def test_create_port_binding_ext_attr(self): - post_body = {"network_id": self.network['id'], - "binding:host_id": self.host_id} - body = self.admin_ports_client.create_port(**post_body) - port = body['port'] - self.addCleanup(self.admin_ports_client.delete_port, port['id']) - host_id = port['binding:host_id'] - self.assertIsNotNone(host_id) - self.assertEqual(self.host_id, host_id) - - @decorators.idempotent_id('6f6c412c-711f-444d-8502-0ac30fbf5dd5') - def test_update_port_binding_ext_attr(self): - post_body = {"network_id": self.network['id']} - body = self.admin_ports_client.create_port(**post_body) - port = body['port'] - self.addCleanup(self.admin_ports_client.delete_port, port['id']) - update_body = {"binding:host_id": self.host_id} - body = self.admin_ports_client.update_port(port['id'], **update_body) - updated_port = body['port'] - host_id = updated_port['binding:host_id'] - self.assertIsNotNone(host_id) - self.assertEqual(self.host_id, host_id) - - @decorators.idempotent_id('1c82a44a-6c6e-48ff-89e1-abe7eaf8f9f8') - def test_list_ports_binding_ext_attr(self): - # Create a new port - post_body = {"network_id": self.network['id']} - body = self.admin_ports_client.create_port(**post_body) - port = body['port'] - self.addCleanup(self.admin_ports_client.delete_port, port['id']) - - # Update the port's binding attributes so that is now 'bound' - # to a host - update_body = {"binding:host_id": self.host_id} - self.admin_ports_client.update_port(port['id'], **update_body) - - # List all ports, ensure new port is part of list and its binding - # attributes are set and accurate - body = self.admin_ports_client.list_ports() - ports_list = body['ports'] - pids_list = [p['id'] for p in ports_list] - self.assertIn(port['id'], pids_list) - listed_port = [p for p in ports_list if p['id'] == port['id']] - self.assertEqual(1, len(listed_port), - 'Multiple ports listed with id %s in ports listing: ' - '%s' % (port['id'], ports_list)) - self.assertEqual(self.host_id, listed_port[0]['binding:host_id']) - - @decorators.idempotent_id('b54ac0ff-35fc-4c79-9ca3-c7dbd4ea4f13') - def test_show_port_binding_ext_attr(self): - body = self.admin_ports_client.create_port( - network_id=self.network['id']) - port = body['port'] - self.addCleanup(self.admin_ports_client.delete_port, port['id']) - body = self.admin_ports_client.show_port(port['id']) - show_port = body['port'] - self.assertEqual(port['binding:host_id'], - show_port['binding:host_id']) - self.assertEqual(port['binding:vif_type'], - show_port['binding:vif_type']) - self.assertEqual(port['binding:vif_details'], - show_port['binding:vif_details']) - - -class PortsAdminExtendedAttrsIpV6TestJSON(PortsAdminExtendedAttrsTestJSON): - _ip_version = 6 diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py deleted file mode 100644 index aa8b2dca9..000000000 --- a/tempest/api/network/admin/test_quotas.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest import test - - -class QuotasTest(base.BaseAdminNetworkTest): - """Tests the following operations in the Neutron API: - - list quotas for projects who have non-default quota values - show quotas for a specified project - update quotas for a specified project - reset quotas to default values for a specified project - - v2.0 of the API is assumed. - It is also assumed that the per-project quota extension API is configured - in /etc/neutron/neutron.conf as follows: - - quota_driver = neutron.db.quota_db.DbQuotaDriver - """ - - @classmethod - def skip_checks(cls): - super(QuotasTest, cls).skip_checks() - if not test.is_extension_enabled('quotas', 'network'): - msg = "quotas extension not enabled." - raise cls.skipException(msg) - - def _check_quotas(self, new_quotas): - # Add a project to conduct the test - project = data_utils.rand_name('test_project_') - description = data_utils.rand_name('desc_') - project = self.identity_utils.create_project(name=project, - description=description) - project_id = project['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - - # Change quotas for project - quota_set = self.admin_quotas_client.update_quotas( - project_id, **new_quotas)['quota'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.admin_quotas_client.reset_quotas, project_id) - for key, value in new_quotas.items(): - self.assertEqual(value, quota_set[key]) - - # Confirm our project is listed among projects with non default quotas - non_default_quotas = self.admin_quotas_client.list_quotas() - found = False - for qs in non_default_quotas['quotas']: - if qs['tenant_id'] == project_id: - found = True - self.assertTrue(found) - - # Confirm from API quotas were changed as requested for project - quota_set = self.admin_quotas_client.show_quotas(project_id) - quota_set = quota_set['quota'] - for key, value in new_quotas.items(): - self.assertEqual(value, quota_set[key]) - - # Reset quotas to default and confirm - self.admin_quotas_client.reset_quotas(project_id) - non_default_quotas = self.admin_quotas_client.list_quotas() - for q in non_default_quotas['quotas']: - self.assertNotEqual(project_id, q['tenant_id']) - - @decorators.idempotent_id('2390f766-836d-40ef-9aeb-e810d78207fb') - def test_quotas(self): - new_quotas = {'network': 0, 'port': 0} - self._check_quotas(new_quotas) diff --git a/tempest/api/network/admin/test_routers.py b/tempest/api/network/admin/test_routers.py deleted file mode 100644 index f180cdaea..000000000 --- a/tempest/api/network/admin/test_routers.py +++ /dev/null @@ -1,224 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class RoutersAdminTest(base.BaseAdminNetworkTest): - # NOTE(salv-orlando): This class inherits from BaseAdminNetworkTest - # as some router operations, such as enabling or disabling SNAT - # require admin credentials by default - - def _cleanup_router(self, router): - self.delete_router(router) - self.routers.remove(router) - - def _create_router(self, name=None, admin_state_up=False, - external_network_id=None, enable_snat=None): - # associate a cleanup with created routers to avoid quota limits - router = self.create_router(name, admin_state_up, - external_network_id, enable_snat) - self.addCleanup(self._cleanup_router, router) - return router - - def _add_router_interface_with_subnet_id(self, router_id, subnet_id): - interface = self.routers_client.add_router_interface( - router_id, subnet_id=subnet_id) - self.addCleanup(self._remove_router_interface_with_subnet_id, - router_id, subnet_id) - self.assertEqual(subnet_id, interface['subnet_id']) - return interface - - def _remove_router_interface_with_subnet_id(self, router_id, subnet_id): - body = self.routers_client.remove_router_interface(router_id, - subnet_id=subnet_id) - self.assertEqual(subnet_id, body['subnet_id']) - - @classmethod - def skip_checks(cls): - super(RoutersAdminTest, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - - @decorators.idempotent_id('e54dd3a3-4352-4921-b09d-44369ae17397') - def test_create_router_setting_project_id(self): - # Test creating router from admin user setting project_id. - project = data_utils.rand_name('test_tenant_') - description = data_utils.rand_name('desc_') - project = self.identity_utils.create_project(name=project, - description=description) - project_id = project['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - - name = data_utils.rand_name('router-') - create_body = self.admin_routers_client.create_router( - name=name, tenant_id=project_id) - self.addCleanup(self.admin_routers_client.delete_router, - create_body['router']['id']) - self.assertEqual(project_id, create_body['router']['tenant_id']) - - @decorators.idempotent_id('847257cc-6afd-4154-b8fb-af49f5670ce8') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_create_router_with_default_snat_value(self): - # Create a router with default snat rule - router = self._create_router( - external_network_id=CONF.network.public_network_id) - self._verify_router_gateway( - router['id'], {'network_id': CONF.network.public_network_id, - 'enable_snat': True}) - - @decorators.idempotent_id('ea74068d-09e9-4fd7-8995-9b6a1ace920f') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_create_router_with_snat_explicit(self): - name = data_utils.rand_name('snat-router') - # Create a router enabling snat attributes - enable_snat_states = [False, True] - for enable_snat in enable_snat_states: - external_gateway_info = { - 'network_id': CONF.network.public_network_id, - 'enable_snat': enable_snat} - create_body = self.admin_routers_client.create_router( - name=name, external_gateway_info=external_gateway_info) - self.addCleanup(self.admin_routers_client.delete_router, - create_body['router']['id']) - # Verify snat attributes after router creation - self._verify_router_gateway(create_body['router']['id'], - exp_ext_gw_info=external_gateway_info) - - def _verify_router_gateway(self, router_id, exp_ext_gw_info=None): - show_body = self.admin_routers_client.show_router(router_id) - actual_ext_gw_info = show_body['router']['external_gateway_info'] - if exp_ext_gw_info is None: - self.assertIsNone(actual_ext_gw_info) - return - # Verify only keys passed in exp_ext_gw_info - for k, v in exp_ext_gw_info.items(): - self.assertEqual(v, actual_ext_gw_info[k]) - - def _verify_gateway_port(self, router_id): - list_body = self.admin_ports_client.list_ports( - network_id=CONF.network.public_network_id, - device_id=router_id) - self.assertEqual(len(list_body['ports']), 1) - gw_port = list_body['ports'][0] - fixed_ips = gw_port['fixed_ips'] - self.assertNotEmpty(fixed_ips) - # Assert that all of the IPs from the router gateway port - # are allocated from a valid public subnet. - public_net_body = self.admin_networks_client.show_network( - CONF.network.public_network_id) - public_subnet_ids = public_net_body['network']['subnets'] - for fixed_ip in fixed_ips: - subnet_id = fixed_ip['subnet_id'] - self.assertIn(subnet_id, public_subnet_ids) - - @decorators.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_update_router_set_gateway(self): - router = self._create_router() - self.routers_client.update_router( - router['id'], - external_gateway_info={ - 'network_id': CONF.network.public_network_id}) - # Verify operation - router - self._verify_router_gateway( - router['id'], - {'network_id': CONF.network.public_network_id}) - self._verify_gateway_port(router['id']) - - @decorators.idempotent_id('b386c111-3b21-466d-880c-5e72b01e1a33') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_update_router_set_gateway_with_snat_explicit(self): - router = self._create_router() - self.admin_routers_client.update_router( - router['id'], - external_gateway_info={ - 'network_id': CONF.network.public_network_id, - 'enable_snat': True}) - self._verify_router_gateway( - router['id'], - {'network_id': CONF.network.public_network_id, - 'enable_snat': True}) - self._verify_gateway_port(router['id']) - - @decorators.idempotent_id('96536bc7-8262-4fb2-9967-5c46940fa279') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_update_router_set_gateway_without_snat(self): - router = self._create_router() - self.admin_routers_client.update_router( - router['id'], - external_gateway_info={ - 'network_id': CONF.network.public_network_id, - 'enable_snat': False}) - self._verify_router_gateway( - router['id'], - {'network_id': CONF.network.public_network_id, - 'enable_snat': False}) - self._verify_gateway_port(router['id']) - - @decorators.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_update_router_unset_gateway(self): - router = self._create_router( - external_network_id=CONF.network.public_network_id) - self.routers_client.update_router(router['id'], - external_gateway_info={}) - self._verify_router_gateway(router['id']) - # No gateway port expected - list_body = self.admin_ports_client.list_ports( - network_id=CONF.network.public_network_id, - device_id=router['id']) - self.assertFalse(list_body['ports']) - - @decorators.idempotent_id('f2faf994-97f4-410b-a831-9bc977b64374') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_update_router_reset_gateway_without_snat(self): - router = self._create_router( - external_network_id=CONF.network.public_network_id) - self.admin_routers_client.update_router( - router['id'], - external_gateway_info={ - 'network_id': CONF.network.public_network_id, - 'enable_snat': False}) - self._verify_router_gateway( - router['id'], - {'network_id': CONF.network.public_network_id, - 'enable_snat': False}) - self._verify_gateway_port(router['id']) - - -class RoutersIpV6AdminTest(RoutersAdminTest): - _ip_version = 6 diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py deleted file mode 100644 index f9a0cfb51..000000000 --- a/tempest/api/network/admin/test_routers_dvr.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.network import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class RoutersTestDVR(base.BaseAdminNetworkTest): - - @classmethod - def resource_setup(cls): - for ext in ['router', 'dvr']: - if not test.is_extension_enabled(ext, 'network'): - msg = "%s extension not enabled." % ext - raise cls.skipException(msg) - # The check above will pass if api_extensions=all, which does - # not mean DVR extension itself is present. - # Instead, we have to check whether DVR is actually present by using - # admin credentials to create router with distributed=True attribute - # and checking for BadRequest exception and that the resulting router - # has a distributed attribute. - super(RoutersTestDVR, cls).resource_setup() - name = data_utils.rand_name('pretest-check') - router = cls.admin_routers_client.create_router(name=name) - cls.admin_routers_client.delete_router(router['router']['id']) - if 'distributed' not in router['router']: - msg = "'distributed' flag not found. DVR Possibly not enabled" - raise cls.skipException(msg) - - @decorators.idempotent_id('08a2a0a8-f1e4-4b34-8e30-e522e836c44e') - def test_distributed_router_creation(self): - """Test distributed router creation - - Test uses administrative credentials to creates a - DVR (Distributed Virtual Routing) router using the - distributed=True. - - Acceptance - The router is created and the "distributed" attribute is - set to True - """ - name = data_utils.rand_name('router') - router = self.admin_routers_client.create_router(name=name, - distributed=True) - self.addCleanup(self.admin_routers_client.delete_router, - router['router']['id']) - self.assertTrue(router['router']['distributed']) - - @decorators.idempotent_id('8a0a72b4-7290-4677-afeb-b4ffe37bc352') - def test_centralized_router_creation(self): - """Test centralized router creation - - Test uses administrative credentials to creates a - CVR (Centralized Virtual Routing) router using the - distributed=False. - - Acceptance - The router is created and the "distributed" attribute is - set to False, thus making it a "Centralized Virtual Router" - as opposed to a "Distributed Virtual Router" - """ - name = data_utils.rand_name('router') - router = self.admin_routers_client.create_router(name=name, - distributed=False) - self.addCleanup(self.admin_routers_client.delete_router, - router['router']['id']) - self.assertFalse(router['router']['distributed']) - - @decorators.idempotent_id('acd43596-c1fb-439d-ada8-31ad48ae3c2e') - @testtools.skipUnless(test.is_extension_enabled('l3-ha', 'network'), - 'HA routers are not available.') - def test_centralized_router_update_to_dvr(self): - """Test centralized router update - - Test uses administrative credentials to creates a - CVR (Centralized Virtual Routing) router using the - distributed=False. Then it will "update" the router - distributed attribute to True - - Acceptance - The router is created and the "distributed" attribute is - set to False. Once the router is updated, the distributed - attribute will be set to True - """ - name = data_utils.rand_name('router') - tenant_id = self.routers_client.tenant_id - # router needs to be in admin state down in order to be upgraded to DVR - # l3ha routers are not upgradable to dvr, make it explicitly non ha - router = self.admin_routers_client.create_router(name=name, - distributed=False, - admin_state_up=False, - ha=False, - tenant_id=tenant_id) - router_id = router['router']['id'] - self.addCleanup(self.admin_routers_client.delete_router, - router_id) - self.assertFalse(router['router']['distributed']) - router = self.admin_routers_client.update_router( - router_id, distributed=True) - self.assertTrue(router['router']['distributed']) - show_body = self.admin_routers_client.show_router(router_id) - self.assertTrue(show_body['router']['distributed']) - show_body = self.routers_client.show_router(router_id) - self.assertNotIn('distributed', show_body['router']) diff --git a/tempest/api/network/admin/test_routers_negative.py b/tempest/api/network/admin/test_routers_negative.py deleted file mode 100644 index f350a1571..000000000 --- a/tempest/api/network/admin/test_routers_negative.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.network import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class RoutersAdminNegativeTest(base.BaseAdminNetworkTest): - - @classmethod - def skip_checks(cls): - super(RoutersAdminNegativeTest, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7101cc02-058a-11e7-93e1-fa163e4fa634') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_router_set_gateway_used_ip_returns_409(self): - # At first create a address from public_network_id - port = self.admin_ports_client.create_port( - network_id=CONF.network.public_network_id)['port'] - self.addCleanup(self.admin_ports_client.delete_port, - port_id=port['id']) - # Add used ip and subnet_id in external_fixed_ips - fixed_ip = { - 'subnet_id': port['fixed_ips'][0]['subnet_id'], - 'ip_address': port['fixed_ips'][0]['ip_address'] - } - external_gateway_info = { - 'network_id': CONF.network.public_network_id, - 'external_fixed_ips': [fixed_ip] - } - # Create a router and set gateway to used ip - self.assertRaises(lib_exc.Conflict, - self.admin_routers_client.create_router, - external_gateway_info=external_gateway_info) - - -class RoutersAdminNegativeIpV6Test(RoutersAdminNegativeTest): - _ip_version = 6 diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py deleted file mode 100644 index 6bec0d7e4..000000000 --- a/tempest/api/network/base.py +++ /dev/null @@ -1,272 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr - -from tempest import config -from tempest import exceptions -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -import tempest.test - -CONF = config.CONF - - -class BaseNetworkTest(tempest.test.BaseTestCase): - """Base class for the Neutron tests. - - Per the Neutron API Guide, API v1.x was removed from the source code tree - (docs.openstack.org/api/openstack-network/2.0/content/Overview-d1e71.html) - Therefore, v2.x of the Neutron API is assumed. It is also assumed that the - following options are defined in the [network] section of etc/tempest.conf: - - project_network_cidr with a block of cidr's from which smaller blocks - can be allocated for project networks - - project_network_mask_bits with the mask bits to be used to partition - the block defined by project-network_cidr - - Finally, it is assumed that the following option is defined in the - [service_available] section of etc/tempest.conf - - neutron as True - """ - - force_tenant_isolation = False - credentials = ['primary'] - - # Default to ipv4. - _ip_version = 4 - - @classmethod - def skip_checks(cls): - super(BaseNetworkTest, cls).skip_checks() - if not CONF.service_available.neutron: - raise cls.skipException("Neutron support is required") - if cls._ip_version == 6 and not CONF.network_feature_enabled.ipv6: - raise cls.skipException("IPv6 Tests are disabled.") - - @classmethod - def setup_credentials(cls): - # Create no network resources for these test. - cls.set_network_resources() - super(BaseNetworkTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(BaseNetworkTest, cls).setup_clients() - cls.agents_client = cls.os_primary.network_agents_client - cls.network_extensions_client =\ - cls.os_primary.network_extensions_client - cls.networks_client = cls.os_primary.networks_client - cls.routers_client = cls.os_primary.routers_client - cls.subnetpools_client = cls.os_primary.subnetpools_client - cls.subnets_client = cls.os_primary.subnets_client - cls.ports_client = cls.os_primary.ports_client - cls.quotas_client = cls.os_primary.network_quotas_client - cls.floating_ips_client = cls.os_primary.floating_ips_client - cls.security_groups_client = cls.os_primary.security_groups_client - cls.security_group_rules_client = ( - cls.os_primary.security_group_rules_client) - cls.network_versions_client = cls.os_primary.network_versions_client - cls.service_providers_client = cls.os_primary.service_providers_client - cls.tags_client = cls.os_primary.tags_client - - @classmethod - def resource_setup(cls): - super(BaseNetworkTest, cls).resource_setup() - cls.networks = [] - cls.subnets = [] - cls.ports = [] - cls.routers = [] - cls.floating_ips = [] - cls.metering_labels = [] - cls.metering_label_rules = [] - cls.ethertype = "IPv" + str(cls._ip_version) - - @classmethod - def resource_cleanup(cls): - if CONF.service_available.neutron: - # Clean up floating IPs - for floating_ip in cls.floating_ips: - test_utils.call_and_ignore_notfound_exc( - cls.floating_ips_client.delete_floatingip, - floating_ip['id']) - - # Clean up metering label rules - # Not all classes in the hierarchy have the client class variable - if cls.metering_label_rules: - label_rules_client = cls.admin_metering_label_rules_client - for metering_label_rule in cls.metering_label_rules: - test_utils.call_and_ignore_notfound_exc( - label_rules_client.delete_metering_label_rule, - metering_label_rule['id']) - # Clean up metering labels - for metering_label in cls.metering_labels: - test_utils.call_and_ignore_notfound_exc( - cls.admin_metering_labels_client.delete_metering_label, - metering_label['id']) - # Clean up ports - for port in cls.ports: - test_utils.call_and_ignore_notfound_exc( - cls.ports_client.delete_port, port['id']) - # Clean up routers - for router in cls.routers: - test_utils.call_and_ignore_notfound_exc( - cls.delete_router, router) - # Clean up subnets - for subnet in cls.subnets: - test_utils.call_and_ignore_notfound_exc( - cls.subnets_client.delete_subnet, subnet['id']) - # Clean up networks - for network in cls.networks: - test_utils.call_and_ignore_notfound_exc( - cls.networks_client.delete_network, network['id']) - super(BaseNetworkTest, cls).resource_cleanup() - - @classmethod - def create_network(cls, network_name=None, **kwargs): - """Wrapper utility that returns a test network.""" - network_name = network_name or data_utils.rand_name( - cls.__name__ + '-test-network') - - body = cls.networks_client.create_network(name=network_name, **kwargs) - network = body['network'] - cls.networks.append(network) - return network - - @classmethod - def create_subnet(cls, network, gateway='', cidr=None, mask_bits=None, - ip_version=None, client=None, **kwargs): - """Wrapper utility that returns a test subnet.""" - # allow tests to use admin client - if not client: - client = cls.subnets_client - - # The cidr and mask_bits depend on the ip version. - ip_version = ip_version if ip_version is not None else cls._ip_version - gateway_not_set = gateway == '' - if ip_version == 4: - cidr = cidr or netaddr.IPNetwork(CONF.network.project_network_cidr) - mask_bits = mask_bits or CONF.network.project_network_mask_bits - elif ip_version == 6: - cidr = (cidr or - netaddr.IPNetwork(CONF.network.project_network_v6_cidr)) - mask_bits = mask_bits or CONF.network.project_network_v6_mask_bits - # Find a cidr that is not in use yet and create a subnet with it - for subnet_cidr in cidr.subnet(mask_bits): - if gateway_not_set: - gateway_ip = str(netaddr.IPAddress(subnet_cidr) + 1) - else: - gateway_ip = gateway - try: - body = client.create_subnet( - network_id=network['id'], - cidr=str(subnet_cidr), - ip_version=ip_version, - gateway_ip=gateway_ip, - **kwargs) - break - except lib_exc.BadRequest as e: - is_overlapping_cidr = 'overlaps with another subnet' in str(e) - if not is_overlapping_cidr: - raise - else: - message = 'Available CIDR for subnet creation could not be found' - raise exceptions.BuildErrorException(message) - subnet = body['subnet'] - cls.subnets.append(subnet) - return subnet - - @classmethod - def create_port(cls, network, **kwargs): - """Wrapper utility that returns a test port.""" - body = cls.ports_client.create_port(network_id=network['id'], - **kwargs) - port = body['port'] - cls.ports.append(port) - return port - - @classmethod - def update_port(cls, port, **kwargs): - """Wrapper utility that updates a test port.""" - body = cls.ports_client.update_port(port['id'], - **kwargs) - return body['port'] - - @classmethod - def create_router(cls, router_name=None, admin_state_up=False, - external_network_id=None, enable_snat=None, - **kwargs): - router_name = router_name or data_utils.rand_name( - cls.__name__ + "-router") - - ext_gw_info = {} - if external_network_id: - ext_gw_info['network_id'] = external_network_id - if enable_snat is not None: - ext_gw_info['enable_snat'] = enable_snat - body = cls.routers_client.create_router( - name=router_name, external_gateway_info=ext_gw_info, - admin_state_up=admin_state_up, **kwargs) - router = body['router'] - cls.routers.append(router) - return router - - @classmethod - def create_floatingip(cls, external_network_id): - """Wrapper utility that returns a test floating IP.""" - body = cls.floating_ips_client.create_floatingip( - floating_network_id=external_network_id) - fip = body['floatingip'] - cls.floating_ips.append(fip) - return fip - - @classmethod - def create_router_interface(cls, router_id, subnet_id): - """Wrapper utility that returns a router interface.""" - interface = cls.routers_client.add_router_interface( - router_id, subnet_id=subnet_id) - return interface - - @classmethod - def delete_router(cls, router): - body = cls.ports_client.list_ports(device_id=router['id']) - interfaces = body['ports'] - for i in interfaces: - test_utils.call_and_ignore_notfound_exc( - cls.routers_client.remove_router_interface, router['id'], - subnet_id=i['fixed_ips'][0]['subnet_id']) - cls.routers_client.delete_router(router['id']) - - -class BaseAdminNetworkTest(BaseNetworkTest): - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(BaseAdminNetworkTest, cls).setup_clients() - cls.admin_agents_client = cls.os_admin.network_agents_client - cls.admin_networks_client = cls.os_admin.networks_client - cls.admin_routers_client = cls.os_admin.routers_client - cls.admin_subnets_client = cls.os_admin.subnets_client - cls.admin_ports_client = cls.os_admin.ports_client - cls.admin_quotas_client = cls.os_admin.network_quotas_client - cls.admin_floating_ips_client = cls.os_admin.floating_ips_client - cls.admin_metering_labels_client = cls.os_admin.metering_labels_client - cls.admin_metering_label_rules_client = ( - cls.os_admin.metering_label_rules_client) diff --git a/tempest/api/network/base_security_groups.py b/tempest/api/network/base_security_groups.py deleted file mode 100644 index b8d677a69..000000000 --- a/tempest/api/network/base_security_groups.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest.lib.common.utils import data_utils - - -class BaseSecGroupTest(base.BaseNetworkTest): - - def _create_security_group(self): - # Create a security group - name = data_utils.rand_name('secgroup-') - group_create_body = ( - self.security_groups_client.create_security_group(name=name)) - self.addCleanup(self._delete_security_group, - group_create_body['security_group']['id']) - self.assertEqual(group_create_body['security_group']['name'], name) - return group_create_body, name - - def _delete_security_group(self, secgroup_id): - self.security_groups_client.delete_security_group(secgroup_id) - # Asserting that the security group is not found in the list - # after deletion - list_body = self.security_groups_client.list_security_groups() - secgroup_list = list() - for secgroup in list_body['security_groups']: - secgroup_list.append(secgroup['id']) - self.assertNotIn(secgroup_id, secgroup_list) - - def _delete_security_group_rule(self, rule_id): - self.security_group_rules_client.delete_security_group_rule(rule_id) - # Asserting that the security group is not found in the list - # after deletion - list_body = ( - self.security_group_rules_client.list_security_group_rules()) - rules_list = list() - for rule in list_body['security_group_rules']: - rules_list.append(rule['id']) - self.assertNotIn(rule_id, rules_list) diff --git a/tempest/api/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py deleted file mode 100644 index a90e4bfe4..000000000 --- a/tempest/api/network/test_allowed_address_pair.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr -import six - -from tempest.api.network import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class AllowedAddressPairTestJSON(base.BaseNetworkTest): - """Tests the Neutron Allowed Address Pair API extension - - The following API operations are tested with this extension: - - create port - list ports - update port - show port - - v2.0 of the Neutron API is assumed. It is also assumed that the following - options are defined in the [network-feature-enabled] section of - etc/tempest.conf - - api_extensions - """ - - @classmethod - def skip_checks(cls): - super(AllowedAddressPairTestJSON, cls).skip_checks() - if not test.is_extension_enabled('allowed-address-pairs', 'network'): - msg = "Allowed Address Pairs extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(AllowedAddressPairTestJSON, cls).resource_setup() - cls.network = cls.create_network() - cls.create_subnet(cls.network) - port = cls.create_port(cls.network) - cls.ip_address = port['fixed_ips'][0]['ip_address'] - cls.mac_address = port['mac_address'] - - @decorators.idempotent_id('86c3529b-1231-40de-803c-00e40882f043') - def test_create_list_port_with_address_pair(self): - # Create port with allowed address pair attribute - allowed_address_pairs = [{'ip_address': self.ip_address, - 'mac_address': self.mac_address}] - body = self.ports_client.create_port( - network_id=self.network['id'], - allowed_address_pairs=allowed_address_pairs) - port_id = body['port']['id'] - self.addCleanup(self.ports_client.delete_port, port_id) - - # Confirm port was created with allowed address pair attribute - body = self.ports_client.list_ports() - ports = body['ports'] - port = [p for p in ports if p['id'] == port_id] - msg = 'Created port not found in list of ports returned by Neutron' - self.assertTrue(port, msg) - self._confirm_allowed_address_pair(port[0], self.ip_address) - - def _update_port_with_address(self, address, mac_address=None, **kwargs): - # Create a port without allowed address pair - body = self.ports_client.create_port(network_id=self.network['id']) - port_id = body['port']['id'] - self.addCleanup(self.ports_client.delete_port, port_id) - if mac_address is None: - mac_address = self.mac_address - - # Update allowed address pair attribute of port - allowed_address_pairs = [{'ip_address': address, - 'mac_address': mac_address}] - if kwargs: - allowed_address_pairs.append(kwargs['allowed_address_pairs']) - body = self.ports_client.update_port( - port_id, allowed_address_pairs=allowed_address_pairs) - allowed_address_pair = body['port']['allowed_address_pairs'] - six.assertCountEqual(self, allowed_address_pair, - allowed_address_pairs) - - @decorators.idempotent_id('9599b337-272c-47fd-b3cf-509414414ac4') - def test_update_port_with_address_pair(self): - # Update port with allowed address pair - self._update_port_with_address(self.ip_address) - - @decorators.idempotent_id('4d6d178f-34f6-4bff-a01c-0a2f8fe909e4') - def test_update_port_with_cidr_address_pair(self): - # Update allowed address pair with cidr - cidr = str(netaddr.IPNetwork(CONF.network.project_network_cidr)) - self._update_port_with_address(cidr) - - @decorators.idempotent_id('b3f20091-6cd5-472b-8487-3516137df933') - def test_update_port_with_multiple_ip_mac_address_pair(self): - # Create an ip _address and mac_address through port create - resp = self.ports_client.create_port(network_id=self.network['id']) - newportid = resp['port']['id'] - self.addCleanup(self.ports_client.delete_port, newportid) - ipaddress = resp['port']['fixed_ips'][0]['ip_address'] - macaddress = resp['port']['mac_address'] - - # Update allowed address pair port with multiple ip and mac - allowed_address_pairs = {'ip_address': ipaddress, - 'mac_address': macaddress} - self._update_port_with_address( - self.ip_address, self.mac_address, - allowed_address_pairs=allowed_address_pairs) - - def _confirm_allowed_address_pair(self, port, ip): - msg = 'Port allowed address pairs should not be empty' - self.assertTrue(port['allowed_address_pairs'], msg) - ip_address = port['allowed_address_pairs'][0]['ip_address'] - mac_address = port['allowed_address_pairs'][0]['mac_address'] - self.assertEqual(ip_address, ip) - self.assertEqual(mac_address, self.mac_address) - - -class AllowedAddressPairIpV6TestJSON(AllowedAddressPairTestJSON): - _ip_version = 6 diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py deleted file mode 100644 index 9d6d7008d..000000000 --- a/tempest/api/network/test_dhcp_ipv6.py +++ /dev/null @@ -1,374 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import random - -import netaddr -from oslo_utils import netutils - -from tempest.api.network import base -from tempest.common.utils import net_info -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class NetworksTestDHCPv6(base.BaseNetworkTest): - _ip_version = 6 - - """Test DHCPv6 specific features using SLAAC, stateless and - stateful settings for subnets. Also it shall check dual-stack - functionality (IPv4 + IPv6 together). - The tests include: - generating of SLAAC EUI-64 address in subnets with various settings - receiving SLAAC addresses in combinations of various subnets - receiving stateful IPv6 addresses - addressing in subnets with router - """ - - @classmethod - def skip_checks(cls): - super(NetworksTestDHCPv6, cls).skip_checks() - msg = None - if not CONF.network_feature_enabled.ipv6: - msg = "IPv6 is not enabled" - elif not CONF.network_feature_enabled.ipv6_subnet_attributes: - msg = "DHCPv6 attributes are not enabled." - if msg: - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(NetworksTestDHCPv6, cls).resource_setup() - cls.network = cls.create_network() - - def _remove_from_list_by_index(self, things_list, elem): - for index, i in enumerate(things_list): - if i['id'] == elem['id']: - break - del things_list[index] - - def _clean_network(self): - body = self.ports_client.list_ports() - ports = body['ports'] - for port in ports: - if (net_info.is_router_interface_port(port) and - port['device_id'] in [r['id'] for r in self.routers]): - self.routers_client.remove_router_interface(port['device_id'], - port_id=port['id']) - else: - if port['id'] in [p['id'] for p in self.ports]: - self.ports_client.delete_port(port['id']) - self._remove_from_list_by_index(self.ports, port) - body = self.subnets_client.list_subnets() - subnets = body['subnets'] - for subnet in subnets: - if subnet['id'] in [s['id'] for s in self.subnets]: - self.subnets_client.delete_subnet(subnet['id']) - self._remove_from_list_by_index(self.subnets, subnet) - body = self.routers_client.list_routers() - routers = body['routers'] - for router in routers: - if router['id'] in [r['id'] for r in self.routers]: - self.routers_client.delete_router(router['id']) - self._remove_from_list_by_index(self.routers, router) - - def _get_ips_from_subnet(self, **kwargs): - subnet = self.create_subnet(self.network, **kwargs) - port_mac = data_utils.rand_mac_address() - port = self.create_port(self.network, mac_address=port_mac) - real_ip = next(iter(port['fixed_ips']), None)['ip_address'] - eui_ip = str(netutils.get_ipv6_addr_by_EUI64( - subnet['cidr'], port_mac)) - return real_ip, eui_ip - - @decorators.idempotent_id('e5517e62-6f16-430d-a672-f80875493d4c') - def test_dhcpv6_stateless_eui64(self): - # NOTE: When subnets configured with RAs SLAAC (AOM=100) and DHCP - # stateless (AOM=110) both for radvd and dnsmasq, port shall receive - # IP address calculated from its MAC. - for ra_mode, add_mode in ( - ('slaac', 'slaac'), - ('dhcpv6-stateless', 'dhcpv6-stateless'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - real_ip, eui_ip = self._get_ips_from_subnet(**kwargs) - self._clean_network() - self.assertEqual(eui_ip, real_ip, - ('Real port IP is %s, but shall be %s when ' - 'ipv6_ra_mode=%s and ipv6_address_mode=%s') % ( - real_ip, eui_ip, ra_mode, add_mode)) - - @decorators.idempotent_id('ae2f4a5d-03ff-4c42-a3b0-ce2fcb7ea832') - def test_dhcpv6_stateless_no_ra(self): - # NOTE: When subnets configured with dnsmasq SLAAC and DHCP stateless - # and there is no radvd, port shall receive IP address calculated - # from its MAC and mask of subnet. - for ra_mode, add_mode in ( - (None, 'slaac'), - (None, 'dhcpv6-stateless'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - kwargs = dict((k, v) for k, v in kwargs.items() if v) - real_ip, eui_ip = self._get_ips_from_subnet(**kwargs) - self._clean_network() - self.assertEqual(eui_ip, real_ip, - ('Real port IP %s shall be equal to EUI-64 %s' - 'when ipv6_ra_mode=%s,ipv6_address_mode=%s') % ( - real_ip, eui_ip, - ra_mode if ra_mode else "Off", - add_mode if add_mode else "Off")) - - @decorators.idempotent_id('81f18ef6-95b5-4584-9966-10d480b7496a') - def test_dhcpv6_invalid_options(self): - """Different configurations for radvd and dnsmasq are not allowed""" - for ra_mode, add_mode in ( - ('dhcpv6-stateless', 'dhcpv6-stateful'), - ('dhcpv6-stateless', 'slaac'), - ('slaac', 'dhcpv6-stateful'), - ('dhcpv6-stateful', 'dhcpv6-stateless'), - ('dhcpv6-stateful', 'slaac'), - ('slaac', 'dhcpv6-stateless'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - self.assertRaises(lib_exc.BadRequest, - self.create_subnet, - self.network, - **kwargs) - - @decorators.idempotent_id('21635b6f-165a-4d42-bf49-7d195e47342f') - def test_dhcpv6_stateless_no_ra_no_dhcp(self): - # NOTE: If no radvd option and no dnsmasq option is configured - # port shall receive IP from fixed IPs list of subnet. - real_ip, eui_ip = self._get_ips_from_subnet() - self._clean_network() - self.assertNotEqual(eui_ip, real_ip, - ('Real port IP %s equal to EUI-64 %s when ' - 'ipv6_ra_mode=Off and ipv6_address_mode=Off,' - 'but shall be taken from fixed IPs') % ( - real_ip, eui_ip)) - - @decorators.idempotent_id('4544adf7-bb5f-4bdc-b769-b3e77026cef2') - def test_dhcpv6_two_subnets(self): - # NOTE: When one IPv6 subnet configured with dnsmasq SLAAC or DHCP - # stateless and other IPv6 is with DHCP stateful, port shall receive - # EUI-64 IP addresses from first subnet and DHCP address from second - # one. Order of subnet creating should be unimportant. - for order in ("slaac_first", "dhcp_first"): - for ra_mode, add_mode in ( - ('slaac', 'slaac'), - ('dhcpv6-stateless', 'dhcpv6-stateless'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - kwargs_dhcp = {'ipv6_address_mode': 'dhcpv6-stateful'} - if order == "slaac_first": - subnet_slaac = self.create_subnet(self.network, **kwargs) - subnet_dhcp = self.create_subnet( - self.network, **kwargs_dhcp) - else: - subnet_dhcp = self.create_subnet( - self.network, **kwargs_dhcp) - subnet_slaac = self.create_subnet(self.network, **kwargs) - port_mac = data_utils.rand_mac_address() - eui_ip = str(netutils.get_ipv6_addr_by_EUI64( - subnet_slaac['cidr'], port_mac)) - port = self.create_port(self.network, mac_address=port_mac) - real_ips = dict([(k['subnet_id'], k['ip_address']) - for k in port['fixed_ips']]) - real_dhcp_ip, real_eui_ip = [real_ips[sub['id']] - for sub in [subnet_dhcp, - subnet_slaac]] - self.ports_client.delete_port(port['id']) - self.ports.pop() - body = self.ports_client.list_ports() - ports_id_list = [i['id'] for i in body['ports']] - self.assertNotIn(port['id'], ports_id_list) - self._clean_network() - self.assertEqual(real_eui_ip, - eui_ip, - 'Real IP is {0}, but shall be {1}'.format( - real_eui_ip, - eui_ip)) - msg = ('Real IP address is {0} and it is NOT on ' - 'subnet {1}'.format(real_dhcp_ip, subnet_dhcp['cidr'])) - self.assertIn(netaddr.IPAddress(real_dhcp_ip), - netaddr.IPNetwork(subnet_dhcp['cidr']), msg) - - @decorators.idempotent_id('4256c61d-c538-41ea-9147-3c450c36669e') - def test_dhcpv6_64_subnets(self): - # NOTE: When one IPv6 subnet configured with dnsmasq SLAAC or DHCP - # stateless and other IPv4 is with DHCP of IPv4, port shall receive - # EUI-64 IP addresses from first subnet and IPv4 DHCP address from - # second one. Order of subnet creating should be unimportant. - for order in ("slaac_first", "dhcp_first"): - for ra_mode, add_mode in ( - ('slaac', 'slaac'), - ('dhcpv6-stateless', 'dhcpv6-stateless'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - if order == "slaac_first": - subnet_slaac = self.create_subnet(self.network, **kwargs) - subnet_dhcp = self.create_subnet( - self.network, ip_version=4) - else: - subnet_dhcp = self.create_subnet( - self.network, ip_version=4) - subnet_slaac = self.create_subnet(self.network, **kwargs) - port_mac = data_utils.rand_mac_address() - eui_ip = str(netutils.get_ipv6_addr_by_EUI64( - subnet_slaac['cidr'], port_mac)) - port = self.create_port(self.network, mac_address=port_mac) - real_ips = dict([(k['subnet_id'], k['ip_address']) - for k in port['fixed_ips']]) - real_dhcp_ip, real_eui_ip = [real_ips[sub['id']] - for sub in [subnet_dhcp, - subnet_slaac]] - self._clean_network() - self.assertEqual(real_eui_ip, - eui_ip, - 'Real IP is {0}, but shall be {1}'.format( - real_eui_ip, - eui_ip)) - msg = ('Real IP address is {0} and it is NOT on ' - 'subnet {1}'.format(real_dhcp_ip, subnet_dhcp['cidr'])) - self.assertIn(netaddr.IPAddress(real_dhcp_ip), - netaddr.IPNetwork(subnet_dhcp['cidr']), msg) - - @decorators.idempotent_id('4ab211a0-276f-4552-9070-51e27f58fecf') - def test_dhcp_stateful(self): - # NOTE: With all options below, DHCPv6 shall allocate address from - # subnet pool to port. - for ra_mode, add_mode in ( - ('dhcpv6-stateful', 'dhcpv6-stateful'), - ('dhcpv6-stateful', None), - (None, 'dhcpv6-stateful'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - kwargs = dict((k, v) for k, v in kwargs.items() if v) - subnet = self.create_subnet(self.network, **kwargs) - port = self.create_port(self.network) - port_ip = next(iter(port['fixed_ips']), None)['ip_address'] - self._clean_network() - msg = ('Real IP address is {0} and it is NOT on ' - 'subnet {1}'.format(port_ip, subnet['cidr'])) - self.assertIn(netaddr.IPAddress(port_ip), - netaddr.IPNetwork(subnet['cidr']), msg) - - @decorators.idempotent_id('51a5e97f-f02e-4e4e-9a17-a69811d300e3') - def test_dhcp_stateful_fixedips(self): - # NOTE: With all options below, port shall be able to get - # requested IP from fixed IP range not depending on - # DHCP stateful (not SLAAC!) settings configured. - for ra_mode, add_mode in ( - ('dhcpv6-stateful', 'dhcpv6-stateful'), - ('dhcpv6-stateful', None), - (None, 'dhcpv6-stateful'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - kwargs = dict((k, v) for k, v in kwargs.items() if v) - subnet = self.create_subnet(self.network, **kwargs) - ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"], - subnet["allocation_pools"][0]["end"]) - ip = netaddr.IPAddress(random.randrange(ip_range.first, - ip_range.last)).format() - port = self.create_port(self.network, - fixed_ips=[{'subnet_id': subnet['id'], - 'ip_address': ip}]) - port_ip = next(iter(port['fixed_ips']), None)['ip_address'] - self._clean_network() - self.assertEqual(port_ip, ip, - ("Port IP %s is not as fixed IP from " - "port create request: %s") % ( - port_ip, ip)) - - @decorators.idempotent_id('98244d88-d990-4570-91d4-6b25d70d08af') - def test_dhcp_stateful_fixedips_outrange(self): - # NOTE: When port gets IP address from fixed IP range it - # shall be checked if it's from subnets range. - kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful', - 'ipv6_address_mode': 'dhcpv6-stateful'} - subnet = self.create_subnet(self.network, **kwargs) - ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"], - subnet["allocation_pools"][0]["end"]) - ip = netaddr.IPAddress(random.randrange( - ip_range.last + 1, ip_range.last + 10)).format() - self.assertRaises(lib_exc.BadRequest, - self.create_port, - self.network, - fixed_ips=[{'subnet_id': subnet['id'], - 'ip_address': ip}]) - - @decorators.idempotent_id('57b8302b-cba9-4fbb-8835-9168df029051') - def test_dhcp_stateful_fixedips_duplicate(self): - # NOTE: When port gets IP address from fixed IP range it - # shall be checked if it's not duplicate. - kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful', - 'ipv6_address_mode': 'dhcpv6-stateful'} - subnet = self.create_subnet(self.network, **kwargs) - ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"], - subnet["allocation_pools"][0]["end"]) - ip = netaddr.IPAddress(random.randrange( - ip_range.first, ip_range.last)).format() - self.create_port(self.network, - fixed_ips=[ - {'subnet_id': subnet['id'], - 'ip_address': ip}]) - self.assertRaisesRegex(lib_exc.Conflict, - "IpAddressAlreadyAllocated|IpAddressInUse", - self.create_port, - self.network, - fixed_ips=[{'subnet_id': subnet['id'], - 'ip_address': ip}]) - - def _create_subnet_router(self, kwargs): - subnet = self.create_subnet(self.network, **kwargs) - router = self.create_router(admin_state_up=True) - port = self.create_router_interface(router['id'], - subnet['id']) - body = self.ports_client.show_port(port['port_id']) - return subnet, body['port'] - - @decorators.idempotent_id('e98f65db-68f4-4330-9fea-abd8c5192d4d') - def test_dhcp_stateful_router(self): - # NOTE: With all options below the router interface shall - # receive DHCPv6 IP address from allocation pool. - for ra_mode, add_mode in ( - ('dhcpv6-stateful', 'dhcpv6-stateful'), - ('dhcpv6-stateful', None), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - kwargs = dict((k, v) for k, v in kwargs.items() if v) - subnet, port = self._create_subnet_router(kwargs) - port_ip = next(iter(port['fixed_ips']), None)['ip_address'] - self._clean_network() - self.assertEqual(port_ip, subnet['gateway_ip'], - ("Port IP %s is not as first IP from " - "subnets allocation pool: %s") % ( - port_ip, subnet['gateway_ip'])) - - def tearDown(self): - self._clean_network() - super(NetworksTestDHCPv6, self).tearDown() diff --git a/tempest/api/network/test_extensions.py b/tempest/api/network/test_extensions.py deleted file mode 100644 index 014d06445..000000000 --- a/tempest/api/network/test_extensions.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2013 OpenStack, Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.api.network import base -from tempest.lib import decorators -from tempest import test - - -class ExtensionsTestJSON(base.BaseNetworkTest): - """Tests the following operations in the Neutron API: - - List all available extensions - - v2.0 of the Neutron API is assumed. It is also assumed that api-extensions - option is defined in the [network-feature-enabled] section of - etc/tempest.conf. - """ - - @decorators.attr(type='smoke') - @decorators.idempotent_id('ef28c7e6-e646-4979-9d67-deb207bc5564') - def test_list_show_extensions(self): - # List available extensions for the project - expected_alias = ['security-group', 'l3_agent_scheduler', - 'ext-gw-mode', 'binding', 'quotas', - 'agent', 'dhcp_agent_scheduler', 'provider', - 'router', 'extraroute', 'external-net', - 'allowed-address-pairs', 'extra_dhcp_opt', - 'metering', 'dvr'] - expected_alias = [ext for ext in expected_alias if - test.is_extension_enabled(ext, 'network')] - actual_alias = list() - extensions = self.network_extensions_client.list_extensions() - list_extensions = extensions['extensions'] - # Show and verify the details of the available extensions - for ext in list_extensions: - ext_name = ext['name'] - ext_alias = ext['alias'] - actual_alias.append(ext['alias']) - ext_details = self.network_extensions_client.show_extension( - ext_alias) - ext_details = ext_details['extension'] - - self.assertIsNotNone(ext_details) - self.assertIn('updated', ext_details.keys()) - self.assertIn('name', ext_details.keys()) - self.assertIn('description', ext_details.keys()) - self.assertIn('links', ext_details.keys()) - self.assertIn('alias', ext_details.keys()) - self.assertEqual(ext_details['name'], ext_name) - self.assertEqual(ext_details['alias'], ext_alias) - self.assertEqual(ext_details, ext) - # Verify if expected extensions are present in the actual list - # of extensions returned, but only for those that have been - # enabled via configuration - for e in expected_alias: - if test.is_extension_enabled(e, 'network'): - self.assertIn(e, actual_alias) diff --git a/tempest/api/network/test_extra_dhcp_options.py b/tempest/api/network/test_extra_dhcp_options.py deleted file mode 100644 index dc9042ef1..000000000 --- a/tempest/api/network/test_extra_dhcp_options.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class ExtraDHCPOptionsTestJSON(base.BaseNetworkTest): - """Tests the following operations with the Extra DHCP Options: - - port create - port list - port show - port update - - v2.0 of the Neutron API is assumed. It is also assumed that the Extra - DHCP Options extension is enabled in the [network-feature-enabled] - section of etc/tempest.conf - """ - - @classmethod - def skip_checks(cls): - super(ExtraDHCPOptionsTestJSON, cls).skip_checks() - if not test.is_extension_enabled('extra_dhcp_opt', 'network'): - msg = "Extra DHCP Options extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(ExtraDHCPOptionsTestJSON, cls).resource_setup() - cls.network = cls.create_network() - cls.create_subnet(cls.network) - cls.port = cls.create_port(cls.network) - ip_tftp = ('123.123.123.123' if cls._ip_version == 4 - else '2015::dead') - ip_server = ('123.123.123.45' if cls._ip_version == 4 - else '2015::badd') - cls.extra_dhcp_opts = [ - {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'}, - {'opt_value': ip_tftp, 'opt_name': 'tftp-server'}, - {'opt_value': ip_server, 'opt_name': 'server-ip-address'} - ] - - @decorators.idempotent_id('d2c17063-3767-4a24-be4f-a23dbfa133c9') - def test_create_list_port_with_extra_dhcp_options(self): - # Create a port with Extra DHCP Options - body = self.ports_client.create_port( - network_id=self.network['id'], - extra_dhcp_opts=self.extra_dhcp_opts) - port_id = body['port']['id'] - self.addCleanup(self.ports_client.delete_port, port_id) - - # Confirm port created has Extra DHCP Options - body = self.ports_client.list_ports() - ports = body['ports'] - port = [p for p in ports if p['id'] == port_id] - self.assertTrue(port) - self._confirm_extra_dhcp_options(port[0], self.extra_dhcp_opts) - - @decorators.idempotent_id('9a6aebf4-86ee-4f47-b07a-7f7232c55607') - def test_update_show_port_with_extra_dhcp_options(self): - # Update port with extra dhcp options - name = data_utils.rand_name('new-port-name') - body = self.ports_client.update_port( - self.port['id'], - name=name, - extra_dhcp_opts=self.extra_dhcp_opts) - # Confirm extra dhcp options were added to the port - body = self.ports_client.show_port(self.port['id']) - self._confirm_extra_dhcp_options(body['port'], self.extra_dhcp_opts) - - def _confirm_extra_dhcp_options(self, port, extra_dhcp_opts): - retrieved = port['extra_dhcp_opts'] - self.assertEqual(len(retrieved), len(extra_dhcp_opts)) - for retrieved_option in retrieved: - for option in extra_dhcp_opts: - if (retrieved_option['opt_value'] == option['opt_value'] and - retrieved_option['opt_name'] == option['opt_name']): - break - else: - self.fail('Extra DHCP option not found in port %s' % - str(retrieved_option)) - - -class ExtraDHCPOptionsIpV6TestJSON(ExtraDHCPOptionsTestJSON): - _ip_version = 6 diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py deleted file mode 100644 index c799b15a3..000000000 --- a/tempest/api/network/test_floating_ips.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest.common.utils import net_utils -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class FloatingIPTestJSON(base.BaseNetworkTest): - """Tests the following operations in the Neutron API: - - Create a Floating IP - Update a Floating IP - Delete a Floating IP - List all Floating IPs - Show Floating IP details - Associate a Floating IP with a port and then delete that port - Associate a Floating IP with a port and then with a port on another - router - - v2.0 of the Neutron API is assumed. It is also assumed that the following - options are defined in the [network] section of etc/tempest.conf: - - public_network_id which is the id for the external network present - """ - - @classmethod - def skip_checks(cls): - super(FloatingIPTestJSON, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - if not CONF.network.public_network_id: - msg = "The public_network_id option must be specified." - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def resource_setup(cls): - super(FloatingIPTestJSON, cls).resource_setup() - cls.ext_net_id = CONF.network.public_network_id - - # Create network, subnet, router and add interface - cls.network = cls.create_network() - cls.subnet = cls.create_subnet(cls.network, enable_dhcp=False) - cls.router = cls.create_router(external_network_id=cls.ext_net_id) - cls.create_router_interface(cls.router['id'], cls.subnet['id']) - # Create two ports one each for Creation and Updating of floatingIP - for i in range(2): - cls.create_port(cls.network) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e8718') - def test_create_list_show_update_delete_floating_ip(self): - # Creates a floating IP - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id, - port_id=self.ports[0]['id']) - created_floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - created_floating_ip['id']) - self.assertIsNotNone(created_floating_ip['id']) - self.assertIsNotNone(created_floating_ip['tenant_id']) - self.assertIsNotNone(created_floating_ip['floating_ip_address']) - self.assertEqual(created_floating_ip['port_id'], self.ports[0]['id']) - self.assertEqual(created_floating_ip['floating_network_id'], - self.ext_net_id) - self.assertIn(created_floating_ip['fixed_ip_address'], - [ip['ip_address'] for ip in self.ports[0]['fixed_ips']]) - # Verifies the details of a floating_ip - floating_ip = self.floating_ips_client.show_floatingip( - created_floating_ip['id']) - shown_floating_ip = floating_ip['floatingip'] - self.assertEqual(shown_floating_ip['id'], created_floating_ip['id']) - self.assertEqual(shown_floating_ip['floating_network_id'], - self.ext_net_id) - self.assertEqual(shown_floating_ip['tenant_id'], - created_floating_ip['tenant_id']) - self.assertEqual(shown_floating_ip['floating_ip_address'], - created_floating_ip['floating_ip_address']) - self.assertEqual(shown_floating_ip['port_id'], self.ports[0]['id']) - - # Verify the floating ip exists in the list of all floating_ips - floating_ips = self.floating_ips_client.list_floatingips() - floatingip_id_list = list() - for f in floating_ips['floatingips']: - floatingip_id_list.append(f['id']) - self.assertIn(created_floating_ip['id'], floatingip_id_list) - # Associate floating IP to the other port - floating_ip = self.floating_ips_client.update_floatingip( - created_floating_ip['id'], - port_id=self.ports[1]['id']) - updated_floating_ip = floating_ip['floatingip'] - self.assertEqual(updated_floating_ip['port_id'], self.ports[1]['id']) - self.assertEqual(updated_floating_ip['fixed_ip_address'], - self.ports[1]['fixed_ips'][0]['ip_address']) - self.assertEqual(updated_floating_ip['router_id'], self.router['id']) - - # Disassociate floating IP from the port - floating_ip = self.floating_ips_client.update_floatingip( - created_floating_ip['id'], - port_id=None) - updated_floating_ip = floating_ip['floatingip'] - self.assertIsNone(updated_floating_ip['port_id']) - self.assertIsNone(updated_floating_ip['fixed_ip_address']) - self.assertIsNone(updated_floating_ip['router_id']) - - @decorators.idempotent_id('e1f6bffd-442f-4668-b30e-df13f2705e77') - def test_floating_ip_delete_port(self): - # Create a floating IP - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id) - created_floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - created_floating_ip['id']) - # Create a port - port = self.ports_client.create_port(network_id=self.network['id']) - created_port = port['port'] - floating_ip = self.floating_ips_client.update_floatingip( - created_floating_ip['id'], - port_id=created_port['id']) - # Delete port - self.ports_client.delete_port(created_port['id']) - # Verifies the details of the floating_ip - floating_ip = self.floating_ips_client.show_floatingip( - created_floating_ip['id']) - shown_floating_ip = floating_ip['floatingip'] - # Confirm the fields are back to None - self.assertEqual(shown_floating_ip['id'], created_floating_ip['id']) - self.assertIsNone(shown_floating_ip['port_id']) - self.assertIsNone(shown_floating_ip['fixed_ip_address']) - self.assertIsNone(shown_floating_ip['router_id']) - - @decorators.idempotent_id('1bb2f731-fe5a-4b8c-8409-799ade1bed4d') - def test_floating_ip_update_different_router(self): - # Associate a floating IP to a port on a router - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id, - port_id=self.ports[1]['id']) - created_floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - created_floating_ip['id']) - self.assertEqual(created_floating_ip['router_id'], self.router['id']) - network2 = self.create_network() - subnet2 = self.create_subnet(network2) - router2 = self.create_router(external_network_id=self.ext_net_id) - self.create_router_interface(router2['id'], subnet2['id']) - port_other_router = self.create_port(network2) - # Associate floating IP to the other port on another router - floating_ip = self.floating_ips_client.update_floatingip( - created_floating_ip['id'], - port_id=port_other_router['id']) - updated_floating_ip = floating_ip['floatingip'] - self.assertEqual(updated_floating_ip['router_id'], router2['id']) - self.assertEqual(updated_floating_ip['port_id'], - port_other_router['id']) - self.assertIsNotNone(updated_floating_ip['fixed_ip_address']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('36de4bd0-f09c-43e3-a8e1-1decc1ffd3a5') - def test_create_floating_ip_specifying_a_fixed_ip_address(self): - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id, - port_id=self.ports[1]['id'], - fixed_ip_address=self.ports[1]['fixed_ips'][0]['ip_address']) - created_floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - created_floating_ip['id']) - self.assertIsNotNone(created_floating_ip['id']) - self.assertEqual(created_floating_ip['fixed_ip_address'], - self.ports[1]['fixed_ips'][0]['ip_address']) - floating_ip = self.floating_ips_client.update_floatingip( - created_floating_ip['id'], - port_id=None) - self.assertIsNone(floating_ip['floatingip']['port_id']) - - @decorators.idempotent_id('45c4c683-ea97-41ef-9c51-5e9802f2f3d7') - def test_create_update_floatingip_with_port_multiple_ip_address(self): - # Find out ips that can be used for tests - list_ips = net_utils.get_unused_ip_addresses( - self.ports_client, - self.subnets_client, - self.subnet['network_id'], - self.subnet['id'], - 2) - fixed_ips = [{'ip_address': list_ips[0]}, {'ip_address': list_ips[1]}] - # Create port - body = self.ports_client.create_port(network_id=self.network['id'], - fixed_ips=fixed_ips) - port = body['port'] - self.addCleanup(self.ports_client.delete_port, port['id']) - # Create floating ip - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id, - port_id=port['id'], - fixed_ip_address=list_ips[0]) - floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - floating_ip['id']) - self.assertIsNotNone(floating_ip['id']) - self.assertEqual(floating_ip['fixed_ip_address'], list_ips[0]) - # Update floating ip - body = self.floating_ips_client.update_floatingip( - floating_ip['id'], port_id=port['id'], - fixed_ip_address=list_ips[1]) - update_floating_ip = body['floatingip'] - self.assertEqual(update_floating_ip['fixed_ip_address'], - list_ips[1]) diff --git a/tempest/api/network/test_floating_ips_negative.py b/tempest/api/network/test_floating_ips_negative.py deleted file mode 100644 index 5ca17fec0..000000000 --- a/tempest/api/network/test_floating_ips_negative.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FloatingIPNegativeTestJSON(base.BaseNetworkTest): - """Test the following negative operations for floating ips: - - Create floatingip with a port that is unreachable to external network - Create floatingip in private network - Associate floatingip with port that is unreachable to external network - """ - - @classmethod - def skip_checks(cls): - super(FloatingIPNegativeTestJSON, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - if not CONF.network.public_network_id: - msg = "The public_network_id option must be specified." - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def resource_setup(cls): - super(FloatingIPNegativeTestJSON, cls).resource_setup() - cls.ext_net_id = CONF.network.public_network_id - # Create a network with a subnet connected to a router. - cls.network = cls.create_network() - subnet = cls.create_subnet(cls.network) - router = cls.create_router() - cls.create_router_interface(router['id'], subnet['id']) - cls.port = cls.create_port(cls.network) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('22996ea8-4a81-4b27-b6e1-fa5df92fa5e8') - def test_create_floatingip_with_port_ext_net_unreachable(self): - self.assertRaises( - lib_exc.NotFound, self.floating_ips_client.create_floatingip, - floating_network_id=self.ext_net_id, port_id=self.port['id'], - fixed_ip_address=self.port['fixed_ips'][0] - ['ip_address']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('50b9aeb4-9f0b-48ee-aa31-fa955a48ff54') - def test_create_floatingip_in_private_network(self): - self.assertRaises(lib_exc.BadRequest, - self.floating_ips_client.create_floatingip, - floating_network_id=self.network['id'], - port_id=self.port['id'], - fixed_ip_address=self.port['fixed_ips'][0] - ['ip_address']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6b3b8797-6d43-4191-985c-c48b773eb429') - def test_associate_floatingip_port_ext_net_unreachable(self): - # Create floating ip - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id) - floating_ip = body['floatingip'] - self.addCleanup( - self.floating_ips_client.delete_floatingip, floating_ip['id']) - # Associate floating IP to the other port - self.assertRaises( - lib_exc.NotFound, self.floating_ips_client.update_floatingip, - floating_ip['id'], port_id=self.port['id'], - fixed_ip_address=self.port['fixed_ips'][0]['ip_address']) diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py deleted file mode 100644 index 269f2c2d6..000000000 --- a/tempest/api/network/test_networks.py +++ /dev/null @@ -1,654 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import netaddr -import six -import testtools - -from tempest.api.network import base -from tempest.common import custom_matchers -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class BaseNetworkTestResources(base.BaseNetworkTest): - - @classmethod - def resource_setup(cls): - super(BaseNetworkTestResources, cls).resource_setup() - cls.network = cls.create_network() - cls.subnet = cls._create_subnet_with_last_subnet_block(cls.network, - cls._ip_version) - cls._subnet_data = {6: {'gateway': - str(cls._get_gateway_from_tempest_conf(6)), - 'allocation_pools': - cls._get_allocation_pools_from_gateway(6), - 'dns_nameservers': ['2001:4860:4860::8844', - '2001:4860:4860::8888'], - 'host_routes': [{'destination': '2001::/64', - 'nexthop': '2003::1'}], - 'new_host_routes': [{'destination': - '2001::/64', - 'nexthop': '2005::1'}], - 'new_dns_nameservers': - ['2001:4860:4860::7744', - '2001:4860:4860::7888']}, - 4: {'gateway': - str(cls._get_gateway_from_tempest_conf(4)), - 'allocation_pools': - cls._get_allocation_pools_from_gateway(4), - 'dns_nameservers': ['8.8.4.4', '8.8.8.8'], - 'host_routes': [{'destination': '10.20.0.0/32', - 'nexthop': '10.100.1.1'}], - 'new_host_routes': [{'destination': - '10.20.0.0/32', - 'nexthop': - '10.100.1.2'}], - 'new_dns_nameservers': ['7.8.8.8', '7.8.4.4']}} - - @classmethod - def _create_subnet_with_last_subnet_block(cls, network, ip_version): - # Derive last subnet CIDR block from project CIDR and - # create the subnet with that derived CIDR - if ip_version == 4: - cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - mask_bits = CONF.network.project_network_mask_bits - elif ip_version == 6: - cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - mask_bits = CONF.network.project_network_v6_mask_bits - - subnet_cidr = list(cidr.subnet(mask_bits))[-1] - gateway_ip = str(netaddr.IPAddress(subnet_cidr) + 1) - return cls.create_subnet(network, gateway=gateway_ip, - cidr=subnet_cidr, mask_bits=mask_bits) - - @classmethod - def _get_gateway_from_tempest_conf(cls, ip_version): - """Return first subnet gateway for configured CIDR """ - if ip_version == 4: - cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - mask_bits = CONF.network.project_network_mask_bits - elif ip_version == 6: - cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - mask_bits = CONF.network.project_network_v6_mask_bits - - if mask_bits >= cidr.prefixlen: - return netaddr.IPAddress(cidr) + 1 - else: - for subnet in cidr.subnet(mask_bits): - return netaddr.IPAddress(subnet) + 1 - - @classmethod - def _get_allocation_pools_from_gateway(cls, ip_version): - """Return allocation range for subnet of given gateway""" - gateway = cls._get_gateway_from_tempest_conf(ip_version) - return [{'start': str(gateway + 2), 'end': str(gateway + 6)}] - - def subnet_dict(self, include_keys): - # Return a subnet dict which has include_keys and their corresponding - # value from self._subnet_data - return dict((key, self._subnet_data[self._ip_version][key]) - for key in include_keys) - - def _compare_resource_attrs(self, actual, expected): - exclude_keys = set(actual).symmetric_difference(expected) - self.assertThat(actual, custom_matchers.MatchesDictExceptForKeys( - expected, exclude_keys)) - - def _delete_network(self, network): - # Deleting network also deletes its subnets if exists - self.networks_client.delete_network(network['id']) - if network in self.networks: - self.networks.remove(network) - for subnet in self.subnets: - if subnet['network_id'] == network['id']: - self.subnets.remove(subnet) - - def _create_verify_delete_subnet(self, cidr=None, mask_bits=None, - **kwargs): - network = self.create_network() - net_id = network['id'] - gateway = kwargs.pop('gateway', None) - subnet = self.create_subnet(network, gateway, cidr, mask_bits, - **kwargs) - compare_args_full = dict(gateway_ip=gateway, cidr=cidr, - mask_bits=mask_bits, **kwargs) - compare_args = dict((k, v) for k, v in compare_args_full.items() - if v is not None) - - if 'dns_nameservers' in set(subnet).intersection(compare_args): - self.assertEqual(sorted(compare_args['dns_nameservers']), - sorted(subnet['dns_nameservers'])) - del subnet['dns_nameservers'], compare_args['dns_nameservers'] - - self._compare_resource_attrs(subnet, compare_args) - self.networks_client.delete_network(net_id) - self.networks.pop() - self.subnets.pop() - - -class NetworksTest(BaseNetworkTestResources): - """Tests the following operations in the Neutron API: - - create a network for a project - list project's networks - show a project network details - create a subnet for a project - list project's subnets - show a project subnet details - network update - subnet update - delete a network also deletes its subnets - list external networks - - All subnet tests are run once with ipv4 and once with ipv6. - - v2.0 of the Neutron API is assumed. It is also assumed that the following - options are defined in the [network] section of etc/tempest.conf: - - project_network_cidr with a block of cidr's from which smaller blocks - can be allocated for project ipv4 subnets - - project_network_v6_cidr is the equivalent for ipv6 subnets - - project_network_mask_bits with the mask bits to be used to partition - the block defined by project_network_cidr - - project_network_v6_mask_bits is the equivalent for ipv6 subnets - """ - - @decorators.attr(type='smoke') - @decorators.idempotent_id('0e269138-0da6-4efc-a46d-578161e7b221') - def test_create_update_delete_network_subnet(self): - # Create a network - network = self.create_network() - self.addCleanup(self._delete_network, network) - net_id = network['id'] - self.assertEqual('ACTIVE', network['status']) - # Verify network update - new_name = "New_network" - body = self.networks_client.update_network(net_id, name=new_name) - updated_net = body['network'] - self.assertEqual(updated_net['name'], new_name) - # Find a cidr that is not in use yet and create a subnet with it - subnet = self.create_subnet(network) - subnet_id = subnet['id'] - # Verify subnet update - new_name = "New_subnet" - body = self.subnets_client.update_subnet(subnet_id, name=new_name) - updated_subnet = body['subnet'] - self.assertEqual(updated_subnet['name'], new_name) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2bf13842-c93f-4a69-83ed-717d2ec3b44e') - def test_show_network(self): - # Verify the details of a network - body = self.networks_client.show_network(self.network['id']) - network = body['network'] - for key in ['id', 'name']: - self.assertEqual(network[key], self.network[key]) - - @decorators.idempotent_id('867819bb-c4b6-45f7-acf9-90edcf70aa5e') - def test_show_network_fields(self): - # Verify specific fields of a network - fields = ['id', 'name'] - if test.is_extension_enabled('net-mtu', 'network'): - fields.append('mtu') - body = self.networks_client.show_network(self.network['id'], - fields=fields) - network = body['network'] - self.assertEqual(sorted(network.keys()), sorted(fields)) - for field_name in fields: - self.assertEqual(network[field_name], self.network[field_name]) - self.assertNotIn('tenant_id', network) - self.assertNotIn('project_id', network) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f7ffdeda-e200-4a7a-bcbe-05716e86bf43') - def test_list_networks(self): - # Verify the network exists in the list of all networks - body = self.networks_client.list_networks() - networks = [network['id'] for network in body['networks'] - if network['id'] == self.network['id']] - self.assertNotEmpty(networks, "Created network not found in the list") - - @decorators.idempotent_id('6ae6d24f-9194-4869-9c85-c313cb20e080') - def test_list_networks_fields(self): - # Verify specific fields of the networks - fields = ['id', 'name'] - if test.is_extension_enabled('net-mtu', 'network'): - fields.append('mtu') - body = self.networks_client.list_networks(fields=fields) - networks = body['networks'] - self.assertNotEmpty(networks, "Network list returned is empty") - for network in networks: - self.assertEqual(sorted(network.keys()), sorted(fields)) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('bd635d81-6030-4dd1-b3b9-31ba0cfdf6cc') - def test_show_subnet(self): - # Verify the details of a subnet - body = self.subnets_client.show_subnet(self.subnet['id']) - subnet = body['subnet'] - self.assertNotEmpty(subnet, "Subnet returned has no fields") - for key in ['id', 'cidr']: - self.assertIn(key, subnet) - self.assertEqual(subnet[key], self.subnet[key]) - - @decorators.idempotent_id('270fff0b-8bfc-411f-a184-1e8fd35286f0') - def test_show_subnet_fields(self): - # Verify specific fields of a subnet - fields = ['id', 'network_id'] - body = self.subnets_client.show_subnet(self.subnet['id'], - fields=fields) - subnet = body['subnet'] - self.assertEqual(sorted(subnet.keys()), sorted(fields)) - for field_name in fields: - self.assertEqual(subnet[field_name], self.subnet[field_name]) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('db68ba48-f4ea-49e9-81d1-e367f6d0b20a') - def test_list_subnets(self): - # Verify the subnet exists in the list of all subnets - body = self.subnets_client.list_subnets() - subnets = [subnet['id'] for subnet in body['subnets'] - if subnet['id'] == self.subnet['id']] - self.assertNotEmpty(subnets, "Created subnet not found in the list") - - @decorators.idempotent_id('842589e3-9663-46b0-85e4-7f01273b0412') - def test_list_subnets_fields(self): - # Verify specific fields of subnets - fields = ['id', 'network_id'] - body = self.subnets_client.list_subnets(fields=fields) - subnets = body['subnets'] - self.assertNotEmpty(subnets, "Subnet list returned is empty") - for subnet in subnets: - self.assertEqual(sorted(subnet.keys()), sorted(fields)) - - @decorators.idempotent_id('f04f61a9-b7f3-4194-90b2-9bcf660d1bfe') - def test_delete_network_with_subnet(self): - # Creates a network - network = self.create_network() - net_id = network['id'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self._delete_network, network) - - # Find a cidr that is not in use yet and create a subnet with it - subnet = self.create_subnet(network) - subnet_id = subnet['id'] - - # Delete network while the subnet still exists - self.networks_client.delete_network(net_id) - - # Verify that the subnet got automatically deleted. - self.assertRaises(lib_exc.NotFound, self.subnets_client.show_subnet, - subnet_id) - - @decorators.idempotent_id('d2d596e2-8e76-47a9-ac51-d4648009f4d3') - def test_create_delete_subnet_without_gateway(self): - self._create_verify_delete_subnet() - - @decorators.idempotent_id('9393b468-186d-496d-aa36-732348cd76e7') - def test_create_delete_subnet_with_gw(self): - self._create_verify_delete_subnet( - **self.subnet_dict(['gateway'])) - - @decorators.idempotent_id('bec949c4-3147-4ba6-af5f-cd2306118404') - def test_create_delete_subnet_with_allocation_pools(self): - self._create_verify_delete_subnet( - **self.subnet_dict(['allocation_pools'])) - - @decorators.idempotent_id('8217a149-0c6c-4cfb-93db-0486f707d13f') - def test_create_delete_subnet_with_gw_and_allocation_pools(self): - self._create_verify_delete_subnet(**self.subnet_dict( - ['gateway', 'allocation_pools'])) - - @decorators.idempotent_id('d830de0a-be47-468f-8f02-1fd996118289') - def test_create_delete_subnet_with_host_routes_and_dns_nameservers(self): - self._create_verify_delete_subnet( - **self.subnet_dict(['host_routes', 'dns_nameservers'])) - - @decorators.idempotent_id('94ce038d-ff0a-4a4c-a56b-09da3ca0b55d') - def test_create_delete_subnet_with_dhcp_enabled(self): - self._create_verify_delete_subnet(enable_dhcp=True) - - @decorators.idempotent_id('3d3852eb-3009-49ec-97ac-5ce83b73010a') - def test_update_subnet_gw_dns_host_routes_dhcp(self): - network = self.create_network() - self.addCleanup(self._delete_network, network) - - subnet = self.create_subnet( - network, **self.subnet_dict(['gateway', 'host_routes', - 'dns_nameservers', - 'allocation_pools'])) - subnet_id = subnet['id'] - new_gateway = str(netaddr.IPAddress( - self._subnet_data[self._ip_version]['gateway']) + 1) - # Verify subnet update - new_host_routes = self._subnet_data[self._ip_version][ - 'new_host_routes'] - - new_dns_nameservers = self._subnet_data[self._ip_version][ - 'new_dns_nameservers'] - kwargs = {'host_routes': new_host_routes, - 'dns_nameservers': new_dns_nameservers, - 'gateway_ip': new_gateway, 'enable_dhcp': True} - - new_name = "New_subnet" - body = self.subnets_client.update_subnet(subnet_id, name=new_name, - **kwargs) - updated_subnet = body['subnet'] - kwargs['name'] = new_name - self.assertEqual(sorted(updated_subnet['dns_nameservers']), - sorted(kwargs['dns_nameservers'])) - del subnet['dns_nameservers'], kwargs['dns_nameservers'] - - self._compare_resource_attrs(updated_subnet, kwargs) - - @decorators.idempotent_id('a4d9ec4c-0306-4111-a75c-db01a709030b') - def test_create_delete_subnet_all_attributes(self): - self._create_verify_delete_subnet( - enable_dhcp=True, - **self.subnet_dict(['gateway', 'host_routes', 'dns_nameservers'])) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('af774677-42a9-4e4b-bb58-16fe6a5bc1ec') - @test.requires_ext(extension='external-net', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_external_network_visibility(self): - """Verifies user can see external networks but not subnets.""" - body = self.networks_client.list_networks(**{'router:external': True}) - networks = [network['id'] for network in body['networks']] - self.assertNotEmpty(networks, "No external networks found") - - nonexternal = [net for net in body['networks'] if - not net['router:external']] - self.assertEmpty(nonexternal, "Found non-external networks" - " in filtered list (%s)." % nonexternal) - self.assertIn(CONF.network.public_network_id, networks) - # only check the public network ID because the other networks may - # belong to other tests and their state may have changed during this - # test - body = self.subnets_client.list_subnets( - network_id=CONF.network.public_network_id) - self.assertEmpty(body['subnets'], "Public subnets visible") - - @decorators.idempotent_id('c72c1c0c-2193-4aca-ccc4-b1442640bbbb') - @test.requires_ext(extension="standard-attr-description", - service="network") - def test_create_update_network_description(self): - body = self.create_network(description='d1') - self.assertEqual('d1', body['description']) - net_id = body['id'] - body = self.networks_client.list_networks(id=net_id)['networks'][0] - self.assertEqual('d1', body['description']) - body = self.networks_client.update_network(body['id'], - description='d2') - self.assertEqual('d2', body['network']['description']) - body = self.networks_client.list_networks(id=net_id)['networks'][0] - self.assertEqual('d2', body['description']) - - -class BulkNetworkOpsTest(base.BaseNetworkTest): - """Tests the following operations in the Neutron API: - - bulk network creation - bulk subnet creation - bulk port creation - list project's networks - - v2.0 of the Neutron API is assumed. It is also assumed that the following - options are defined in the [network] section of etc/tempest.conf: - - project_network_cidr with a block of cidr's from which smaller blocks - can be allocated for project networks - - project_network_mask_bits with the mask bits to be used to partition - the block defined by project-network_cidr - """ - - def _delete_networks(self, created_networks): - for n in created_networks: - self.networks_client.delete_network(n['id']) - # Asserting that the networks are not found in the list after deletion - body = self.networks_client.list_networks() - networks_list = [network['id'] for network in body['networks']] - for n in created_networks: - self.assertNotIn(n['id'], networks_list) - - def _delete_subnets(self, created_subnets): - for n in created_subnets: - self.subnets_client.delete_subnet(n['id']) - # Asserting that the subnets are not found in the list after deletion - body = self.subnets_client.list_subnets() - subnets_list = [subnet['id'] for subnet in body['subnets']] - for n in created_subnets: - self.assertNotIn(n['id'], subnets_list) - - def _delete_ports(self, created_ports): - for n in created_ports: - self.ports_client.delete_port(n['id']) - # Asserting that the ports are not found in the list after deletion - body = self.ports_client.list_ports() - ports_list = [port['id'] for port in body['ports']] - for n in created_ports: - self.assertNotIn(n['id'], ports_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('d4f9024d-1e28-4fc1-a6b1-25dbc6fa11e2') - def test_bulk_create_delete_network(self): - # Creates 2 networks in one request - network_list = [{'name': data_utils.rand_name('network-')}, - {'name': data_utils.rand_name('network-')}] - body = self.networks_client.create_bulk_networks(networks=network_list) - created_networks = body['networks'] - self.addCleanup(self._delete_networks, created_networks) - # Asserting that the networks are found in the list after creation - body = self.networks_client.list_networks() - networks_list = [network['id'] for network in body['networks']] - for n in created_networks: - self.assertIsNotNone(n['id']) - self.assertIn(n['id'], networks_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('8936533b-c0aa-4f29-8e53-6cc873aec489') - def test_bulk_create_delete_subnet(self): - networks = [self.create_network(), self.create_network()] - # Creates 2 subnets in one request - if self._ip_version == 4: - cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - mask_bits = CONF.network.project_network_mask_bits - else: - cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - mask_bits = CONF.network.project_network_v6_mask_bits - - cidrs = [subnet_cidr for subnet_cidr in cidr.subnet(mask_bits)] - - names = [data_utils.rand_name('subnet-') for i in range(len(networks))] - subnets_list = [] - for i in range(len(names)): - p1 = { - 'network_id': networks[i]['id'], - 'cidr': str(cidrs[(i)]), - 'name': names[i], - 'ip_version': self._ip_version - } - subnets_list.append(p1) - del subnets_list[1]['name'] - body = self.subnets_client.create_bulk_subnets(subnets=subnets_list) - created_subnets = body['subnets'] - self.addCleanup(self._delete_subnets, created_subnets) - # Asserting that the subnets are found in the list after creation - body = self.subnets_client.list_subnets() - subnets_list = [subnet['id'] for subnet in body['subnets']] - for n in created_subnets: - self.assertIsNotNone(n['id']) - self.assertIn(n['id'], subnets_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('48037ff2-e889-4c3b-b86a-8e3f34d2d060') - def test_bulk_create_delete_port(self): - networks = [self.create_network(), self.create_network()] - # Creates 2 ports in one request - names = [data_utils.rand_name('port-') for i in range(len(networks))] - port_list = [] - state = [True, False] - for i in range(len(names)): - p1 = { - 'network_id': networks[i]['id'], - 'name': names[i], - 'admin_state_up': state[i], - } - port_list.append(p1) - del port_list[1]['name'] - body = self.ports_client.create_bulk_ports(ports=port_list) - created_ports = body['ports'] - self.addCleanup(self._delete_ports, created_ports) - # Asserting that the ports are found in the list after creation - body = self.ports_client.list_ports() - ports_list = [port['id'] for port in body['ports']] - for n in created_ports: - self.assertIsNotNone(n['id']) - self.assertIn(n['id'], ports_list) - - -class BulkNetworkOpsIpV6Test(BulkNetworkOpsTest): - _ip_version = 6 - - -class NetworksIpV6Test(NetworksTest): - _ip_version = 6 - - @decorators.idempotent_id('e41a4888-65a6-418c-a095-f7c2ef4ad59a') - def test_create_delete_subnet_with_gw(self): - net = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - gateway = str(netaddr.IPAddress(net.first + 2)) - network = self.create_network() - subnet = self.create_subnet(network, gateway) - # Verifies Subnet GW in IPv6 - self.assertEqual(subnet['gateway_ip'], gateway) - - @decorators.idempotent_id('ebb4fd95-524f-46af-83c1-0305b239338f') - def test_create_delete_subnet_with_default_gw(self): - net = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - gateway_ip = str(netaddr.IPAddress(net.first + 1)) - network = self.create_network() - subnet = self.create_subnet(network) - # Verifies Subnet GW in IPv6 - self.assertEqual(subnet['gateway_ip'], gateway_ip) - - @decorators.idempotent_id('a9653883-b2a4-469b-8c3c-4518430a7e55') - def test_create_list_subnet_with_no_gw64_one_network(self): - network = self.create_network() - ipv6_gateway = self.subnet_dict(['gateway'])['gateway'] - subnet1 = self.create_subnet(network, - ip_version=6, - gateway=ipv6_gateway) - self.assertEqual(netaddr.IPNetwork(subnet1['cidr']).version, 6, - 'The created subnet is not IPv6') - subnet2 = self.create_subnet(network, - gateway=None, - ip_version=4) - self.assertEqual(netaddr.IPNetwork(subnet2['cidr']).version, 4, - 'The created subnet is not IPv4') - # Verifies Subnet GW is set in IPv6 - self.assertEqual(subnet1['gateway_ip'], ipv6_gateway) - # Verifies Subnet GW is None in IPv4 - self.assertIsNone(subnet2['gateway_ip']) - # Verifies all 2 subnets in the same network - body = self.subnets_client.list_subnets() - subnets = [sub['id'] for sub in body['subnets'] - if sub['network_id'] == network['id']] - test_subnet_ids = [sub['id'] for sub in (subnet1, subnet2)] - six.assertCountEqual(self, subnets, - test_subnet_ids, - 'Subnet are not in the same network') - - -class NetworksIpV6TestAttrs(BaseNetworkTestResources): - - _ip_version = 6 - - @classmethod - def skip_checks(cls): - super(NetworksIpV6TestAttrs, cls).skip_checks() - if not CONF.network_feature_enabled.ipv6_subnet_attributes: - raise cls.skipException("IPv6 extended attributes for " - "subnets not available") - - @decorators.idempotent_id('da40cd1b-a833-4354-9a85-cd9b8a3b74ca') - def test_create_delete_subnet_with_v6_attributes_stateful(self): - self._create_verify_delete_subnet( - gateway=self._subnet_data[self._ip_version]['gateway'], - ipv6_ra_mode='dhcpv6-stateful', - ipv6_address_mode='dhcpv6-stateful') - - @decorators.idempotent_id('176b030f-a923-4040-a755-9dc94329e60c') - def test_create_delete_subnet_with_v6_attributes_slaac(self): - self._create_verify_delete_subnet( - ipv6_ra_mode='slaac', - ipv6_address_mode='slaac') - - @decorators.idempotent_id('7d410310-8c86-4902-adf9-865d08e31adb') - def test_create_delete_subnet_with_v6_attributes_stateless(self): - self._create_verify_delete_subnet( - ipv6_ra_mode='dhcpv6-stateless', - ipv6_address_mode='dhcpv6-stateless') - - def _test_delete_subnet_with_ports(self, mode): - """Create subnet and delete it with existing ports""" - slaac_network = self.create_network() - subnet_slaac = self.create_subnet(slaac_network, - **{'ipv6_ra_mode': mode, - 'ipv6_address_mode': mode}) - port = self.create_port(slaac_network) - self.assertIsNotNone(port['fixed_ips'][0]['ip_address']) - self.subnets_client.delete_subnet(subnet_slaac['id']) - self.subnets.pop() - subnets = self.subnets_client.list_subnets() - subnet_ids = [subnet['id'] for subnet in subnets['subnets']] - self.assertNotIn(subnet_slaac['id'], subnet_ids, - "Subnet wasn't deleted") - self.assertRaisesRegex( - lib_exc.Conflict, - "There are one or more ports still in use on the network", - self.networks_client.delete_network, - slaac_network['id']) - - @decorators.idempotent_id('88554555-ebf8-41ef-9300-4926d45e06e9') - def test_create_delete_slaac_subnet_with_ports(self): - """Test deleting subnet with SLAAC ports - - Create subnet with SLAAC, create ports in network - and then you shall be able to delete subnet without port - deletion. But you still can not delete the network. - """ - self._test_delete_subnet_with_ports("slaac") - - @decorators.idempotent_id('2de6ab5a-fcf0-4144-9813-f91a940291f1') - def test_create_delete_stateless_subnet_with_ports(self): - """Test deleting subnet with DHCPv6 stateless ports - - Create subnet with DHCPv6 stateless, create ports in network - and then you shall be able to delete subnet without port - deletion. But you still can not delete the network. - """ - self._test_delete_subnet_with_ports("dhcpv6-stateless") diff --git a/tempest/api/network/test_networks_negative.py b/tempest/api/network/test_networks_negative.py deleted file mode 100644 index bc4f41f99..000000000 --- a/tempest/api/network/test_networks_negative.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class NetworksNegativeTestJSON(base.BaseNetworkTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9293e937-824d-42d2-8d5b-e985ea67002a') - def test_show_non_existent_network(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.networks_client.show_network, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d746b40c-5e09-4043-99f7-cba1be8b70df') - def test_show_non_existent_subnet(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.subnets_client.show_subnet, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a954861d-cbfd-44e8-b0a9-7fab111f235d') - def test_show_non_existent_port(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.ports_client.show_port, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('98bfe4e3-574e-4012-8b17-b2647063de87') - def test_update_non_existent_network(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises( - lib_exc.NotFound, self.networks_client.update_network, - non_exist_id, name="new_name") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('03795047-4a94-4120-a0a1-bd376e36fd4e') - def test_delete_non_existent_network(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.networks_client.delete_network, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1cc47884-ac52-4415-a31c-e7ce5474a868') - def test_update_non_existent_subnet(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.subnets_client.update_subnet, - non_exist_id, name='new_name') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a176c859-99fb-42ec-a208-8a85b552a239') - def test_delete_non_existent_subnet(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.subnets_client.delete_subnet, non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('13d3b106-47e6-4b9b-8d53-dae947f092fe') - def test_create_port_on_non_existent_network(self): - non_exist_net_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.ports_client.create_port, - network_id=non_exist_net_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('cf8eef21-4351-4f53-adcd-cc5cb1e76b92') - def test_update_non_existent_port(self): - non_exist_port_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.ports_client.update_port, - non_exist_port_id, name='new_name') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('49ec2bbd-ac2e-46fd-8054-798e679ff894') - def test_delete_non_existent_port(self): - non_exist_port_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.ports_client.delete_port, non_exist_port_id) diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py deleted file mode 100644 index f81927d7a..000000000 --- a/tempest/api/network/test_ports.py +++ /dev/null @@ -1,359 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr -import testtools - -from tempest.api.network import base_security_groups as sec_base -from tempest.common import custom_matchers -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest import test - -CONF = config.CONF - - -class PortsTestJSON(sec_base.BaseSecGroupTest): - """Test the following operations for ports: - - port create - port delete - port list - port show - port update - """ - - @classmethod - def resource_setup(cls): - super(PortsTestJSON, cls).resource_setup() - cls.network = cls.create_network() - cls.port = cls.create_port(cls.network) - - def _delete_port(self, port_id): - self.ports_client.delete_port(port_id) - body = self.ports_client.list_ports() - ports_list = body['ports'] - self.assertFalse(port_id in [n['id'] for n in ports_list]) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('c72c1c0c-2193-4aca-aaa4-b1442640f51c') - def test_create_update_delete_port(self): - # Verify port creation - body = self.ports_client.create_port(network_id=self.network['id']) - port = body['port'] - # Schedule port deletion with verification upon test completion - self.addCleanup(self._delete_port, port['id']) - self.assertTrue(port['admin_state_up']) - # Verify port update - new_name = "New_Port" - body = self.ports_client.update_port(port['id'], - name=new_name, - admin_state_up=False) - updated_port = body['port'] - self.assertEqual(updated_port['name'], new_name) - self.assertFalse(updated_port['admin_state_up']) - - @decorators.idempotent_id('67f1b811-f8db-43e2-86bd-72c074d4a42c') - def test_create_bulk_port(self): - network1 = self.network - network2 = self.create_network() - network_list = [network1['id'], network2['id']] - port_list = [{'network_id': net_id} for net_id in network_list] - body = self.ports_client.create_bulk_ports(ports=port_list) - created_ports = body['ports'] - port1 = created_ports[0] - port2 = created_ports[1] - self.addCleanup(self._delete_port, port1['id']) - self.addCleanup(self._delete_port, port2['id']) - self.assertEqual(port1['network_id'], network1['id']) - self.assertEqual(port2['network_id'], network2['id']) - self.assertTrue(port1['admin_state_up']) - self.assertTrue(port2['admin_state_up']) - - @classmethod - def _get_ipaddress_from_tempest_conf(cls): - """Return subnet with mask bits for configured CIDR """ - if cls._ip_version == 4: - cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - cidr.prefixlen = CONF.network.project_network_mask_bits - - elif cls._ip_version == 6: - cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - cidr.prefixlen = CONF.network.project_network_v6_mask_bits - - return cidr - - @decorators.attr(type='smoke') - @decorators.idempotent_id('0435f278-40ae-48cb-a404-b8a087bc09b1') - def test_create_port_in_allowed_allocation_pools(self): - network = self.create_network() - net_id = network['id'] - address = self._get_ipaddress_from_tempest_conf() - if ((address.version == 4 and address.prefixlen >= 30) or - (address.version == 6 and address.prefixlen >= 126)): - msg = ("Subnet %s isn't large enough for the test" % address.cidr) - raise exceptions.InvalidConfiguration(msg) - allocation_pools = {'allocation_pools': [{'start': str(address[2]), - 'end': str(address[-2])}]} - subnet = self.create_subnet(network, cidr=address, - mask_bits=address.prefixlen, - **allocation_pools) - self.addCleanup(self.subnets_client.delete_subnet, subnet['id']) - body = self.ports_client.create_port(network_id=net_id) - self.addCleanup(self.ports_client.delete_port, body['port']['id']) - port = body['port'] - ip_address = port['fixed_ips'][0]['ip_address'] - start_ip_address = allocation_pools['allocation_pools'][0]['start'] - end_ip_address = allocation_pools['allocation_pools'][0]['end'] - ip_range = netaddr.IPRange(start_ip_address, end_ip_address) - self.assertIn(ip_address, ip_range) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('c9a685bd-e83f-499c-939f-9f7863ca259f') - def test_show_port(self): - # Verify the details of port - body = self.ports_client.show_port(self.port['id']) - port = body['port'] - self.assertIn('id', port) - # NOTE(rfolco): created_at and updated_at may get inconsistent values - # due to possible delay between POST request and resource creation. - # TODO(rfolco): Neutron Bug #1365341 is fixed, can remove the key - # extra_dhcp_opts in the O release (K/L gate jobs still need it). - self.assertThat(self.port, - custom_matchers.MatchesDictExceptForKeys - (port, excluded_keys=['extra_dhcp_opts', - 'created_at', - 'updated_at'])) - - @decorators.idempotent_id('45fcdaf2-dab0-4c13-ac6c-fcddfb579dbd') - def test_show_port_fields(self): - # Verify specific fields of a port - fields = ['id', 'mac_address'] - body = self.ports_client.show_port(self.port['id'], - fields=fields) - port = body['port'] - self.assertEqual(sorted(port.keys()), sorted(fields)) - for field_name in fields: - self.assertEqual(port[field_name], self.port[field_name]) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('cf95b358-3e92-4a29-a148-52445e1ac50e') - def test_list_ports(self): - # Verify the port exists in the list of all ports - body = self.ports_client.list_ports() - ports = [port['id'] for port in body['ports'] - if port['id'] == self.port['id']] - self.assertNotEmpty(ports, "Created port not found in the list") - - @decorators.idempotent_id('e7fe260b-1e79-4dd3-86d9-bec6a7959fc5') - def test_port_list_filter_by_ip(self): - # Create network and subnet - network = self.create_network() - subnet = self.create_subnet(network) - self.addCleanup(self.subnets_client.delete_subnet, subnet['id']) - # Create two ports - port_1 = self.ports_client.create_port(network_id=network['id']) - self.addCleanup(self.ports_client.delete_port, port_1['port']['id']) - port_2 = self.ports_client.create_port(network_id=network['id']) - self.addCleanup(self.ports_client.delete_port, port_2['port']['id']) - # List ports filtered by fixed_ips - port_1_fixed_ip = port_1['port']['fixed_ips'][0]['ip_address'] - fixed_ips = 'ip_address=' + port_1_fixed_ip - port_list = self.ports_client.list_ports(fixed_ips=fixed_ips) - # Check that we got the desired port - ports = port_list['ports'] - tenant_ids = set([port['tenant_id'] for port in ports]) - self.assertEqual(len(tenant_ids), 1, - 'Ports from multiple tenants are in the list resp') - port_ids = [port['id'] for port in ports] - fixed_ips = [port['fixed_ips'] for port in ports] - port_ips = [] - for addr in fixed_ips: - port_ips.extend([port['ip_address'] for port in addr]) - - port_net_ids = [port['network_id'] for port in ports] - self.assertIn(port_1['port']['id'], port_ids) - self.assertIn(port_1_fixed_ip, port_ips) - self.assertIn(network['id'], port_net_ids) - - @decorators.idempotent_id('5ad01ed0-0e6e-4c5d-8194-232801b15c72') - def test_port_list_filter_by_router_id(self): - # Create a router - network = self.create_network() - self.addCleanup(self.networks_client.delete_network, network['id']) - subnet = self.create_subnet(network) - self.addCleanup(self.subnets_client.delete_subnet, subnet['id']) - router = self.create_router() - self.addCleanup(self.routers_client.delete_router, router['id']) - port = self.ports_client.create_port(network_id=network['id']) - # Add router interface to port created above - self.routers_client.add_router_interface(router['id'], - port_id=port['port']['id']) - self.addCleanup(self.routers_client.remove_router_interface, - router['id'], port_id=port['port']['id']) - # List ports filtered by router_id - port_list = self.ports_client.list_ports(device_id=router['id']) - ports = port_list['ports'] - self.assertEqual(len(ports), 1) - self.assertEqual(ports[0]['id'], port['port']['id']) - self.assertEqual(ports[0]['device_id'], router['id']) - - @decorators.idempotent_id('ff7f117f-f034-4e0e-abff-ccef05c454b4') - def test_list_ports_fields(self): - # Verify specific fields of ports - fields = ['id', 'mac_address'] - body = self.ports_client.list_ports(fields=fields) - ports = body['ports'] - self.assertNotEmpty(ports, "Port list returned is empty") - # Asserting the fields returned are correct - for port in ports: - self.assertEqual(sorted(fields), sorted(port.keys())) - - @decorators.idempotent_id('63aeadd4-3b49-427f-a3b1-19ca81f06270') - def test_create_update_port_with_second_ip(self): - # Create a network with two subnets - network = self.create_network() - self.addCleanup(self.networks_client.delete_network, network['id']) - subnet_1 = self.create_subnet(network) - self.addCleanup(self.subnets_client.delete_subnet, subnet_1['id']) - subnet_2 = self.create_subnet(network) - self.addCleanup(self.subnets_client.delete_subnet, subnet_2['id']) - fixed_ip_1 = [{'subnet_id': subnet_1['id']}] - fixed_ip_2 = [{'subnet_id': subnet_2['id']}] - - fixed_ips = fixed_ip_1 + fixed_ip_2 - - # Create a port with multiple IP addresses - port = self.create_port(network, - fixed_ips=fixed_ips) - self.addCleanup(self.ports_client.delete_port, port['id']) - self.assertEqual(2, len(port['fixed_ips'])) - check_fixed_ips = [subnet_1['id'], subnet_2['id']] - for item in port['fixed_ips']: - self.assertIn(item['subnet_id'], check_fixed_ips) - - # Update the port to return to a single IP address - port = self.update_port(port, fixed_ips=fixed_ip_1) - self.assertEqual(1, len(port['fixed_ips'])) - - # Update the port with a second IP address from second subnet - port = self.update_port(port, fixed_ips=fixed_ips) - self.assertEqual(2, len(port['fixed_ips'])) - - def _update_port_with_security_groups(self, security_groups_names): - subnet_1 = self.create_subnet(self.network) - self.addCleanup(self.subnets_client.delete_subnet, subnet_1['id']) - fixed_ip_1 = [{'subnet_id': subnet_1['id']}] - - security_groups_list = list() - sec_grps_client = self.security_groups_client - for name in security_groups_names: - group_create_body = sec_grps_client.create_security_group( - name=name) - self.addCleanup(self.security_groups_client.delete_security_group, - group_create_body['security_group']['id']) - security_groups_list.append(group_create_body['security_group'] - ['id']) - # Create a port - sec_grp_name = data_utils.rand_name('secgroup') - security_group = sec_grps_client.create_security_group( - name=sec_grp_name) - self.addCleanup(self.security_groups_client.delete_security_group, - security_group['security_group']['id']) - post_body = { - "name": data_utils.rand_name('port-'), - "security_groups": [security_group['security_group']['id']], - "network_id": self.network['id'], - "admin_state_up": True, - "fixed_ips": fixed_ip_1} - body = self.ports_client.create_port(**post_body) - self.addCleanup(self.ports_client.delete_port, body['port']['id']) - port = body['port'] - - # Update the port with security groups - subnet_2 = self.create_subnet(self.network) - fixed_ip_2 = [{'subnet_id': subnet_2['id']}] - update_body = {"name": data_utils.rand_name('port-'), - "admin_state_up": False, - "fixed_ips": fixed_ip_2, - "security_groups": security_groups_list} - body = self.ports_client.update_port(port['id'], **update_body) - port_show = body['port'] - # Verify the security groups and other attributes updated to port - exclude_keys = set(port_show).symmetric_difference(update_body) - exclude_keys.add('fixed_ips') - exclude_keys.add('security_groups') - self.assertThat(port_show, custom_matchers.MatchesDictExceptForKeys( - update_body, exclude_keys)) - self.assertEqual(fixed_ip_2[0]['subnet_id'], - port_show['fixed_ips'][0]['subnet_id']) - - for security_group in security_groups_list: - self.assertIn(security_group, port_show['security_groups']) - - @decorators.idempotent_id('58091b66-4ff4-4cc1-a549-05d60c7acd1a') - @testtools.skipUnless( - test.is_extension_enabled('security-group', 'network'), - 'security-group extension not enabled.') - def test_update_port_with_security_group_and_extra_attributes(self): - self._update_port_with_security_groups( - [data_utils.rand_name('secgroup')]) - - @decorators.idempotent_id('edf6766d-3d40-4621-bc6e-2521a44c257d') - @testtools.skipUnless( - test.is_extension_enabled('security-group', 'network'), - 'security-group extension not enabled.') - def test_update_port_with_two_security_groups_and_extra_attributes(self): - self._update_port_with_security_groups( - [data_utils.rand_name('secgroup'), - data_utils.rand_name('secgroup')]) - - @decorators.idempotent_id('13e95171-6cbd-489c-9d7c-3f9c58215c18') - def test_create_show_delete_port_user_defined_mac(self): - # Create a port for a legal mac - body = self.ports_client.create_port(network_id=self.network['id']) - old_port = body['port'] - free_mac_address = old_port['mac_address'] - self.ports_client.delete_port(old_port['id']) - # Create a new port with user defined mac - body = self.ports_client.create_port(network_id=self.network['id'], - mac_address=free_mac_address) - self.addCleanup(self.ports_client.delete_port, body['port']['id']) - port = body['port'] - body = self.ports_client.show_port(port['id']) - show_port = body['port'] - self.assertEqual(free_mac_address, - show_port['mac_address']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('4179dcb9-1382-4ced-84fe-1b91c54f5735') - @testtools.skipUnless( - test.is_extension_enabled('security-group', 'network'), - 'security-group extension not enabled.') - def test_create_port_with_no_securitygroups(self): - network = self.create_network() - self.addCleanup(self.networks_client.delete_network, network['id']) - subnet = self.create_subnet(network) - self.addCleanup(self.subnets_client.delete_subnet, subnet['id']) - port = self.create_port(network, security_groups=[]) - self.addCleanup(self.ports_client.delete_port, port['id']) - self.assertIsNotNone(port['security_groups']) - self.assertEmpty(port['security_groups']) - - -class PortsIpV6TestJSON(PortsTestJSON): - _ip_version = 6 diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py deleted file mode 100644 index 128544b1b..000000000 --- a/tempest/api/network/test_routers.py +++ /dev/null @@ -1,319 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr -import testtools - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class RoutersTest(base.BaseNetworkTest): - - def _cleanup_router(self, router): - self.delete_router(router) - self.routers.remove(router) - - def _create_router(self, name=None, admin_state_up=False, - external_network_id=None, enable_snat=None): - # associate a cleanup with created routers to avoid quota limits - router = self.create_router(name, admin_state_up, - external_network_id, enable_snat) - self.addCleanup(self._cleanup_router, router) - return router - - def _add_router_interface_with_subnet_id(self, router_id, subnet_id): - interface = self.routers_client.add_router_interface( - router_id, subnet_id=subnet_id) - self.addCleanup(self._remove_router_interface_with_subnet_id, - router_id, subnet_id) - self.assertEqual(subnet_id, interface['subnet_id']) - return interface - - def _remove_router_interface_with_subnet_id(self, router_id, subnet_id): - body = self.routers_client.remove_router_interface(router_id, - subnet_id=subnet_id) - self.assertEqual(subnet_id, body['subnet_id']) - - @classmethod - def skip_checks(cls): - super(RoutersTest, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(RoutersTest, cls).resource_setup() - cls.tenant_cidr = (CONF.network.project_network_cidr - if cls._ip_version == 4 else - CONF.network.project_network_v6_cidr) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f64403e2-8483-4b34-8ccd-b09a87bcc68c') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_create_show_list_update_delete_router(self): - # Create a router - router = self._create_router( - admin_state_up=False, - external_network_id=CONF.network.public_network_id) - self.assertEqual(router['admin_state_up'], False) - self.assertEqual( - router['external_gateway_info']['network_id'], - CONF.network.public_network_id) - # Show details of the created router - router_show = self.routers_client.show_router( - router['id'])['router'] - self.assertEqual(router_show['name'], router['name']) - self.assertEqual( - router_show['external_gateway_info']['network_id'], - CONF.network.public_network_id) - # List routers and verify if created router is there in response - routers = self.routers_client.list_routers()['routers'] - self.assertIn(router['id'], map(lambda x: x['id'], routers)) - # Update the name of router and verify if it is updated - updated_name = 'updated' + router['name'] - router_update = self.routers_client.update_router( - router['id'], name=updated_name)['router'] - self.assertEqual(router_update['name'], updated_name) - router_show = self.routers_client.show_router( - router['id'])['router'] - self.assertEqual(router_show['name'], updated_name) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('b42e6e39-2e37-49cc-a6f4-8467e940900a') - def test_add_remove_router_interface_with_subnet_id(self): - network = self.create_network() - subnet = self.create_subnet(network) - router = self._create_router() - # Add router interface with subnet id - interface = self.routers_client.add_router_interface( - router['id'], subnet_id=subnet['id']) - self.addCleanup(self._remove_router_interface_with_subnet_id, - router['id'], subnet['id']) - self.assertIn('subnet_id', interface.keys()) - self.assertIn('port_id', interface.keys()) - # Verify router id is equal to device id in port details - show_port_body = self.ports_client.show_port( - interface['port_id']) - self.assertEqual(show_port_body['port']['device_id'], - router['id']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2b7d2f37-6748-4d78-92e5-1d590234f0d5') - def test_add_remove_router_interface_with_port_id(self): - network = self.create_network() - self.create_subnet(network) - router = self._create_router() - port_body = self.ports_client.create_port( - network_id=network['id']) - # add router interface to port created above - interface = self.routers_client.add_router_interface( - router['id'], - port_id=port_body['port']['id']) - self.addCleanup(self.routers_client.remove_router_interface, - router['id'], port_id=port_body['port']['id']) - self.assertIn('subnet_id', interface.keys()) - self.assertIn('port_id', interface.keys()) - # Verify router id is equal to device id in port details - show_port_body = self.ports_client.show_port( - interface['port_id']) - self.assertEqual(show_port_body['port']['device_id'], - router['id']) - - def _verify_router_gateway(self, router_id, exp_ext_gw_info=None): - show_body = self.admin_routers_client.show_router(router_id) - actual_ext_gw_info = show_body['router']['external_gateway_info'] - if exp_ext_gw_info is None: - self.assertIsNone(actual_ext_gw_info) - return - # Verify only keys passed in exp_ext_gw_info - for k, v in exp_ext_gw_info.items(): - self.assertEqual(v, actual_ext_gw_info[k]) - - def _verify_gateway_port(self, router_id): - list_body = self.admin_ports_client.list_ports( - network_id=CONF.network.public_network_id, - device_id=router_id) - self.assertEqual(len(list_body['ports']), 1) - gw_port = list_body['ports'][0] - fixed_ips = gw_port['fixed_ips'] - self.assertNotEmpty(fixed_ips) - # Assert that all of the IPs from the router gateway port - # are allocated from a valid public subnet. - public_net_body = self.admin_networks_client.show_network( - CONF.network.public_network_id) - public_subnet_ids = public_net_body['network']['subnets'] - for fixed_ip in fixed_ips: - subnet_id = fixed_ip['subnet_id'] - self.assertIn(subnet_id, public_subnet_ids) - - @decorators.idempotent_id('cbe42f84-04c2-11e7-8adb-fa163e4fa634') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @decorators.skip_because(bug='1676207') - def test_create_router_set_gateway_with_fixed_ip(self): - # Don't know public_network_address, so at first create address - # from public_network and delete - port = self.admin_ports_client.create_port( - network_id=CONF.network.public_network_id)['port'] - self.admin_ports_client.delete_port(port_id=port['id']) - - fixed_ip = { - 'subnet_id': port['fixed_ips'][0]['subnet_id'], - 'ip_address': port['fixed_ips'][0]['ip_address'] - } - external_gateway_info = { - 'network_id': CONF.network.public_network_id, - 'external_fixed_ips': [fixed_ip] - } - - # Create a router and set gateway to fixed_ip - router = self.admin_routers_client.create_router( - external_gateway_info=external_gateway_info)['router'] - self.addCleanup(self.admin_routers_client.delete_router, - router_id=router['id']) - # Examine router's gateway is equal to fixed_ip - self.assertEqual(router['external_gateway_info'][ - 'external_fixed_ips'][0]['ip_address'], - fixed_ip['ip_address']) - - @decorators.idempotent_id('c86ac3a8-50bd-4b00-a6b8-62af84a0765c') - @test.requires_ext(extension='extraroute', service='network') - def test_update_delete_extra_route(self): - # Create different cidr for each subnet to avoid cidr duplicate - # The cidr starts from project_cidr - next_cidr = netaddr.IPNetwork(self.tenant_cidr) - # Prepare to build several routes - test_routes = [] - routes_num = 4 - # Create a router - router = self._create_router(admin_state_up=True) - self.addCleanup( - self._delete_extra_routes, - router['id']) - # Update router extra route, second ip of the range is - # used as next hop - for i in range(routes_num): - network = self.create_network() - subnet = self.create_subnet(network, cidr=next_cidr) - next_cidr = next_cidr.next() - - # Add router interface with subnet id - self.create_router_interface(router['id'], subnet['id']) - - cidr = netaddr.IPNetwork(subnet['cidr']) - next_hop = str(cidr[2]) - destination = str(subnet['cidr']) - test_routes.append( - {'nexthop': next_hop, 'destination': destination} - ) - - test_routes.sort(key=lambda x: x['destination']) - extra_route = self.routers_client.update_router( - router['id'], routes=test_routes) - show_body = self.routers_client.show_router(router['id']) - # Assert the number of routes - self.assertEqual(routes_num, len(extra_route['router']['routes'])) - self.assertEqual(routes_num, len(show_body['router']['routes'])) - - routes = extra_route['router']['routes'] - routes.sort(key=lambda x: x['destination']) - # Assert the nexthops & destination - for i in range(routes_num): - self.assertEqual(test_routes[i]['destination'], - routes[i]['destination']) - self.assertEqual(test_routes[i]['nexthop'], routes[i]['nexthop']) - - routes = show_body['router']['routes'] - routes.sort(key=lambda x: x['destination']) - for i in range(routes_num): - self.assertEqual(test_routes[i]['destination'], - routes[i]['destination']) - self.assertEqual(test_routes[i]['nexthop'], routes[i]['nexthop']) - - self._delete_extra_routes(router['id']) - show_body_after_deletion = self.routers_client.show_router( - router['id']) - self.assertEmpty(show_body_after_deletion['router']['routes']) - - def _delete_extra_routes(self, router_id): - self.routers_client.update_router(router_id, routes=None) - - @decorators.idempotent_id('a8902683-c788-4246-95c7-ad9c6d63a4d9') - def test_update_router_admin_state(self): - router = self._create_router() - self.assertFalse(router['admin_state_up']) - # Update router admin state - update_body = self.routers_client.update_router(router['id'], - admin_state_up=True) - self.assertTrue(update_body['router']['admin_state_up']) - show_body = self.routers_client.show_router(router['id']) - self.assertTrue(show_body['router']['admin_state_up']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('802c73c9-c937-4cef-824b-2191e24a6aab') - def test_add_multiple_router_interfaces(self): - network01 = self.create_network( - network_name=data_utils.rand_name('router-network01-')) - network02 = self.create_network( - network_name=data_utils.rand_name('router-network02-')) - subnet01 = self.create_subnet(network01) - sub02_cidr = netaddr.IPNetwork(self.tenant_cidr).next() - subnet02 = self.create_subnet(network02, cidr=sub02_cidr) - router = self._create_router() - interface01 = self._add_router_interface_with_subnet_id(router['id'], - subnet01['id']) - self._verify_router_interface(router['id'], subnet01['id'], - interface01['port_id']) - interface02 = self._add_router_interface_with_subnet_id(router['id'], - subnet02['id']) - self._verify_router_interface(router['id'], subnet02['id'], - interface02['port_id']) - - @decorators.idempotent_id('96522edf-b4b5-45d9-8443-fa11c26e6eff') - def test_router_interface_port_update_with_fixed_ip(self): - network = self.create_network() - subnet = self.create_subnet(network) - router = self._create_router() - fixed_ip = [{'subnet_id': subnet['id']}] - interface = self._add_router_interface_with_subnet_id(router['id'], - subnet['id']) - self.assertIn('port_id', interface) - self.assertIn('subnet_id', interface) - port = self.ports_client.show_port(interface['port_id']) - self.assertEqual(port['port']['id'], interface['port_id']) - router_port = self.ports_client.update_port(port['port']['id'], - fixed_ips=fixed_ip) - self.assertEqual(subnet['id'], - router_port['port']['fixed_ips'][0]['subnet_id']) - - def _verify_router_interface(self, router_id, subnet_id, port_id): - show_port_body = self.ports_client.show_port(port_id) - interface_port = show_port_body['port'] - self.assertEqual(router_id, interface_port['device_id']) - self.assertEqual(subnet_id, - interface_port['fixed_ips'][0]['subnet_id']) - - -class RoutersIpV6Test(RoutersTest): - _ip_version = 6 diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py deleted file mode 100644 index 72face872..000000000 --- a/tempest/api/network/test_routers_negative.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class RoutersNegativeTest(base.BaseNetworkTest): - - @classmethod - def skip_checks(cls): - super(RoutersNegativeTest, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(RoutersNegativeTest, cls).resource_setup() - cls.router = cls.create_router() - cls.network = cls.create_network() - cls.subnet = cls.create_subnet(cls.network) - cls.tenant_cidr = (CONF.network.project_network_cidr - if cls._ip_version == 4 else - CONF.network.project_network_v6_cidr) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('37a94fc0-a834-45b9-bd23-9a81d2fd1e22') - def test_router_add_gateway_invalid_network_returns_404(self): - self.assertRaises(lib_exc.NotFound, - self.routers_client.update_router, - self.router['id'], - external_gateway_info={ - 'network_id': self.router['id']}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('11836a18-0b15-4327-a50b-f0d9dc66bddd') - def test_router_add_gateway_net_not_external_returns_400(self): - alt_network = self.create_network() - sub_cidr = netaddr.IPNetwork(self.tenant_cidr).next() - self.create_subnet(alt_network, cidr=sub_cidr) - self.assertRaises(lib_exc.BadRequest, - self.routers_client.update_router, - self.router['id'], - external_gateway_info={ - 'network_id': alt_network['id']}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('957751a3-3c68-4fa2-93b6-eb52ea10db6e') - def test_add_router_interfaces_on_overlapping_subnets_returns_400(self): - network01 = self.create_network( - network_name=data_utils.rand_name('router-network01-')) - network02 = self.create_network( - network_name=data_utils.rand_name('router-network02-')) - subnet01 = self.create_subnet(network01) - subnet02 = self.create_subnet(network02) - interface = self.routers_client.add_router_interface( - self.router['id'], subnet_id=subnet01['id']) - self.addCleanup(self.routers_client.remove_router_interface, - self.router['id'], subnet_id=subnet01['id']) - self.assertEqual(subnet01['id'], interface['subnet_id']) - self.assertRaises(lib_exc.BadRequest, - self.routers_client.add_router_interface, - self.router['id'], - subnet_id=subnet02['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('04df80f9-224d-47f5-837a-bf23e33d1c20') - def test_router_remove_interface_in_use_returns_409(self): - self.routers_client.add_router_interface(self.router['id'], - subnet_id=self.subnet['id']) - self.assertRaises(lib_exc.Conflict, - self.routers_client.delete_router, - self.router['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c2a70d72-8826-43a7-8208-0209e6360c47') - def test_show_non_existent_router_returns_404(self): - router = data_utils.rand_name('non_exist_router') - self.assertRaises(lib_exc.NotFound, self.routers_client.show_router, - router) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b23d1569-8b0c-4169-8d4b-6abd34fad5c7') - def test_update_non_existent_router_returns_404(self): - router = data_utils.rand_name('non_exist_router') - self.assertRaises(lib_exc.NotFound, self.routers_client.update_router, - router, name="new_name") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c7edc5ad-d09d-41e6-a344-5c0c31e2e3e4') - def test_delete_non_existent_router_returns_404(self): - router = data_utils.rand_name('non_exist_router') - self.assertRaises(lib_exc.NotFound, self.routers_client.delete_router, - router) - - -class RoutersNegativeIpV6Test(RoutersNegativeTest): - _ip_version = 6 - - -class DvrRoutersNegativeTest(base.BaseNetworkTest): - - @classmethod - def skip_checks(cls): - super(DvrRoutersNegativeTest, cls).skip_checks() - if not test.is_extension_enabled('dvr', 'network'): - msg = "DVR extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(DvrRoutersNegativeTest, cls).resource_setup() - cls.router = cls.create_router() - cls.network = cls.create_network() - cls.subnet = cls.create_subnet(cls.network) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4990b055-8fc7-48ab-bba7-aa28beaad0b9') - def test_router_create_tenant_distributed_returns_forbidden(self): - self.assertRaises(lib_exc.Forbidden, self.create_router, - distributed=True) diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py deleted file mode 100644 index a1218644d..000000000 --- a/tempest/api/network/test_security_groups.py +++ /dev/null @@ -1,241 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base_security_groups as base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class SecGroupTest(base.BaseSecGroupTest): - _project_network_cidr = CONF.network.project_network_cidr - - @classmethod - def skip_checks(cls): - super(SecGroupTest, cls).skip_checks() - if not test.is_extension_enabled('security-group', 'network'): - msg = "security-group extension not enabled." - raise cls.skipException(msg) - - def _create_verify_security_group_rule(self, sg_id, direction, - ethertype, protocol, - port_range_min, - port_range_max, - remote_group_id=None, - remote_ip_prefix=None): - # Create Security Group rule with the input params and validate - # that SG rule is created with the same parameters. - sec_group_rules_client = self.security_group_rules_client - rule_create_body = sec_group_rules_client.create_security_group_rule( - security_group_id=sg_id, - direction=direction, - ethertype=ethertype, - protocol=protocol, - port_range_min=port_range_min, - port_range_max=port_range_max, - remote_group_id=remote_group_id, - remote_ip_prefix=remote_ip_prefix - ) - - sec_group_rule = rule_create_body['security_group_rule'] - self.addCleanup(self._delete_security_group_rule, - sec_group_rule['id']) - - expected = {'direction': direction, 'protocol': protocol, - 'ethertype': ethertype, 'port_range_min': port_range_min, - 'port_range_max': port_range_max, - 'remote_group_id': remote_group_id, - 'remote_ip_prefix': remote_ip_prefix} - for key, value in expected.items(): - self.assertEqual(value, sec_group_rule[key], - "Field %s of the created security group " - "rule does not match with %s." % - (key, value)) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('e30abd17-fef9-4739-8617-dc26da88e686') - def test_list_security_groups(self): - # Verify the security group belonging to project exist in list - body = self.security_groups_client.list_security_groups() - security_groups = body['security_groups'] - found = None - for n in security_groups: - if (n['name'] == 'default'): - found = n['id'] - msg = "Security-group list doesn't contain default security-group" - self.assertIsNotNone(found, msg) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('bfd128e5-3c92-44b6-9d66-7fe29d22c802') - def test_create_list_update_show_delete_security_group(self): - group_create_body, _ = self._create_security_group() - - # List security groups and verify if created group is there in response - list_body = self.security_groups_client.list_security_groups() - secgroup_list = list() - for secgroup in list_body['security_groups']: - secgroup_list.append(secgroup['id']) - self.assertIn(group_create_body['security_group']['id'], secgroup_list) - # Update the security group - new_name = data_utils.rand_name('security-') - new_description = data_utils.rand_name('security-description') - update_body = self.security_groups_client.update_security_group( - group_create_body['security_group']['id'], - name=new_name, - description=new_description) - # Verify if security group is updated - self.assertEqual(update_body['security_group']['name'], new_name) - self.assertEqual(update_body['security_group']['description'], - new_description) - # Show details of the updated security group - show_body = self.security_groups_client.show_security_group( - group_create_body['security_group']['id']) - self.assertEqual(show_body['security_group']['name'], new_name) - self.assertEqual(show_body['security_group']['description'], - new_description) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('cfb99e0e-7410-4a3d-8a0c-959a63ee77e9') - def test_create_show_delete_security_group_rule(self): - group_create_body, _ = self._create_security_group() - - # Create rules for each protocol - protocols = ['tcp', 'udp', 'icmp'] - client = self.security_group_rules_client - for protocol in protocols: - rule_create_body = client.create_security_group_rule( - security_group_id=group_create_body['security_group']['id'], - protocol=protocol, - direction='ingress', - ethertype=self.ethertype - ) - - # Show details of the created security rule - show_rule_body = client.show_security_group_rule( - rule_create_body['security_group_rule']['id'] - ) - create_dict = rule_create_body['security_group_rule'] - for key, value in create_dict.items(): - self.assertEqual(value, - show_rule_body['security_group_rule'][key], - "%s does not match." % key) - - # List rules and verify created rule is in response - rule_list_body = ( - self.security_group_rules_client.list_security_group_rules()) - rule_list = [rule['id'] - for rule in rule_list_body['security_group_rules']] - self.assertIn(rule_create_body['security_group_rule']['id'], - rule_list) - - @decorators.idempotent_id('87dfbcf9-1849-43ea-b1e4-efa3eeae9f71') - def test_create_security_group_rule_with_additional_args(self): - """Verify security group rule with additional arguments works. - - direction:ingress, ethertype:[IPv4/IPv6], - protocol:tcp, port_range_min:77, port_range_max:77 - """ - group_create_body, _ = self._create_security_group() - sg_id = group_create_body['security_group']['id'] - direction = 'ingress' - protocol = 'tcp' - port_range_min = 77 - port_range_max = 77 - self._create_verify_security_group_rule(sg_id, direction, - self.ethertype, protocol, - port_range_min, - port_range_max) - - @decorators.idempotent_id('c9463db8-b44d-4f52-b6c0-8dbda99f26ce') - def test_create_security_group_rule_with_icmp_type_code(self): - """Verify security group rule for icmp protocol works. - - Specify icmp type (port_range_min) and icmp code - (port_range_max) with different values. A separate testcase - is added for icmp protocol as icmp validation would be - different from tcp/udp. - """ - group_create_body, _ = self._create_security_group() - - sg_id = group_create_body['security_group']['id'] - direction = 'ingress' - protocol = 'icmp' - icmp_type_codes = [(3, 2), (3, 0), (8, 0), (0, 0), (11, None)] - for icmp_type, icmp_code in icmp_type_codes: - self._create_verify_security_group_rule(sg_id, direction, - self.ethertype, protocol, - icmp_type, icmp_code) - - @decorators.idempotent_id('c2ed2deb-7a0c-44d8-8b4c-a5825b5c310b') - def test_create_security_group_rule_with_remote_group_id(self): - # Verify creating security group rule with remote_group_id works - sg1_body, _ = self._create_security_group() - sg2_body, _ = self._create_security_group() - - sg_id = sg1_body['security_group']['id'] - direction = 'ingress' - protocol = 'udp' - port_range_min = 50 - port_range_max = 55 - remote_id = sg2_body['security_group']['id'] - self._create_verify_security_group_rule(sg_id, direction, - self.ethertype, protocol, - port_range_min, - port_range_max, - remote_group_id=remote_id) - - @decorators.idempotent_id('16459776-5da2-4634-bce4-4b55ee3ec188') - def test_create_security_group_rule_with_remote_ip_prefix(self): - # Verify creating security group rule with remote_ip_prefix works - sg1_body, _ = self._create_security_group() - - sg_id = sg1_body['security_group']['id'] - direction = 'ingress' - protocol = 'tcp' - port_range_min = 76 - port_range_max = 77 - ip_prefix = self._project_network_cidr - self._create_verify_security_group_rule(sg_id, direction, - self.ethertype, protocol, - port_range_min, - port_range_max, - remote_ip_prefix=ip_prefix) - - @decorators.idempotent_id('0a307599-6655-4220-bebc-fd70c64f2290') - def test_create_security_group_rule_with_protocol_integer_value(self): - # Verify creating security group rule with the - # protocol as integer value - # arguments : "protocol": 17 - group_create_body, _ = self._create_security_group() - direction = 'ingress' - protocol = 17 - security_group_id = group_create_body['security_group']['id'] - client = self.security_group_rules_client - rule_create_body = client.create_security_group_rule( - security_group_id=security_group_id, - direction=direction, - protocol=protocol - ) - sec_group_rule = rule_create_body['security_group_rule'] - self.assertEqual(sec_group_rule['direction'], direction) - self.assertEqual(int(sec_group_rule['protocol']), protocol) - - -class SecGroupIPv6Test(SecGroupTest): - _ip_version = 6 - _project_network_cidr = CONF.network.project_network_v6_cidr diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py deleted file mode 100644 index f51fb3302..000000000 --- a/tempest/api/network/test_security_groups_negative.py +++ /dev/null @@ -1,248 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base_security_groups as base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class NegativeSecGroupTest(base.BaseSecGroupTest): - _project_network_cidr = CONF.network.project_network_cidr - - @classmethod - def skip_checks(cls): - super(NegativeSecGroupTest, cls).skip_checks() - if not test.is_extension_enabled('security-group', 'network'): - msg = "security-group extension not enabled." - raise cls.skipException(msg) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('424fd5c3-9ddc-486a-b45f-39bf0c820fc6') - def test_show_non_existent_security_group(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises( - lib_exc.NotFound, self.security_groups_client.show_security_group, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4c094c09-000b-4e41-8100-9617600c02a6') - def test_show_non_existent_security_group_rule(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises( - lib_exc.NotFound, - self.security_group_rules_client.show_security_group_rule, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1f1bb89d-5664-4956-9fcd-83ee0fa603df') - def test_delete_non_existent_security_group(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.security_groups_client.delete_security_group, - non_exist_id - ) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('981bdc22-ce48-41ed-900a-73148b583958') - def test_create_security_group_rule_with_bad_protocol(self): - group_create_body, _ = self._create_security_group() - - # Create rule with bad protocol name - pname = 'bad_protocol_name' - self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol=pname, direction='ingress', ethertype=self.ethertype) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5f8daf69-3c5f-4aaa-88c9-db1d66f68679') - def test_create_security_group_rule_with_bad_remote_ip_prefix(self): - group_create_body, _ = self._create_security_group() - - # Create rule with bad remote_ip_prefix - prefix = ['192.168.1./24', '192.168.1.1/33', 'bad_prefix', '256'] - for remote_ip_prefix in prefix: - self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='tcp', direction='ingress', ethertype=self.ethertype, - remote_ip_prefix=remote_ip_prefix) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4bf786fd-2f02-443c-9716-5b98e159a49a') - def test_create_security_group_rule_with_non_existent_remote_groupid(self): - group_create_body, _ = self._create_security_group() - non_exist_id = data_utils.rand_uuid() - - # Create rule with non existent remote_group_id - group_ids = ['bad_group_id', non_exist_id] - for remote_group_id in group_ids: - self.assertRaises( - lib_exc.NotFound, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='tcp', direction='ingress', ethertype=self.ethertype, - remote_group_id=remote_group_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b5c4b247-6b02-435b-b088-d10d45650881') - def test_create_security_group_rule_with_remote_ip_and_group(self): - sg1_body, _ = self._create_security_group() - sg2_body, _ = self._create_security_group() - - # Create rule specifying both remote_ip_prefix and remote_group_id - prefix = self._project_network_cidr - self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=sg1_body['security_group']['id'], - protocol='tcp', direction='ingress', - ethertype=self.ethertype, remote_ip_prefix=prefix, - remote_group_id=sg2_body['security_group']['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5666968c-fff3-40d6-9efc-df1c8bd01abb') - def test_create_security_group_rule_with_bad_ethertype(self): - group_create_body, _ = self._create_security_group() - - # Create rule with bad ethertype - ethertype = 'bad_ethertype' - self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='udp', direction='ingress', ethertype=ethertype) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0d9c7791-f2ad-4e2f-ac73-abf2373b0d2d') - def test_create_security_group_rule_with_invalid_ports(self): - group_create_body, _ = self._create_security_group() - - # Create rule for tcp protocol with invalid ports - states = [(-16, 80, 'Invalid value for port -16'), - (80, 79, 'port_range_min must be <= port_range_max'), - (80, 65536, 'Invalid value for port 65536'), - (None, 6, 'port_range_min must be <= port_range_max'), - (-16, 65536, 'Invalid value for port')] - for pmin, pmax, msg in states: - ex = self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='tcp', port_range_min=pmin, port_range_max=pmax, - direction='ingress', ethertype=self.ethertype) - self.assertIn(msg, str(ex)) - - # Create rule for icmp protocol with invalid ports - states = [(1, 256, 'Invalid value for ICMP code'), - (-1, 25, 'Invalid value'), - (None, 6, 'ICMP type (port-range-min) is missing'), - (300, 1, 'Invalid value for ICMP type')] - for pmin, pmax, msg in states: - ex = self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='icmp', port_range_min=pmin, port_range_max=pmax, - direction='ingress', ethertype=self.ethertype) - self.assertIn(msg, str(ex)) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('2323061e-9fbf-4eb0-b547-7e8fafc90849') - def test_create_additional_default_security_group_fails(self): - # Create security group named 'default', it should be failed. - name = 'default' - self.assertRaises(lib_exc.Conflict, - self.security_groups_client.create_security_group, - name=name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('966e2b96-023a-11e7-a9e4-fa163e4fa634') - def test_create_security_group_update_name_default(self): - # Update security group name to 'default', it should be failed. - group_create_body, _ = self._create_security_group() - self.assertRaises(lib_exc.Conflict, - self.security_groups_client.update_security_group, - group_create_body['security_group']['id'], - name="default") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8fde898f-ce88-493b-adc9-4e4692879fc5') - def test_create_duplicate_security_group_rule_fails(self): - # Create duplicate security group rule, it should fail. - body, _ = self._create_security_group() - - min_port = 66 - max_port = 67 - # Create a rule with valid params - self.security_group_rules_client.create_security_group_rule( - security_group_id=body['security_group']['id'], - direction='ingress', - ethertype=self.ethertype, - protocol='tcp', - port_range_min=min_port, - port_range_max=max_port - ) - - # Try creating the same security group rule, it should fail - self.assertRaises( - lib_exc.Conflict, - self.security_group_rules_client.create_security_group_rule, - security_group_id=body['security_group']['id'], - protocol='tcp', direction='ingress', ethertype=self.ethertype, - port_range_min=min_port, port_range_max=max_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('be308db6-a7cf-4d5c-9baf-71bafd73f35e') - def test_create_security_group_rule_with_non_existent_security_group(self): - # Create security group rules with not existing security group. - non_existent_sg = data_utils.rand_uuid() - self.assertRaises( - lib_exc.NotFound, - self.security_group_rules_client.create_security_group_rule, - security_group_id=non_existent_sg, - direction='ingress', ethertype=self.ethertype) - - -class NegativeSecGroupIPv6Test(NegativeSecGroupTest): - _ip_version = 6 - _project_network_cidr = CONF.network.project_network_v6_cidr - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7607439c-af73-499e-bf64-f687fd12a842') - def test_create_security_group_rule_wrong_ip_prefix_version(self): - group_create_body, _ = self._create_security_group() - - # Create rule with bad remote_ip_prefix - pairs = ({'ethertype': 'IPv6', - 'ip_prefix': CONF.network.project_network_cidr}, - {'ethertype': 'IPv4', - 'ip_prefix': CONF.network.project_network_v6_cidr}) - for pair in pairs: - self.assertRaisesRegex( - lib_exc.BadRequest, - "Conflicting value ethertype", - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='tcp', direction='ingress', - ethertype=pair['ethertype'], - remote_ip_prefix=pair['ip_prefix']) diff --git a/tempest/api/network/test_service_providers.py b/tempest/api/network/test_service_providers.py deleted file mode 100644 index b90c81b7f..000000000 --- a/tempest/api/network/test_service_providers.py +++ /dev/null @@ -1,29 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.network import base -from tempest.lib import decorators -from tempest import test - - -class ServiceProvidersTest(base.BaseNetworkTest): - - @decorators.idempotent_id('2cbbeea9-f010-40f6-8df5-4eaa0c918ea6') - @testtools.skipUnless( - test.is_extension_enabled('service-type', 'network'), - 'service-type extension not enabled.') - def test_service_providers_list(self): - body = self.service_providers_client.list_service_providers() - self.assertIn('service_providers', body) - self.assertIsInstance(body['service_providers'], list) diff --git a/tempest/api/network/test_subnetpools_extensions.py b/tempest/api/network/test_subnetpools_extensions.py deleted file mode 100644 index 01d7db254..000000000 --- a/tempest/api/network/test_subnetpools_extensions.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2015 GlobalLogic. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class SubnetPoolsTestJSON(base.BaseNetworkTest): - """Tests the following operations in the subnetpools API: - - Create a subnet pool. - Update a subnet pool. - Delete a subnet pool. - Lists subnet pool. - Show subnet pool details. - - v2.0 of the Neutron API is assumed. It is assumed that subnet_allocation - options mentioned in the [network-feature-enabled] section and - default_network option mentioned in the [network] section of - etc/tempest.conf: - - """ - - @classmethod - def skip_checks(cls): - super(SubnetPoolsTestJSON, cls).skip_checks() - if not test.is_extension_enabled('subnet_allocation', 'network'): - msg = "subnet_allocation extension not enabled." - raise cls.skipException(msg) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e9811') - def test_create_list_show_update_delete_subnetpools(self): - subnetpool_name = data_utils.rand_name('subnetpools') - # create subnet pool - prefix = CONF.network.default_network - body = self.subnetpools_client.create_subnetpool(name=subnetpool_name, - prefixes=prefix) - subnetpool_id = body["subnetpool"]["id"] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.subnetpools_client.delete_subnetpool, - subnetpool_id) - self.assertEqual(subnetpool_name, body["subnetpool"]["name"]) - # get detail about subnet pool - body = self.subnetpools_client.show_subnetpool(subnetpool_id) - self.assertEqual(subnetpool_name, body["subnetpool"]["name"]) - # update the subnet pool - subnetpool_name = data_utils.rand_name('subnetpools_update') - body = self.subnetpools_client.update_subnetpool(subnetpool_id, - name=subnetpool_name) - self.assertEqual(subnetpool_name, body["subnetpool"]["name"]) - # delete subnet pool - body = self.subnetpools_client.delete_subnetpool(subnetpool_id) - self.assertRaises(lib_exc.NotFound, - self.subnetpools_client.show_subnetpool, - subnetpool_id) diff --git a/tempest/api/network/test_tags.py b/tempest/api/network/test_tags.py deleted file mode 100644 index 567a4621f..000000000 --- a/tempest/api/network/test_tags.py +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class TagsTest(base.BaseNetworkTest): - """Tests the following operations in the tags API: - - Update all tags. - Delete all tags. - Check tag existence. - Create a tag. - List tags. - Remove a tag. - - v2.0 of the Neutron API is assumed. The tag extension allows users to set - tags on their networks. The extension supports networks only. - """ - - @classmethod - def skip_checks(cls): - super(TagsTest, cls).skip_checks() - if not test.is_extension_enabled('tag', 'network'): - msg = "tag extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(TagsTest, cls).resource_setup() - cls.network = cls.create_network() - - @decorators.idempotent_id('ee76bfaf-ac94-4d74-9ecc-4bbd4c583cb1') - def test_create_list_show_update_delete_tags(self): - # Validate that creating a tag on a network resource works. - tag_name = data_utils.rand_name(self.__class__.__name__ + '-Tag') - self.tags_client.create_tag('networks', self.network['id'], tag_name) - self.addCleanup(self.tags_client.delete_all_tags, 'networks', - self.network['id']) - self.tags_client.check_tag_existence('networks', self.network['id'], - tag_name) - - # Validate that listing tags on a network resource works. - retrieved_tags = self.tags_client.list_tags( - 'networks', self.network['id'])['tags'] - self.assertEqual([tag_name], retrieved_tags) - - # Generate 3 new tag names. - replace_tags = [data_utils.rand_name( - self.__class__.__name__ + '-Tag') for _ in range(3)] - - # Replace the current tag with the 3 new tags and validate that the - # network resource has the 3 new tags. - updated_tags = self.tags_client.update_all_tags( - 'networks', self.network['id'], replace_tags)['tags'] - self.assertEqual(3, len(updated_tags)) - self.assertEqual(set(replace_tags), set(updated_tags)) - - # Delete the first tag and check that it has been removed. - self.tags_client.delete_tag( - 'networks', self.network['id'], replace_tags[0]) - self.assertRaises(lib_exc.NotFound, - self.tags_client.check_tag_existence, 'networks', - self.network['id'], replace_tags[0]) - for i in range(1, 3): - self.tags_client.check_tag_existence( - 'networks', self.network['id'], replace_tags[i]) - - # Delete all the remaining tags and check that they have been removed. - self.tags_client.delete_all_tags('networks', self.network['id']) - for i in range(1, 3): - self.assertRaises(lib_exc.NotFound, - self.tags_client.check_tag_existence, 'networks', - self.network['id'], replace_tags[i]) - - -class TagsExtTest(base.BaseNetworkTest): - """Tests the following operations in the tags API: - - Update all tags. - Delete all tags. - Check tag existence. - Create a tag. - List tags. - Remove a tag. - - v2.0 of the Neutron API is assumed. The tag-ext extension allows users to - set tags on the following resources: subnets, ports, routers and - subnetpools. - """ - - # NOTE(felipemonteiro): The supported resource names are plural. Use - # the singular case for the corresponding class resource object. - SUPPORTED_RESOURCES = ['subnets', 'ports', 'routers', 'subnetpools'] - - @classmethod - def skip_checks(cls): - super(TagsExtTest, cls).skip_checks() - if not test.is_extension_enabled('tag-ext', 'network'): - msg = "tag-ext extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(TagsExtTest, cls).resource_setup() - cls.network = cls.create_network() - cls.subnet = cls.create_subnet(cls.network) - cls.port = cls.create_port(cls.network) - cls.router = cls.create_router() - - subnetpool_name = data_utils.rand_name(cls.__name__ + '-Subnetpool') - prefix = CONF.network.default_network - cls.subnetpool = cls.subnetpools_client.create_subnetpool( - name=subnetpool_name, prefixes=prefix)['subnetpool'] - - @classmethod - def resource_cleanup(cls): - cls.subnetpools_client.delete_subnetpool(cls.subnetpool['id']) - super(TagsExtTest, cls).resource_cleanup() - - def _create_tags_for_each_resource(self): - # Create a tag for each resource in `SUPPORTED_RESOURCES` and return - # the list of tag names. - tag_names = [] - - for resource in self.SUPPORTED_RESOURCES: - tag_name = data_utils.rand_name(self.__class__.__name__ + '-Tag') - tag_names.append(tag_name) - resource_object = getattr(self, resource[:-1]) - - self.tags_client.create_tag(resource, resource_object['id'], - tag_name) - self.addCleanup(self.tags_client.delete_all_tags, resource, - resource_object['id']) - - return tag_names - - @decorators.idempotent_id('c6231efa-9a89-4adf-b050-2a3156b8a1d9') - def test_create_check_list_and_delete_tags(self): - tag_names = self._create_tags_for_each_resource() - - for i, resource in enumerate(self.SUPPORTED_RESOURCES): - # Ensure that a tag was created for each resource. - resource_object = getattr(self, resource[:-1]) - retrieved_tags = self.tags_client.list_tags( - resource, resource_object['id'])['tags'] - self.assertEqual(1, len(retrieved_tags)) - self.assertEqual(tag_names[i], retrieved_tags[0]) - - # Check that the expected tag exists for each resource. - self.tags_client.check_tag_existence( - resource, resource_object['id'], tag_names[i]) - - # Delete the tag and ensure it was deleted. - self.tags_client.delete_tag( - resource, resource_object['id'], tag_names[i]) - retrieved_tags = self.tags_client.list_tags( - resource, resource_object['id'])['tags'] - self.assertEmpty(retrieved_tags) - - @decorators.idempotent_id('663a90f5-f334-4b44-afe0-c5fc1d408791') - def test_update_and_delete_all_tags(self): - self._create_tags_for_each_resource() - - for resource in self.SUPPORTED_RESOURCES: - # Generate 3 new tag names. - replace_tags = [data_utils.rand_name( - self.__class__.__name__ + '-Tag') for _ in range(3)] - - # Replace the current tag with the 3 new tags and validate that the - # current resource has the 3 new tags. - resource_object = getattr(self, resource[:-1]) - updated_tags = self.tags_client.update_all_tags( - resource, resource_object['id'], replace_tags)['tags'] - self.assertEqual(3, len(updated_tags)) - self.assertEqual(set(replace_tags), set(updated_tags)) - - # Delete all the tags and check that they have been removed. - self.tags_client.delete_all_tags(resource, resource_object['id']) - for i in range(3): - self.assertRaises( - lib_exc.NotFound, self.tags_client.check_tag_existence, - resource, resource_object['id'], replace_tags[i]) diff --git a/tempest/api/network/test_versions.py b/tempest/api/network/test_versions.py deleted file mode 100644 index 2f01e5040..000000000 --- a/tempest/api/network/test_versions.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2016 VMware, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.network import base -from tempest.lib import decorators - - -class NetworksApiDiscovery(base.BaseNetworkTest): - @decorators.attr(type='smoke') - @decorators.idempotent_id('cac8a836-c2e0-4304-b556-cd299c7281d1') - def test_api_version_resources(self): - """Test that GET / returns expected resources. - - The versions document returned by Neutron returns a few other - resources other than just available API versions: it also - states the status of each API version and provides links to - schema. - """ - - result = self.network_versions_client.list_versions() - expected_versions = ('v2.0') - expected_resources = ('id', 'links', 'status') - received_list = result.values() - - for item in received_list: - for version in item: - for resource in expected_resources: - self.assertIn(resource, version) - self.assertIn(version['id'], expected_versions) diff --git a/tempest/api/object_storage/__init__.py b/tempest/api/object_storage/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py deleted file mode 100644 index 11273e459..000000000 --- a/tempest/api/object_storage/base.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from tempest.common import custom_matchers -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -import tempest.test - -CONF = config.CONF - - -def delete_containers(containers, container_client, object_client): - """Remove containers and all objects in them. - - The containers should be visible from the container_client given. - Will not throw any error if the containers don't exist. - Will not check that object and container deletions succeed. - After delete all the objects from a container, it will wait 2 - seconds before delete the container itself, in order to deployments - using HA proxy sync the deletion properly, otherwise, the container - might fail to be deleted because it's not empty. - - :param containers: List of containers to be deleted - :param container_client: Client to be used to delete containers - :param object_client: Client to be used to delete objects - """ - for cont in containers: - try: - params = {'limit': 9999, 'format': 'json'} - _, objlist = container_client.list_container_contents(cont, params) - # delete every object in the container - for obj in objlist: - test_utils.call_and_ignore_notfound_exc( - object_client.delete_object, cont, obj['name']) - # sleep 2 seconds to sync the deletion of the objects - # in HA deployment - time.sleep(2) - container_client.delete_container(cont) - except lib_exc.NotFound: - pass - - -class BaseObjectTest(tempest.test.BaseTestCase): - - credentials = [['operator', CONF.object_storage.operator_role]] - - @classmethod - def skip_checks(cls): - super(BaseObjectTest, cls).skip_checks() - if not CONF.service_available.swift: - skip_msg = ("%s skipped as swift is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(BaseObjectTest, cls).setup_credentials() - # credentials may be overwritten by children classes - if hasattr(cls, 'os_roles_operator'): - cls.os = cls.os_roles_operator - - @classmethod - def setup_clients(cls): - super(BaseObjectTest, cls).setup_clients() - cls.object_client = cls.os_roles_operator.object_client - cls.bulk_client = cls.os_roles_operator.bulk_client - cls.container_client = cls.os_roles_operator.container_client - cls.account_client = cls.os_roles_operator.account_client - cls.capabilities_client = cls.os_roles_operator.capabilities_client - - @classmethod - def resource_setup(cls): - super(BaseObjectTest, cls).resource_setup() - - # Make sure we get fresh auth data after assigning swift role - cls.object_client.auth_provider.clear_auth() - cls.container_client.auth_provider.clear_auth() - cls.account_client.auth_provider.clear_auth() - - # make sure that discoverability is enabled and that the sections - # have not been disallowed by Swift - cls.policies = None - - if CONF.object_storage_feature_enabled.discoverability: - body = cls.capabilities_client.list_capabilities() - - if 'swift' in body and 'policies' in body['swift']: - cls.policies = body['swift']['policies'] - - cls.containers = [] - - @classmethod - def create_container(cls): - # wrapper that returns a test container - container_name = data_utils.rand_name(name='TestContainer') - cls.container_client.create_container(container_name) - cls.containers.append(container_name) - - return container_name - - @classmethod - def create_object(cls, container_name, object_name=None, - data=None, metadata=None): - # wrapper that returns a test object - if object_name is None: - object_name = data_utils.rand_name(name='TestObject') - if data is None: - data = data_utils.random_bytes() - cls.object_client.create_object(container_name, - object_name, - data, - metadata=metadata) - - return object_name, data - - @classmethod - def delete_containers(cls, container_client=None, object_client=None): - if container_client is None: - container_client = cls.container_client - if object_client is None: - object_client = cls.object_client - delete_containers(cls.containers, container_client, object_client) - - def assertHeaders(self, resp, target, method): - """Check the existence and the format of response headers""" - - self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders( - target, method, self.policies)) - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py deleted file mode 100644 index 7c538e8f3..000000000 --- a/tempest/api/object_storage/test_account_bulk.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2013 NTT Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import tarfile -import tempfile - -from tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest.lib import decorators -from tempest import test - - -class BulkTest(base.BaseObjectTest): - - def setUp(self): - super(BulkTest, self).setUp() - self.containers = [] - - def tearDown(self): - # NOTE(andreaf) BulkTests needs to cleanup containers after each - # test is executed. - base.delete_containers(self.containers, self.container_client, - self.object_client) - super(BulkTest, self).tearDown() - - def _create_archive(self): - # Create an archived file for bulk upload testing. - # Directory and files contained in the directory correspond to - # container and subsidiary objects. - tmp_dir = tempfile.mkdtemp() - tmp_file = tempfile.mkstemp(dir=tmp_dir) - - # Extract a container name and an object name - container_name = tmp_dir.split("/")[-1] - object_name = tmp_file[1].split("/")[-1] - - # Create tar file - tarpath = tempfile.NamedTemporaryFile(suffix=".tar") - tar = tarfile.open(None, 'w', tarpath) - tar.add(tmp_dir, arcname=container_name) - tar.close() - tarpath.flush() - - return tarpath.name, container_name, object_name - - def _upload_archive(self, filepath): - # upload an archived file - with open(filepath) as fh: - mydata = fh.read() - resp = self.bulk_client.upload_archive( - upload_path='', data=mydata, archive_file_format='tar') - return resp - - def _check_contents_deleted(self, container_name): - param = {'format': 'txt'} - resp, body = self.account_client.list_account_containers(param) - self.assertHeaders(resp, 'Account', 'GET') - self.assertNotIn(container_name, body) - - @decorators.idempotent_id('a407de51-1983-47cc-9f14-47c2b059413c') - @test.requires_ext(extension='bulk_upload', service='object') - def test_extract_archive(self): - # Test bulk operation of file upload with an archived file - filepath, container_name, object_name = self._create_archive() - resp = self._upload_archive(filepath) - self.containers.append(container_name) - - # When uploading an archived file with the bulk operation, the response - # does not contain 'content-length' header. This is the special case, - # therefore the existence of response headers is checked without - # custom matcher. - self.assertIn('transfer-encoding', resp.response) - self.assertIn('content-type', resp.response) - self.assertIn('x-trans-id', resp.response) - self.assertIn('date', resp.response) - - # Check only the format of common headers with custom matcher - self.assertThat(resp.response, custom_matchers.AreAllWellFormatted()) - - param = {'format': 'json'} - resp, body = self.account_client.list_account_containers(param) - - self.assertHeaders(resp, 'Account', 'GET') - - self.assertIn(container_name, [b['name'] for b in body]) - - param = {'format': 'json'} - resp, contents_list = self.container_client.list_container_contents( - container_name, param) - - self.assertHeaders(resp, 'Container', 'GET') - - self.assertIn(object_name, [c['name'] for c in contents_list]) - - @decorators.idempotent_id('c075e682-0d2a-43b2-808d-4116200d736d') - @test.requires_ext(extension='bulk_delete', service='object') - def test_bulk_delete(self): - # Test bulk operation of deleting multiple files - filepath, container_name, object_name = self._create_archive() - self._upload_archive(filepath) - - data = '%s/%s\n%s' % (container_name, object_name, container_name) - resp = self.bulk_client.delete_bulk_data(data=data) - - # When deleting multiple files using the bulk operation, the response - # does not contain 'content-length' header. This is the special case, - # therefore the existence of response headers is checked without - # custom matcher. - self.assertIn('transfer-encoding', resp.response) - self.assertIn('content-type', resp.response) - self.assertIn('x-trans-id', resp.response) - self.assertIn('date', resp.response) - - # Check only the format of common headers with custom matcher - self.assertThat(resp.response, custom_matchers.AreAllWellFormatted()) - - # Check if uploaded contents are completely deleted - self._check_contents_deleted(container_name) - - @decorators.idempotent_id('dbea2bcb-efbb-4674-ac8a-a5a0e33d1d79') - @test.requires_ext(extension='bulk_delete', service='object') - def test_bulk_delete_by_POST(self): - # Test bulk operation of deleting multiple files - filepath, container_name, object_name = self._create_archive() - self._upload_archive(filepath) - - data = '%s/%s\n%s' % (container_name, object_name, container_name) - - resp = self.bulk_client.delete_bulk_data_with_post(data=data) - - # When deleting multiple files using the bulk operation, the response - # does not contain 'content-length' header. This is the special case, - # therefore the existence of response headers is checked without - # custom matcher. - self.assertIn('transfer-encoding', resp.response) - self.assertIn('content-type', resp.response) - self.assertIn('x-trans-id', resp.response) - self.assertIn('date', resp.response) - - # Check only the format of common headers with custom matcher - self.assertThat(resp.response, custom_matchers.AreAllWellFormatted()) - - # Check if uploaded contents are completely deleted - self._check_contents_deleted(container_name) diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py deleted file mode 100644 index 092d36969..000000000 --- a/tempest/api/object_storage/test_account_quotas.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class AccountQuotasTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['reseller', CONF.object_storage.reseller_admin_role]] - - @classmethod - def setup_credentials(cls): - super(AccountQuotasTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_reselleradmin = cls.os_roles_reseller - - @classmethod - def resource_setup(cls): - super(AccountQuotasTest, cls).resource_setup() - cls.container_name = cls.create_container() - - # Retrieve a ResellerAdmin auth data and use it to set a quota - # on the client's account - cls.reselleradmin_auth_data = \ - cls.os_reselleradmin.auth_provider.auth_data - - def setUp(self): - super(AccountQuotasTest, self).setUp() - - # Set the reselleradmin auth in headers for next account_client - # request - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.reselleradmin_auth_data - ) - # Set a quota of 20 bytes on the user's account before each test - headers = {"X-Account-Meta-Quota-Bytes": "20"} - - self.os_roles_operator.account_client.request( - "POST", url="", headers=headers, body="") - - def tearDown(self): - # Set the reselleradmin auth in headers for next account_client - # request - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.reselleradmin_auth_data - ) - # remove the quota from the container - headers = {"X-Remove-Account-Meta-Quota-Bytes": "x"} - - self.os_roles_operator.account_client.request( - "POST", url="", headers=headers, body="") - super(AccountQuotasTest, self).tearDown() - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(AccountQuotasTest, cls).resource_cleanup() - - @decorators.attr(type="smoke") - @decorators.idempotent_id('a22ef352-a342-4587-8f47-3bbdb5b039c4') - @test.requires_ext(extension='account_quotas', service='object') - def test_upload_valid_object(self): - object_name = data_utils.rand_name(name="TestObject") - data = data_utils.arbitrary_string() - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - - self.assertHeaders(resp, 'Object', 'PUT') - - @decorators.attr(type=["smoke"]) - @decorators.idempotent_id('63f51f9f-5f1d-4fc6-b5be-d454d70949d6') - @test.requires_ext(extension='account_quotas', service='object') - def test_admin_modify_quota(self): - """Test ResellerAdmin can modify/remove the quota on a user's account - - Using the account client, the test modifies the quota - successively to: - - * "25": a random value different from the initial quota value. - * "" : an empty value, equivalent to the removal of the quota. - * "20": set the quota to its initial value. - """ - for quota in ("25", "", "20"): - - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.reselleradmin_auth_data - ) - headers = {"X-Account-Meta-Quota-Bytes": quota} - - resp, _ = self.os_roles_operator.account_client.request( - "POST", url="", headers=headers, body="") - - self.assertEqual(resp["status"], "204") - self.assertHeaders(resp, 'Account', 'POST') diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py deleted file mode 100644 index 55a6c7ad4..000000000 --- a/tempest/api/object_storage/test_account_quotas_negative.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.object_storage import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class AccountQuotasNegativeTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['reseller', CONF.object_storage.reseller_admin_role]] - - @classmethod - def setup_credentials(cls): - super(AccountQuotasNegativeTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_reselleradmin = cls.os_roles_reseller - - @classmethod - def resource_setup(cls): - super(AccountQuotasNegativeTest, cls).resource_setup() - cls.container_name = cls.create_container() - - # Retrieve a ResellerAdmin auth data and use it to set a quota - # on the client's account - cls.reselleradmin_auth_data = \ - cls.os_reselleradmin.auth_provider.auth_data - - def setUp(self): - super(AccountQuotasNegativeTest, self).setUp() - # Set the reselleradmin auth in headers for next account_client - # request - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.reselleradmin_auth_data - ) - # Set a quota of 20 bytes on the user's account before each test - headers = {"X-Account-Meta-Quota-Bytes": "20"} - - self.os_roles_operator.account_client.request( - "POST", url="", headers=headers, body="") - - def tearDown(self): - # Set the reselleradmin auth in headers for next account_client - # request - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.reselleradmin_auth_data - ) - # remove the quota from the container - headers = {"X-Remove-Account-Meta-Quota-Bytes": "x"} - - self.os_roles_operator.account_client.request( - "POST", url="", headers=headers, body="") - super(AccountQuotasNegativeTest, self).tearDown() - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(AccountQuotasNegativeTest, cls).resource_cleanup() - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('d1dc5076-555e-4e6d-9697-28f1fe976324') - @test.requires_ext(extension='account_quotas', service='object') - def test_user_modify_quota(self): - """Test that a user cannot modify or remove a quota on its account.""" - - # Not able to remove quota - self.assertRaises( - lib_exc.Forbidden, - self.account_client.create_update_or_delete_account_metadata, - create_update_metadata={"Quota-Bytes": ""}) - - # Not able to modify quota - self.assertRaises( - lib_exc.Forbidden, - self.account_client.create_update_or_delete_account_metadata, - create_update_metadata={"Quota-Bytes": "100"}) diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py deleted file mode 100644 index 2fb676fe3..000000000 --- a/tempest/api/object_storage/test_account_services.py +++ /dev/null @@ -1,368 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import random - -import six -import testtools - -from tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class AccountTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - containers = [] - - @classmethod - def setup_credentials(cls): - super(AccountTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_operator = cls.os_roles_operator_alt - - @classmethod - def resource_setup(cls): - super(AccountTest, cls).resource_setup() - for i in range(ord('a'), ord('f') + 1): - name = data_utils.rand_name(name='%s-' % chr(i)) - cls.container_client.create_container(name) - cls.containers.append(name) - cls.containers_count = len(cls.containers) - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(AccountTest, cls).resource_cleanup() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('3499406a-ae53-4f8c-b43a-133d4dc6fe3f') - def test_list_containers(self): - # list of all containers should not be empty - resp, container_list = self.account_client.list_account_containers() - self.assertHeaders(resp, 'Account', 'GET') - - self.assertIsNotNone(container_list) - - for container_name in self.containers: - self.assertIn(six.text_type(container_name).encode('utf-8'), - container_list) - - @decorators.idempotent_id('884ec421-fbad-4fcc-916b-0580f2699565') - def test_list_no_containers(self): - # List request to empty account - - # To test listing no containers, create new user other than - # the base user of this instance. - - resp, container_list = \ - self.os_operator.account_client.list_account_containers() - - # When sending a request to an account which has not received a PUT - # container request, the response does not contain 'accept-ranges' - # header. This is a special case, therefore the existence of response - # headers is checked without custom matcher. - # - # As the expected response is 204 No Content, Content-Length presence - # is not checked here intentionally. According to RFC 7230 a server - # MUST NOT send the header in such responses. Thus, clients should not - # depend on this header. However, the standard does not require them - # to validate the server's behavior. We leverage that to not refuse - # any implementation violating it like Swift [1] or some versions of - # Ceph RadosGW [2]. - # [1] https://bugs.launchpad.net/swift/+bug/1537811 - # [2] http://tracker.ceph.com/issues/13582 - self.assertIn('x-timestamp', resp) - self.assertIn('x-account-bytes-used', resp) - self.assertIn('x-account-container-count', resp) - self.assertIn('x-account-object-count', resp) - self.assertIn('content-type', resp) - self.assertIn('x-trans-id', resp) - self.assertIn('date', resp) - - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) - - self.assertEmpty(container_list) - - @decorators.idempotent_id('1c7efa35-e8a2-4b0b-b5ff-862c7fd83704') - def test_list_containers_with_format_json(self): - # list containers setting format parameter to 'json' - params = {'format': 'json'} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertIsNotNone(container_list) - self.assertTrue([c['name'] for c in container_list]) - self.assertTrue([c['count'] for c in container_list]) - self.assertTrue([c['bytes'] for c in container_list]) - - @decorators.idempotent_id('4477b609-1ca6-4d4b-b25d-ad3f01086089') - def test_list_containers_with_format_xml(self): - # list containers setting format parameter to 'xml' - params = {'format': 'xml'} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertIsNotNone(container_list) - self.assertEqual(container_list.tag, 'account') - self.assertIn('name', container_list.keys()) - self.assertEqual(container_list.find(".//container").tag, 'container') - self.assertEqual(container_list.find(".//name").tag, 'name') - self.assertEqual(container_list.find(".//count").tag, 'count') - self.assertEqual(container_list.find(".//bytes").tag, 'bytes') - - @decorators.idempotent_id('6eb04a6a-4860-4e31-ba91-ea3347d76b58') - @testtools.skipIf( - not CONF.object_storage_feature_enabled.discoverability, - 'Discoverability function is disabled') - def test_list_extensions(self): - resp = self.capabilities_client.list_capabilities() - - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) - - @decorators.idempotent_id('5cfa4ab2-4373-48dd-a41f-a532b12b08b2') - def test_list_containers_with_limit(self): - # list containers one of them, half of them then all of them - for limit in (1, self.containers_count // 2, - self.containers_count): - params = {'limit': limit} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - - self.assertEqual(len(container_list), limit) - - @decorators.idempotent_id('638f876d-6a43-482a-bbb3-0840bca101c6') - def test_list_containers_with_marker(self): - # list containers using marker param - # first expect to get 0 container as we specified last - # the container as marker - # second expect to get the bottom half of the containers - params = {'marker': self.containers[-1]} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - - self.assertEmpty(container_list) - - params = {'marker': self.containers[self.containers_count // 2]} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - - self.assertEqual(len(container_list), - self.containers_count // 2 - 1) - - @decorators.idempotent_id('5ca164e4-7bde-43fa-bafb-913b53b9e786') - def test_list_containers_with_end_marker(self): - # list containers using end_marker param - # first expect to get 0 container as we specified first container as - # end_marker - # second expect to get the top half of the containers - params = {'end_marker': self.containers[0]} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEmpty(container_list) - - params = {'end_marker': self.containers[self.containers_count // 2]} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEqual(len(container_list), self.containers_count // 2) - - @decorators.idempotent_id('ac8502c2-d4e4-4f68-85a6-40befea2ef5e') - def test_list_containers_with_marker_and_end_marker(self): - # list containers combining marker and end_marker param - params = {'marker': self.containers[0], - 'end_marker': self.containers[self.containers_count - 1]} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEqual(len(container_list), self.containers_count - 2) - - @decorators.idempotent_id('f7064ae8-dbcc-48da-b594-82feef6ea5af') - def test_list_containers_with_limit_and_marker(self): - # list containers combining marker and limit param - # result are always limitated by the limit whatever the marker - for marker in random.choice(self.containers): - limit = random.randint(0, self.containers_count - 1) - params = {'marker': marker, - 'limit': limit} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - - self.assertLessEqual(len(container_list), limit, - str(container_list)) - - @decorators.idempotent_id('888a3f0e-7214-4806-8e50-5e0c9a69bb5e') - def test_list_containers_with_limit_and_end_marker(self): - # list containers combining limit and end_marker param - limit = random.randint(1, self.containers_count) - params = {'limit': limit, - 'end_marker': self.containers[self.containers_count // 2]} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEqual(len(container_list), - min(limit, self.containers_count // 2)) - - @decorators.idempotent_id('8cf98d9c-e3a0-4e44-971b-c87656fdddbd') - def test_list_containers_with_limit_and_marker_and_end_marker(self): - # list containers combining limit, marker and end_marker param - limit = random.randint(1, self.containers_count) - params = {'limit': limit, - 'marker': self.containers[0], - 'end_marker': self.containers[self.containers_count - 1]} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEqual(len(container_list), - min(limit, self.containers_count - 2)) - - @decorators.idempotent_id('365e6fc7-1cfe-463b-a37c-8bd08d47b6aa') - def test_list_containers_with_prefix(self): - # list containers that have a name that starts with a prefix - prefix = '{0}-a'.format(CONF.resources_prefix) - params = {'prefix': prefix} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - for container in container_list: - self.assertEqual(True, container.decode( - 'utf-8').startswith(prefix)) - - @decorators.idempotent_id('b1811cff-d1ed-4c15-a52e-efd8de41cf34') - def test_list_containers_reverse_order(self): - # list containers in reverse order - _, orig_container_list = self.account_client.list_account_containers() - - params = {'reverse': True} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEqual(sorted(orig_container_list, reverse=True), - container_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('4894c312-6056-4587-8d6f-86ffbf861f80') - def test_list_account_metadata(self): - # list all account metadata - - # set metadata to account - metadata = {'test-account-meta1': 'Meta1', - 'test-account-meta2': 'Meta2'} - resp, _ = self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - - resp, _ = self.account_client.list_account_metadata() - self.assertHeaders(resp, 'Account', 'HEAD') - self.assertIn('x-account-meta-test-account-meta1', resp) - self.assertIn('x-account-meta-test-account-meta2', resp) - self.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata) - - @decorators.idempotent_id('b904c2e3-24c2-4dba-ad7d-04e90a761be5') - def test_list_no_account_metadata(self): - # list no account metadata - resp, _ = self.account_client.list_account_metadata() - self.assertHeaders(resp, 'Account', 'HEAD') - self.assertNotIn('x-account-meta-', str(resp)) - - @decorators.idempotent_id('e2a08b5f-3115-4768-a3ee-d4287acd6c08') - def test_update_account_metadata_with_create_metadata(self): - # add metadata to account - metadata = {'test-account-meta1': 'Meta1'} - resp, _ = self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - self.assertHeaders(resp, 'Account', 'POST') - - resp, _ = self.account_client.list_account_metadata() - self.assertIn('x-account-meta-test-account-meta1', resp) - self.assertEqual(resp['x-account-meta-test-account-meta1'], - metadata['test-account-meta1']) - - self.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata) - - @decorators.idempotent_id('9f60348d-c46f-4465-ae06-d51dbd470953') - def test_update_account_metadata_with_delete_metadata(self): - # delete metadata from account - metadata = {'test-account-meta1': 'Meta1'} - self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - resp, _ = self.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata) - self.assertHeaders(resp, 'Account', 'POST') - - resp, _ = self.account_client.list_account_metadata() - self.assertNotIn('x-account-meta-test-account-meta1', resp) - - @decorators.idempotent_id('64fd53f3-adbd-4639-af54-436e4982dbfb') - def test_update_account_metadata_with_create_metadata_key(self): - # if the value of metadata is not set, the metadata is not - # registered at a server - metadata = {'test-account-meta1': ''} - resp, _ = self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - self.assertHeaders(resp, 'Account', 'POST') - - resp, _ = self.account_client.list_account_metadata() - self.assertNotIn('x-account-meta-test-account-meta1', resp) - - @decorators.idempotent_id('d4d884d3-4696-4b85-bc98-4f57c4dd2bf1') - def test_update_account_metadata_with_delete_metadata_key(self): - # Although the value of metadata is not set, the feature of - # deleting metadata is valid - metadata_1 = {'test-account-meta1': 'Meta1'} - self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata_1) - metadata_2 = {'test-account-meta1': ''} - resp, _ = self.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata_2) - self.assertHeaders(resp, 'Account', 'POST') - - resp, _ = self.account_client.list_account_metadata() - self.assertNotIn('x-account-meta-test-account-meta1', resp) - - @decorators.idempotent_id('8e5fc073-59b9-42ee-984a-29ed11b2c749') - def test_update_account_metadata_with_create_and_delete_metadata(self): - # Send a request adding and deleting metadata requests simultaneously - metadata_1 = {'test-account-meta1': 'Meta1'} - self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata_1) - metadata_2 = {'test-account-meta2': 'Meta2'} - resp, _ = ( - self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata_2, - delete_metadata=metadata_1)) - self.assertHeaders(resp, 'Account', 'POST') - - resp, _ = self.account_client.list_account_metadata() - self.assertNotIn('x-account-meta-test-account-meta1', resp) - self.assertIn('x-account-meta-test-account-meta2', resp) - self.assertEqual(resp['x-account-meta-test-account-meta2'], - metadata_2['test-account-meta2']) - - self.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata_2) diff --git a/tempest/api/object_storage/test_account_services_negative.py b/tempest/api/object_storage/test_account_services_negative.py deleted file mode 100644 index e98a4f540..000000000 --- a/tempest/api/object_storage/test_account_services_negative.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.object_storage import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class AccountNegativeTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - @classmethod - def setup_credentials(cls): - super(AccountNegativeTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_operator = cls.os_roles_operator_alt - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('070e6aca-6152-4867-868d-1118d68fb38c') - def test_list_containers_with_non_authorized_user(self): - # list containers using non-authorized user - - test_auth_provider = self.os_operator.auth_provider - # Get auth for the test user - test_auth_provider.auth_data - - # Get fresh auth for test user and set it to next auth request for - # account_client - delattr(test_auth_provider, 'auth_data') - test_auth_new_data = test_auth_provider.auth_data - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=test_auth_new_data - ) - - params = {'format': 'json'} - # list containers with non-authorized user token - self.assertRaises(lib_exc.Forbidden, - self.account_client.list_account_containers, - params=params) diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py deleted file mode 100644 index 4b66ebf16..000000000 --- a/tempest/api/object_storage/test_container_acl.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ObjectTestACLs(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - def setUp(self): - super(ObjectTestACLs, self).setUp() - self.container_name = self.create_container() - - def tearDown(self): - self.delete_containers() - super(ObjectTestACLs, self).tearDown() - - @decorators.idempotent_id('a3270f3f-7640-4944-8448-c7ea783ea5b6') - def test_read_object_with_rights(self): - # attempt to read object using authorized user - # update X-Container-Read metadata ACL - tenant_name = self.os_roles_operator_alt.credentials.tenant_name - username = self.os_roles_operator_alt.credentials.username - cont_headers = {'X-Container-Read': tenant_name + ':' + username} - resp_meta, _ = ( - self.os_roles_operator.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='')) - self.assertHeaders(resp_meta, 'Container', 'POST') - # create object - object_name = data_utils.rand_name(name='Object') - resp, _ = self.os_roles_operator.object_client.create_object( - self.container_name, object_name, 'data') - self.assertHeaders(resp, 'Object', 'PUT') - # set alternative authentication data; cannot simply use the - # other object client. - self.os_roles_operator.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.os_roles_operator_alt.object_client.auth_provider. - auth_data) - resp, _ = self.os_roles_operator.object_client.get_object( - self.container_name, object_name) - self.assertHeaders(resp, 'Object', 'GET') - - @decorators.idempotent_id('aa58bfa5-40d9-4bc3-82b4-d07f4a9e392a') - def test_write_object_with_rights(self): - # attempt to write object using authorized user - # update X-Container-Write metadata ACL - tenant_name = self.os_roles_operator_alt.credentials.tenant_name - username = self.os_roles_operator_alt.credentials.username - cont_headers = {'X-Container-Write': tenant_name + ':' + username} - resp_meta, _ = ( - self.os_roles_operator.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='')) - self.assertHeaders(resp_meta, 'Container', 'POST') - # set alternative authentication data; cannot simply use the - # other object client. - self.os_roles_operator.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.os_roles_operator_alt.object_client.auth_provider. - auth_data) - # Trying to write the object with rights - object_name = data_utils.rand_name(name='Object') - resp, _ = self.os_roles_operator.object_client.create_object( - self.container_name, - object_name, 'data', headers={}) - self.assertHeaders(resp, 'Object', 'PUT') diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py deleted file mode 100644 index 655626c29..000000000 --- a/tempest/api/object_storage/test_container_acl_negative.py +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ObjectACLsNegativeTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - @classmethod - def setup_credentials(cls): - super(ObjectACLsNegativeTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_operator = cls.os_roles_operator_alt - - @classmethod - def resource_setup(cls): - super(ObjectACLsNegativeTest, cls).resource_setup() - cls.test_auth_data = cls.os_operator.auth_provider.auth_data - - def setUp(self): - super(ObjectACLsNegativeTest, self).setUp() - self.container_name = data_utils.rand_name(name='TestContainer') - self.container_client.create_container(self.container_name) - - def tearDown(self): - self.delete_containers([self.container_name]) - super(ObjectACLsNegativeTest, self).tearDown() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('af587587-0c24-4e15-9822-8352ce711013') - def test_write_object_without_using_creds(self): - # trying to create object with empty headers - # X-Auth-Token is not provided - object_name = data_utils.rand_name(name='Object') - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - self.assertRaises(lib_exc.Unauthorized, - self.object_client.create_object, - self.container_name, object_name, 'data', headers={}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('af85af0b-a025-4e72-a90e-121babf55720') - def test_delete_object_without_using_creds(self): - # create object - object_name = data_utils.rand_name(name='Object') - self.object_client.create_object(self.container_name, object_name, - 'data') - # trying to delete object with empty headers - # X-Auth-Token is not provided - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - self.assertRaises(lib_exc.Unauthorized, - self.object_client.delete_object, - self.container_name, object_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('63d84e37-55a6-42e2-9e5f-276e60e26a00') - def test_write_object_with_non_authorized_user(self): - # attempt to upload another file using non-authorized user - # User provided token is forbidden. ACL are not set - object_name = data_utils.rand_name(name='Object') - # trying to create object with non-authorized user - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - self.assertRaises(lib_exc.Forbidden, - self.object_client.create_object, - self.container_name, object_name, 'data', headers={}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('abf63359-be52-4feb-87dd-447689fc77fd') - def test_read_object_with_non_authorized_user(self): - # attempt to read object using non-authorized user - # User provided token is forbidden. ACL are not set - object_name = data_utils.rand_name(name='Object') - resp, _ = self.object_client.create_object( - self.container_name, object_name, 'data') - self.assertHeaders(resp, 'Object', 'PUT') - # trying to get object with non authorized user token - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - self.assertRaises(lib_exc.Forbidden, - self.object_client.get_object, - self.container_name, object_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7343ac3d-cfed-4198-9bb0-00149741a492') - def test_delete_object_with_non_authorized_user(self): - # attempt to delete object using non-authorized user - # User provided token is forbidden. ACL are not set - object_name = data_utils.rand_name(name='Object') - resp, _ = self.object_client.create_object( - self.container_name, object_name, 'data') - self.assertHeaders(resp, 'Object', 'PUT') - # trying to delete object with non-authorized user token - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - self.assertRaises(lib_exc.Forbidden, - self.object_client.delete_object, - self.container_name, object_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9ed01334-01e9-41ea-87ea-e6f465582823') - def test_read_object_without_rights(self): - # attempt to read object using non-authorized user - # update X-Container-Read metadata ACL - cont_headers = {'X-Container-Read': 'badtenant:baduser'} - resp_meta, _ = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - # create object - object_name = data_utils.rand_name(name='Object') - resp, _ = self.object_client.create_object(self.container_name, - object_name, 'data') - self.assertHeaders(resp, 'Object', 'PUT') - # Trying to read the object without rights - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - self.assertRaises(lib_exc.Forbidden, - self.object_client.get_object, - self.container_name, object_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a3a585a7-d8cf-4b65-a1a0-edc2b1204f85') - def test_write_object_without_rights(self): - # attempt to write object using non-authorized user - # update X-Container-Write metadata ACL - cont_headers = {'X-Container-Write': 'badtenant:baduser'} - resp_meta, _ = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - # Trying to write the object without rights - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - object_name = data_utils.rand_name(name='Object') - self.assertRaises(lib_exc.Forbidden, - self.object_client.create_object, - self.container_name, - object_name, 'data', headers={}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8ba512ad-aa6e-444e-b882-2906a0ea2052') - def test_write_object_without_write_rights(self): - # attempt to write object using non-authorized user - # update X-Container-Read and X-Container-Write metadata ACL - tenant_name = self.os_operator.credentials.tenant_name - username = self.os_operator.credentials.username - cont_headers = {'X-Container-Read': - tenant_name + ':' + username, - 'X-Container-Write': ''} - resp_meta, _ = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - # Trying to write the object without write rights - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - object_name = data_utils.rand_name(name='Object') - self.assertRaises(lib_exc.Forbidden, - self.object_client.create_object, - self.container_name, - object_name, 'data', headers={}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b4e366f8-f185-47ab-b789-df4416f9ecdb') - def test_delete_object_without_write_rights(self): - # attempt to delete object using non-authorized user - # update X-Container-Read and X-Container-Write metadata ACL - tenant_name = self.os_operator.credentials.tenant_name - username = self.os_operator.credentials.username - cont_headers = {'X-Container-Read': - tenant_name + ':' + username, - 'X-Container-Write': ''} - resp_meta, _ = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - # create object - object_name = data_utils.rand_name(name='Object') - resp, _ = self.object_client.create_object(self.container_name, - object_name, 'data') - self.assertHeaders(resp, 'Object', 'PUT') - # Trying to delete the object without write rights - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - self.assertRaises(lib_exc.Forbidden, - self.object_client.delete_object, - self.container_name, - object_name) diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py deleted file mode 100644 index 8266341af..000000000 --- a/tempest/api/object_storage/test_container_quotas.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2013 Cloudwatt -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -QUOTA_BYTES = 10 -QUOTA_COUNT = 3 - - -class ContainerQuotasTest(base.BaseObjectTest): - """Attempts to test the perfect behavior of quotas in a container.""" - - def setUp(self): - """Creates and sets a container with quotas. - - Quotas are set by adding meta values to the container, - and are validated when set: - - X-Container-Meta-Quota-Bytes: - Maximum size of the container, in bytes. - - X-Container-Meta-Quota-Count: - Maximum object count of the container. - """ - super(ContainerQuotasTest, self).setUp() - self.container_name = self.create_container() - metadata = {"quota-bytes": str(QUOTA_BYTES), - "quota-count": str(QUOTA_COUNT), } - self.container_client.update_container_metadata( - self.container_name, metadata) - - def tearDown(self): - """Cleans the container of any object after each test.""" - self.delete_containers() - super(ContainerQuotasTest, self).tearDown() - - @decorators.idempotent_id('9a0fb034-86af-4df0-86fa-f8bd7db21ae0') - @test.requires_ext(extension='container_quotas', service='object') - @decorators.attr(type="smoke") - def test_upload_valid_object(self): - """Attempts to uploads an object smaller than the bytes quota.""" - object_name = data_utils.rand_name(name="TestObject") - data = data_utils.arbitrary_string(QUOTA_BYTES) - - nbefore = self._get_bytes_used() - - resp, _ = self.object_client.create_object( - self.container_name, object_name, data) - self.assertHeaders(resp, 'Object', 'PUT') - - nafter = self._get_bytes_used() - self.assertEqual(nbefore + len(data), nafter) - - @decorators.idempotent_id('22eeeb2b-3668-4160-baef-44790f65a5a0') - @test.requires_ext(extension='container_quotas', service='object') - @decorators.attr(type="smoke") - def test_upload_large_object(self): - """Attempts to upload an object larger than the bytes quota.""" - object_name = data_utils.rand_name(name="TestObject") - data = data_utils.arbitrary_string(QUOTA_BYTES + 1) - - nbefore = self._get_bytes_used() - - self.assertRaises(lib_exc.OverLimit, - self.object_client.create_object, - self.container_name, object_name, data) - - nafter = self._get_bytes_used() - self.assertEqual(nbefore, nafter) - - @decorators.idempotent_id('3a387039-697a-44fc-a9c0-935de31f426b') - @test.requires_ext(extension='container_quotas', service='object') - @decorators.attr(type="smoke") - def test_upload_too_many_objects(self): - """Attempts to upload many objects that exceeds the count limit.""" - for _ in range(QUOTA_COUNT): - name = data_utils.rand_name(name="TestObject") - self.object_client.create_object(self.container_name, name, "") - - nbefore = self._get_object_count() - self.assertEqual(nbefore, QUOTA_COUNT) - - self.assertRaises(lib_exc.OverLimit, - self.object_client.create_object, - self.container_name, "OverQuotaObject", "") - - nafter = self._get_object_count() - self.assertEqual(nbefore, nafter) - - def _get_container_metadata(self): - resp, _ = self.container_client.list_container_metadata( - self.container_name) - return resp - - def _get_object_count(self): - resp = self._get_container_metadata() - return int(resp["x-container-object-count"]) - - def _get_bytes_used(self): - resp = self._get_container_metadata() - return int(resp["x-container-bytes-used"]) diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py deleted file mode 100644 index 76fe8d4f5..000000000 --- a/tempest/api/object_storage/test_container_services.py +++ /dev/null @@ -1,389 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class ContainerTest(base.BaseObjectTest): - def tearDown(self): - self.delete_containers() - super(ContainerTest, self).tearDown() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('92139d73-7819-4db1-85f8-3f2f22a8d91f') - def test_create_container(self): - container_name = data_utils.rand_name(name='TestContainer') - resp, _ = self.container_client.create_container(container_name) - self.containers.append(container_name) - self.assertHeaders(resp, 'Container', 'PUT') - - @decorators.idempotent_id('49f866ed-d6af-4395-93e7-4187eb56d322') - def test_create_container_overwrite(self): - # overwrite container with the same name - container_name = data_utils.rand_name(name='TestContainer') - self.container_client.create_container(container_name) - self.containers.append(container_name) - - resp, _ = self.container_client.create_container(container_name) - self.assertHeaders(resp, 'Container', 'PUT') - - @decorators.idempotent_id('c2ac4d59-d0f5-40d5-ba19-0635056d48cd') - def test_create_container_with_metadata_key(self): - # create container with the blank value of metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata = {'test-container-meta': ''} - resp, _ = self.container_client.create_container( - container_name, - metadata=metadata) - self.containers.append(container_name) - self.assertHeaders(resp, 'Container', 'PUT') - - resp, _ = self.container_client.list_container_metadata( - container_name) - # if the value of metadata is blank, metadata is not registered - # in the server - self.assertNotIn('x-container-meta-test-container-meta', resp) - - @decorators.idempotent_id('e1e8df32-7b22-44e1-aa08-ccfd8d446b58') - def test_create_container_with_metadata_value(self): - # create container with metadata value - container_name = data_utils.rand_name(name='TestContainer') - - # metadata name using underscores should be converted to hyphens - metadata = {'test_container_meta': 'Meta1'} - resp, _ = self.container_client.create_container( - container_name, - metadata=metadata) - self.containers.append(container_name) - self.assertHeaders(resp, 'Container', 'PUT') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertIn('x-container-meta-test-container-meta', resp) - self.assertEqual(resp['x-container-meta-test-container-meta'], - metadata['test_container_meta']) - - @decorators.idempotent_id('24d16451-1c0c-4e4f-b59c-9840a3aba40e') - def test_create_container_with_remove_metadata_key(self): - # create container with the blank value of remove metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata_1 = {'test-container-meta': 'Meta1'} - self.container_client.create_container( - container_name, - metadata=metadata_1) - self.containers.append(container_name) - - metadata_2 = {'test-container-meta': ''} - resp, _ = self.container_client.create_container( - container_name, - remove_metadata=metadata_2) - self.assertHeaders(resp, 'Container', 'PUT') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertNotIn('x-container-meta-test-container-meta', resp) - - @decorators.idempotent_id('8a21ebad-a5c7-4e29-b428-384edc8cd156') - def test_create_container_with_remove_metadata_value(self): - # create container with remove metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata = {'test-container-meta': 'Meta1'} - self.container_client.create_container(container_name, - metadata=metadata) - self.containers.append(container_name) - - resp, _ = self.container_client.create_container( - container_name, - remove_metadata=metadata) - self.assertHeaders(resp, 'Container', 'PUT') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertNotIn('x-container-meta-test-container-meta', resp) - - @decorators.idempotent_id('95d3a249-b702-4082-a2c4-14bb860cf06a') - def test_delete_container(self): - # create a container - container_name = self.create_container() - # delete container, success asserted within - resp, _ = self.container_client.delete_container(container_name) - self.assertHeaders(resp, 'Container', 'DELETE') - - @decorators.attr(type='smoke') - @decorators.idempotent_id('312ff6bd-5290-497f-bda1-7c5fec6697ab') - def test_list_container_contents(self): - # get container contents list - container_name = self.create_container() - object_name, _ = self.create_object(container_name) - - resp, object_list = self.container_client.list_container_contents( - container_name) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.idempotent_id('4646ac2d-9bfb-4c7d-a3c5-0f527402b3df') - def test_list_container_contents_with_no_object(self): - # get empty container contents list - container_name = self.create_container() - - resp, object_list = self.container_client.list_container_contents( - container_name) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEmpty(object_list) - - @decorators.idempotent_id('fe323a32-57b9-4704-a996-2e68f83b09bc') - def test_list_container_contents_with_delimiter(self): - # get container contents list using delimiter param - container_name = self.create_container() - object_name = data_utils.rand_name(name='TestObject/') - self.create_object(container_name, object_name) - - params = {'delimiter': '/'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name.split('/')[0] + '/'], object_list) - - @decorators.idempotent_id('55b4fa5c-e12e-4ca9-8fcf-a79afe118522') - def test_list_container_contents_with_end_marker(self): - # get container contents list using end_marker param - container_name = self.create_container() - object_name, _ = self.create_object(container_name) - - params = {'end_marker': object_name + 'zzzz'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.idempotent_id('196f5034-6ab0-4032-9da9-a937bbb9fba9') - def test_list_container_contents_with_format_json(self): - # get container contents list using format_json param - container_name = self.create_container() - self.create_object(container_name) - - params = {'format': 'json'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - - self.assertIsNotNone(object_list) - self.assertTrue([c['name'] for c in object_list]) - self.assertTrue([c['hash'] for c in object_list]) - self.assertTrue([c['bytes'] for c in object_list]) - self.assertTrue([c['content_type'] for c in object_list]) - self.assertTrue([c['last_modified'] for c in object_list]) - - @decorators.idempotent_id('655a53ca-4d15-408c-a377-f4c6dbd0a1fa') - def test_list_container_contents_with_format_xml(self): - # get container contents list using format_xml param - container_name = self.create_container() - self.create_object(container_name) - - params = {'format': 'xml'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - - self.assertIsNotNone(object_list) - self.assertEqual(object_list.tag, 'container') - self.assertIn('name', object_list.keys()) - self.assertEqual(object_list.find(".//object").tag, 'object') - self.assertEqual(object_list.find(".//name").tag, 'name') - self.assertEqual(object_list.find(".//hash").tag, 'hash') - self.assertEqual(object_list.find(".//bytes").tag, 'bytes') - self.assertEqual(object_list.find(".//content_type").tag, - 'content_type') - self.assertEqual(object_list.find(".//last_modified").tag, - 'last_modified') - - @decorators.idempotent_id('297ec38b-2b61-4ff4-bcd1-7fa055e97b61') - def test_list_container_contents_with_limit(self): - # get container contents list using limit param - container_name = self.create_container() - object_name, _ = self.create_object(container_name) - - params = {'limit': data_utils.rand_int_id(1, 10000)} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.idempotent_id('c31ddc63-2a58-4f6b-b25c-94d2937e6867') - def test_list_container_contents_with_marker(self): - # get container contents list using marker param - container_name = self.create_container() - object_name, _ = self.create_object(container_name) - - params = {'marker': 'AaaaObject1234567890'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.idempotent_id('58ca6cc9-6af0-408d-aaec-2a6a7b2f0df9') - def test_list_container_contents_with_path(self): - # get container contents list using path param - container_name = self.create_container() - object_name = data_utils.rand_name(name='TestObject') - object_name = 'Swift/' + object_name - self.create_object(container_name, object_name) - - params = {'path': 'Swift'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.idempotent_id('77e742c7-caf2-4ec9-8aa4-f7d509a3344c') - def test_list_container_contents_with_prefix(self): - # get container contents list using prefix param - container_name = self.create_container() - object_name, _ = self.create_object(container_name) - - prefix_key = object_name[0:8] - params = {'prefix': prefix_key} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('96e68f0e-19ec-4aa2-86f3-adc6a45e14dd') - def test_list_container_metadata(self): - # List container metadata - container_name = self.create_container() - - metadata = {'name': 'Pictures'} - self.container_client.update_container_metadata( - container_name, - metadata=metadata) - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertHeaders(resp, 'Container', 'HEAD') - self.assertIn('x-container-meta-name', resp) - self.assertEqual(resp['x-container-meta-name'], metadata['name']) - - @decorators.idempotent_id('a2faf936-6b13-4f8d-92a2-c2278355821e') - def test_list_no_container_metadata(self): - # HEAD container without metadata - container_name = self.create_container() - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertHeaders(resp, 'Container', 'HEAD') - self.assertNotIn('x-container-meta-', str(resp)) - - @decorators.idempotent_id('cf19bc0b-7e16-4a5a-aaed-cb0c2fe8deef') - def test_update_container_metadata_with_create_and_delete_metadata(self): - # Send one request of adding and deleting metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata_1 = {'test-container-meta1': 'Meta1'} - self.container_client.create_container(container_name, - metadata=metadata_1) - self.containers.append(container_name) - - metadata_2 = {'test-container-meta2': 'Meta2'} - resp, _ = self.container_client.update_container_metadata( - container_name, - metadata=metadata_2, - remove_metadata=metadata_1) - self.assertHeaders(resp, 'Container', 'POST') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertNotIn('x-container-meta-test-container-meta1', resp) - self.assertIn('x-container-meta-test-container-meta2', resp) - self.assertEqual(resp['x-container-meta-test-container-meta2'], - metadata_2['test-container-meta2']) - - @decorators.idempotent_id('2ae5f295-4bf1-4e04-bfad-21e54b62cec5') - def test_update_container_metadata_with_create_metadata(self): - # update container metadata using add metadata - container_name = self.create_container() - - metadata = {'test-container-meta1': 'Meta1'} - resp, _ = self.container_client.update_container_metadata( - container_name, - metadata=metadata) - self.assertHeaders(resp, 'Container', 'POST') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertIn('x-container-meta-test-container-meta1', resp) - self.assertEqual(resp['x-container-meta-test-container-meta1'], - metadata['test-container-meta1']) - - @decorators.idempotent_id('3a5ce7d4-6e4b-47d0-9d87-7cd42c325094') - def test_update_container_metadata_with_delete_metadata(self): - # update container metadata using delete metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata = {'test-container-meta1': 'Meta1'} - self.container_client.create_container(container_name, - metadata=metadata) - self.containers.append(container_name) - - resp, _ = self.container_client.delete_container_metadata( - container_name, - metadata=metadata) - self.assertHeaders(resp, 'Container', 'POST') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertNotIn('x-container-meta-test-container-meta1', resp) - - @decorators.idempotent_id('31f40a5f-6a52-4314-8794-cd89baed3040') - def test_update_container_metadata_with_create_metadata_key(self): - # update container metadata with a blank value of metadata - container_name = self.create_container() - - metadata = {'test-container-meta1': ''} - resp, _ = self.container_client.update_container_metadata( - container_name, - metadata=metadata) - self.assertHeaders(resp, 'Container', 'POST') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertNotIn('x-container-meta-test-container-meta1', resp) - - @decorators.idempotent_id('a2e36378-6f1f-43f4-840a-ffd9cfd61914') - def test_update_container_metadata_with_delete_metadata_key(self): - # update container metadata with a blank value of metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata = {'test-container-meta1': 'Meta1'} - self.container_client.create_container(container_name, - metadata=metadata) - self.containers.append(container_name) - - metadata = {'test-container-meta1': ''} - resp, _ = self.container_client.delete_container_metadata( - container_name, - metadata=metadata) - self.assertHeaders(resp, 'Container', 'POST') - - resp, _ = self.container_client.list_container_metadata(container_name) - self.assertNotIn('x-container-meta-test-container-meta1', resp) diff --git a/tempest/api/object_storage/test_container_services_negative.py b/tempest/api/object_storage/test_container_services_negative.py deleted file mode 100644 index 387b7b61b..000000000 --- a/tempest/api/object_storage/test_container_services_negative.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class ContainerNegativeTest(base.BaseObjectTest): - - @classmethod - def resource_setup(cls): - super(ContainerNegativeTest, cls).resource_setup() - - if CONF.object_storage_feature_enabled.discoverability: - # use /info to get default constraints - body = cls.capabilities_client.list_capabilities() - cls.constraints = body['swift'] - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('30686921-4bed-4764-a038-40d741ed4e78') - @testtools.skipUnless( - CONF.object_storage_feature_enabled.discoverability, - 'Discoverability function is disabled') - def test_create_container_name_exceeds_max_length(self): - # Attempts to create a container name that is longer than max - max_length = self.constraints['max_container_name_length'] - # create a container with long name - container_name = data_utils.arbitrary_string(size=max_length + 1) - ex = self.assertRaises(exceptions.BadRequest, - self.container_client.create_container, - container_name) - self.assertIn('Container name length of ' + str(max_length + 1) + - ' longer than ' + str(max_length), str(ex)) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('41e645bf-2e68-4f84-bf7b-c71aa5cd76ce') - @testtools.skipUnless( - CONF.object_storage_feature_enabled.discoverability, - 'Discoverability function is disabled') - def test_create_container_metadata_name_exceeds_max_length(self): - # Attempts to create container with metadata name - # that is longer than max. - max_length = self.constraints['max_meta_name_length'] - container_name = data_utils.rand_name(name='TestContainer') - metadata_name = data_utils.arbitrary_string(size=max_length + 1) - metadata = {metadata_name: 'penguin'} - ex = self.assertRaises(exceptions.BadRequest, - self.container_client.create_container, - container_name, metadata=metadata) - self.assertIn('Metadata name too long', str(ex)) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('81e36922-326b-4b7c-8155-3bbceecd7a82') - @testtools.skipUnless( - CONF.object_storage_feature_enabled.discoverability, - 'Discoverability function is disabled') - def test_create_container_metadata_value_exceeds_max_length(self): - # Attempts to create container with metadata value - # that is longer than max. - max_length = self.constraints['max_meta_value_length'] - container_name = data_utils.rand_name(name='TestContainer') - metadata_value = data_utils.arbitrary_string(size=max_length + 1) - metadata = {'animal': metadata_value} - ex = self.assertRaises(exceptions.BadRequest, - self.container_client.create_container, - container_name, metadata=metadata) - self.assertIn('Metadata value longer than ' + str(max_length), str(ex)) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('ac666539-d566-4f02-8ceb-58e968dfb732') - @testtools.skipUnless( - CONF.object_storage_feature_enabled.discoverability, - 'Discoverability function is disabled') - def test_create_container_metadata_exceeds_overall_metadata_count(self): - # Attempts to create container with metadata that exceeds the - # default count - max_count = self.constraints['max_meta_count'] - container_name = data_utils.rand_name(name='TestContainer') - metadata = {} - for i in range(max_count + 1): - metadata['animal-' + str(i)] = 'penguin' - - ex = self.assertRaises(exceptions.BadRequest, - self.container_client.create_container, - container_name, metadata=metadata) - self.assertIn('Too many metadata items; max ' + str(max_count), - str(ex)) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('1a95ab2e-b712-4a98-8a4d-8ce21b7557d6') - def test_get_metadata_headers_with_invalid_container_name(self): - # Attempts to retrieve metadata headers with an invalid - # container name. - self.assertRaises(exceptions.NotFound, - self.container_client.list_container_metadata, - 'invalid_container_name') - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('125a24fa-90a7-4cfc-b604-44e49d788390') - def test_update_metadata_with_nonexistent_container_name(self): - # Attempts to update metadata using a nonexistent container name. - metadata = {'animal': 'penguin'} - - self.assertRaises(exceptions.NotFound, - self.container_client.update_container_metadata, - 'nonexistent_container_name', metadata) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('65387dbf-a0e2-4aac-9ddc-16eb3f1f69ba') - def test_delete_with_nonexistent_container_name(self): - # Attempts to delete metadata using a nonexistent container name. - metadata = {'animal': 'penguin'} - - self.assertRaises(exceptions.NotFound, - self.container_client.delete_container_metadata, - 'nonexistent_container_name', metadata) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('14331d21-1e81-420a-beea-19cb5e5207f5') - def test_list_all_container_objects_with_nonexistent_container(self): - # Attempts to get a listing of all objects on a container - # that doesn't exist. - params = {'limit': 9999, 'format': 'json'} - self.assertRaises(exceptions.NotFound, - self.container_client.list_container_contents, - 'nonexistent_container_name', params) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('86b2ab08-92d5-493d-acd2-85f0c848819e') - def test_list_all_container_objects_on_deleted_container(self): - # Attempts to get a listing of all objects on a container - # that was deleted. - container_name = self.create_container() - # delete container - resp, _ = self.container_client.delete_container(container_name) - self.assertHeaders(resp, 'Container', 'DELETE') - params = {'limit': 9999, 'format': 'json'} - self.assertRaises(exceptions.NotFound, - self.container_client.list_container_contents, - container_name, params) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('42da116e-1e8c-4c96-9e06-2f13884ed2b1') - def test_delete_non_empty_container(self): - # create a container and an object within it - # attempt to delete a container that isn't empty. - container_name = self.create_container() - self.addCleanup(self.container_client.delete_container, - container_name) - object_name, _ = self.create_object(container_name) - self.addCleanup(self.object_client.delete_object, - container_name, object_name) - - ex = self.assertRaises(exceptions.Conflict, - self.container_client.delete_container, - container_name) - self.assertIn('There was a conflict when trying to complete your ' - 'request.', str(ex)) diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py deleted file mode 100644 index 378061a59..000000000 --- a/tempest/api/object_storage/test_container_staticweb.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class StaticWebTest(base.BaseObjectTest): - - @classmethod - def resource_setup(cls): - super(StaticWebTest, cls).resource_setup() - - # This header should be posted on the container before every test - cls.headers_public_read_acl = {'Read': '.r:*,.rlistings'} - - # Create test container and create one object in it - cls.container_name = cls.create_container() - cls.object_name, cls.object_data = cls.create_object( - cls.container_name) - - cls.container_client.update_container_metadata( - cls.container_name, - metadata=cls.headers_public_read_acl, - metadata_prefix="X-Container-") - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(StaticWebTest, cls).resource_cleanup() - - @decorators.idempotent_id('c1f055ab-621d-4a6a-831f-846fcb578b8b') - @test.requires_ext(extension='staticweb', service='object') - def test_web_index(self): - headers = {'web-index': self.object_name} - - self.container_client.update_container_metadata( - self.container_name, metadata=headers) - - # Maintain original headers, no auth added - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - - # test GET on http://account_url/container_name - # we should retrieve the self.object_name file - resp, body = self.account_client.request("GET", - self.container_name, - headers={}) - # This request is equivalent to GET object - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, self.object_data) - - # clean up before exiting - self.container_client.update_container_metadata(self.container_name, - {'web-index': ""}) - - _, body = self.container_client.list_container_metadata( - self.container_name) - self.assertNotIn('x-container-meta-web-index', body) - - @decorators.idempotent_id('941814cf-db9e-4b21-8112-2b6d0af10ee5') - @test.requires_ext(extension='staticweb', service='object') - def test_web_listing(self): - headers = {'web-listings': 'true'} - - self.container_client.update_container_metadata( - self.container_name, metadata=headers) - - # test GET on http://account_url/container_name - # we should retrieve a listing of objects - resp, body = self.account_client.request("GET", - self.container_name, - headers={}) - # The target of the request is not any Swift resource. Therefore, the - # existence of response header is checked without a custom matcher. - self.assertIn('content-length', resp) - self.assertIn('content-type', resp) - self.assertIn('x-trans-id', resp) - self.assertIn('date', resp) - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) - - self.assertIn(self.object_name, body.decode()) - - # clean up before exiting - self.container_client.update_container_metadata(self.container_name, - {'web-listings': ""}) - - _, body = self.container_client.list_container_metadata( - self.container_name) - self.assertNotIn('x-container-meta-web-listings', body) - - @decorators.idempotent_id('bc37ec94-43c8-4990-842e-0e5e02fc8926') - @test.requires_ext(extension='staticweb', service='object') - def test_web_listing_css(self): - headers = {'web-listings': 'true', - 'web-listings-css': 'listings.css'} - - self.container_client.update_container_metadata( - self.container_name, metadata=headers) - - # Maintain original headers, no auth added - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - - # test GET on http://account_url/container_name - # we should retrieve a listing of objects - _, body = self.account_client.request("GET", self.container_name, - headers={}) - self.assertIn(self.object_name, body.decode()) - css = '' - self.assertIn(css, body.decode()) - - @decorators.idempotent_id('f18b4bef-212e-45e7-b3ca-59af3a465f82') - @test.requires_ext(extension='staticweb', service='object') - def test_web_error(self): - headers = {'web-listings': 'true', - 'web-error': self.object_name} - - self.container_client.update_container_metadata( - self.container_name, metadata=headers) - - # Create object to return when requested object not found - object_name_404 = "404" + self.object_name - object_data_404 = data_utils.arbitrary_string() - self.object_client.create_object(self.container_name, - object_name_404, - object_data_404) - - # Do not set auth in HTTP headers for next request - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - - # Request non-existing object - self.assertRaises( - lib_exc.NotFound, self.object_client.get_object, - self.container_name, "notexisting") diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py deleted file mode 100644 index 4cb191404..000000000 --- a/tempest/api/object_storage/test_container_sync.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from six.moves.urllib import parse as urlparse -import testtools - -from tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -# This test can be quite long to run due to its -# dependency on container-sync process running interval. -# You can obviously reduce the container-sync interval in the -# container-server configuration. - - -class ContainerSyncTest(base.BaseObjectTest): - clients = {} - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - @classmethod - def setup_credentials(cls): - super(ContainerSyncTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_alt = cls.os_roles_operator_alt - - @classmethod - def setup_clients(cls): - super(ContainerSyncTest, cls).setup_clients() - cls.object_client_alt = cls.os_alt.object_client - cls.container_client_alt = cls.os_alt.container_client - - @classmethod - def resource_setup(cls): - super(ContainerSyncTest, cls).resource_setup() - cls.containers = [] - cls.objects = [] - - # Default container-server config only allows localhost - cls.local_ip = '127.0.0.1' - - # Must be configure according to container-sync interval - container_sync_timeout = CONF.object_storage.container_sync_timeout - cls.container_sync_interval = \ - CONF.object_storage.container_sync_interval - cls.attempts = \ - int(container_sync_timeout / cls.container_sync_interval) - - # define container and object clients - cls.clients[data_utils.rand_name(name='TestContainerSync')] = \ - (cls.container_client, cls.object_client) - cls.clients[data_utils.rand_name(name='TestContainerSync')] = \ - (cls.container_client_alt, cls.object_client_alt) - for cont_name, client in cls.clients.items(): - client[0].create_container(cont_name) - cls.containers.append(cont_name) - - @classmethod - def resource_cleanup(cls): - for client in cls.clients.values(): - cls.delete_containers(client[0], client[1]) - super(ContainerSyncTest, cls).resource_cleanup() - - def _test_container_synchronization(self, make_headers): - # container to container synchronization - # to allow/accept sync requests to/from other accounts - - # turn container synchronization on and create object in container - for cont in (self.containers, self.containers[::-1]): - cont_client = [self.clients[c][0] for c in cont] - obj_client = [self.clients[c][1] for c in cont] - headers = make_headers(cont[1], cont_client[1]) - cont_client[0].put(str(cont[0]), body=None, headers=headers) - # create object in container - object_name = data_utils.rand_name(name='TestSyncObject') - data = object_name[::-1].encode() # Raw data, we need bytes - resp, _ = obj_client[0].create_object(cont[0], object_name, data) - self.objects.append(object_name) - - # wait until container contents list is not empty - cont_client = [self.clients[c][0] for c in self.containers] - params = {'format': 'json'} - while self.attempts > 0: - object_lists = [] - for c_client, cont in zip(cont_client, self.containers): - resp, object_list = c_client.list_container_contents( - cont, params=params) - object_lists.append(dict( - (obj['name'], obj) for obj in object_list)) - # check that containers are not empty and have equal keys() - # or wait for next attempt - if object_lists[0] and object_lists[1] and \ - set(object_lists[0].keys()) == set(object_lists[1].keys()): - break - else: - time.sleep(self.container_sync_interval) - self.attempts -= 1 - - self.assertEqual(object_lists[0], object_lists[1], - 'Different object lists in containers.') - - # Verify object content - obj_clients = [(self.clients[c][1], c) for c in self.containers] - for obj_client, cont in obj_clients: - for obj_name in object_lists[0]: - resp, object_content = obj_client.get_object(cont, obj_name) - self.assertEqual(object_content, obj_name[::-1].encode()) - - @decorators.attr(type='slow') - @decorators.skip_because(bug='1317133') - @decorators.idempotent_id('be008325-1bba-4925-b7dd-93b58f22ce9b') - @testtools.skipIf( - not CONF.object_storage_feature_enabled.container_sync, - 'Old-style container sync function is disabled') - def test_container_synchronization(self): - def make_headers(cont, cont_client): - # tell first container to synchronize to a second - client_proxy_ip = \ - urlparse.urlparse(cont_client.base_url).netloc.split(':')[0] - client_base_url = \ - cont_client.base_url.replace(client_proxy_ip, - self.local_ip) - headers = {'X-Container-Sync-Key': 'sync_key', - 'X-Container-Sync-To': "%s/%s" % - (client_base_url, str(cont))} - return headers - self._test_container_synchronization(make_headers) diff --git a/tempest/api/object_storage/test_container_sync_middleware.py b/tempest/api/object_storage/test_container_sync_middleware.py deleted file mode 100644 index 9eae13874..000000000 --- a/tempest/api/object_storage/test_container_sync_middleware.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright(c)2015 NTT corp. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.object_storage import test_container_sync -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -# This test can be quite long to run due to its -# dependency on container-sync process running interval. -# You can obviously reduce the container-sync interval in the -# container-server configuration. - - -class ContainerSyncMiddlewareTest(test_container_sync.ContainerSyncTest): - - @classmethod - def resource_setup(cls): - super(ContainerSyncMiddlewareTest, cls).resource_setup() - - # Set container-sync-realms.conf info - cls.realm_name = CONF.object_storage.realm_name - cls.key = 'sync_key' - cls.cluster_name = CONF.object_storage.cluster_name - - @decorators.attr(type='slow') - @decorators.idempotent_id('ea4645a1-d147-4976-82f7-e5a7a3065f80') - @test.requires_ext(extension='container_sync', service='object') - def test_container_synchronization(self): - def make_headers(cont, cont_client): - # tell first container to synchronize to a second - account_name = cont_client.base_url.split('/')[-1] - - headers = {'X-Container-Sync-Key': "%s" % (self.key), - 'X-Container-Sync-To': "//%s/%s/%s/%s" % - (self.realm_name, self.cluster_name, - str(account_name), str(cont))} - return headers - self._test_container_synchronization(make_headers) diff --git a/tempest/api/object_storage/test_crossdomain.py b/tempest/api/object_storage/test_crossdomain.py deleted file mode 100644 index c47aa93eb..000000000 --- a/tempest/api/object_storage/test_crossdomain.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest.lib import decorators -from tempest import test - - -class CrossdomainTest(base.BaseObjectTest): - - @classmethod - def resource_setup(cls): - super(CrossdomainTest, cls).resource_setup() - - cls.xml_start = '\n' \ - '\n\n' - - cls.xml_end = "" - - def setUp(self): - super(CrossdomainTest, self).setUp() - - # Turning http://.../v1/foobar into http://.../ - self.account_client.skip_path() - - @decorators.idempotent_id('d1b8b031-b622-4010-82f9-ff78a9e915c7') - @test.requires_ext(extension='crossdomain', service='object') - def test_get_crossdomain_policy(self): - resp, body = self.account_client.get("crossdomain.xml", {}) - body = body.decode() - - self.assertTrue(body.startswith(self.xml_start) and - body.endswith(self.xml_end)) - - # The target of the request is not any Swift resource. Therefore, the - # existence of response header is checked without a custom matcher. - self.assertIn('content-length', resp) - self.assertIn('content-type', resp) - self.assertIn('x-trans-id', resp) - self.assertIn('date', resp) - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) diff --git a/tempest/api/object_storage/test_healthcheck.py b/tempest/api/object_storage/test_healthcheck.py deleted file mode 100644 index a186f9ee6..000000000 --- a/tempest/api/object_storage/test_healthcheck.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest.lib import decorators - - -class HealthcheckTest(base.BaseObjectTest): - - def setUp(self): - super(HealthcheckTest, self).setUp() - # Turning http://.../v1/foobar into http://.../ - self.account_client.skip_path() - - @decorators.idempotent_id('db5723b1-f25c-49a9-bfeb-7b5640caf337') - def test_get_healthcheck(self): - - resp, _ = self.account_client.get("healthcheck", {}) - - # The target of the request is not any Swift resource. Therefore, the - # existence of response header is checked without a custom matcher. - self.assertIn('content-length', resp) - self.assertIn('content-type', resp) - self.assertIn('x-trans-id', resp) - self.assertIn('date', resp) - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py deleted file mode 100644 index ed1be9081..000000000 --- a/tempest/api/object_storage/test_object_expiry.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from tempest.api.object_storage import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ObjectExpiryTest(base.BaseObjectTest): - @classmethod - def resource_setup(cls): - super(ObjectExpiryTest, cls).resource_setup() - cls.container_name = cls.create_container() - - def setUp(self): - super(ObjectExpiryTest, self).setUp() - # create object - self.object_name, _ = self.create_object( - self.container_name) - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(ObjectExpiryTest, cls).resource_cleanup() - - def _test_object_expiry(self, metadata): - # update object metadata - resp, _ = \ - self.object_client.update_object_metadata(self.container_name, - self.object_name, - metadata, - metadata_prefix='') - # verify object metadata - resp, _ = \ - self.object_client.list_object_metadata(self.container_name, - self.object_name) - self.assertHeaders(resp, 'Object', 'HEAD') - self.assertIn('x-delete-at', resp) - # we want to ensure that we will sleep long enough for things to - # actually expire, so figure out how many secs in the future that is. - sleepy_time = int(resp['x-delete-at']) - int(time.time()) - sleepy_time = sleepy_time if sleepy_time > 0 else 0 - resp, _ = self.object_client.get_object(self.container_name, - self.object_name) - self.assertHeaders(resp, 'Object', 'GET') - self.assertIn('x-delete-at', resp) - - # add several seconds for safety. - time.sleep(sleepy_time) - - # Checking whether object still exists for several seconds: - # sometimes object is not deleted immediately, so we are making - # get calls for an approximately 1 minute in a total. Get calls - # can take 3s each sometimes so we are making the requests in - # exponential periodicity - for i in range(1, 6): - time.sleep(2 ** i) - try: - self.object_client.get_object(self.container_name, - self.object_name) - except lib_exc.NotFound: - break - - # object should not be there anymore - self.assertRaises(lib_exc.NotFound, - self.object_client.get_object, - self.container_name, - self.object_name) - - @decorators.idempotent_id('fb024a42-37f3-4ba5-9684-4f40a7910b41') - def test_get_object_after_expiry_time(self): - # the 10s is important, because the get calls can take 3s each - # some times - metadata = {'X-Delete-After': '10'} - self._test_object_expiry(metadata) - - @decorators.idempotent_id('e592f18d-679c-48fe-9e36-4be5f47102c5') - def test_get_object_at_expiry_time(self): - metadata = {'X-Delete-At': str(int(time.time()) + 10)} - self._test_object_expiry(metadata) diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py deleted file mode 100644 index 3a2233a6e..000000000 --- a/tempest/api/object_storage/test_object_formpost.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import hashlib -import hmac -import time - -from six.moves.urllib import parse as urlparse - -from tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class ObjectFormPostTest(base.BaseObjectTest): - - metadata = {} - containers = [] - - @classmethod - def resource_setup(cls): - super(ObjectFormPostTest, cls).resource_setup() - cls.container_name = cls.create_container() - cls.object_name = data_utils.rand_name(name='ObjectTemp') - - cls.key = 'Meta' - cls.metadata = {'Temp-URL-Key': cls.key} - cls.account_client.create_update_or_delete_account_metadata( - create_update_metadata=cls.metadata) - - def setUp(self): - super(ObjectFormPostTest, self).setUp() - - # make sure the metadata has been set - account_client_metadata, _ = \ - self.account_client.list_account_metadata() - self.assertIn('x-account-meta-temp-url-key', - account_client_metadata) - self.assertEqual( - account_client_metadata['x-account-meta-temp-url-key'], - self.key) - - @classmethod - def resource_cleanup(cls): - cls.account_client.create_update_or_delete_account_metadata( - delete_metadata=cls.metadata) - cls.delete_containers() - super(ObjectFormPostTest, cls).resource_cleanup() - - def get_multipart_form(self, expires=600): - path = "%s/%s/%s" % ( - urlparse.urlparse(self.container_client.base_url).path, - self.container_name, - self.object_name) - - redirect = '' - max_file_size = 104857600 - max_file_count = 10 - expires += int(time.time()) - hmac_body = '%s\n%s\n%s\n%s\n%s' % (path, - redirect, - max_file_size, - max_file_count, - expires) - - signature = hmac.new( - self.key.encode(), hmac_body.encode(), hashlib.sha1 - ).hexdigest() - - fields = {'redirect': redirect, - 'max_file_size': str(max_file_size), - 'max_file_count': str(max_file_count), - 'expires': str(expires), - 'signature': signature} - - boundary = '--boundary--' - data = [] - for (key, value) in fields.items(): - data.append('--' + boundary) - data.append('Content-Disposition: form-data; name="%s"' % key) - data.append('') - data.append(value) - - data.append('--' + boundary) - data.append('Content-Disposition: form-data; ' - 'name="file1"; filename="testfile"') - data.append('Content-Type: application/octet-stream') - data.append('') - data.append('hello world') - - data.append('--' + boundary + '--') - data.append('') - - body = '\r\n'.join(data) - content_type = 'multipart/form-data; boundary=%s' % boundary - return body, content_type - - @decorators.idempotent_id('80fac02b-6e54-4f7b-be0d-a965b5cbef76') - @test.requires_ext(extension='formpost', service='object') - def test_post_object_using_form(self): - body, content_type = self.get_multipart_form() - - headers = {'Content-Type': content_type, - 'Content-Length': str(len(body))} - - url = "%s/%s" % (self.container_name, self.object_name) - - resp, body = self.object_client.post(url, body, headers=headers) - self.assertHeaders(resp, "Object", "POST") - - # Ensure object is available - resp, body = self.object_client.get("%s/%s%s" % ( - self.container_name, self.object_name, "testfile")) - self.assertHeaders(resp, "Object", "GET") - self.assertEqual(body.decode(), "hello world") diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py deleted file mode 100644 index c56d91a00..000000000 --- a/tempest/api/object_storage/test_object_formpost_negative.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import hashlib -import hmac -import time - -from six.moves.urllib import parse as urlparse - -from tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class ObjectFormPostNegativeTest(base.BaseObjectTest): - - metadata = {} - containers = [] - - @classmethod - def resource_setup(cls): - super(ObjectFormPostNegativeTest, cls).resource_setup() - cls.container_name = cls.create_container() - cls.object_name = data_utils.rand_name(name='ObjectTemp') - - cls.key = 'Meta' - cls.metadata = {'Temp-URL-Key': cls.key} - cls.account_client.create_update_or_delete_account_metadata( - create_update_metadata=cls.metadata) - - def setUp(self): - super(ObjectFormPostNegativeTest, self).setUp() - - # make sure the metadata has been set - account_client_metadata, _ = \ - self.account_client.list_account_metadata() - self.assertIn('x-account-meta-temp-url-key', - account_client_metadata) - self.assertEqual( - account_client_metadata['x-account-meta-temp-url-key'], - self.key) - - @classmethod - def resource_cleanup(cls): - cls.account_client.create_update_or_delete_account_metadata( - delete_metadata=cls.metadata) - cls.delete_containers() - super(ObjectFormPostNegativeTest, cls).resource_cleanup() - - def get_multipart_form(self, expires=600): - path = "%s/%s/%s" % ( - urlparse.urlparse(self.container_client.base_url).path, - self.container_name, - self.object_name) - - redirect = '' - max_file_size = 104857600 - max_file_count = 10 - expires += int(time.time()) - hmac_body = '%s\n%s\n%s\n%s\n%s' % (path, - redirect, - max_file_size, - max_file_count, - expires) - - signature = hmac.new( - self.key.encode(), hmac_body.encode(), hashlib.sha1 - ).hexdigest() - - fields = {'redirect': redirect, - 'max_file_size': str(max_file_size), - 'max_file_count': str(max_file_count), - 'expires': str(expires), - 'signature': signature} - - boundary = '--boundary--' - data = [] - for (key, value) in fields.items(): - data.append('--' + boundary) - data.append('Content-Disposition: form-data; name="%s"' % key) - data.append('') - data.append(value) - - data.append('--' + boundary) - data.append('Content-Disposition: form-data; ' - 'name="file1"; filename="testfile"') - data.append('Content-Type: application/octet-stream') - data.append('') - data.append('hello world') - - data.append('--' + boundary + '--') - data.append('') - - body = '\r\n'.join(data) - content_type = 'multipart/form-data; boundary=%s' % boundary - return body, content_type - - @decorators.idempotent_id('d3fb3c4d-e627-48ce-9379-a1631f21336d') - @test.requires_ext(extension='formpost', service='object') - @decorators.attr(type=['negative']) - def test_post_object_using_form_expired(self): - body, content_type = self.get_multipart_form(expires=1) - time.sleep(2) - - headers = {'Content-Type': content_type, - 'Content-Length': str(len(body))} - - url = "%s/%s" % (self.container_name, self.object_name) - exc = self.assertRaises( - lib_exc.Unauthorized, - self.object_client.post, - url, body, headers=headers) - self.assertIn('FormPost: Form Expired', str(exc)) - - @decorators.idempotent_id('b277257f-113c-4499-b8d1-5fead79f7360') - @test.requires_ext(extension='formpost', service='object') - @decorators.attr(type=['negative']) - def test_post_object_using_form_invalid_signature(self): - self.key = "Wrong" - body, content_type = self.get_multipart_form() - - headers = {'Content-Type': content_type, - 'Content-Length': str(len(body))} - - url = "%s/%s" % (self.container_name, self.object_name) - exc = self.assertRaises( - lib_exc.Unauthorized, - self.object_client.post, - url, body, headers=headers) - self.assertIn('FormPost: Invalid Signature', str(exc)) diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py deleted file mode 100644 index b29a77f03..000000000 --- a/tempest/api/object_storage/test_object_services.py +++ /dev/null @@ -1,1060 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import hashlib -import random -import re -import time -import zlib - -from tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ObjectTest(base.BaseObjectTest): - - @classmethod - def resource_setup(cls): - super(ObjectTest, cls).resource_setup() - cls.container_name = cls.create_container() - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(ObjectTest, cls).resource_cleanup() - - def _upload_segments(self): - # create object - object_name = data_utils.rand_name(name='LObject') - data = data_utils.arbitrary_string() - segments = 10 - data_segments = [data + str(i) for i in range(segments)] - # uploading segments - for i in range(segments): - self.object_client.create_object_segments( - self.container_name, object_name, i, data_segments[i]) - - return object_name, data_segments - - def _copy_object_2d(self, src_object_name, metadata=None): - dst_object_name = data_utils.rand_name(name='TestObject') - resp, _ = self.object_client.copy_object_2d_way(self.container_name, - src_object_name, - dst_object_name, - metadata=metadata) - return dst_object_name, resp - - def _check_copied_obj(self, dst_object_name, src_body, - in_meta=None, not_in_meta=None): - resp, dest_body = self.object_client.get_object(self.container_name, - dst_object_name) - - self.assertEqual(src_body, dest_body) - if in_meta: - for meta_key in in_meta: - self.assertIn('x-object-meta-' + meta_key, resp) - if not_in_meta: - for meta_key in not_in_meta: - self.assertNotIn('x-object-meta-' + meta_key, resp) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('5b4ce26f-3545-46c9-a2ba-5754358a4c62') - def test_create_object(self): - # create object - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - # create another object - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - self.assertHeaders(resp, 'Object', 'PUT') - - # check uploaded content - _, body = self.object_client.get_object(self.container_name, - object_name) - self.assertEqual(data, body) - - @decorators.idempotent_id('5daebb1d-f0d5-4dc9-b541-69672eff00b0') - def test_create_object_with_content_disposition(self): - # create object with content_disposition - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata = {} - metadata['content-disposition'] = 'inline' - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=None) - self.assertIn('content-disposition', resp) - self.assertEqual(resp['content-disposition'], 'inline') - self.assertEqual(body, data) - - @decorators.idempotent_id('605f8317-f945-4bee-ae91-013f1da8f0a0') - def test_create_object_with_content_encoding(self): - # create object with content_encoding - object_name = data_utils.rand_name(name='TestObject') - - # put compressed string - data_before = b'x' * 2000 - data = zlib.compress(data_before) - metadata = {} - metadata['content-encoding'] = 'deflate' - - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - # download compressed object - metadata = {} - metadata['accept-encoding'] = 'deflate' - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=metadata) - self.assertEqual(body, data_before) - - @decorators.idempotent_id('73820093-0503-40b1-a478-edf0e69c7d1f') - def test_create_object_with_etag(self): - # create object with etag - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - md5 = hashlib.md5(data).hexdigest() - metadata = {'Etag': md5} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - # check uploaded content - _, body = self.object_client.get_object(self.container_name, - object_name) - self.assertEqual(data, body) - - @decorators.idempotent_id('84dafe57-9666-4f6d-84c8-0814d37923b8') - def test_create_object_with_expect_continue(self): - # create object with expect_continue - - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - - status, _ = self.object_client.create_object_continue( - self.container_name, object_name, data) - - self.assertEqual(status, 201) - - # check uploaded content - _, body = self.object_client.get_object(self.container_name, - object_name) - self.assertEqual(data, body) - - @decorators.idempotent_id('4f84422a-e2f2-4403-b601-726a4220b54e') - def test_create_object_with_transfer_encoding(self): - # create object with transfer_encoding - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes(1024) - _, _, resp_headers = self.object_client.put_object_with_chunk( - container=self.container_name, - name=object_name, - contents=data_utils.chunkify(data, 512) - ) - self.assertHeaders(resp_headers, 'Object', 'PUT') - - # check uploaded content - _, body = self.object_client.get_object(self.container_name, - object_name) - self.assertEqual(data, body) - - @decorators.idempotent_id('0f3d62a6-47e3-4554-b0e5-1a5dc372d501') - def test_create_object_with_x_fresh_metadata(self): - # create object with x_fresh_metadata - object_name_base = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata_1 = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name_base, - data, - metadata=metadata_1) - object_name = data_utils.rand_name(name='TestObject') - metadata_2 = {'X-Copy-From': '%s/%s' % (self.container_name, - object_name_base), - 'X-Fresh-Metadata': 'true'} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - '', - metadata=metadata_2) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta', resp) - self.assertEqual(data, body) - - @decorators.idempotent_id('1c7ed3e4-2099-406b-b843-5301d4811baf') - def test_create_object_with_x_object_meta(self): - # create object with object_meta - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata = {'X-Object-Meta-test-meta': 'Meta'} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], 'Meta') - self.assertEqual(data, body) - - @decorators.idempotent_id('e4183917-33db-4153-85cc-4dacbb938865') - def test_create_object_with_x_object_metakey(self): - # create object with the blank value of metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata = {'X-Object-Meta-test-meta': ''} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], '') - self.assertEqual(data, body) - - @decorators.idempotent_id('ce798afc-b278-45de-a5ce-2ea124b98b99') - def test_create_object_with_x_remove_object_meta(self): - # create object with x_remove_object_meta - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata_add = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=metadata_add) - metadata_remove = {'X-Remove-Object-Meta-test-meta': 'Meta'} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata_remove) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta', resp) - self.assertEqual(data, body) - - @decorators.idempotent_id('ad21e342-7916-4f9e-ab62-a1f885f2aaf9') - def test_create_object_with_x_remove_object_metakey(self): - # create object with the blank value of remove metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata_add = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=metadata_add) - metadata_remove = {'X-Remove-Object-Meta-test-meta': ''} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata_remove) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta', resp) - self.assertEqual(data, body) - - @decorators.idempotent_id('17738d45-03bd-4d45-9e0b-7b2f58f98687') - def test_delete_object(self): - # create object - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - # delete object - resp, _ = self.object_client.delete_object(self.container_name, - object_name) - self.assertHeaders(resp, 'Object', 'DELETE') - - @decorators.attr(type='smoke') - @decorators.idempotent_id('7a94c25d-66e6-434c-9c38-97d4e2c29945') - def test_update_object_metadata(self): - # update object metadata - object_name, _ = self.create_object(self.container_name) - - metadata = {'X-Object-Meta-test-meta': 'Meta'} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], 'Meta') - - @decorators.idempotent_id('48650ed0-c189-4e1e-ad6b-1d4770c6e134') - def test_update_object_metadata_with_remove_metadata(self): - # update object metadata with remove metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=create_metadata) - - update_metadata = {'X-Remove-Object-Meta-test-meta1': 'Meta1'} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - update_metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta1', resp) - - @decorators.idempotent_id('f726174b-2ded-4708-bff7-729d12ce1f84') - def test_update_object_metadata_with_create_and_remove_metadata(self): - # creation and deletion of metadata with one request - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=create_metadata) - - update_metadata = {'X-Object-Meta-test-meta2': 'Meta2', - 'X-Remove-Object-Meta-test-meta1': 'Meta1'} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - update_metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta1', resp) - self.assertIn('x-object-meta-test-meta2', resp) - self.assertEqual(resp['x-object-meta-test-meta2'], 'Meta2') - - @decorators.idempotent_id('08854588-6449-4bb7-8cca-f2e1040f5e6f') - def test_update_object_metadata_with_x_object_manifest(self): - # update object metadata with x_object_manifest - - # uploading segments - object_name, _ = self._upload_segments() - # creating a manifest file - data_empty = '' - self.object_client.create_object(self.container_name, - object_name, - data_empty, - metadata=None) - object_prefix = '%s/%s' % (self.container_name, object_name) - update_metadata = {'X-Object-Manifest': object_prefix} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - update_metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertIn('x-object-manifest', resp) - self.assertNotEmpty(resp['x-object-manifest']) - - @decorators.idempotent_id('0dbbe89c-6811-4d84-a2df-eca2bdd40c0e') - def test_update_object_metadata_with_x_object_metakey(self): - # update object metadata with a blank value of metadata - object_name, _ = self.create_object(self.container_name) - - update_metadata = {'X-Object-Meta-test-meta': ''} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - update_metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], '') - - @decorators.idempotent_id('9a88dca4-b684-425b-806f-306cd0e57e42') - def test_update_object_metadata_with_x_remove_object_metakey(self): - # update object metadata with a blank value of remove metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.arbitrary_string() - create_metadata = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=create_metadata) - - update_metadata = {'X-Remove-Object-Meta-test-meta': ''} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - update_metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta', resp) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('9a447cf6-de06-48de-8226-a8c6ed31caf2') - def test_list_object_metadata(self): - # get object metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=metadata) - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertHeaders(resp, 'Object', 'HEAD') - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], 'Meta') - - @decorators.idempotent_id('170fb90e-f5c3-4b1f-ae1b-a18810821172') - def test_list_no_object_metadata(self): - # get empty list of object metadata - object_name, _ = self.create_object(self.container_name) - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertHeaders(resp, 'Object', 'HEAD') - self.assertNotIn('x-object-meta-', str(resp)) - - @decorators.idempotent_id('23a3674c-d6de-46c3-86af-ff92bfc8a3da') - def test_list_object_metadata_with_x_object_manifest(self): - # get object metadata with x_object_manifest - - # uploading segments - object_name, _ = self._upload_segments() - # creating a manifest file - object_prefix = '%s/%s' % (self.container_name, object_name) - metadata = {'X-Object-Manifest': object_prefix} - data_empty = '' - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data_empty, - metadata=metadata) - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - - # Check only the existence of common headers with custom matcher - self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders( - 'Object', 'HEAD')) - self.assertIn('x-object-manifest', resp) - - # Etag value of a large object is enclosed in double-quotations. - # This is a special case, therefore the formats of response headers - # are checked without a custom matcher. - self.assertTrue(resp['etag'].startswith('\"')) - self.assertTrue(resp['etag'].endswith('\"')) - self.assertTrue(resp['etag'].strip('\"').isalnum()) - self.assertTrue(re.match(r"^\d+\.?\d*\Z", resp['x-timestamp'])) - self.assertNotEmpty(resp['content-type']) - self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*", - resp['x-trans-id'])) - self.assertNotEmpty(resp['date']) - self.assertEqual(resp['accept-ranges'], 'bytes') - self.assertEqual(resp['x-object-manifest'], - '%s/%s' % (self.container_name, object_name)) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('02610ba7-86b7-4272-9ed8-aa8d417cb3cd') - def test_get_object(self): - # retrieve object's data (in response body) - - # create object - object_name, data = self.create_object(self.container_name) - # get object - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertHeaders(resp, 'Object', 'GET') - - self.assertEqual(body, data) - - @decorators.idempotent_id('005f9bf6-e06d-41ec-968e-96c78e0b1d82') - def test_get_object_with_metadata(self): - # get object with metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=metadata) - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=None) - self.assertHeaders(resp, 'Object', 'GET') - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], 'Meta') - self.assertEqual(body, data) - - @decorators.idempotent_id('05a1890e-7db9-4a6c-90a8-ce998a2bddfa') - def test_get_object_with_range(self): - # get object with range - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes(100) - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=None) - rand_num = random.randint(3, len(data) - 1) - metadata = {'Range': 'bytes=%s-%s' % (rand_num - 3, rand_num - 1)} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data[rand_num - 3: rand_num]) - - @decorators.idempotent_id('11b4515b-7ba7-4ca8-8838-357ded86fc10') - def test_get_object_with_x_object_manifest(self): - # get object with x_object_manifest - - # uploading segments - object_name, data_segments = self._upload_segments() - # creating a manifest file - object_prefix = '%s/%s' % (self.container_name, object_name) - metadata = {'X-Object-Manifest': object_prefix} - data_empty = '' - resp, body = self.object_client.create_object( - self.container_name, - object_name, - data_empty, - metadata=metadata) - - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=None) - - # Check only the existence of common headers with custom matcher - self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders( - 'Object', 'GET')) - self.assertIn('x-object-manifest', resp) - - # Etag value of a large object is enclosed in double-quotations. - # This is a special case, therefore the formats of response headers - # are checked without a custom matcher. - self.assertTrue(resp['etag'].startswith('\"')) - self.assertTrue(resp['etag'].endswith('\"')) - self.assertTrue(resp['etag'].strip('\"').isalnum()) - self.assertTrue(re.match(r"^\d+\.?\d*\Z", resp['x-timestamp'])) - self.assertNotEmpty(resp['content-type']) - self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*", - resp['x-trans-id'])) - self.assertNotEmpty(resp['date']) - self.assertEqual(resp['accept-ranges'], 'bytes') - self.assertEqual(resp['x-object-manifest'], - '%s/%s' % (self.container_name, object_name)) - - self.assertEqual(''.join(data_segments), body.decode()) - - @decorators.idempotent_id('c05b4013-e4de-47af-be84-e598062b16fc') - def test_get_object_with_if_match(self): - # get object with if_match - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes(10) - create_md5 = hashlib.md5(data).hexdigest() - create_metadata = {'Etag': create_md5} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=create_metadata) - - list_metadata = {'If-Match': create_md5} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=list_metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data) - - @decorators.idempotent_id('be133639-e5d2-4313-9b1f-2d59fc054a16') - def test_get_object_with_if_modified_since(self): - # get object with if_modified_since - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - time_now = time.time() - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=None) - - http_date = time.ctime(time_now - 86400) - list_metadata = {'If-Modified-Since': http_date} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=list_metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data) - - @decorators.idempotent_id('641500d5-1612-4042-a04d-01fc4528bc30') - def test_get_object_with_if_none_match(self): - # get object with if_none_match - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - create_md5 = hashlib.md5(data).hexdigest() - create_metadata = {'Etag': create_md5} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=create_metadata) - - list_data = data_utils.random_bytes() - list_md5 = hashlib.md5(list_data).hexdigest() - list_metadata = {'If-None-Match': list_md5} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=list_metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data) - - @decorators.idempotent_id('0aa1201c-10aa-467a-bee7-63cbdd463152') - def test_get_object_with_if_unmodified_since(self): - # get object with if_unmodified_since - object_name, data = self.create_object(self.container_name) - - time_now = time.time() - http_date = time.ctime(time_now + 86400) - list_metadata = {'If-Unmodified-Since': http_date} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=list_metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data) - - @decorators.idempotent_id('94587078-475f-48f9-a40f-389c246e31cd') - def test_get_object_with_x_newest(self): - # get object with x_newest - object_name, data = self.create_object(self.container_name) - - list_metadata = {'X-Newest': 'true'} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=list_metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data) - - @decorators.idempotent_id('1a9ab572-1b66-4981-8c21-416e2a5e6011') - def test_copy_object_in_same_container(self): - # create source object - src_object_name = data_utils.rand_name(name='SrcObject') - src_data = data_utils.random_bytes(size=len(src_object_name) * 2) - resp, _ = self.object_client.create_object(self.container_name, - src_object_name, - src_data) - # create destination object - dst_object_name = data_utils.rand_name(name='DstObject') - dst_data = data_utils.random_bytes(size=len(dst_object_name) * 3) - resp, _ = self.object_client.create_object(self.container_name, - dst_object_name, - dst_data) - # copy source object to destination - resp, _ = self.object_client.copy_object_in_same_container( - self.container_name, src_object_name, dst_object_name) - self.assertHeaders(resp, 'Object', 'PUT') - - # check data - resp, body = self.object_client.get_object(self.container_name, - dst_object_name) - self.assertEqual(body, src_data) - - @decorators.idempotent_id('2248abba-415d-410b-9c30-22dff9cd6e67') - def test_copy_object_to_itself(self): - # change the content type of an existing object - - # create object - object_name, _ = self.create_object(self.container_name) - # get the old content type - resp_tmp, _ = self.object_client.list_object_metadata( - self.container_name, object_name) - # change the content type of the object - metadata = {'content-type': 'text/plain; charset=UTF-8'} - self.assertNotEqual(resp_tmp['content-type'], metadata['content-type']) - resp, _ = self.object_client.copy_object_in_same_container( - self.container_name, object_name, object_name, metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - # check the content type - resp, _ = self.object_client.list_object_metadata(self.container_name, - object_name) - self.assertEqual(resp['content-type'], metadata['content-type']) - - @decorators.idempotent_id('06f90388-2d0e-40aa-934c-e9a8833e958a') - def test_copy_object_2d_way(self): - # create source object - src_object_name = data_utils.rand_name(name='SrcObject') - src_data = data_utils.random_bytes(size=len(src_object_name) * 2) - resp, _ = self.object_client.create_object(self.container_name, - src_object_name, src_data) - # create destination object - dst_object_name = data_utils.rand_name(name='DstObject') - dst_data = data_utils.random_bytes(size=len(dst_object_name) * 3) - resp, _ = self.object_client.create_object(self.container_name, - dst_object_name, dst_data) - # copy source object to destination - resp, _ = self.object_client.copy_object_2d_way(self.container_name, - src_object_name, - dst_object_name) - self.assertHeaders(resp, 'Object', 'COPY') - self.assertEqual( - resp['x-copied-from'], - self.container_name + "/" + src_object_name) - - # check data - self._check_copied_obj(dst_object_name, src_data) - - @decorators.idempotent_id('aa467252-44f3-472a-b5ae-5b57c3c9c147') - def test_copy_object_across_containers(self): - # create a container to use as a source container - src_container_name = data_utils.rand_name(name='TestSourceContainer') - self.container_client.create_container(src_container_name) - self.containers.append(src_container_name) - # create a container to use as a destination container - dst_container_name = data_utils.rand_name( - name='TestDestinationContainer') - self.container_client.create_container(dst_container_name) - self.containers.append(dst_container_name) - # create object in source container - object_name = data_utils.rand_name(name='Object') - data = data_utils.random_bytes(size=len(object_name) * 2) - resp, _ = self.object_client.create_object(src_container_name, - object_name, data) - # set object metadata - meta_key = data_utils.rand_name(name='test') - meta_value = data_utils.rand_name(name='MetaValue') - orig_metadata = {meta_key: meta_value} - resp, _ = self.object_client.update_object_metadata(src_container_name, - object_name, - orig_metadata) - self.assertHeaders(resp, 'Object', 'POST') - - # copy object from source container to destination container - resp, _ = self.object_client.copy_object_across_containers( - src_container_name, object_name, dst_container_name, - object_name) - self.assertHeaders(resp, 'Object', 'PUT') - - # check if object is present in destination container - resp, body = self.object_client.get_object(dst_container_name, - object_name) - self.assertEqual(body, data) - actual_meta_key = 'x-object-meta-' + meta_key - self.assertIn(actual_meta_key, resp) - self.assertEqual(resp[actual_meta_key], meta_value) - - @decorators.idempotent_id('5a9e2cc6-85b6-46fc-916d-0cbb7a88e5fd') - def test_copy_object_with_x_fresh_metadata(self): - # create source object - metadata = {'x-object-meta-src': 'src_value'} - src_object_name, data = self.create_object(self.container_name, - metadata=metadata) - - # copy source object with x_fresh_metadata header - metadata = {'X-Fresh-Metadata': 'true'} - dst_object_name, resp = self._copy_object_2d(src_object_name, - metadata) - - self.assertHeaders(resp, 'Object', 'COPY') - - self.assertNotIn('x-object-meta-src', resp) - self.assertEqual(resp['x-copied-from'], - self.container_name + "/" + src_object_name) - - # check that destination object does NOT have any object-meta - self._check_copied_obj(dst_object_name, data, not_in_meta=["src"]) - - @decorators.idempotent_id('a28a8b99-e701-4d7e-9d84-3b66f121460b') - def test_copy_object_with_x_object_metakey(self): - # create source object - metadata = {'x-object-meta-src': 'src_value'} - src_obj_name, data = self.create_object(self.container_name, - metadata=metadata) - - # copy source object to destination with x-object-meta-key - metadata = {'x-object-meta-test': ''} - dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata) - - self.assertHeaders(resp, 'Object', 'COPY') - - expected = {'x-object-meta-test': '', - 'x-object-meta-src': 'src_value', - 'x-copied-from': self.container_name + "/" + src_obj_name} - for key, value in expected.items(): - self.assertIn(key, resp) - self.assertEqual(value, resp[key]) - - # check destination object - self._check_copied_obj(dst_obj_name, data, in_meta=["test", "src"]) - - @decorators.idempotent_id('edabedca-24c3-4322-9b70-d6d9f942a074') - def test_copy_object_with_x_object_meta(self): - # create source object - metadata = {'x-object-meta-src': 'src_value'} - src_obj_name, data = self.create_object(self.container_name, - metadata=metadata) - - # copy source object to destination with object metadata - metadata = {'x-object-meta-test': 'value'} - dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata) - - self.assertHeaders(resp, 'Object', 'COPY') - - expected = {'x-object-meta-test': 'value', - 'x-object-meta-src': 'src_value', - 'x-copied-from': self.container_name + "/" + src_obj_name} - for key, value in expected.items(): - self.assertIn(key, resp) - self.assertEqual(value, resp[key]) - - # check destination object - self._check_copied_obj(dst_obj_name, data, in_meta=["test", "src"]) - - @decorators.idempotent_id('e3e6a64a-9f50-4955-b987-6ce6767c97fb') - def test_object_upload_in_segments(self): - # create object - object_name = data_utils.rand_name(name='LObject') - data = data_utils.arbitrary_string() - segments = 10 - data_segments = [data + str(i) for i in range(segments)] - # uploading segments - for i in range(segments): - resp, _ = self.object_client.create_object_segments( - self.container_name, object_name, i, data_segments[i]) - # creating a manifest file - metadata = {'X-Object-Manifest': '%s/%s/' - % (self.container_name, object_name)} - resp, _ = self.object_client.create_object(self.container_name, - object_name, data='') - self.assertHeaders(resp, 'Object', 'PUT') - - resp, _ = self.object_client.update_object_metadata( - self.container_name, object_name, metadata, metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, object_name) - - # Etag value of a large object is enclosed in double-quotations. - # After etag quotes are checked they are removed and the response is - # checked if all common headers are present and well formatted - self.assertTrue(resp['etag'].startswith('\"')) - self.assertTrue(resp['etag'].endswith('\"')) - resp['etag'] = resp['etag'].strip('"') - self.assertHeaders(resp, 'Object', 'HEAD') - - self.assertIn('x-object-manifest', resp) - self.assertEqual(resp['x-object-manifest'], - '%s/%s/' % (self.container_name, object_name)) - - # downloading the object - resp, body = self.object_client.get_object( - self.container_name, object_name) - self.assertEqual(''.join(data_segments), body.decode()) - - @decorators.idempotent_id('50d01f12-526f-4360-9ac2-75dd508d7b68') - def test_get_object_if_different(self): - # http://en.wikipedia.org/wiki/HTTP_ETag - # Make a conditional request for an object using the If-None-Match - # header, it should get downloaded only if the local file is different, - # otherwise the response code should be 304 Not Modified - object_name, data = self.create_object(self.container_name) - # local copy is identical, no download - md5 = hashlib.md5(data).hexdigest() - headers = {'If-None-Match': md5} - url = "%s/%s" % (self.container_name, object_name) - resp, _ = self.object_client.get(url, headers=headers) - self.assertEqual(resp['status'], '304') - - # When the file is not downloaded from Swift server, response does - # not contain 'X-Timestamp' header. This is the special case, therefore - # the existence of response headers is checked without custom matcher. - self.assertIn('date', resp) - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) - - # local copy is different, download - local_data = "something different" - md5 = hashlib.md5(local_data.encode()).hexdigest() - headers = {'If-None-Match': md5} - resp, _ = self.object_client.get(url, headers=headers) - self.assertHeaders(resp, 'Object', 'GET') - - -class PublicObjectTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - @classmethod - def setup_credentials(cls): - super(PublicObjectTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_alt = cls.os_roles_operator_alt - - @classmethod - def setup_clients(cls): - super(PublicObjectTest, cls).setup_clients() - cls.identity_client_alt = cls.os_alt.identity_client - - def setUp(self): - super(PublicObjectTest, self).setUp() - self.container_name = data_utils.rand_name(name='TestContainer') - self.container_client.create_container(self.container_name) - - def tearDown(self): - self.delete_containers([self.container_name]) - super(PublicObjectTest, self).tearDown() - - @decorators.idempotent_id('07c9cf95-c0d4-4b49-b9c8-0ef2c9b27193') - def test_access_public_container_object_without_using_creds(self): - # make container public-readable and access an object in it object - # anonymously, without using credentials - - # update container metadata to make it publicly readable - cont_headers = {'X-Container-Read': '.r:*,.rlistings'} - resp_meta, body = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - - # create object - object_name = data_utils.rand_name(name='Object') - data = data_utils.random_bytes(size=len(object_name)) - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - self.assertHeaders(resp, 'Object', 'PUT') - - # list container metadata - resp_meta, _ = self.container_client.list_container_metadata( - self.container_name) - self.assertHeaders(resp_meta, 'Container', 'HEAD') - - self.assertIn('x-container-read', resp_meta) - self.assertEqual(resp_meta['x-container-read'], '.r:*,.rlistings') - - # trying to get object with empty headers as it is public readable - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - resp, body = self.object_client.get_object( - self.container_name, object_name) - self.assertHeaders(resp, 'Object', 'GET') - - self.assertEqual(body, data) - - @decorators.idempotent_id('54e2a2fe-42dc-491b-8270-8e4217dd4cdc') - def test_access_public_object_with_another_user_creds(self): - # make container public-readable and access an object in it using - # another user's credentials - cont_headers = {'X-Container-Read': '.r:*,.rlistings'} - resp_meta, body = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - - # create object - object_name = data_utils.rand_name(name='Object') - data = data_utils.random_bytes(size=len(object_name)) - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - self.assertHeaders(resp, 'Object', 'PUT') - - # list container metadata - resp, _ = self.container_client.list_container_metadata( - self.container_name) - self.assertHeaders(resp, 'Container', 'HEAD') - - self.assertIn('x-container-read', resp) - self.assertEqual(resp['x-container-read'], '.r:*,.rlistings') - - # get auth token of alternative user - alt_auth_data = self.identity_client_alt.auth_provider.auth_data - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=alt_auth_data - ) - # access object using alternate user creds - resp, body = self.object_client.get_object( - self.container_name, object_name) - self.assertHeaders(resp, 'Object', 'GET') - - self.assertEqual(body, data) diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py deleted file mode 100644 index 894e42d5b..000000000 --- a/tempest/api/object_storage/test_object_slo.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright 2013 NTT Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import hashlib - -from oslo_serialization import jsonutils as json - -from tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest import test - -# Each segment, except for the final one, must be at least 1 megabyte -MIN_SEGMENT_SIZE = 1024 * 1024 - - -class ObjectSloTest(base.BaseObjectTest): - - def setUp(self): - super(ObjectSloTest, self).setUp() - self.container_name = self.create_container() - self.objects = [] - - def tearDown(self): - for obj in self.objects: - test_utils.call_and_ignore_notfound_exc( - self.object_client.delete_object, - self.container_name, obj) - self.container_client.delete_container(self.container_name) - super(ObjectSloTest, self).tearDown() - - def _create_object(self, container_name, object_name, data, params=None): - resp, _ = self.object_client.create_object(container_name, - object_name, - data, - params) - self.objects.append(object_name) - - return resp - - def _create_manifest(self): - # Create a manifest file for SLO uploading - object_name = data_utils.rand_name(name='TestObject') - object_name_base_1 = object_name + '_01' - object_name_base_2 = object_name + '_02' - data_size = MIN_SEGMENT_SIZE - self.content = data_utils.random_bytes(data_size) - self._create_object(self.container_name, - object_name_base_1, - self.content) - self._create_object(self.container_name, - object_name_base_2, - self.content) - - path_object_1 = '/%s/%s' % (self.container_name, - object_name_base_1) - path_object_2 = '/%s/%s' % (self.container_name, - object_name_base_2) - data_manifest = [{'path': path_object_1, - 'etag': hashlib.md5(self.content).hexdigest(), - 'size_bytes': data_size}, - {'path': path_object_2, - 'etag': hashlib.md5(self.content).hexdigest(), - 'size_bytes': data_size}] - - return json.dumps(data_manifest) - - def _create_large_object(self): - # Create a large object for preparation of testing various SLO - # features - manifest = self._create_manifest() - - params = {'multipart-manifest': 'put'} - object_name = data_utils.rand_name(name='TestObject') - self._create_object(self.container_name, - object_name, - manifest, - params) - return object_name - - def _assertHeadersSLO(self, resp, method): - # When sending GET or HEAD requests to SLO the response contains - # 'X-Static-Large-Object' header - if method in ('GET', 'HEAD'): - self.assertIn('x-static-large-object', resp) - self.assertEqual(resp['x-static-large-object'], 'True') - - # Etag value of a large object is enclosed in double-quotations. - # After etag quotes are checked they are removed and the response is - # checked if all common headers are present and well formatted - self.assertTrue(resp['etag'].startswith('\"')) - self.assertTrue(resp['etag'].endswith('\"')) - resp['etag'] = resp['etag'].strip('"') - self.assertHeaders(resp, 'Object', method) - - @decorators.idempotent_id('2c3f24a6-36e8-4711-9aa2-800ee1fc7b5b') - @test.requires_ext(extension='slo', service='object') - def test_upload_manifest(self): - # create static large object from multipart manifest - manifest = self._create_manifest() - - params = {'multipart-manifest': 'put'} - object_name = data_utils.rand_name(name='TestObject') - resp = self._create_object(self.container_name, - object_name, - manifest, - params) - - self._assertHeadersSLO(resp, 'PUT') - - @decorators.idempotent_id('e69ad766-e1aa-44a2-bdd2-bf62c09c1456') - @test.requires_ext(extension='slo', service='object') - def test_list_large_object_metadata(self): - # list static large object metadata using multipart manifest - object_name = self._create_large_object() - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - - self._assertHeadersSLO(resp, 'HEAD') - - @decorators.idempotent_id('49bc49bc-dd1b-4c0f-904e-d9f10b830ee8') - @test.requires_ext(extension='slo', service='object') - def test_retrieve_large_object(self): - # list static large object using multipart manifest - object_name = self._create_large_object() - - resp, body = self.object_client.get_object( - self.container_name, - object_name) - - self._assertHeadersSLO(resp, 'GET') - - sum_data = self.content + self.content - self.assertEqual(body, sum_data) - - @decorators.idempotent_id('87b6dfa1-abe9-404d-8bf0-6c3751e6aa77') - @test.requires_ext(extension='slo', service='object') - def test_delete_large_object(self): - # delete static large object using multipart manifest - object_name = self._create_large_object() - - params_del = {'multipart-manifest': 'delete'} - resp, _ = self.object_client.delete_object( - self.container_name, - object_name, - params=params_del) - - # When deleting SLO using multipart manifest, the response contains - # not 'content-length' but 'transfer-encoding' header. This is the - # special case, therefore the existence of response headers is checked - # outside of custom matcher. - self.assertIn('transfer-encoding', resp) - self.assertIn('content-type', resp) - self.assertIn('x-trans-id', resp) - self.assertIn('date', resp) - - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) - - resp, body = self.container_client.list_container_contents( - self.container_name) - self.assertEqual(int(resp['x-container-object-count']), 0) diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py deleted file mode 100644 index 91bc6770c..000000000 --- a/tempest/api/object_storage/test_object_temp_url.py +++ /dev/null @@ -1,188 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import hashlib -import hmac -import time - -from six.moves.urllib import parse as urlparse - -from tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class ObjectTempUrlTest(base.BaseObjectTest): - - @classmethod - def resource_setup(cls): - super(ObjectTempUrlTest, cls).resource_setup() - # create a container - cls.container_name = cls.create_container() - - # update account metadata - cls.key = 'Meta' - cls.metadatas = [] - metadata = {'Temp-URL-Key': cls.key} - cls.metadatas.append(metadata) - cls.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - - # create an object - cls.object_name, cls.content = cls.create_object(cls.container_name) - - @classmethod - def resource_cleanup(cls): - for metadata in cls.metadatas: - cls.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata) - - cls.delete_containers() - - super(ObjectTempUrlTest, cls).resource_cleanup() - - def setUp(self): - super(ObjectTempUrlTest, self).setUp() - - # make sure the metadata has been set - account_client_metadata, _ = \ - self.account_client.list_account_metadata() - self.assertIn('x-account-meta-temp-url-key', - account_client_metadata) - self.assertEqual( - account_client_metadata['x-account-meta-temp-url-key'], - self.key) - - def _get_expiry_date(self, expiration_time=1000): - return int(time.time() + expiration_time) - - def _get_temp_url(self, container, object_name, method, expires, - key): - """Create the temporary URL.""" - - path = "%s/%s/%s" % ( - urlparse.urlparse(self.object_client.base_url).path, - container, object_name) - - hmac_body = '%s\n%s\n%s' % (method, expires, path) - sig = hmac.new( - key.encode(), hmac_body.encode(), hashlib.sha1 - ).hexdigest() - - url = "%s/%s?temp_url_sig=%s&temp_url_expires=%s" % (container, - object_name, - sig, expires) - - return url - - @decorators.idempotent_id('f91c96d4-1230-4bba-8eb9-84476d18d991') - @test.requires_ext(extension='tempurl', service='object') - def test_get_object_using_temp_url(self): - expires = self._get_expiry_date() - - # get a temp URL for the created object - url = self._get_temp_url(self.container_name, - self.object_name, "GET", - expires, self.key) - - # trying to get object using temp url within expiry time - resp, body = self.object_client.get(url) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, self.content) - - # Testing a HEAD on this Temp URL - resp, body = self.object_client.head(url) - self.assertHeaders(resp, 'Object', 'HEAD') - - @decorators.idempotent_id('671f9583-86bd-4128-a034-be282a68c5d8') - @test.requires_ext(extension='tempurl', service='object') - def test_get_object_using_temp_url_key_2(self): - key2 = 'Meta2-' - metadata = {'Temp-URL-Key-2': key2} - self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - self.metadatas.append(metadata) - - # make sure the metadata has been set - account_client_metadata, _ = \ - self.account_client.list_account_metadata() - self.assertIn('x-account-meta-temp-url-key-2', - account_client_metadata) - self.assertEqual( - account_client_metadata['x-account-meta-temp-url-key-2'], - key2) - - expires = self._get_expiry_date() - url = self._get_temp_url(self.container_name, - self.object_name, "GET", - expires, key2) - _, body = self.object_client.get(url) - self.assertEqual(body, self.content) - - @decorators.idempotent_id('9b08dade-3571-4152-8a4f-a4f2a873a735') - @test.requires_ext(extension='tempurl', service='object') - def test_put_object_using_temp_url(self): - new_data = data_utils.random_bytes(size=len(self.object_name)) - - expires = self._get_expiry_date() - url = self._get_temp_url(self.container_name, - self.object_name, "PUT", - expires, self.key) - - # trying to put random data in the object using temp url - resp, body = self.object_client.put(url, new_data, None) - self.assertHeaders(resp, 'Object', 'PUT') - - # Testing a HEAD on this Temp URL - resp, body = self.object_client.head(url) - self.assertHeaders(resp, 'Object', 'HEAD') - - # Validate that the content of the object has been modified - url = self._get_temp_url(self.container_name, - self.object_name, "GET", - expires, self.key) - - _, body = self.object_client.get(url) - self.assertEqual(body, new_data) - - @decorators.idempotent_id('249a0111-5ad3-4534-86a7-1993d55f9185') - @test.requires_ext(extension='tempurl', service='object') - def test_head_object_using_temp_url(self): - expires = self._get_expiry_date() - - # get a temp URL for the created object - url = self._get_temp_url(self.container_name, - self.object_name, "HEAD", - expires, self.key) - - # Testing a HEAD on this Temp URL - resp, _ = self.object_client.head(url) - self.assertHeaders(resp, 'Object', 'HEAD') - - @decorators.idempotent_id('9d9cfd90-708b-465d-802c-e4a8090b823d') - @test.requires_ext(extension='tempurl', service='object') - def test_get_object_using_temp_url_with_inline_query_parameter(self): - expires = self._get_expiry_date() - - # get a temp URL for the created object - url = self._get_temp_url(self.container_name, self.object_name, "GET", - expires, self.key) - url = url + '&inline' - - # trying to get object using temp url within expiry time - resp, body = self.object_client.get(url) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, self.content) - self.assertEqual(resp['content-disposition'], 'inline') diff --git a/tempest/api/object_storage/test_object_temp_url_negative.py b/tempest/api/object_storage/test_object_temp_url_negative.py deleted file mode 100644 index 3edaa8665..000000000 --- a/tempest/api/object_storage/test_object_temp_url_negative.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import hashlib -import hmac -import time - -from six.moves.urllib import parse as urlparse - -from tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class ObjectTempUrlNegativeTest(base.BaseObjectTest): - - metadata = {} - containers = [] - - @classmethod - def resource_setup(cls): - super(ObjectTempUrlNegativeTest, cls).resource_setup() - - cls.container_name = cls.create_container() - - # update account metadata - cls.key = 'Meta' - cls.metadata = {'Temp-URL-Key': cls.key} - cls.account_client.create_update_or_delete_account_metadata( - create_update_metadata=cls.metadata) - cls.account_client_metadata, _ = \ - cls.account_client.list_account_metadata() - - @classmethod - def resource_cleanup(cls): - cls.account_client.create_update_or_delete_account_metadata( - delete_metadata=cls.metadata) - - cls.delete_containers() - - super(ObjectTempUrlNegativeTest, cls).resource_cleanup() - - def setUp(self): - super(ObjectTempUrlNegativeTest, self).setUp() - # make sure the metadata has been set - self.assertIn('x-account-meta-temp-url-key', - self.account_client_metadata) - - self.assertEqual( - self.account_client_metadata['x-account-meta-temp-url-key'], - self.key) - - # create object - self.object_name = data_utils.rand_name(name='ObjectTemp') - self.content = data_utils.arbitrary_string(size=len(self.object_name), - base_text=self.object_name) - self.object_client.create_object(self.container_name, - self.object_name, self.content) - - def _get_expiry_date(self, expiration_time=1000): - return int(time.time() + expiration_time) - - def _get_temp_url(self, container, object_name, method, expires, - key): - """Create the temporary URL.""" - - path = "%s/%s/%s" % ( - urlparse.urlparse(self.object_client.base_url).path, - container, object_name) - - hmac_body = '%s\n%s\n%s' % (method, expires, path) - sig = hmac.new( - key.encode(), hmac_body.encode(), hashlib.sha1 - ).hexdigest() - - url = "%s/%s?temp_url_sig=%s&temp_url_expires=%s" % (container, - object_name, - sig, expires) - - return url - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5a583aca-c804-41ba-9d9a-e7be132bdf0b') - @test.requires_ext(extension='tempurl', service='object') - def test_get_object_after_expiration_time(self): - - expires = self._get_expiry_date(1) - # get a temp URL for the created object - url = self._get_temp_url(self.container_name, - self.object_name, "GET", - expires, self.key) - - # temp URL is valid for 1 seconds, let's wait 2 - time.sleep(2) - - self.assertRaises(lib_exc.Unauthorized, - self.object_client.get, url) diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py deleted file mode 100644 index dc0d179ec..000000000 --- a/tempest/api/object_storage/test_object_version.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ContainerTest(base.BaseObjectTest): - @classmethod - def resource_setup(cls): - super(ContainerTest, cls).resource_setup() - cls.containers = [] - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(ContainerTest, cls).resource_cleanup() - - def assertContainer(self, container, count, byte, versioned): - resp, _ = self.container_client.list_container_metadata(container) - self.assertHeaders(resp, 'Container', 'HEAD') - header_value = resp.get('x-container-object-count', 'Missing Header') - self.assertEqual(header_value, count) - header_value = resp.get('x-container-bytes-used', 'Missing Header') - self.assertEqual(header_value, byte) - header_value = resp.get('x-versions-location', 'Missing Header') - self.assertEqual(header_value, versioned) - - @decorators.idempotent_id('a151e158-dcbf-4a1f-a1e7-46cd65895a6f') - @testtools.skipIf( - not CONF.object_storage_feature_enabled.object_versioning, - 'Object-versioning is disabled') - def test_versioned_container(self): - # create container - vers_container_name = data_utils.rand_name(name='TestVersionContainer') - resp, body = self.container_client.create_container( - vers_container_name) - self.containers.append(vers_container_name) - self.assertHeaders(resp, 'Container', 'PUT') - self.assertContainer(vers_container_name, '0', '0', 'Missing Header') - - base_container_name = data_utils.rand_name(name='TestBaseContainer') - headers = {'X-versions-Location': vers_container_name} - resp, body = self.container_client.create_container( - base_container_name, - metadata=headers, - metadata_prefix='') - self.containers.append(base_container_name) - self.assertHeaders(resp, 'Container', 'PUT') - self.assertContainer(base_container_name, '0', '0', - vers_container_name) - object_name = data_utils.rand_name(name='TestObject') - # create object - data_1 = data_utils.random_bytes() - resp, _ = self.object_client.create_object(base_container_name, - object_name, data_1) - # create 2nd version of object - data_2 = data_utils.random_bytes() - resp, _ = self.object_client.create_object(base_container_name, - object_name, data_2) - resp, body = self.object_client.get_object(base_container_name, - object_name) - self.assertEqual(body, data_2) - # delete object version 2 - resp, _ = self.object_client.delete_object(base_container_name, - object_name) - self.assertContainer(base_container_name, '1', '1024', - vers_container_name) - resp, body = self.object_client.get_object(base_container_name, - object_name) - self.assertEqual(body, data_1) - # delete object version 1 - resp, _ = self.object_client.delete_object(base_container_name, - object_name) - # containers should be empty - self.assertContainer(base_container_name, '0', '0', - vers_container_name) - self.assertContainer(vers_container_name, '0', '0', - 'Missing Header') diff --git a/tempest/api/volume/__init__.py b/tempest/api/volume/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/volume/admin/__init__.py b/tempest/api/volume/admin/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/volume/admin/test_backends_capabilities.py b/tempest/api/volume/admin/test_backends_capabilities.py deleted file mode 100644 index 607fc43e6..000000000 --- a/tempest/api/volume/admin/test_backends_capabilities.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import operator - -from tempest.api.volume import base -from tempest.lib import decorators - - -class BackendsCapabilitiesAdminTestsJSON(base.BaseVolumeAdminTest): - - CAPABILITIES = ('namespace', - 'vendor_name', - 'volume_backend_name', - 'pool_name', - 'driver_version', - 'storage_protocol', - 'display_name', - 'description', - 'visibility', - 'properties') - - @classmethod - def resource_setup(cls): - super(BackendsCapabilitiesAdminTestsJSON, cls).resource_setup() - # Get host list, formation: host@backend-name - cls.hosts = [ - pool['name'] for pool in - cls.admin_scheduler_stats_client.list_pools()['pools'] - ] - - @decorators.idempotent_id('3750af44-5ea2-4cd4-bc3e-56e7e6caf854') - def test_get_capabilities_backend(self): - # Test backend properties - backend = self.admin_capabilities_client.show_backend_capabilities( - self.hosts[0]) - - # Verify getting capabilities parameters from a backend - for key in self.CAPABILITIES: - self.assertIn(key, backend) - - @decorators.idempotent_id('a9035743-d46a-47c5-9cb7-3c80ea16dea0') - def test_compare_volume_stats_values(self): - # Test values comparison between show_backend_capabilities - # to show_pools - VOLUME_STATS = ('vendor_name', - 'volume_backend_name', - 'storage_protocol') - - # Get list backend capabilities using show_pools - cinder_pools = [ - pool['capabilities'] for pool in - self.admin_scheduler_stats_client.list_pools(detail=True)['pools'] - ] - - # Get list backends capabilities using show_backend_capabilities - capabilities = [ - self.admin_capabilities_client.show_backend_capabilities( - host=host) for host in self.hosts - ] - - # Returns a tuple of VOLUME_STATS values - expected_list = list(map(operator.itemgetter(*VOLUME_STATS), - cinder_pools)) - observed_list = list(map(operator.itemgetter(*VOLUME_STATS), - capabilities)) - self.assertEqual(expected_list, observed_list) diff --git a/tempest/api/volume/admin/test_group_types.py b/tempest/api/volume/admin/test_group_types.py deleted file mode 100644 index 0df5fbd88..000000000 --- a/tempest/api/volume/admin/test_group_types.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class GroupTypesTest(base.BaseVolumeAdminTest): - _api_version = 3 - min_microversion = '3.11' - max_microversion = 'latest' - - @decorators.idempotent_id('dd71e5f9-393e-4d4f-90e9-fa1b8d278864') - def test_group_type_create_list_show(self): - # Create/list/show group type. - name = data_utils.rand_name(self.__class__.__name__ + '-group-type') - description = data_utils.rand_name("group-type-description") - group_specs = {"consistent_group_snapshot_enabled": " False"} - params = {'name': name, - 'description': description, - 'group_specs': group_specs, - 'is_public': True} - body = self.create_group_type(**params) - self.assertIn('name', body) - err_msg = ("The created group_type %(var)s is not equal to the " - "requested %(var)s") - self.assertEqual(name, body['name'], err_msg % {"var": "name"}) - self.assertEqual(description, body['description'], - err_msg % {"var": "description"}) - - group_list = ( - self.admin_group_types_client.list_group_types()['group_types']) - self.assertIsInstance(group_list, list) - self.assertNotEmpty(group_list) - - fetched_group_type = self.admin_group_types_client.show_group_type( - body['id'])['group_type'] - for key in params.keys(): - self.assertEqual(params[key], fetched_group_type[key], - '%s of the fetched group_type is different ' - 'from the created group_type' % key) diff --git a/tempest/api/volume/admin/test_groups.py b/tempest/api/volume/admin/test_groups.py deleted file mode 100644 index 8609bdb30..000000000 --- a/tempest/api/volume/admin/test_groups.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class GroupsTest(base.BaseVolumeAdminTest): - _api_version = 3 - min_microversion = '3.14' - max_microversion = 'latest' - - def _delete_group(self, grp_id, delete_volumes=True): - self.admin_groups_client.delete_group(grp_id, delete_volumes) - vols = self.admin_volume_client.list_volumes(detail=True)['volumes'] - for vol in vols: - if vol['group_id'] == grp_id: - self.admin_volume_client.wait_for_resource_deletion(vol['id']) - self.admin_groups_client.wait_for_resource_deletion(grp_id) - - @decorators.idempotent_id('4b111d28-b73d-4908-9bd2-03dc2992e4d4') - def test_group_create_show_list_delete(self): - # Create volume type - volume_type = self.create_volume_type() - - # Create group type - group_type = self.create_group_type() - - # Create group - grp1_name = data_utils.rand_name('Group1') - grp1 = self.admin_groups_client.create_group( - group_type=group_type['id'], - volume_types=[volume_type['id']], - name=grp1_name)['group'] - waiters.wait_for_volume_resource_status( - self.admin_groups_client, grp1['id'], 'available') - grp1_id = grp1['id'] - - grp2_name = data_utils.rand_name('Group2') - grp2 = self.admin_groups_client.create_group( - group_type=group_type['id'], - volume_types=[volume_type['id']], - name=grp2_name)['group'] - waiters.wait_for_volume_resource_status( - self.admin_groups_client, grp2['id'], 'available') - grp2_id = grp2['id'] - - # Create volume - vol1_name = data_utils.rand_name("volume") - params = {'name': vol1_name, - 'volume_type': volume_type['id'], - 'group_id': grp1['id'], - 'size': CONF.volume.volume_size} - vol1 = self.admin_volume_client.create_volume(**params)['volume'] - self.assertEqual(grp1['id'], vol1['group_id']) - waiters.wait_for_volume_resource_status( - self.admin_volume_client, vol1['id'], 'available') - vol1_id = vol1['id'] - - # Get a given group - grp1 = self.admin_groups_client.show_group(grp1['id'])['group'] - self.assertEqual(grp1_name, grp1['name']) - self.assertEqual(grp1_id, grp1['id']) - - grp2 = self.admin_groups_client.show_group(grp2['id'])['group'] - self.assertEqual(grp2_name, grp2['name']) - self.assertEqual(grp2_id, grp2['id']) - - # Get all groups with detail - grps = self.admin_groups_client.list_groups( - detail=True)['groups'] - filtered_grps = [g for g in grps if g['id'] in [grp1_id, grp2_id]] - self.assertEqual(2, len(filtered_grps)) - for grp in filtered_grps: - self.assertEqual([volume_type['id']], grp['volume_types']) - self.assertEqual(group_type['id'], grp['group_type']) - - vols = self.admin_volume_client.list_volumes( - detail=True)['volumes'] - filtered_vols = [v for v in vols if v['id'] in [vol1_id]] - self.assertEqual(1, len(filtered_vols)) - for vol in filtered_vols: - self.assertEqual(grp1_id, vol['group_id']) - - # Delete group - # grp1 has a volume so delete_volumes flag is set to True by default - self._delete_group(grp1_id) - # grp2 is empty so delete_volumes flag can be set to False - self._delete_group(grp2_id, delete_volumes=False) - grps = self.admin_groups_client.list_groups( - detail=True)['groups'] - self.assertEmpty(grps) diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py deleted file mode 100644 index 2db801025..000000000 --- a/tempest/api/volume/admin/test_multi_backend.py +++ /dev/null @@ -1,141 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumeMultiBackendTest(base.BaseVolumeAdminTest): - - @classmethod - def skip_checks(cls): - super(VolumeMultiBackendTest, cls).skip_checks() - - if not CONF.volume_feature_enabled.multi_backend: - raise cls.skipException("Cinder multi-backend feature disabled") - - @classmethod - def resource_setup(cls): - super(VolumeMultiBackendTest, cls).resource_setup() - - # read backend name from a list . - backend_names = set(CONF.volume.backend_names) - - cls.volume_id_list_with_prefix = [] - cls.volume_id_list_without_prefix = [] - - # Volume/Type creation (uses volume_backend_name) - # It is not allowed to create the same backend name twice - if len(backend_names) < 2: - raise cls.skipException("Requires at least two different " - "backend names") - for backend_name in backend_names: - # Volume/Type creation (uses backend_name) - cls._create_type_and_volume(backend_name, False) - # Volume/Type creation (uses capabilities:volume_backend_name) - cls._create_type_and_volume(backend_name, True) - - @classmethod - def _create_type_and_volume(cls, backend_name_key, with_prefix): - # Volume/Type creation - type_name = data_utils.rand_name(cls.__name__ + '-Type') - vol_name = data_utils.rand_name(cls.__name__ + '-Volume') - spec_key_with_prefix = "capabilities:volume_backend_name" - spec_key_without_prefix = "volume_backend_name" - if with_prefix: - extra_specs = {spec_key_with_prefix: backend_name_key} - else: - extra_specs = {spec_key_without_prefix: backend_name_key} - cls.create_volume_type(name=type_name, - extra_specs=extra_specs) - - params = {'name': vol_name, 'volume_type': type_name, - 'size': CONF.volume.volume_size} - cls.volume = cls.admin_volume_client.create_volume( - **params)['volume'] - if with_prefix: - cls.volume_id_list_with_prefix.append(cls.volume['id']) - else: - cls.volume_id_list_without_prefix.append( - cls.volume['id']) - waiters.wait_for_volume_resource_status(cls.admin_volume_client, - cls.volume['id'], 'available') - - @classmethod - def resource_cleanup(cls): - # volumes deletion - vid_prefix = getattr(cls, 'volume_id_list_with_prefix', []) - for volume_id in vid_prefix: - cls.admin_volume_client.delete_volume(volume_id) - cls.admin_volume_client.wait_for_resource_deletion(volume_id) - - vid_no_pre = getattr(cls, 'volume_id_list_without_prefix', []) - for volume_id in vid_no_pre: - cls.admin_volume_client.delete_volume(volume_id) - cls.admin_volume_client.wait_for_resource_deletion(volume_id) - - super(VolumeMultiBackendTest, cls).resource_cleanup() - - @decorators.idempotent_id('c1a41f3f-9dad-493e-9f09-3ff197d477cc') - def test_backend_name_reporting(self): - # get volume id which created by type without prefix - for volume_id in self.volume_id_list_without_prefix: - self._test_backend_name_reporting_by_volume_id(volume_id) - - @decorators.idempotent_id('f38e647f-ab42-4a31-a2e7-ca86a6485215') - def test_backend_name_reporting_with_prefix(self): - # get volume id which created by type with prefix - for volume_id in self.volume_id_list_with_prefix: - self._test_backend_name_reporting_by_volume_id(volume_id) - - @decorators.idempotent_id('46435ab1-a0af-4401-8373-f14e66b0dd58') - def test_backend_name_distinction(self): - # get volume ids which created by type without prefix - self._test_backend_name_distinction(self.volume_id_list_without_prefix) - - @decorators.idempotent_id('4236305b-b65a-4bfc-a9d2-69cb5b2bf2ed') - def test_backend_name_distinction_with_prefix(self): - # get volume ids which created by type without prefix - self._test_backend_name_distinction(self.volume_id_list_with_prefix) - - def _get_volume_host(self, volume_id): - return self.admin_volume_client.show_volume( - volume_id)['volume']['os-vol-host-attr:host'] - - def _test_backend_name_reporting_by_volume_id(self, volume_id): - # this test checks if os-vol-attr:host is populated correctly after - # the multi backend feature has been enabled - # if multi-backend is enabled: os-vol-attr:host should be like: - # host@backend_name - volume = self.admin_volume_client.show_volume(volume_id)['volume'] - - volume1_host = volume['os-vol-host-attr:host'] - msg = ("multi-backend reporting incorrect values for volume %s" % - volume_id) - self.assertGreater(len(volume1_host.split("@")), 1, msg) - - def _test_backend_name_distinction(self, volume_id_list): - # this test checks that the volumes created at setUp don't - # belong to the same backend (if they are, than the - # volume backend distinction is not working properly) - volume_hosts = [self._get_volume_host(volume) for volume in - volume_id_list] - # assert that volumes are each created on separate hosts: - msg = ("volumes %s were created in the same backend" % ", " - .join(volume_hosts)) - six.assertCountEqual(self, volume_hosts, set(volume_hosts), msg) diff --git a/tempest/api/volume/admin/test_qos.py b/tempest/api/volume/admin/test_qos.py deleted file mode 100644 index e31c0ef29..000000000 --- a/tempest/api/volume/admin/test_qos.py +++ /dev/null @@ -1,159 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.common import waiters -from tempest.lib.common.utils import data_utils as utils -from tempest.lib import decorators - - -class QosSpecsTestJSON(base.BaseVolumeAdminTest): - """Test the Cinder QoS-specs. - - Tests for create, list, delete, show, associate, - disassociate, set/unset key APIs. - """ - - @classmethod - def resource_setup(cls): - super(QosSpecsTestJSON, cls).resource_setup() - # Create admin qos client - # Create a test shared qos-specs for tests - cls.qos_name = utils.rand_name(cls.__name__ + '-QoS') - cls.qos_consumer = 'front-end' - - cls.created_qos = cls.create_test_qos_specs(cls.qos_name, - cls.qos_consumer, - read_iops_sec='2000') - - def _create_delete_test_qos_with_given_consumer(self, consumer): - name = utils.rand_name(self.__class__.__name__ + '-qos') - qos = {'name': name, 'consumer': consumer} - body = self.create_test_qos_specs(name, consumer) - for key in ['name', 'consumer']: - self.assertEqual(qos[key], body[key]) - - self.admin_volume_qos_client.delete_qos(body['id']) - self.admin_volume_qos_client.wait_for_resource_deletion(body['id']) - - # validate the deletion - list_qos = self.admin_volume_qos_client.list_qos()['qos_specs'] - self.assertNotIn(body, list_qos) - - def _test_associate_qos(self, vol_type_id): - self.admin_volume_qos_client.associate_qos( - self.created_qos['id'], vol_type_id) - - @decorators.idempotent_id('7e15f883-4bef-49a9-95eb-f94209a1ced1') - def test_create_delete_qos_with_front_end_consumer(self): - """Tests the creation and deletion of QoS specs - - With consumer as front end - """ - self._create_delete_test_qos_with_given_consumer('front-end') - - @decorators.idempotent_id('b115cded-8f58-4ee4-aab5-9192cfada08f') - def test_create_delete_qos_with_back_end_consumer(self): - """Tests the creation and deletion of QoS specs - - With consumer as back-end - """ - self._create_delete_test_qos_with_given_consumer('back-end') - - @decorators.idempotent_id('f88d65eb-ea0d-487d-af8d-71f4011575a4') - def test_create_delete_qos_with_both_consumer(self): - """Tests the creation and deletion of QoS specs - - With consumer as both front end and back end - """ - self._create_delete_test_qos_with_given_consumer('both') - - @decorators.idempotent_id('7aa214cc-ac1a-4397-931f-3bb2e83bb0fd') - def test_get_qos(self): - """Tests the detail of a given qos-specs""" - body = self.admin_volume_qos_client.show_qos( - self.created_qos['id'])['qos_specs'] - self.assertEqual(self.qos_name, body['name']) - self.assertEqual(self.qos_consumer, body['consumer']) - - @decorators.idempotent_id('75e04226-bcf7-4595-a34b-fdf0736f38fc') - def test_list_qos(self): - """Tests the list of all qos-specs""" - body = self.admin_volume_qos_client.list_qos()['qos_specs'] - self.assertIn(self.created_qos, body) - - @decorators.idempotent_id('ed00fd85-4494-45f2-8ceb-9e2048919aed') - def test_set_unset_qos_key(self): - """Test the addition of a specs key to qos-specs""" - args = {'iops_bytes': '500'} - body = self.admin_volume_qos_client.set_qos_key( - self.created_qos['id'], - iops_bytes='500')['qos_specs'] - self.assertEqual(args, body) - body = self.admin_volume_qos_client.show_qos( - self.created_qos['id'])['qos_specs'] - self.assertEqual(args['iops_bytes'], body['specs']['iops_bytes']) - - # test the deletion of a specs key from qos-specs - keys = ['iops_bytes'] - self.admin_volume_qos_client.unset_qos_key(self.created_qos['id'], - keys) - operation = 'qos-key-unset' - waiters.wait_for_qos_operations(self.admin_volume_qos_client, - self.created_qos['id'], - operation, keys) - body = self.admin_volume_qos_client.show_qos( - self.created_qos['id'])['qos_specs'] - self.assertNotIn(keys[0], body['specs']) - - @decorators.idempotent_id('1dd93c76-6420-485d-a771-874044c416ac') - def test_associate_disassociate_qos(self): - """Test the following operations : - - 1. associate_qos - 2. get_association_qos - 3. disassociate_qos - 4. disassociate_all_qos - """ - - # create a test volume-type - vol_type = [] - for _ in range(0, 3): - vol_type.append(self.create_volume_type()) - - # associate the qos-specs with volume-types - for i in range(0, 3): - self._test_associate_qos(vol_type[i]['id']) - - # get the association of the qos-specs - body = self.admin_volume_qos_client.show_association_qos( - self.created_qos['id'])['qos_associations'] - associations = [association['id'] for association in body] - for i in range(0, 3): - self.assertIn(vol_type[i]['id'], associations) - - # disassociate a volume-type with qos-specs - self.admin_volume_qos_client.disassociate_qos( - self.created_qos['id'], vol_type[0]['id']) - operation = 'disassociate' - waiters.wait_for_qos_operations(self.admin_volume_qos_client, - self.created_qos['id'], operation, - vol_type[0]['id']) - - # disassociate all volume-types from qos-specs - self.admin_volume_qos_client.disassociate_all_qos( - self.created_qos['id']) - operation = 'disassociate-all' - waiters.wait_for_qos_operations(self.admin_volume_qos_client, - self.created_qos['id'], operation) diff --git a/tempest/api/volume/admin/test_snapshot_manage.py b/tempest/api/volume/admin/test_snapshot_manage.py deleted file mode 100644 index 9ff7160a4..000000000 --- a/tempest/api/volume/admin/test_snapshot_manage.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class SnapshotManageAdminTest(base.BaseVolumeAdminTest): - """Unmanage & manage snapshots - - This feature provides the ability to import/export volume snapshot - from one Cinder to another and to import snapshots that have not been - managed by Cinder from a storage back end to Cinder - """ - - @classmethod - def skip_checks(cls): - super(SnapshotManageAdminTest, cls).skip_checks() - - if not CONF.volume_feature_enabled.manage_snapshot: - raise cls.skipException("Manage snapshot tests are disabled") - - if len(CONF.volume.manage_snapshot_ref) != 2: - msg = ("Manage snapshot ref is not correctly configured, " - "it should be a list of two elements") - raise exceptions.InvalidConfiguration(msg) - - @decorators.idempotent_id('0132f42d-0147-4b45-8501-cc504bbf7810') - def test_unmanage_manage_snapshot(self): - # Create a volume - volume = self.create_volume() - - # Create a snapshot - snapshot = self.create_snapshot(volume_id=volume['id']) - - # Unmanage the snapshot - # Unmanage snapshot function works almost the same as delete snapshot, - # but it does not delete the snapshot data - self.admin_snapshots_client.unmanage_snapshot(snapshot['id']) - self.admin_snapshots_client.wait_for_resource_deletion(snapshot['id']) - - # Verify the original snapshot does not exist in snapshot list - params = {'all_tenants': 1} - all_snapshots = self.admin_snapshots_client.list_snapshots( - detail=True, params=params)['snapshots'] - self.assertNotIn(snapshot['id'], [v['id'] for v in all_snapshots]) - - # Manage the snapshot - name = data_utils.rand_name(self.__class__.__name__ + - '-Managed-Snapshot') - description = data_utils.rand_name(self.__class__.__name__ + - '-Managed-Snapshot-Description') - metadata = {"manage-snap-meta1": "value1", - "manage-snap-meta2": "value2", - "manage-snap-meta3": "value3"} - snapshot_ref = { - 'volume_id': volume['id'], - 'ref': {CONF.volume.manage_snapshot_ref[0]: - CONF.volume.manage_snapshot_ref[1] % snapshot['id']}, - 'name': name, - 'description': description, - 'metadata': metadata - } - new_snapshot = self.admin_snapshot_manage_client.manage_snapshot( - **snapshot_ref)['snapshot'] - self.addCleanup(self.delete_snapshot, new_snapshot['id'], - self.admin_snapshots_client) - - # Wait for the snapshot to be available after manage operation - waiters.wait_for_volume_resource_status(self.admin_snapshots_client, - new_snapshot['id'], - 'available') - - # Verify the managed snapshot has the expected parent volume - # and the expected field values. - new_snapshot_info = self.admin_snapshots_client.show_snapshot( - new_snapshot['id'])['snapshot'] - self.assertEqual(snapshot['size'], new_snapshot_info['size']) - for key in ['volume_id', 'name', 'description', 'metadata']: - self.assertEqual(snapshot_ref[key], new_snapshot_info[key]) diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py deleted file mode 100644 index 471f39a11..000000000 --- a/tempest/api/volume/admin/test_snapshots_actions.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class SnapshotsActionsTest(base.BaseVolumeAdminTest): - @classmethod - def skip_checks(cls): - super(SnapshotsActionsTest, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder snapshot feature disabled") - - @classmethod - def resource_setup(cls): - super(SnapshotsActionsTest, cls).resource_setup() - - # Create a test shared volume for tests - cls.volume = cls.create_volume() - - # Create a test shared snapshot for tests - cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id']) - - def tearDown(self): - # Set snapshot's status to available after test - status = 'available' - snapshot_id = self.snapshot['id'] - self.admin_snapshots_client.reset_snapshot_status(snapshot_id, - status) - super(SnapshotsActionsTest, self).tearDown() - - def _create_reset_and_force_delete_temp_snapshot(self, status=None): - # Create snapshot, reset snapshot status, - # and force delete temp snapshot - temp_snapshot = self.create_snapshot(volume_id=self.volume['id']) - if status: - self.admin_snapshots_client.\ - reset_snapshot_status(temp_snapshot['id'], status) - self.admin_snapshots_client.\ - force_delete_snapshot(temp_snapshot['id']) - self.snapshots_client.wait_for_resource_deletion(temp_snapshot['id']) - - def _get_progress_alias(self): - return 'os-extended-snapshot-attributes:progress' - - @decorators.idempotent_id('3e13ca2f-48ea-49f3-ae1a-488e9180d535') - def test_reset_snapshot_status(self): - # Reset snapshot status to creating - status = 'creating' - self.admin_snapshots_client.\ - reset_snapshot_status(self.snapshot['id'], status) - snapshot_get = self.admin_snapshots_client.show_snapshot( - self.snapshot['id'])['snapshot'] - self.assertEqual(status, snapshot_get['status']) - - @decorators.idempotent_id('41288afd-d463-485e-8f6e-4eea159413eb') - def test_update_snapshot_status(self): - # Reset snapshot status to creating - status = 'creating' - self.admin_snapshots_client.\ - reset_snapshot_status(self.snapshot['id'], status) - - # Update snapshot status to error - progress = '80%' - status = 'error' - progress_alias = self._get_progress_alias() - self.snapshots_client.update_snapshot_status(self.snapshot['id'], - status=status, - progress=progress) - snapshot_get = self.admin_snapshots_client.show_snapshot( - self.snapshot['id'])['snapshot'] - self.assertEqual(status, snapshot_get['status']) - self.assertEqual(progress, snapshot_get[progress_alias]) - - @decorators.idempotent_id('05f711b6-e629-4895-8103-7ca069f2073a') - def test_snapshot_force_delete_when_snapshot_is_creating(self): - # test force delete when status of snapshot is creating - self._create_reset_and_force_delete_temp_snapshot('creating') - - @decorators.idempotent_id('92ce8597-b992-43a1-8868-6316b22a969e') - def test_snapshot_force_delete_when_snapshot_is_deleting(self): - # test force delete when status of snapshot is deleting - self._create_reset_and_force_delete_temp_snapshot('deleting') - - @decorators.idempotent_id('645a4a67-a1eb-4e8e-a547-600abac1525d') - def test_snapshot_force_delete_when_snapshot_is_error(self): - # test force delete when status of snapshot is error - self._create_reset_and_force_delete_temp_snapshot('error') - - @decorators.idempotent_id('bf89080f-8129-465e-9327-b2f922666ba5') - def test_snapshot_force_delete_when_snapshot_is_error_deleting(self): - # test force delete when status of snapshot is error_deleting - self._create_reset_and_force_delete_temp_snapshot('error_deleting') diff --git a/tempest/api/volume/admin/test_user_messages.py b/tempest/api/volume/admin/test_user_messages.py deleted file mode 100755 index 20c3538cd..000000000 --- a/tempest/api/volume/admin/test_user_messages.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2016 Andrew Kerr -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - -MESSAGE_KEYS = [ - 'created_at', - 'event_id', - 'guaranteed_until', - 'id', - 'message_level', - 'request_id', - 'resource_type', - 'resource_uuid', - 'user_message', - 'links'] - - -class UserMessagesTest(base.BaseVolumeAdminTest): - _api_version = 3 - min_microversion = '3.3' - max_microversion = 'latest' - - def _create_user_message(self): - """Trigger a 'no valid host' situation to generate a message.""" - bad_protocol = data_utils.rand_name('storage_protocol') - bad_vendor = data_utils.rand_name('vendor_name') - extra_specs = {'storage_protocol': bad_protocol, - 'vendor_name': bad_vendor} - vol_type_name = data_utils.rand_name( - self.__class__.__name__ + '-volume-type') - bogus_type = self.create_volume_type( - name=vol_type_name, extra_specs=extra_specs) - params = {'volume_type': bogus_type['id'], - 'size': CONF.volume.volume_size} - volume = self.create_volume(wait_until="error", **params) - messages = self.messages_client.list_messages()['messages'] - message_id = None - for message in messages: - if message['resource_uuid'] == volume['id']: - message_id = message['id'] - break - self.assertIsNotNone(message_id, 'No user message generated for ' - 'volume %s' % volume['id']) - return message_id - - @decorators.idempotent_id('50f29e6e-f363-42e1-8ad1-f67ae7fd4d5a') - def test_list_messages(self): - self._create_user_message() - messages = self.messages_client.list_messages()['messages'] - self.assertIsInstance(messages, list) - for message in messages: - for key in MESSAGE_KEYS: - self.assertIn(key, message.keys(), - 'Missing expected key %s' % key) - - @decorators.idempotent_id('55a4a61e-c7b2-4ba0-a05d-b914bdef3070') - def test_show_message(self): - message_id = self._create_user_message() - self.addCleanup(self.messages_client.delete_message, message_id) - - message = self.messages_client.show_message(message_id)['message'] - - for key in MESSAGE_KEYS: - self.assertIn(key, message.keys(), 'Missing expected key %s' % key) - - @decorators.idempotent_id('c6eb6901-cdcc-490f-b735-4fe251842aed') - def test_delete_message(self): - message_id = self._create_user_message() - self.messages_client.delete_message(message_id) - self.messages_client.wait_for_resource_deletion(message_id) diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py deleted file mode 100644 index e4ec44264..000000000 --- a/tempest/api/volume/admin/test_volume_hosts.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import random - -from tempest.api.volume import base -from tempest.lib import decorators - - -class VolumeHostsAdminTestsJSON(base.BaseVolumeAdminTest): - - @decorators.idempotent_id('d5f3efa2-6684-4190-9ced-1c2f526352ad') - def test_list_hosts(self): - hosts = self.admin_hosts_client.list_hosts()['hosts'] - self.assertGreaterEqual(len(hosts), 2, - "The count of volume hosts is < 2, " - "response of list hosts is: %s" % hosts) - - # Check elements in volume hosts list - host_list_keys = ['service', 'host_name', 'last-update', - 'zone', 'service-status', 'service-state'] - for host in hosts: - for key in host_list_keys: - self.assertIn(key, host) - - @decorators.idempotent_id('21168d57-b373-4b71-a3ac-f2c88f0c5d31') - def test_show_host(self): - hosts = self.admin_hosts_client.list_hosts()['hosts'] - self.assertGreaterEqual(len(hosts), 2, - "The count of volume hosts is < 2, " - "response of list hosts is: %s" % hosts) - - # Note(jeremyZ): Host in volume is always presented in two formats: - # or @. Since Mitaka is EOL, - # both formats can be chosen for test. - host_names = [host['host_name'] for host in hosts] - self.assertNotEmpty(host_names, "No available volume host is found, " - "all hosts that found are: %s" % hosts) - - # Choose a random host to get and check its elements - host_details = self.admin_hosts_client.show_host( - random.choice(host_names))['host'] - self.assertNotEmpty(host_details) - host_detail_keys = ['project', 'volume_count', 'snapshot_count', - 'host', 'total_volume_gb', 'total_snapshot_gb'] - for detail in host_details: - self.assertIn('resource', detail) - for key in host_detail_keys: - self.assertIn(key, detail['resource']) diff --git a/tempest/api/volume/admin/test_volume_manage.py b/tempest/api/volume/admin/test_volume_manage.py deleted file mode 100644 index 4b352e0c5..000000000 --- a/tempest/api/volume/admin/test_volume_manage.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class VolumeManageAdminTest(base.BaseVolumeAdminTest): - - @classmethod - def skip_checks(cls): - super(VolumeManageAdminTest, cls).skip_checks() - - if not CONF.volume_feature_enabled.manage_volume: - raise cls.skipException("Manage volume tests are disabled") - - if len(CONF.volume.manage_volume_ref) != 2: - msg = ("Manage volume ref is not correctly configured, " - "it should be a list of two elements") - raise exceptions.InvalidConfiguration(msg) - - @decorators.idempotent_id('70076c71-0ce1-4208-a8ff-36a66e65cc1e') - def test_unmanage_manage_volume(self): - # Create original volume - org_vol_id = self.create_volume()['id'] - org_vol_info = self.admin_volume_client.show_volume( - org_vol_id)['volume'] - - # Unmanage the original volume - self.admin_volume_client.unmanage_volume(org_vol_id) - self.admin_volume_client.wait_for_resource_deletion(org_vol_id) - - # Verify the original volume does not exist in volume list - params = {'all_tenants': 1} - all_tenants_volumes = self.admin_volume_client.list_volumes( - detail=True, params=params)['volumes'] - self.assertNotIn(org_vol_id, [v['id'] for v in all_tenants_volumes]) - - # Manage volume - new_vol_name = data_utils.rand_name( - self.__class__.__name__ + '-volume') - new_vol_ref = { - 'name': new_vol_name, - 'host': org_vol_info['os-vol-host-attr:host'], - 'ref': {CONF.volume.manage_volume_ref[0]: - CONF.volume.manage_volume_ref[1] % org_vol_id}, - 'volume_type': org_vol_info['volume_type'], - 'availability_zone': org_vol_info['availability_zone']} - new_vol_id = self.admin_volume_manage_client.manage_volume( - **new_vol_ref)['volume']['id'] - self.addCleanup(self.delete_volume, - self.admin_volume_client, new_vol_id) - waiters.wait_for_volume_resource_status(self.admin_volume_client, - new_vol_id, 'available') - - # Compare the managed volume with the original - new_vol_info = self.admin_volume_client.show_volume( - new_vol_id)['volume'] - self.assertNotIn(new_vol_id, [org_vol_id]) - self.assertEqual(new_vol_info['name'], new_vol_name) - for key in ['size', - 'volume_type', - 'availability_zone', - 'os-vol-host-attr:host']: - self.assertEqual(new_vol_info[key], org_vol_info[key]) diff --git a/tempest/api/volume/admin/test_volume_pools.py b/tempest/api/volume/admin/test_volume_pools.py deleted file mode 100644 index d389c26d2..000000000 --- a/tempest/api/volume/admin/test_volume_pools.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumePoolsAdminTestsJSON(base.BaseVolumeAdminTest): - def _assert_pools(self, with_detail=False): - cinder_pools = self.admin_scheduler_stats_client.list_pools( - detail=with_detail)['pools'] - self.assertIn('name', cinder_pools[0]) - if with_detail: - self.assertIn(CONF.volume.vendor_name, - [pool['capabilities']['vendor_name'] - for pool in cinder_pools]) - - @decorators.idempotent_id('0248a46c-e226-4933-be10-ad6fca8227e7') - def test_get_pools_without_details(self): - self._assert_pools() - - @decorators.idempotent_id('d4bb61f7-762d-4437-b8a4-5785759a0ced') - def test_get_pools_with_details(self): - self._assert_pools(with_detail=True) diff --git a/tempest/api/volume/admin/test_volume_quota_classes.py b/tempest/api/volume/admin/test_volume_quota_classes.py deleted file mode 100644 index f551575c0..000000000 --- a/tempest/api/volume/admin/test_volume_quota_classes.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import random - -from oslo_log import log as logging -from testtools import matchers - -from tempest.api.volume import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -LOG = logging.getLogger(__name__) -QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes', 'backups', - 'backup_gigabytes', 'per_volume_gigabytes'] - - -class VolumeQuotaClassesTest(base.BaseVolumeAdminTest): - - def setUp(self): - # Note(jeremy.zhang): All test cases in this class need to externally - # lock on doing anything with default quota values. - self.useFixture(fixtures.LockFixture('volume_quotas')) - super(VolumeQuotaClassesTest, self).setUp() - - def _restore_default_quotas(self, original_defaults): - LOG.debug("Restoring volume quota class defaults") - self.admin_quota_classes_client.update_quota_class_set( - 'default', **original_defaults) - - @decorators.idempotent_id('abb9198e-67d0-4b09-859f-4f4a1418f176') - def test_show_default_quota(self): - default_quotas = self.admin_quota_classes_client.show_quota_class_set( - 'default')['quota_class_set'] - self.assertIn('id', default_quotas) - self.assertEqual('default', default_quotas.pop('id')) - for key in QUOTA_KEYS: - self.assertIn(key, default_quotas) - - @decorators.idempotent_id('a7644c63-2669-467a-b00e-452dd5c5397b') - def test_update_default_quota(self): - LOG.debug("Get the current default quota class values") - body = self.admin_quota_classes_client.show_quota_class_set( - 'default')['quota_class_set'] - - # Note(jeremyZ) Only include specified quota keys to avoid the conflict - # that other tests may create/delete volume types or update volume - # type's default quotas in concurrency running. - update_kwargs = {key: body[key] for key in body if key in QUOTA_KEYS} - - # Restore the defaults when the test is done. - self.addCleanup(self._restore_default_quotas, update_kwargs.copy()) - - # Note(jeremyZ) Increment some of the values for updating the default - # quota class. For safety, only items with value >= 0 will be updated, - # and items with value < 0 (-1 means unlimited) will be ignored. - for quota, default in update_kwargs.items(): - if default >= 0: - update_kwargs[quota] = default + 1 - - # Create a volume type for updating default quotas class. - volume_type_name = self.create_volume_type()['name'] - for key in ['volumes', 'snapshots', 'gigabytes']: - update_kwargs['%s_%s' % (key, volume_type_name)] = \ - random.randint(1, 10) - - LOG.debug("Update limits for the default quota class set") - update_body = self.admin_quota_classes_client.update_quota_class_set( - 'default', **update_kwargs)['quota_class_set'] - self.assertThat(update_body.items(), - matchers.ContainsAll(update_kwargs.items())) - - # Verify current project's default quotas. - default_quotas = self.admin_quotas_client.show_default_quota_set( - self.os_admin.credentials.tenant_id)['quota_set'] - self.assertThat(default_quotas.items(), - matchers.ContainsAll(update_kwargs.items())) - - # Verify a new project's default quotas. - project_name = data_utils.rand_name('quota_class_tenant') - description = data_utils.rand_name('desc_') - project_id = self.identity_utils.create_project( - name=project_name, description=description)['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - default_quotas = self.admin_quotas_client.show_default_quota_set( - project_id)['quota_set'] - self.assertThat(default_quotas.items(), - matchers.ContainsAll(update_kwargs.items())) diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py deleted file mode 100644 index 754104e04..000000000 --- a/tempest/api/volume/admin/test_volume_quotas.py +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright (C) 2014 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.common import tempest_fixtures as fixtures -from tempest.common import waiters -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes', 'backups'] -QUOTA_USAGE_KEYS = ['reserved', 'limit', 'in_use'] - - -class BaseVolumeQuotasAdminTestJSON(base.BaseVolumeAdminTest): - force_tenant_isolation = True - - credentials = ['primary', 'alt', 'admin'] - - def setUp(self): - # NOTE(jeremy.zhang): Avoid conflicts with volume quota class tests. - self.useFixture(fixtures.LockFixture('volume_quotas')) - super(BaseVolumeQuotasAdminTestJSON, self).setUp() - - @classmethod - def setup_credentials(cls): - super(BaseVolumeQuotasAdminTestJSON, cls).setup_credentials() - cls.demo_tenant_id = cls.os_primary.credentials.tenant_id - cls.alt_client = cls.os_alt.volumes_client_latest - - @classmethod - def setup_clients(cls): - super(BaseVolumeQuotasAdminTestJSON, cls).setup_clients() - cls.transfer_client = cls.os_primary.volume_transfers_v2_client - cls.alt_transfer_client = cls.os_alt.volume_transfers_v2_client - - @decorators.idempotent_id('59eada70-403c-4cef-a2a3-a8ce2f1b07a0') - def test_list_quotas(self): - quotas = (self.admin_quotas_client.show_quota_set(self.demo_tenant_id) - ['quota_set']) - for key in QUOTA_KEYS: - self.assertIn(key, quotas) - - @decorators.idempotent_id('2be020a2-5fdd-423d-8d35-a7ffbc36e9f7') - def test_list_default_quotas(self): - quotas = self.admin_quotas_client.show_default_quota_set( - self.demo_tenant_id)['quota_set'] - for key in QUOTA_KEYS: - self.assertIn(key, quotas) - - @decorators.idempotent_id('3d45c99e-cc42-4424-a56e-5cbd212b63a6') - def test_update_all_quota_resources_for_tenant(self): - # Admin can update all the resource quota limits for a tenant - default_quota_set = self.admin_quotas_client.show_default_quota_set( - self.demo_tenant_id)['quota_set'] - new_quota_set = {'gigabytes': 1009, - 'volumes': 11, - 'snapshots': 11, - 'backups': 11} - - # Update limits for all quota resources - quota_set = self.admin_quotas_client.update_quota_set( - self.demo_tenant_id, - **new_quota_set)['quota_set'] - - cleanup_quota_set = dict( - (k, v) for k, v in default_quota_set.items() - if k in QUOTA_KEYS) - self.addCleanup(self.admin_quotas_client.update_quota_set, - self.demo_tenant_id, **cleanup_quota_set) - # test that the specific values we set are actually in - # the final result. There is nothing here that ensures there - # would be no other values in there. - self.assertDictContainsSubset(new_quota_set, quota_set) - - @decorators.idempotent_id('18c51ae9-cb03-48fc-b234-14a19374dbed') - def test_show_quota_usage(self): - quota_usage = self.admin_quotas_client.show_quota_set( - self.os_admin.credentials.tenant_id, - params={'usage': True})['quota_set'] - for key in QUOTA_KEYS: - self.assertIn(key, quota_usage) - for usage_key in QUOTA_USAGE_KEYS: - self.assertIn(usage_key, quota_usage[key]) - - @decorators.idempotent_id('ae8b6091-48ad-4bfa-a188-bbf5cc02115f') - def test_quota_usage(self): - quota_usage = self.admin_quotas_client.show_quota_set( - self.demo_tenant_id, params={'usage': True})['quota_set'] - - volume = self.create_volume() - self.addCleanup(self.delete_volume, - self.admin_volume_client, volume['id']) - - new_quota_usage = self.admin_quotas_client.show_quota_set( - self.demo_tenant_id, params={'usage': True})['quota_set'] - - self.assertEqual(quota_usage['volumes']['in_use'] + 1, - new_quota_usage['volumes']['in_use']) - - self.assertEqual(quota_usage['gigabytes']['in_use'] + - volume["size"], - new_quota_usage['gigabytes']['in_use']) - - @decorators.idempotent_id('874b35a9-51f1-4258-bec5-cd561b6690d3') - def test_delete_quota(self): - # Admin can delete the resource quota set for a project - project_name = data_utils.rand_name('quota_tenant') - description = data_utils.rand_name('desc_') - project = self.identity_utils.create_project(project_name, - description=description) - project_id = project['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - quota_set_default = self.admin_quotas_client.show_default_quota_set( - project_id)['quota_set'] - volume_default = quota_set_default['volumes'] - - self.admin_quotas_client.update_quota_set( - project_id, volumes=(volume_default + 5)) - - self.admin_quotas_client.delete_quota_set(project_id) - quota_set_new = (self.admin_quotas_client.show_quota_set(project_id) - ['quota_set']) - self.assertEqual(volume_default, quota_set_new['volumes']) - - @decorators.idempotent_id('8911036f-9d54-4720-80cc-a1c9796a8805') - def test_quota_usage_after_volume_transfer(self): - # Create a volume for transfer - volume = self.create_volume() - self.addCleanup(self.delete_volume, - self.admin_volume_client, volume['id']) - - # List of tenants quota usage pre-transfer - primary_quota = self.admin_quotas_client.show_quota_set( - self.demo_tenant_id, params={'usage': True})['quota_set'] - - alt_quota = self.admin_quotas_client.show_quota_set( - self.alt_client.tenant_id, params={'usage': True})['quota_set'] - - # Creates a volume transfer - transfer = self.transfer_client.create_volume_transfer( - volume_id=volume['id'])['transfer'] - transfer_id = transfer['id'] - auth_key = transfer['auth_key'] - - # Accepts a volume transfer - self.alt_transfer_client.accept_volume_transfer( - transfer_id, auth_key=auth_key) - - # Verify volume transferred is available - waiters.wait_for_volume_resource_status( - self.alt_client, volume['id'], 'available') - - # List of tenants quota usage post transfer - new_primary_quota = self.admin_quotas_client.show_quota_set( - self.demo_tenant_id, params={'usage': True})['quota_set'] - - new_alt_quota = self.admin_quotas_client.show_quota_set( - self.alt_client.tenant_id, params={'usage': True})['quota_set'] - - # Verify tenants quota usage was updated - self.assertEqual(primary_quota['volumes']['in_use'] - - new_primary_quota['volumes']['in_use'], - new_alt_quota['volumes']['in_use'] - - alt_quota['volumes']['in_use']) - - self.assertEqual(alt_quota['gigabytes']['in_use'] + - volume['size'], - new_alt_quota['gigabytes']['in_use']) - - self.assertEqual(primary_quota['gigabytes']['in_use'] - - volume['size'], - new_primary_quota['gigabytes']['in_use']) diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py deleted file mode 100644 index d127b5f39..000000000 --- a/tempest/api/volume/admin/test_volume_quotas_negative.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class BaseVolumeQuotasNegativeTestJSON(base.BaseVolumeAdminTest): - force_tenant_isolation = True - - @classmethod - def setup_credentials(cls): - super(BaseVolumeQuotasNegativeTestJSON, cls).setup_credentials() - cls.demo_tenant_id = cls.os_primary.credentials.tenant_id - - @classmethod - def resource_setup(cls): - super(BaseVolumeQuotasNegativeTestJSON, cls).resource_setup() - cls.shared_quota_set = {'gigabytes': 2 * CONF.volume.volume_size, - 'volumes': 1} - - # NOTE(gfidente): no need to restore original quota set - # after the tests as they only work with dynamic credentials. - cls.admin_quotas_client.update_quota_set( - cls.demo_tenant_id, - **cls.shared_quota_set) - - # NOTE(gfidente): no need to delete in tearDown as - # they are created using utility wrapper methods. - cls.volume = cls.create_volume() - - @decorators.attr(type='negative') - @decorators.idempotent_id('bf544854-d62a-47f2-a681-90f7a47d86b6') - def test_quota_volumes(self): - self.assertRaises(lib_exc.OverLimit, - self.volumes_client.create_volume, - size=CONF.volume.volume_size) - - @decorators.attr(type='negative') - @decorators.idempotent_id('2dc27eee-8659-4298-b900-169d71a91374') - def test_quota_volume_gigabytes(self): - # NOTE(gfidente): quota set needs to be changed for this test - # or we may be limited by the volumes or snaps quota number, not by - # actual gigs usage; next line ensures shared set is restored. - self.addCleanup(self.admin_quotas_client.update_quota_set, - self.demo_tenant_id, - **self.shared_quota_set) - new_quota_set = {'gigabytes': CONF.volume.volume_size, - 'volumes': 2, 'snapshots': 1} - self.admin_quotas_client.update_quota_set( - self.demo_tenant_id, - **new_quota_set) - self.assertRaises(lib_exc.OverLimit, - self.volumes_client.create_volume, - size=CONF.volume.volume_size) diff --git a/tempest/api/volume/admin/test_volume_retype_with_migration.py b/tempest/api/volume/admin/test_volume_retype_with_migration.py deleted file mode 100644 index 94d5299b5..000000000 --- a/tempest/api/volume/admin/test_volume_retype_with_migration.py +++ /dev/null @@ -1,109 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from oslo_log import log as logging - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class VolumeRetypeWithMigrationTest(base.BaseVolumeAdminTest): - - @classmethod - def skip_checks(cls): - super(VolumeRetypeWithMigrationTest, cls).skip_checks() - - if not CONF.volume_feature_enabled.multi_backend: - raise cls.skipException("Cinder multi-backend feature disabled.") - - if len(set(CONF.volume.backend_names)) < 2: - raise cls.skipException("Requires at least two different " - "backend names") - - @classmethod - def resource_setup(cls): - super(VolumeRetypeWithMigrationTest, cls).resource_setup() - # read backend name from a list. - backend_src = CONF.volume.backend_names[0] - backend_dst = CONF.volume.backend_names[1] - - extra_specs_src = {"volume_backend_name": backend_src} - extra_specs_dst = {"volume_backend_name": backend_dst} - - src_vol_type = cls.create_volume_type(extra_specs=extra_specs_src) - cls.dst_vol_type = cls.create_volume_type(extra_specs=extra_specs_dst) - - cls.src_vol = cls.create_volume(volume_type=src_vol_type['name']) - - @classmethod - def resource_cleanup(cls): - # When retyping a volume, Cinder creates an internal volume in the - # target backend. The volume in the source backend is deleted after - # the migration, so we need to wait for Cinder delete this volume - # before deleting the types we've created. - - # This list should return 2 volumes until the copy and cleanup - # process is finished. - fetched_list = cls.admin_volume_client.list_volumes( - params={'all_tenants': True, - 'display_name': cls.src_vol['name']})['volumes'] - - for fetched_vol in fetched_list: - if fetched_vol['id'] != cls.src_vol['id']: - # This is the Cinder internal volume - LOG.debug('Waiting for internal volume %s deletion', - fetched_vol['id']) - cls.admin_volume_client.wait_for_resource_deletion( - fetched_vol['id']) - break - - super(VolumeRetypeWithMigrationTest, cls).resource_cleanup() - - @decorators.idempotent_id('a1a41f3f-9dad-493e-9f09-3ff197d477cd') - def test_available_volume_retype_with_migration(self): - - keys_with_no_change = ('id', 'size', 'description', 'name', 'user_id', - 'os-vol-tenant-attr:tenant_id') - keys_with_change = ('volume_type', 'os-vol-host-attr:host') - - volume_source = self.admin_volume_client.show_volume( - self.src_vol['id'])['volume'] - - # TODO(erlon): change this to volumes_client client after Bug - # #1657806 is fixed - self.admin_volume_client.retype_volume( - self.src_vol['id'], - new_type=self.dst_vol_type['name'], - migration_policy='on-demand') - - waiters.wait_for_volume_retype(self.volumes_client, self.src_vol['id'], - self.dst_vol_type['name']) - volume_dest = self.admin_volume_client.show_volume( - self.src_vol['id'])['volume'] - - # Check the volume information after the migration. - self.assertEqual('success', - volume_dest['os-vol-mig-status-attr:migstat']) - self.assertEqual('success', volume_dest['migration_status']) - - for key in keys_with_no_change: - self.assertEqual(volume_source[key], volume_dest[key]) - - for key in keys_with_change: - self.assertNotEqual(volume_source[key], volume_dest[key]) diff --git a/tempest/api/volume/admin/test_volume_services.py b/tempest/api/volume/admin/test_volume_services.py deleted file mode 100644 index 293af81ca..000000000 --- a/tempest/api/volume/admin/test_volume_services.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2014 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -from tempest.api.volume import base -from tempest.lib import decorators - - -def _get_host(host): - return host.split('@')[0] - - -class VolumesServicesTestJSON(base.BaseVolumeAdminTest): - """Tests Volume Services API. - - volume service list requires admin privileges. - """ - - @classmethod - def resource_setup(cls): - super(VolumesServicesTestJSON, cls).resource_setup() - cls.services = (cls.admin_volume_services_client.list_services() - ['services']) - # NOTE: Cinder service-list API returns the list contains - # "@" like "nova-compute01@lvmdriver-1". - # So here picks up as a host. - cls.host_name = _get_host(cls.services[0]['host']) - cls.binary_name = cls.services[0]['binary'] - - @decorators.idempotent_id('e0218299-0a59-4f43-8b2b-f1c035b3d26d') - def test_list_services(self): - services = (self.admin_volume_services_client.list_services() - ['services']) - self.assertNotEmpty(services) - - @decorators.idempotent_id('63a3e1ca-37ee-4983-826d-83276a370d25') - def test_get_service_by_service_binary_name(self): - services = (self.admin_volume_services_client.list_services( - binary=self.binary_name)['services']) - self.assertNotEmpty(services) - for service in services: - self.assertEqual(self.binary_name, service['binary']) - - @decorators.idempotent_id('178710e4-7596-4e08-9333-745cb8bc4f8d') - def test_get_service_by_host_name(self): - services_on_host = [service for service in self.services if - _get_host(service['host']) == self.host_name] - - services = (self.admin_volume_services_client.list_services( - host=self.host_name)['services']) - - # we could have a periodic job checkin between the 2 service - # lookups, so only compare binary lists. - s1 = map(lambda x: x['binary'], services) - s2 = map(lambda x: x['binary'], services_on_host) - # sort the lists before comparing, to take out dependency - # on order. - self.assertEqual(sorted(s1), sorted(s2)) - - @decorators.idempotent_id('67ec6902-f91d-4dec-91fa-338523208bbc') - def test_get_service_by_volume_host_name(self): - volume_id = self.create_volume()['id'] - volume = self.admin_volume_client.show_volume(volume_id)['volume'] - hostname = _get_host(volume['os-vol-host-attr:host']) - - services = (self.admin_volume_services_client.list_services( - host=hostname, binary='cinder-volume')['services']) - - self.assertNotEmpty(services, - 'cinder-volume not found on host %s' % hostname) - self.assertEqual(hostname, _get_host(services[0]['host'])) - self.assertEqual('cinder-volume', services[0]['binary']) - - @decorators.idempotent_id('ffa6167c-4497-4944-a464-226bbdb53908') - def test_get_service_by_service_and_host_name(self): - - services = (self.admin_volume_services_client.list_services( - host=self.host_name, binary=self.binary_name))['services'] - - self.assertNotEmpty(services) - self.assertEqual(self.host_name, _get_host(services[0]['host'])) - self.assertEqual(self.binary_name, services[0]['binary']) diff --git a/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py b/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py deleted file mode 100644 index 0f4e90fd3..000000000 --- a/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class VolumeSnapshotQuotasNegativeTestJSON(base.BaseVolumeAdminTest): - force_tenant_isolation = True - - @classmethod - def skip_checks(cls): - super(VolumeSnapshotQuotasNegativeTestJSON, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException('Cinder volume snapshots are disabled') - - @classmethod - def setup_credentials(cls): - super(VolumeSnapshotQuotasNegativeTestJSON, cls).setup_credentials() - cls.demo_tenant_id = cls.os_primary.credentials.tenant_id - - @classmethod - def resource_setup(cls): - super(VolumeSnapshotQuotasNegativeTestJSON, cls).resource_setup() - cls.default_volume_size = CONF.volume.volume_size - cls.shared_quota_set = {'gigabytes': 3 * cls.default_volume_size, - 'volumes': 1, 'snapshots': 1} - - # NOTE(gfidente): no need to restore original quota set - # after the tests as they only work with tenant isolation. - cls.admin_quotas_client.update_quota_set( - cls.demo_tenant_id, - **cls.shared_quota_set) - - # NOTE(gfidente): no need to delete in tearDown as - # they are created using utility wrapper methods. - cls.volume = cls.create_volume() - cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id']) - - @decorators.attr(type='negative') - @decorators.idempotent_id('02bbf63f-6c05-4357-9d98-2926a94064ff') - def test_quota_volume_snapshots(self): - self.assertRaises(lib_exc.OverLimit, - self.snapshots_client.create_snapshot, - volume_id=self.volume['id']) - - @decorators.attr(type='negative') - @decorators.idempotent_id('c99a1ca9-6cdf-498d-9fdf-25832babef27') - def test_quota_volume_gigabytes_snapshots(self): - self.addCleanup(self.admin_quotas_client.update_quota_set, - self.demo_tenant_id, - **self.shared_quota_set) - new_quota_set = {'gigabytes': 2 * self.default_volume_size, - 'volumes': 1, 'snapshots': 2} - self.admin_quotas_client.update_quota_set( - self.demo_tenant_id, - **new_quota_set) - self.assertRaises(lib_exc.OverLimit, - self.snapshots_client.create_snapshot, - volume_id=self.volume['id']) diff --git a/tempest/api/volume/admin/test_volume_type_access.py b/tempest/api/volume/admin/test_volume_type_access.py deleted file mode 100644 index e93bcb5ff..000000000 --- a/tempest/api/volume/admin/test_volume_type_access.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import operator - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class VolumeTypesAccessTest(base.BaseVolumeAdminTest): - - credentials = ['primary', 'alt', 'admin'] - - @classmethod - def setup_clients(cls): - super(VolumeTypesAccessTest, cls).setup_clients() - cls.alt_client = cls.os_alt.volumes_client_latest - - @decorators.idempotent_id('d4dd0027-835f-4554-a6e5-50903fb79184') - def test_volume_type_access_add(self): - # Creating a NON public volume type - params = {'os-volume-type-access:is_public': False} - volume_type = self.create_volume_type(**params) - - # Try creating a volume from volume type in primary tenant - self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume, - volume_type=volume_type['id'], - size=CONF.volume.volume_size) - - # Adding volume type access for primary tenant - self.admin_volume_types_client.add_type_access( - volume_type['id'], project=self.volumes_client.tenant_id) - self.addCleanup(self.admin_volume_types_client.remove_type_access, - volume_type['id'], - project=self.volumes_client.tenant_id) - - # Creating a volume from primary tenant - volume = self.create_volume(volume_type=volume_type['id']) - # Validating the created volume is based on the volume type - self.assertEqual(volume_type['name'], volume['volume_type']) - - @decorators.idempotent_id('5220eb28-a435-43ce-baaf-ed46f0e95159') - def test_volume_type_access_list(self): - # Creating a NON public volume type - params = {'os-volume-type-access:is_public': False} - volume_type = self.create_volume_type(**params) - - # Adding volume type access for primary tenant - self.admin_volume_types_client.add_type_access( - volume_type['id'], project=self.volumes_client.tenant_id) - self.addCleanup(self.admin_volume_types_client.remove_type_access, - volume_type['id'], - project=self.volumes_client.tenant_id) - - # Adding volume type access for alt tenant - self.admin_volume_types_client.add_type_access( - volume_type['id'], project=self.alt_client.tenant_id) - self.addCleanup(self.admin_volume_types_client.remove_type_access, - volume_type['id'], - project=self.alt_client.tenant_id) - - # List tenant access for the given volume type - type_access_list = self.admin_volume_types_client.list_type_access( - volume_type['id'])['volume_type_access'] - volume_type_ids = [ - vol_type['volume_type_id'] for vol_type in type_access_list - ] - - # Validating volume type available for only two tenants - self.assertEqual(2, volume_type_ids.count(volume_type['id'])) - - # Validating the permitted tenants are the expected tenants - self.assertIn(self.volumes_client.tenant_id, - map(operator.itemgetter('project_id'), type_access_list)) - self.assertIn(self.alt_client.tenant_id, - map(operator.itemgetter('project_id'), type_access_list)) diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py deleted file mode 100644 index af1024c93..000000000 --- a/tempest/api/volume/admin/test_volume_types.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumeTypesTest(base.BaseVolumeAdminTest): - - @decorators.idempotent_id('9d9b28e3-1b2e-4483-a2cc-24aa0ea1de54') - def test_volume_type_list(self): - # List volume types. - body = \ - self.admin_volume_types_client.list_volume_types()['volume_types'] - self.assertIsInstance(body, list) - - @decorators.idempotent_id('c03cc62c-f4e9-4623-91ec-64ce2f9c1260') - def test_volume_crud_with_volume_type_and_extra_specs(self): - # Create/update/get/delete volume with volume_type and extra spec. - volume_types = list() - vol_name = data_utils.rand_name(self.__class__.__name__ + '-volume') - proto = CONF.volume.storage_protocol - vendor = CONF.volume.vendor_name - extra_specs = {"storage_protocol": proto, - "vendor_name": vendor} - # Create two volume_types - for _ in range(2): - vol_type = self.create_volume_type( - extra_specs=extra_specs) - volume_types.append(vol_type) - params = {'name': vol_name, - 'volume_type': volume_types[0]['id'], - 'size': CONF.volume.volume_size} - - # Create volume - volume = self.create_volume(**params) - self.assertEqual(volume_types[0]['name'], volume["volume_type"]) - self.assertEqual(volume['name'], vol_name, - "The created volume name is not equal " - "to the requested name") - self.assertIsNotNone(volume['id'], - "Field volume id is empty or not found.") - - # Update volume with new volume_type - self.volumes_client.retype_volume(volume['id'], - new_type=volume_types[1]['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - # Get volume details and Verify - fetched_volume = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual(volume_types[1]['name'], - fetched_volume['volume_type'], - 'The fetched Volume type is different ' - 'from updated volume type') - self.assertEqual(vol_name, fetched_volume['name'], - 'The fetched Volume is different ' - 'from the created Volume') - self.assertEqual(volume['id'], fetched_volume['id'], - 'The fetched Volume is different ' - 'from the created Volume') - - @decorators.idempotent_id('4e955c3b-49db-4515-9590-0c99f8e471ad') - def test_volume_type_create_get_delete(self): - # Create/get volume type. - name = data_utils.rand_name(self.__class__.__name__ + '-volume-type') - description = data_utils.rand_name("volume-type-description") - proto = CONF.volume.storage_protocol - vendor = CONF.volume.vendor_name - extra_specs = {"storage_protocol": proto, - "vendor_name": vendor} - params = {'name': name, - 'description': description, - 'extra_specs': extra_specs, - 'os-volume-type-access:is_public': True} - body = self.create_volume_type(**params) - self.assertIn('name', body) - self.assertEqual(name, body['name'], - "The created volume_type name is not equal " - "to the requested name") - self.assertEqual(description, body['description'], - "The created volume_type_description name is " - "not equal to the requested name") - self.assertIsNotNone(body['id'], - "Field volume_type id is empty or not found.") - fetched_volume_type = self.admin_volume_types_client.show_volume_type( - body['id'])['volume_type'] - self.assertEqual(name, fetched_volume_type['name'], - 'The fetched Volume_type is different ' - 'from the created Volume_type') - self.assertEqual(str(body['id']), fetched_volume_type['id'], - 'The fetched Volume_type is different ' - 'from the created Volume_type') - self.assertEqual(extra_specs, fetched_volume_type['extra_specs'], - 'The fetched Volume_type is different ' - 'from the created Volume_type') - self.assertEqual(description, fetched_volume_type['description']) - self.assertEqual(body['is_public'], - fetched_volume_type['is_public']) - self.assertEqual( - body['os-volume-type-access:is_public'], - fetched_volume_type['os-volume-type-access:is_public']) - - @decorators.idempotent_id('7830abd0-ff99-4793-a265-405684a54d46') - def test_volume_type_encryption_create_get_update_delete(self): - # Create/get/update/delete encryption type. - create_kwargs = {'provider': 'LuksEncryptor', - 'control_location': 'front-end'} - volume_type_id = self.create_volume_type()['id'] - - # Create encryption type - encryption_type = \ - self.admin_encryption_types_client.create_encryption_type( - volume_type_id, **create_kwargs)['encryption'] - self.assertIn('volume_type_id', encryption_type) - for key in create_kwargs: - self.assertEqual(create_kwargs[key], encryption_type[key], - 'The created encryption_type %s is different ' - 'from the requested encryption_type' % key) - - # Get encryption type - encrypt_type_id = encryption_type['volume_type_id'] - fetched_encryption_type = ( - self.admin_encryption_types_client.show_encryption_type( - encrypt_type_id)) - for key in create_kwargs: - self.assertEqual(create_kwargs[key], fetched_encryption_type[key], - 'The fetched encryption_type %s is different ' - 'from the created encryption_type' % key) - - # Update encryption type - update_kwargs = {'key_size': 128, - 'provider': 'SomeProvider', - 'cipher': 'aes-xts-plain64', - 'control_location': 'back-end'} - self.admin_encryption_types_client.update_encryption_type( - encrypt_type_id, **update_kwargs) - updated_encryption_type = ( - self.admin_encryption_types_client.show_encryption_type( - encrypt_type_id)) - for key in update_kwargs: - self.assertEqual(update_kwargs[key], updated_encryption_type[key], - 'The fetched encryption_type %s is different ' - 'from the updated encryption_type' % key) - - # Delete encryption type - self.admin_encryption_types_client.delete_encryption_type( - encrypt_type_id) - self.admin_encryption_types_client.wait_for_resource_deletion( - encrypt_type_id) - deleted_encryption_type = ( - self.admin_encryption_types_client.show_encryption_type( - encrypt_type_id)) - self.assertEmpty(deleted_encryption_type) - - @decorators.idempotent_id('cf9f07c6-db9e-4462-a243-5933ad65e9c8') - def test_volume_type_update(self): - # Create volume type - volume_type = self.create_volume_type() - - # New volume type details - name = data_utils.rand_name("volume-type") - description = data_utils.rand_name("volume-type-description") - is_public = not volume_type['is_public'] - - # Update volume type details - kwargs = {'name': name, - 'description': description, - 'is_public': is_public} - updated_vol_type = self.admin_volume_types_client.update_volume_type( - volume_type['id'], **kwargs)['volume_type'] - - # Verify volume type details were updated - self.assertEqual(name, updated_vol_type['name']) - self.assertEqual(description, updated_vol_type['description']) - self.assertEqual(is_public, updated_vol_type['is_public']) diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs.py b/tempest/api/volume/admin/test_volume_types_extra_specs.py deleted file mode 100644 index b5a2fb72a..000000000 --- a/tempest/api/volume/admin/test_volume_types_extra_specs.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class VolumeTypesExtraSpecsTest(base.BaseVolumeAdminTest): - - @classmethod - def resource_setup(cls): - super(VolumeTypesExtraSpecsTest, cls).resource_setup() - cls.volume_type = cls.create_volume_type() - - @decorators.idempotent_id('b42923e9-0452-4945-be5b-d362ae533e60') - def test_volume_type_extra_specs_list(self): - # List Volume types extra specs. - extra_specs = {"spec1": "val1"} - body = self.admin_volume_types_client.create_volume_type_extra_specs( - self.volume_type['id'], extra_specs)['extra_specs'] - self.assertEqual(extra_specs, body, - "Volume type extra spec incorrectly created") - body = self.admin_volume_types_client.list_volume_types_extra_specs( - self.volume_type['id'])['extra_specs'] - self.assertIsInstance(body, dict) - self.assertIn('spec1', body) - - @decorators.idempotent_id('0806db36-b4a0-47a1-b6f3-c2e7f194d017') - def test_volume_type_extra_specs_update(self): - # Update volume type extra specs - extra_specs = {"spec2": "val1"} - body = self.admin_volume_types_client.create_volume_type_extra_specs( - self.volume_type['id'], extra_specs)['extra_specs'] - self.assertEqual(extra_specs, body, - "Volume type extra spec incorrectly created") - spec_key = "spec2" - extra_spec = {spec_key: "val2"} - body = self.admin_volume_types_client.update_volume_type_extra_specs( - self.volume_type['id'], spec_key, extra_spec) - self.assertIn(spec_key, body) - self.assertEqual(extra_spec[spec_key], body[spec_key], - "Volume type extra spec incorrectly updated") - - @decorators.idempotent_id('d4772798-601f-408a-b2a5-29e8a59d1220') - def test_volume_type_extra_spec_create_get_delete(self): - # Create/Get/Delete volume type extra spec. - spec_key = "spec3" - extra_specs = {spec_key: "val1"} - body = self.admin_volume_types_client.create_volume_type_extra_specs( - self.volume_type['id'], - extra_specs)['extra_specs'] - self.assertEqual(extra_specs, body, - "Volume type extra spec incorrectly created") - - body = self.admin_volume_types_client.show_volume_type_extra_specs( - self.volume_type['id'], - spec_key) - self.assertEqual(extra_specs, body, - "Volume type extra spec incorrectly fetched") - - self.admin_volume_types_client.delete_volume_type_extra_specs( - self.volume_type['id'], spec_key) - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.show_volume_type_extra_specs, - self.volume_type['id'], spec_key) diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py deleted file mode 100644 index 4fa934e10..000000000 --- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ExtraSpecsNegativeTest(base.BaseVolumeAdminTest): - - @classmethod - def resource_setup(cls): - super(ExtraSpecsNegativeTest, cls).resource_setup() - extra_specs = {"spec1": "val1"} - cls.volume_type = cls.create_volume_type(extra_specs=extra_specs) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('08961d20-5cbb-4910-ac0f-89ad6dbb2da1') - def test_update_no_body(self): - # Should not update volume type extra specs with no body - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.update_volume_type_extra_specs, - self.volume_type['id'], "spec1", None) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('25e5a0ee-89b3-4c53-8310-236f76c75365') - def test_update_nonexistent_extra_spec_id(self): - # Should not update volume type extra specs with nonexistent id. - extra_spec = {"spec1": "val2"} - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.update_volume_type_extra_specs, - self.volume_type['id'], data_utils.rand_uuid(), - extra_spec) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9bf7a657-b011-4aec-866d-81c496fbe5c8') - def test_update_none_extra_spec_id(self): - # Should not update volume type extra specs with none id. - extra_spec = {"spec1": "val2"} - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.update_volume_type_extra_specs, - self.volume_type['id'], None, extra_spec) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a77dfda2-9100-448e-9076-ed1711f4bdfc') - def test_update_multiple_extra_spec(self): - # Should not update volume type extra specs with multiple specs as - # body. - extra_spec = {"spec1": "val2", "spec2": "val1"} - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.update_volume_type_extra_specs, - self.volume_type['id'], list(extra_spec)[0], - extra_spec) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('49d5472c-a53d-4eab-a4d3-450c4db1c545') - def test_create_nonexistent_type_id(self): - # Should not create volume type extra spec for nonexistent volume - # type id. - extra_specs = {"spec2": "val1"} - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.create_volume_type_extra_specs, - data_utils.rand_uuid(), extra_specs) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c821bdc8-43a4-4bf4-86c8-82f3858d5f7d') - def test_create_none_body(self): - # Should not create volume type extra spec for none POST body. - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.create_volume_type_extra_specs, - self.volume_type['id'], None) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bc772c71-1ed4-4716-b945-8b5ed0f15e87') - def test_create_invalid_body(self): - # Should not create volume type extra spec for invalid POST body. - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.create_volume_type_extra_specs, - self.volume_type['id'], extra_specs=['invalid']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('031cda8b-7d23-4246-8bf6-bbe73fd67074') - def test_delete_nonexistent_volume_type_id(self): - # Should not delete volume type extra spec for nonexistent - # type id. - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.delete_volume_type_extra_specs, - data_utils.rand_uuid(), "spec1") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dee5cf0c-cdd6-4353-b70c-e847050d71fb') - def test_list_nonexistent_volume_type_id(self): - # Should not list volume type extra spec for nonexistent type id. - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.list_volume_types_extra_specs, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9f402cbd-1838-4eb4-9554-126a6b1908c9') - def test_get_nonexistent_volume_type_id(self): - # Should not get volume type extra spec for nonexistent type id. - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.show_volume_type_extra_specs, - data_utils.rand_uuid(), "spec1") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c881797d-12ff-4f1a-b09d-9f6212159753') - def test_get_nonexistent_extra_spec_id(self): - # Should not get volume type extra spec for nonexistent extra spec - # id. - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.show_volume_type_extra_specs, - self.volume_type['id'], data_utils.rand_uuid()) diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py deleted file mode 100644 index 4cad52a7c..000000000 --- a/tempest/api/volume/admin/test_volume_types_negative.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class VolumeTypesNegativeTest(base.BaseVolumeAdminTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b48c98f2-e662-4885-9b71-032256906314') - def test_create_with_nonexistent_volume_type(self): - # Should not be able to create volume with nonexistent volume_type. - params = {'name': data_utils.rand_uuid(), - 'volume_type': data_utils.rand_uuid()} - self.assertRaises(lib_exc.NotFound, - self.volumes_client.create_volume, **params) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('878b4e57-faa2-4659-b0d1-ce740a06ae81') - def test_create_with_empty_name(self): - # Should not be able to create volume type with an empty name. - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.create_volume_type, name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('994610d6-0476-4018-a644-a2602ef5d4aa') - def test_get_nonexistent_type_id(self): - # Should not be able to get volume type with nonexistent type id. - self.assertRaises(lib_exc.NotFound, - self.admin_volume_types_client.show_volume_type, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6b3926d2-7d73-4896-bc3d-e42dfd11a9f6') - def test_delete_nonexistent_type_id(self): - # Should not be able to delete volume type with nonexistent type id. - self.assertRaises(lib_exc.NotFound, - self.admin_volume_types_client.delete_volume_type, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8c09f849-f225-4d78-ba87-bffd9a5e0c6f') - def test_create_volume_with_private_volume_type(self): - # Should not be able to create volume with private volume type. - params = {'os-volume-type-access:is_public': False} - volume_type = self.create_volume_type(**params) - self.assertRaises(lib_exc.NotFound, - self.create_volume, volume_type=volume_type['id']) diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py deleted file mode 100644 index b81a477a6..000000000 --- a/tempest/api/volume/admin/test_volumes_actions.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class VolumesActionsTest(base.BaseVolumeAdminTest): - - def _create_reset_and_force_delete_temp_volume(self, status=None): - # Create volume, reset volume status, and force delete temp volume - temp_volume = self.create_volume() - if status: - self.admin_volume_client.reset_volume_status( - temp_volume['id'], status=status) - self.admin_volume_client.force_delete_volume(temp_volume['id']) - self.volumes_client.wait_for_resource_deletion(temp_volume['id']) - - @decorators.idempotent_id('d063f96e-a2e0-4f34-8b8a-395c42de1845') - def test_volume_reset_status(self): - # test volume reset status : available->error->available - volume = self.create_volume() - self.addCleanup(self.admin_volume_client.reset_volume_status, - volume['id'], status='available') - for status in ['error', 'available', 'maintenance']: - self.admin_volume_client.reset_volume_status( - volume['id'], status=status) - volume_get = self.admin_volume_client.show_volume( - volume['id'])['volume'] - self.assertEqual(status, volume_get['status']) - - @decorators.idempotent_id('21737d5a-92f2-46d7-b009-a0cc0ee7a570') - def test_volume_force_delete_when_volume_is_creating(self): - # test force delete when status of volume is creating - self._create_reset_and_force_delete_temp_volume('creating') - - @decorators.idempotent_id('db8d607a-aa2e-4beb-b51d-d4005c232011') - def test_volume_force_delete_when_volume_is_attaching(self): - # test force delete when status of volume is attaching - self._create_reset_and_force_delete_temp_volume('attaching') - - @decorators.idempotent_id('3e33a8a8-afd4-4d64-a86b-c27a185c5a4a') - def test_volume_force_delete_when_volume_is_error(self): - # test force delete when status of volume is error - self._create_reset_and_force_delete_temp_volume('error') - - @decorators.idempotent_id('b957cabd-1486-4e21-90cf-a9ed3c39dfb2') - def test_volume_force_delete_when_volume_is_maintenance(self): - # test force delete when status of volume is maintenance - self._create_reset_and_force_delete_temp_volume('maintenance') - - @decorators.idempotent_id('d38285d9-929d-478f-96a5-00e66a115b81') - @test.services('compute') - def test_force_detach_volume(self): - # Create a server and a volume - server_id = self.create_server()['id'] - volume_id = self.create_volume()['id'] - - # Attach volume - self.volumes_client.attach_volume( - volume_id, - instance_uuid=server_id, - mountpoint='/dev/%s' % CONF.compute.volume_device_name) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume_id, 'in-use') - self.addCleanup(waiters.wait_for_volume_resource_status, - self.volumes_client, volume_id, 'available') - self.addCleanup(self.volumes_client.detach_volume, volume_id) - attachment = self.volumes_client.show_volume( - volume_id)['volume']['attachments'][0] - - # Reset volume's status to error - self.admin_volume_client.reset_volume_status(volume_id, status='error') - - # Force detach volume - self.admin_volume_client.force_detach_volume( - volume_id, connector=None, - attachment_id=attachment['attachment_id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume_id, 'available') - vol_info = self.volumes_client.show_volume(volume_id)['volume'] - self.assertIn('attachments', vol_info) - self.assertEmpty(vol_info['attachments']) diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py deleted file mode 100644 index afc328117..000000000 --- a/tempest/api/volume/admin/test_volumes_backup.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import base64 -from oslo_serialization import jsonutils as json - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesBackupsAdminTest(base.BaseVolumeAdminTest): - - @classmethod - def skip_checks(cls): - super(VolumesBackupsAdminTest, cls).skip_checks() - if not CONF.volume_feature_enabled.backup: - raise cls.skipException("Cinder backup feature disabled") - - def _delete_backup(self, backup_id): - self.admin_backups_client.delete_backup(backup_id) - self.admin_backups_client.wait_for_resource_deletion(backup_id) - - def _decode_url(self, backup_url): - return json.loads(base64.decode_as_text(backup_url)) - - def _encode_backup(self, backup): - retval = json.dumps(backup) - return base64.encode_as_text(retval) - - def _modify_backup_url(self, backup_url, changes): - backup = self._decode_url(backup_url) - backup.update(changes) - return self._encode_backup(backup) - - @decorators.idempotent_id('a99c54a1-dd80-4724-8a13-13bf58d4068d') - def test_volume_backup_export_import(self): - """Test backup export import functionality. - - Cinder allows exporting DB backup information through its API so it can - be imported back in case of a DB loss. - """ - volume = self.create_volume() - # Create backup - backup_name = data_utils.rand_name(self.__class__.__name__ + '-Backup') - backup = (self.create_backup(backup_client=self.admin_backups_client, - volume_id=volume['id'], - name=backup_name)) - self.assertEqual(backup_name, backup['name']) - - # Export Backup - export_backup = (self.admin_backups_client.export_backup(backup['id']) - ['backup-record']) - self.assertIn('backup_service', export_backup) - self.assertIn('backup_url', export_backup) - self.assertTrue(export_backup['backup_service'].startswith( - 'cinder.backup.drivers')) - self.assertIsNotNone(export_backup['backup_url']) - - # NOTE(geguileo): Backups are imported with the same backup id - # (important for incremental backups among other things), so we cannot - # import the exported backup information as it is, because that Backup - # ID already exists. So we'll fake the data by changing the backup id - # in the exported backup DB info we have retrieved before importing it - # back. - new_id = data_utils.rand_uuid() - new_url = self._modify_backup_url( - export_backup['backup_url'], {'id': new_id}) - - # Import Backup - import_backup = self.admin_backups_client.import_backup( - backup_service=export_backup['backup_service'], - backup_url=new_url)['backup'] - - # NOTE(geguileo): We delete both backups, but only one of those - # deletions will delete data from the backup back-end because they - # were both pointing to the same backend data. - self.addCleanup(self._delete_backup, new_id) - self.assertIn("id", import_backup) - self.assertEqual(new_id, import_backup['id']) - waiters.wait_for_volume_resource_status(self.admin_backups_client, - import_backup['id'], - 'available') - - # Verify Import Backup - backups = self.admin_backups_client.list_backups( - detail=True)['backups'] - self.assertIn(new_id, [b['id'] for b in backups]) - - # Restore backup - restore = self.admin_backups_client.restore_backup( - backup['id'])['restore'] - self.addCleanup(self.admin_volume_client.delete_volume, - restore['volume_id']) - self.assertEqual(backup['id'], restore['backup_id']) - waiters.wait_for_volume_resource_status(self.admin_volume_client, - restore['volume_id'], - 'available') - - # Verify if restored volume is there in volume list - volumes = self.admin_volume_client.list_volumes()['volumes'] - self.assertIn(restore['volume_id'], [v['id'] for v in volumes]) - waiters.wait_for_volume_resource_status(self.admin_backups_client, - import_backup['id'], - 'available') - - @decorators.idempotent_id('47a35425-a891-4e13-961c-c45deea21e94') - def test_volume_backup_reset_status(self): - # Create a volume - volume = self.create_volume() - # Create a backup - backup_name = data_utils.rand_name( - self.__class__.__name__ + '-Backup') - backup = self.create_backup(backup_client=self.admin_backups_client, - volume_id=volume['id'], - name=backup_name) - self.assertEqual(backup_name, backup['name']) - # Reset backup status to error - self.admin_backups_client.reset_backup_status(backup_id=backup['id'], - status="error") - waiters.wait_for_volume_resource_status(self.admin_backups_client, - backup['id'], 'error') diff --git a/tempest/api/volume/admin/test_volumes_list.py b/tempest/api/volume/admin/test_volumes_list.py deleted file mode 100644 index 9d98b7aa9..000000000 --- a/tempest/api/volume/admin/test_volumes_list.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import operator - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesListAdminTestJSON(base.BaseVolumeAdminTest): - - @classmethod - def resource_setup(cls): - super(VolumesListAdminTestJSON, cls).resource_setup() - # Create 3 test volumes - # NOTE(zhufl): When using pre-provisioned credentials, the project - # may have volumes other than those created below. - cls.volume_list = cls.volumes_client.list_volumes()['volumes'] - for _ in range(3): - volume = cls.create_volume() - # Fetch volume details - volume_details = cls.volumes_client.show_volume( - volume['id'])['volume'] - cls.volume_list.append(volume_details) - - @decorators.idempotent_id('5866286f-3290-4cfd-a414-088aa6cdc469') - def test_volume_list_param_tenant(self): - # Test to list volumes from single tenant - # Create a volume in admin tenant - adm_vol = self.admin_volume_client.create_volume( - size=CONF.volume.volume_size)['volume'] - waiters.wait_for_volume_resource_status(self.admin_volume_client, - adm_vol['id'], 'available') - self.addCleanup(self.admin_volume_client.delete_volume, adm_vol['id']) - params = {'all_tenants': 1, - 'project_id': self.volumes_client.tenant_id} - # Getting volume list from primary tenant using admin credentials - fetched_list = self.admin_volume_client.list_volumes( - detail=True, params=params)['volumes'] - # Verifying fetched volume ids list is related to primary tenant - fetched_list_ids = map(operator.itemgetter('id'), fetched_list) - expected_list_ids = map(operator.itemgetter('id'), self.volume_list) - self.assertEqual(sorted(expected_list_ids), sorted(fetched_list_ids)) - # Verifying tenant id of volumes fetched list is related to - # primary tenant - fetched_tenant_id = [operator.itemgetter( - 'os-vol-tenant-attr:tenant_id')(item) for item in fetched_list] - expected_tenant_id = [self.volumes_client.tenant_id] * \ - len(self.volume_list) - self.assertEqual(expected_tenant_id, fetched_tenant_id) diff --git a/tempest/api/volume/api_microversion_fixture.py b/tempest/api/volume/api_microversion_fixture.py deleted file mode 100644 index 7bbe67497..000000000 --- a/tempest/api/volume/api_microversion_fixture.py +++ /dev/null @@ -1,30 +0,0 @@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures - -from tempest.lib.services.volume import base_client - - -class APIMicroversionFixture(fixtures.Fixture): - - def __init__(self, volume_microversion): - self.volume_microversion = volume_microversion - - def _setUp(self): - super(APIMicroversionFixture, self)._setUp() - base_client.VOLUME_MICROVERSION = self.volume_microversion - self.addCleanup(self._reset_volume_microversion) - - def _reset_volume_microversion(self): - base_client.VOLUME_MICROVERSION = None diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py deleted file mode 100644 index ef69ba3de..000000000 --- a/tempest/api/volume/base.py +++ /dev/null @@ -1,341 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import api_microversion_fixture -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest.lib.common import api_version_utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions -import tempest.test - -CONF = config.CONF - - -class BaseVolumeTest(api_version_utils.BaseMicroversionTest, - tempest.test.BaseTestCase): - """Base test case class for all Cinder API tests.""" - - _api_version = 2 - credentials = ['primary'] - - @classmethod - def skip_checks(cls): - super(BaseVolumeTest, cls).skip_checks() - - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - if cls._api_version == 2: - if not CONF.volume_feature_enabled.api_v2: - msg = "Volume API v2 is disabled" - raise cls.skipException(msg) - elif cls._api_version == 3: - if not CONF.volume_feature_enabled.api_v3: - msg = "Volume API v3 is disabled" - raise cls.skipException(msg) - else: - msg = ("Invalid Cinder API version (%s)" % cls._api_version) - raise exceptions.InvalidConfiguration(msg) - - api_version_utils.check_skip_with_microversion( - cls.min_microversion, cls.max_microversion, - CONF.volume.min_microversion, CONF.volume.max_microversion) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(BaseVolumeTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(BaseVolumeTest, cls).setup_clients() - cls.servers_client = cls.os_primary.servers_client - - if CONF.service_available.glance: - cls.images_client = cls.os_primary.image_client_v2 - - if cls._api_version == 3: - cls.backups_client = cls.os_primary.backups_v3_client - cls.volumes_client = cls.os_primary.volumes_v3_client - else: - cls.backups_client = cls.os_primary.backups_v2_client - cls.volumes_client = cls.os_primary.volumes_v2_client - - cls.snapshots_client = cls.os_primary.snapshots_v2_client - cls.volumes_extension_client =\ - cls.os_primary.volumes_v2_extension_client - cls.availability_zone_client = ( - cls.os_primary.volume_v2_availability_zone_client) - cls.volume_limits_client = cls.os_primary.volume_v2_limits_client - cls.messages_client = cls.os_primary.volume_v3_messages_client - cls.versions_client = cls.os_primary.volume_v3_versions_client - cls.groups_client = cls.os_primary.groups_v3_client - - def setUp(self): - super(BaseVolumeTest, self).setUp() - self.useFixture(api_microversion_fixture.APIMicroversionFixture( - self.request_microversion)) - - @classmethod - def resource_setup(cls): - super(BaseVolumeTest, cls).resource_setup() - cls.request_microversion = ( - api_version_utils.select_request_microversion( - cls.min_microversion, - CONF.volume.min_microversion)) - - cls.snapshots = [] - cls.volumes = [] - cls.image_ref = CONF.compute.image_ref - cls.flavor_ref = CONF.compute.flavor_ref - cls.build_interval = CONF.volume.build_interval - cls.build_timeout = CONF.volume.build_timeout - - @classmethod - def resource_cleanup(cls): - cls.clear_snapshots() - cls.clear_volumes() - super(BaseVolumeTest, cls).resource_cleanup() - - @classmethod - def create_volume(cls, wait_until='available', **kwargs): - """Wrapper utility that returns a test volume. - - :param wait_until: wait till volume status. - """ - if 'size' not in kwargs: - kwargs['size'] = CONF.volume.volume_size - - if 'imageRef' in kwargs: - image = cls.images_client.show_image(kwargs['imageRef']) - min_disk = image['min_disk'] - kwargs['size'] = max(kwargs['size'], min_disk) - - if 'name' not in kwargs: - name = data_utils.rand_name(cls.__name__ + '-Volume') - kwargs['name'] = name - - volume = cls.volumes_client.create_volume(**kwargs)['volume'] - cls.volumes.append(volume) - waiters.wait_for_volume_resource_status(cls.volumes_client, - volume['id'], wait_until) - return volume - - @classmethod - def create_snapshot(cls, volume_id=1, **kwargs): - """Wrapper utility that returns a test snapshot.""" - if 'name' not in kwargs: - name = data_utils.rand_name(cls.__name__ + '-Snapshot') - kwargs['name'] = name - - snapshot = cls.snapshots_client.create_snapshot( - volume_id=volume_id, **kwargs)['snapshot'] - cls.snapshots.append(snapshot['id']) - waiters.wait_for_volume_resource_status(cls.snapshots_client, - snapshot['id'], 'available') - return snapshot - - def create_backup(self, volume_id, backup_client=None, **kwargs): - """Wrapper utility that returns a test backup.""" - if backup_client is None: - backup_client = self.backups_client - if 'name' not in kwargs: - name = data_utils.rand_name(self.__class__.__name__ + '-Backup') - kwargs['name'] = name - - backup = backup_client.create_backup( - volume_id=volume_id, **kwargs)['backup'] - self.addCleanup(backup_client.delete_backup, backup['id']) - waiters.wait_for_volume_resource_status(backup_client, backup['id'], - 'available') - return backup - - # NOTE(afazekas): these create_* and clean_* could be defined - # only in a single location in the source, and could be more general. - - @staticmethod - def delete_volume(client, volume_id): - """Delete volume by the given client""" - client.delete_volume(volume_id) - client.wait_for_resource_deletion(volume_id) - - def delete_snapshot(self, snapshot_id, snapshots_client=None): - """Delete snapshot by the given client""" - if snapshots_client is None: - snapshots_client = self.snapshots_client - snapshots_client.delete_snapshot(snapshot_id) - snapshots_client.wait_for_resource_deletion(snapshot_id) - if snapshot_id in self.snapshots: - self.snapshots.remove(snapshot_id) - - def attach_volume(self, server_id, volume_id): - """Attach a volume to a server""" - self.servers_client.attach_volume( - server_id, volumeId=volume_id, - device='/dev/%s' % CONF.compute.volume_device_name) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume_id, 'in-use') - self.addCleanup(waiters.wait_for_volume_resource_status, - self.volumes_client, volume_id, 'available') - self.addCleanup(self.servers_client.detach_volume, server_id, - volume_id) - - @classmethod - def clear_volumes(cls): - for volume in cls.volumes: - try: - cls.volumes_client.delete_volume(volume['id']) - except Exception: - pass - - for volume in cls.volumes: - try: - cls.volumes_client.wait_for_resource_deletion(volume['id']) - except Exception: - pass - - @classmethod - def clear_snapshots(cls): - for snapshot in cls.snapshots: - test_utils.call_and_ignore_notfound_exc( - cls.snapshots_client.delete_snapshot, snapshot) - - for snapshot in cls.snapshots: - test_utils.call_and_ignore_notfound_exc( - cls.snapshots_client.wait_for_resource_deletion, - snapshot) - - def create_server(self, wait_until='ACTIVE', **kwargs): - name = kwargs.pop( - 'name', - data_utils.rand_name(self.__class__.__name__ + '-instance')) - - tenant_network = self.get_tenant_network() - body, _ = compute.create_test_server( - self.os_primary, - tenant_network=tenant_network, - name=name, - wait_until=wait_until, - **kwargs) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - waiters.wait_for_server_termination, - self.servers_client, body['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.servers_client.delete_server, body['id']) - return body - - -class BaseVolumeAdminTest(BaseVolumeTest): - """Base test case class for all Volume Admin API tests.""" - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(BaseVolumeAdminTest, cls).setup_clients() - - cls.admin_volume_qos_client = cls.os_admin.volume_qos_v2_client - cls.admin_volume_services_client = \ - cls.os_admin.volume_services_v2_client - cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client - cls.admin_volume_manage_client = cls.os_admin.volume_manage_v2_client - cls.admin_volume_client = cls.os_admin.volumes_v2_client - if cls._api_version == 3: - cls.admin_volume_client = cls.os_admin.volumes_v3_client - cls.admin_hosts_client = cls.os_admin.volume_hosts_v2_client - cls.admin_snapshot_manage_client = \ - cls.os_admin.snapshot_manage_v2_client - cls.admin_snapshots_client = cls.os_admin.snapshots_v2_client - cls.admin_backups_client = cls.os_admin.backups_v2_client - cls.admin_encryption_types_client = \ - cls.os_admin.encryption_types_v2_client - cls.admin_quota_classes_client = \ - cls.os_admin.volume_quota_classes_v2_client - cls.admin_quotas_client = cls.os_admin.volume_quotas_v2_client - cls.admin_volume_limits_client = cls.os_admin.volume_v2_limits_client - cls.admin_capabilities_client = \ - cls.os_admin.volume_capabilities_v2_client - cls.admin_scheduler_stats_client = \ - cls.os_admin.volume_scheduler_stats_v2_client - cls.admin_messages_client = cls.os_admin.volume_v3_messages_client - cls.admin_groups_client = cls.os_admin.groups_v3_client - cls.admin_group_types_client = cls.os_admin.group_types_v3_client - - @classmethod - def resource_setup(cls): - super(BaseVolumeAdminTest, cls).resource_setup() - - cls.qos_specs = [] - cls.volume_types = [] - - @classmethod - def resource_cleanup(cls): - cls.clear_qos_specs() - super(BaseVolumeAdminTest, cls).resource_cleanup() - cls.clear_volume_types() - - @classmethod - def create_test_qos_specs(cls, name=None, consumer=None, **kwargs): - """create a test Qos-Specs.""" - name = name or data_utils.rand_name(cls.__name__ + '-QoS') - consumer = consumer or 'front-end' - qos_specs = cls.admin_volume_qos_client.create_qos( - name=name, consumer=consumer, **kwargs)['qos_specs'] - cls.qos_specs.append(qos_specs['id']) - return qos_specs - - @classmethod - def create_volume_type(cls, name=None, **kwargs): - """Create a test volume-type""" - name = name or data_utils.rand_name(cls.__name__ + '-volume-type') - volume_type = cls.admin_volume_types_client.create_volume_type( - name=name, **kwargs)['volume_type'] - cls.volume_types.append(volume_type['id']) - return volume_type - - def create_group_type(self, name=None, **kwargs): - """Create a test group-type""" - name = name or data_utils.rand_name( - self.__class__.__name__ + '-group-type') - group_type = self.admin_group_types_client.create_group_type( - name=name, **kwargs)['group_type'] - self.addCleanup(self.admin_group_types_client.delete_group_type, - group_type['id']) - return group_type - - @classmethod - def clear_qos_specs(cls): - for qos_id in cls.qos_specs: - test_utils.call_and_ignore_notfound_exc( - cls.admin_volume_qos_client.delete_qos, qos_id) - - for qos_id in cls.qos_specs: - test_utils.call_and_ignore_notfound_exc( - cls.admin_volume_qos_client.wait_for_resource_deletion, qos_id) - - @classmethod - def clear_volume_types(cls): - for vol_type in cls.volume_types: - test_utils.call_and_ignore_notfound_exc( - cls.admin_volume_types_client.delete_volume_type, vol_type) - - for vol_type in cls.volume_types: - test_utils.call_and_ignore_notfound_exc( - cls.admin_volume_types_client.wait_for_resource_deletion, - vol_type) diff --git a/tempest/api/volume/test_availability_zone.py b/tempest/api/volume/test_availability_zone.py deleted file mode 100644 index d0a87db59..000000000 --- a/tempest/api/volume/test_availability_zone.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2014 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.lib import decorators - - -class AvailabilityZoneTestJSON(base.BaseVolumeTest): - """Tests Availability Zone API List""" - - @classmethod - def setup_clients(cls): - super(AvailabilityZoneTestJSON, cls).setup_clients() - cls.client = cls.availability_zone_client - - @decorators.idempotent_id('01f1ae88-eba9-4c6b-a011-6f7ace06b725') - def test_get_availability_zone_list(self): - # List of availability zone - availability_zone = (self.client.list_availability_zones() - ['availabilityZoneInfo']) - self.assertNotEmpty(availability_zone) diff --git a/tempest/api/volume/test_extensions.py b/tempest/api/volume/test_extensions.py deleted file mode 100644 index 39ce00c49..000000000 --- a/tempest/api/volume/test_extensions.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -LOG = logging.getLogger(__name__) - - -class ExtensionsTestJSON(base.BaseVolumeTest): - - @decorators.idempotent_id('94607eb0-43a5-47ca-82aa-736b41bd2e2c') - def test_list_extensions(self): - # List of all extensions - extensions = (self.volumes_extension_client.list_extensions() - ['extensions']) - if not CONF.volume_feature_enabled.api_extensions: - raise self.skipException('There are not any extensions configured') - extension_list = [extension.get('alias') for extension in extensions] - LOG.debug("Cinder extensions: %s", ','.join(extension_list)) - ext = CONF.volume_feature_enabled.api_extensions[0] - if ext == 'all': - self.assertIn('Hosts', map(lambda x: x['name'], extensions)) - elif ext: - self.assertIn(ext, map(lambda x: x['alias'], extensions)) - else: - raise self.skipException('There are not any extensions configured') diff --git a/tempest/api/volume/test_image_metadata.py b/tempest/api/volume/test_image_metadata.py deleted file mode 100644 index 77baf18bf..000000000 --- a/tempest/api/volume/test_image_metadata.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from testtools import matchers - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class VolumesImageMetadata(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesImageMetadata, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as Glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def resource_setup(cls): - super(VolumesImageMetadata, cls).resource_setup() - # Create a volume from image ID - cls.volume = cls.create_volume(imageRef=CONF.compute.image_ref) - - @decorators.idempotent_id('03efff0b-5c75-4822-8f10-8789ac15b13e') - @test.services('image') - def test_update_image_metadata(self): - # Update image metadata - image_metadata = {'image_id': '5137a025-3c5f-43c1-bc64-5f41270040a5', - 'image_name': 'image', - 'kernel_id': '6ff710d2-942b-4d6b-9168-8c9cc2404ab1', - 'ramdisk_id': 'somedisk'} - self.volumes_client.update_volume_image_metadata(self.volume['id'], - **image_metadata) - - # Fetch image metadata from the volume - volume_image_metadata = self.volumes_client.show_volume( - self.volume['id'])['volume']['volume_image_metadata'] - - # Verify image metadata was updated - self.assertThat(volume_image_metadata.items(), - matchers.ContainsAll(image_metadata.items())) - - # Delete one item from image metadata of the volume - self.volumes_client.delete_volume_image_metadata(self.volume['id'], - 'ramdisk_id') - del image_metadata['ramdisk_id'] - - # Fetch the new image metadata from the volume - volume_image_metadata = self.volumes_client.show_volume( - self.volume['id'])['volume']['volume_image_metadata'] - - # Verify image metadata was updated after item deletion - self.assertThat(volume_image_metadata.items(), - matchers.ContainsAll(image_metadata.items())) - self.assertNotIn('ramdisk_id', volume_image_metadata) diff --git a/tempest/api/volume/test_snapshot_metadata.py b/tempest/api/volume/test_snapshot_metadata.py deleted file mode 100644 index e6fe25d08..000000000 --- a/tempest/api/volume/test_snapshot_metadata.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from testtools import matchers - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class SnapshotMetadataTestJSON(base.BaseVolumeTest): - @classmethod - def skip_checks(cls): - super(SnapshotMetadataTestJSON, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder snapshot feature disabled") - - @classmethod - def resource_setup(cls): - super(SnapshotMetadataTestJSON, cls).resource_setup() - # Create a volume - cls.volume = cls.create_volume() - # Create a snapshot - cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id']) - - def tearDown(self): - # Update the metadata to {} - self.snapshots_client.update_snapshot_metadata( - self.snapshot['id'], metadata={}) - super(SnapshotMetadataTestJSON, self).tearDown() - - @decorators.idempotent_id('a2f20f99-e363-4584-be97-bc33afb1a56c') - def test_crud_snapshot_metadata(self): - # Create metadata for the snapshot - metadata = {"key1": "value1", - "key2": "value2", - "key3": "value3"} - update = {"key3": "value3_update", - "key4": "value4"} - expect = {"key4": "value4"} - # Create metadata - body = self.snapshots_client.create_snapshot_metadata( - self.snapshot['id'], metadata)['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(metadata.items())) - - # Get the metadata of the snapshot - body = self.snapshots_client.show_snapshot_metadata( - self.snapshot['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(metadata.items()), - 'Create snapshot metadata failed') - - # Update metadata - body = self.snapshots_client.update_snapshot_metadata( - self.snapshot['id'], metadata=update)['metadata'] - self.assertEqual(update, body) - body = self.snapshots_client.show_snapshot_metadata( - self.snapshot['id'])['metadata'] - self.assertEqual(update, body, 'Update snapshot metadata failed') - - # Delete one item metadata of the snapshot - self.snapshots_client.delete_snapshot_metadata_item( - self.snapshot['id'], "key3") - body = self.snapshots_client.show_snapshot_metadata( - self.snapshot['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(expect.items()), - 'Delete one item metadata of the snapshot failed') - self.assertNotIn("key3", body) - - @decorators.idempotent_id('e8ff85c5-8f97-477f-806a-3ac364a949ed') - def test_update_show_snapshot_metadata_item(self): - # Update metadata item for the snapshot - metadata = {"key1": "value1", - "key2": "value2", - "key3": "value3"} - update_item = {"key3": "value3_update"} - expect = {"key1": "value1", - "key2": "value2", - "key3": "value3_update"} - # Create metadata for the snapshot - self.snapshots_client.create_snapshot_metadata( - self.snapshot['id'], metadata) - # Get the metadata of the snapshot - body = self.snapshots_client.show_snapshot_metadata( - self.snapshot['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(metadata.items())) - # Update metadata item - body = self.snapshots_client.update_snapshot_metadata_item( - self.snapshot['id'], "key3", meta=update_item)['meta'] - self.assertEqual(update_item, body) - - # Get a specific metadata item of the snapshot - body = self.snapshots_client.show_snapshot_metadata_item( - self.snapshot['id'], "key3")['meta'] - self.assertEqual({"key3": expect['key3']}, body) - - # Get the metadata of the snapshot - body = self.snapshots_client.show_snapshot_metadata( - self.snapshot['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(expect.items())) diff --git a/tempest/api/volume/test_versions.py b/tempest/api/volume/test_versions.py deleted file mode 100644 index 0083a3b09..000000000 --- a/tempest/api/volume/test_versions.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2017 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.lib import decorators - - -class VersionsTest(base.BaseVolumeTest): - - _api_version = 3 - - @decorators.idempotent_id('77838fc4-b49b-4c64-9533-166762517369') - @decorators.attr(type='smoke') - def test_list_versions(self): - # NOTE: The version data is checked on service client side - # with JSON-Schema validation. It is enough to just call - # the API here. - self.versions_client.list_versions()['versions'] diff --git a/tempest/api/volume/test_volume_absolute_limits.py b/tempest/api/volume/test_volume_absolute_limits.py deleted file mode 100644 index 401846895..000000000 --- a/tempest/api/volume/test_volume_absolute_limits.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - - -CONF = config.CONF - - -# NOTE(zhufl): This inherits from BaseVolumeAdminTest because -# it requires force_tenant_isolation=True, which need admin -# credentials to create non-admin users for the tests. -class AbsoluteLimitsTests(base.BaseVolumeAdminTest): # noqa - - # avoid existing volumes of pre-defined tenant - force_tenant_isolation = True - - @classmethod - def resource_setup(cls): - super(AbsoluteLimitsTests, cls).resource_setup() - # Create a shared volume for tests - cls.volume = cls.create_volume() - - @decorators.idempotent_id('8e943f53-e9d6-4272-b2e9-adcf2f7c29ad') - def test_get_volume_absolute_limits(self): - # get volume limit for a tenant - absolute_limits = \ - self.volume_limits_client.show_limits( - )['limits']['absolute'] - - # verify volume limits and defaults per tenants - self.assertEqual(absolute_limits['totalGigabytesUsed'], - CONF.volume.volume_size) - self.assertEqual(absolute_limits['totalVolumesUsed'], 1) - self.assertEqual(absolute_limits['totalSnapshotsUsed'], 0) - self.assertEqual(absolute_limits['totalBackupsUsed'], 0) - self.assertEqual(absolute_limits['totalBackupGigabytesUsed'], 0) diff --git a/tempest/api/volume/test_volume_delete_cascade.py b/tempest/api/volume/test_volume_delete_cascade.py deleted file mode 100644 index bb32c114a..000000000 --- a/tempest/api/volume/test_volume_delete_cascade.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import operator - -import testtools - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesDeleteCascade(base.BaseVolumeTest): - """Delete a volume with associated snapshots. - - Cinder provides the ability to delete a volume with its - associated snapshots. - It is allow a volume and its snapshots to be removed in one operation - both for usability and performance reasons. - """ - - @classmethod - def skip_checks(cls): - super(VolumesDeleteCascade, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder snapshot feature disabled") - - def _assert_cascade_delete(self, volume_id): - # Fetch volume ids - volume_list = [ - vol['id'] for vol in - self.volumes_client.list_volumes()['volumes'] - ] - - # Verify the parent volume was deleted - self.assertNotIn(volume_id, volume_list) - - # List snapshots - snapshot_list = self.snapshots_client.list_snapshots()['snapshots'] - - # Verify snapshots were deleted - self.assertNotIn(volume_id, map(operator.itemgetter('volume_id'), - snapshot_list)) - - @decorators.idempotent_id('994e2d40-de37-46e8-b328-a58fba7e4a95') - def test_volume_delete_cascade(self): - # The case validates the ability to delete a volume - # with associated snapshots. - - # Create a volume - volume = self.create_volume() - - for _ in range(2): - self.create_snapshot(volume['id']) - - # Delete the parent volume with associated snapshots - self.volumes_client.delete_volume(volume['id'], cascade=True) - self.volumes_client.wait_for_resource_deletion(volume['id']) - - # Verify volume parent was deleted with its associated snapshots - self._assert_cascade_delete(volume['id']) - - @decorators.idempotent_id('59a77ede-609b-4ee8-9f68-fc3c6ffe97b5') - @testtools.skipIf(CONF.volume.storage_protocol == 'ceph', - 'Skip because of Bug#1677525') - def test_volume_from_snapshot_cascade_delete(self): - # The case validates the ability to delete a volume with - # associated snapshot while there is another volume created - # from that snapshot. - - # Create a volume - volume = self.create_volume() - - snapshot = self.create_snapshot(volume['id']) - - # Create volume from snapshot - volume_snap = self.create_volume(snapshot_id=snapshot['id']) - volume_details = self.volumes_client.show_volume( - volume_snap['id'])['volume'] - self.assertEqual(snapshot['id'], volume_details['snapshot_id']) - - # Delete the parent volume with associated snapshot - self.volumes_client.delete_volume(volume['id'], cascade=True) - self.volumes_client.wait_for_resource_deletion(volume['id']) - - # Verify volume parent was deleted with its associated snapshot - self._assert_cascade_delete(volume['id']) diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py deleted file mode 100644 index d203b2d60..000000000 --- a/tempest/api/volume/test_volume_metadata.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from testtools import matchers - -from tempest.api.volume import base -from tempest.lib import decorators - - -class VolumesMetadataTest(base.BaseVolumeTest): - - @classmethod - def resource_setup(cls): - super(VolumesMetadataTest, cls).resource_setup() - # Create a volume - cls.volume = cls.create_volume() - - def tearDown(self): - # Update the metadata to {} - self.volumes_client.update_volume_metadata(self.volume['id'], {}) - super(VolumesMetadataTest, self).tearDown() - - @decorators.idempotent_id('6f5b125b-f664-44bf-910f-751591fe5769') - def test_crud_volume_metadata(self): - # Create metadata for the volume - metadata = {"key1": "value1", - "key2": "value2", - "key3": "value3", - "key4": ""} - update = {"key4": "value4", - "key1": "value1_update"} - expected = {"key4": "value4"} - - body = self.volumes_client.create_volume_metadata(self.volume['id'], - metadata)['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(metadata.items())) - # Get the metadata of the volume - body = self.volumes_client.show_volume_metadata( - self.volume['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(metadata.items()), - 'Create metadata for the volume failed') - - # Update metadata - body = self.volumes_client.update_volume_metadata( - self.volume['id'], update)['metadata'] - self.assertEqual(update, body) - body = self.volumes_client.show_volume_metadata( - self.volume['id'])['metadata'] - self.assertEqual(update, body, 'Update metadata failed') - - # Delete one item metadata of the volume - self.volumes_client.delete_volume_metadata_item( - self.volume['id'], "key1") - body = self.volumes_client.show_volume_metadata( - self.volume['id'])['metadata'] - self.assertNotIn("key1", body) - self.assertThat(body.items(), matchers.ContainsAll(expected.items()), - 'Delete one item metadata of the volume failed') - - @decorators.idempotent_id('862261c5-8df4-475a-8c21-946e50e36a20') - def test_update_show_volume_metadata_item(self): - # Update metadata item for the volume - metadata = {"key1": "value1", - "key2": "value2", - "key3": "value3"} - update_item = {"key3": "value3_update"} - expect = {"key1": "value1", - "key2": "value2", - "key3": "value3_update"} - # Create metadata for the volume - body = self.volumes_client.create_volume_metadata( - self.volume['id'], metadata)['metadata'] - self.assertThat(body.items(), - matchers.ContainsAll(metadata.items())) - # Update metadata item - body = self.volumes_client.update_volume_metadata_item( - self.volume['id'], "key3", update_item)['meta'] - self.assertEqual(update_item, body) - - # Get a specific metadata item of the volume - body = self.volumes_client.show_volume_metadata_item( - self.volume['id'], "key3")['meta'] - self.assertEqual({"key3": expect['key3']}, body) - - # Get the metadata of the volume - body = self.volumes_client.show_volume_metadata( - self.volume['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(expect.items())) diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py deleted file mode 100644 index 4108da5dd..000000000 --- a/tempest/api/volume/test_volume_transfers.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.common import waiters -from tempest.lib import decorators - - -class VolumesTransfersTest(base.BaseVolumeTest): - - credentials = ['primary', 'alt', 'admin'] - - @classmethod - def setup_clients(cls): - super(VolumesTransfersTest, cls).setup_clients() - - cls.client = cls.os_primary.volume_transfers_v2_client - cls.alt_client = cls.os_alt.volume_transfers_v2_client - cls.alt_volumes_client = cls.os_alt.volumes_v2_client - cls.adm_volumes_client = cls.os_admin.volumes_v2_client - - @decorators.idempotent_id('4d75b645-a478-48b1-97c8-503f64242f1a') - def test_create_get_list_accept_volume_transfer(self): - # Create a volume first - volume = self.create_volume() - self.addCleanup(self.delete_volume, - self.adm_volumes_client, - volume['id']) - - # Create a volume transfer - transfer = self.client.create_volume_transfer( - volume_id=volume['id'])['transfer'] - transfer_id = transfer['id'] - auth_key = transfer['auth_key'] - waiters.wait_for_volume_resource_status( - self.volumes_client, volume['id'], 'awaiting-transfer') - - # Get a volume transfer - body = self.client.show_volume_transfer(transfer_id)['transfer'] - self.assertEqual(volume['id'], body['volume_id']) - - # List volume transfers, the result should be greater than - # or equal to 1 - body = self.client.list_volume_transfers()['transfers'] - self.assertNotEmpty(body) - - # Accept a volume transfer by alt_tenant - body = self.alt_client.accept_volume_transfer( - transfer_id, auth_key=auth_key)['transfer'] - for key in ['id', 'name', 'links', 'volume_id']: - self.assertIn(key, body) - waiters.wait_for_volume_resource_status(self.alt_volumes_client, - volume['id'], 'available') - accepted_volume = self.alt_volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual(self.os_alt.credentials.user_id, - accepted_volume['user_id']) - self.assertEqual(self.os_alt.credentials.project_id, - accepted_volume['os-vol-tenant-attr:tenant_id']) - - @decorators.idempotent_id('ab526943-b725-4c07-b875-8e8ef87a2c30') - def test_create_list_delete_volume_transfer(self): - # Create a volume first - volume = self.create_volume() - self.addCleanup(self.delete_volume, - self.adm_volumes_client, - volume['id']) - - # Create a volume transfer - transfer_id = self.client.create_volume_transfer( - volume_id=volume['id'])['transfer']['id'] - waiters.wait_for_volume_resource_status( - self.volumes_client, volume['id'], 'awaiting-transfer') - - # List all volume transfers with details, check the detail-specific - # elements, and look for the created transfer. - transfers = self.client.list_volume_transfers(detail=True)['transfers'] - self.assertNotEmpty(transfers) - for transfer in transfers: - self.assertIn('created_at', transfer) - volume_list = [transfer['volume_id'] for transfer in transfers] - self.assertIn(volume['id'], volume_list, - 'Transfer not found for volume %s' % volume['id']) - - # Delete a volume transfer - self.client.delete_volume_transfer(transfer_id) - waiters.wait_for_volume_resource_status( - self.volumes_client, volume['id'], 'available') diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py deleted file mode 100644 index c4d10c3d1..000000000 --- a/tempest/api/volume/test_volumes_actions.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class VolumesActionsTest(base.BaseVolumeTest): - - @classmethod - def resource_setup(cls): - super(VolumesActionsTest, cls).resource_setup() - - # Create a test shared volume for attach/detach tests - cls.volume = cls.create_volume() - - @decorators.idempotent_id('fff42874-7db5-4487-a8e1-ddda5fb5288d') - @decorators.attr(type='smoke') - @test.services('compute') - def test_attach_detach_volume_to_instance(self): - # Create a server - server = self.create_server() - # Volume is attached and detached successfully from an instance - self.volumes_client.attach_volume(self.volume['id'], - instance_uuid=server['id'], - mountpoint='/dev/%s' % - CONF.compute.volume_device_name) - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'in-use') - self.volumes_client.detach_volume(self.volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'available') - - @decorators.idempotent_id('63e21b4c-0a0c-41f6-bfc3-7c2816815599') - def test_volume_bootable(self): - # Verify that a volume bootable flag is retrieved - for bool_bootable in [True, False]: - self.volumes_client.set_bootable_volume(self.volume['id'], - bootable=bool_bootable) - fetched_volume = self.volumes_client.show_volume( - self.volume['id'])['volume'] - # Get Volume information - # NOTE(masayukig): 'bootable' is "true" or "false" in the current - # cinder implementation. So we need to cast boolean values to str - # and make it lower to compare here. - self.assertEqual(str(bool_bootable).lower(), - fetched_volume['bootable']) - - @decorators.idempotent_id('9516a2c8-9135-488c-8dd6-5677a7e5f371') - @test.services('compute') - def test_get_volume_attachment(self): - # Create a server - server = self.create_server() - # Verify that a volume's attachment information is retrieved - self.volumes_client.attach_volume(self.volume['id'], - instance_uuid=server['id'], - mountpoint='/dev/%s' % - CONF.compute.volume_device_name) - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], - 'in-use') - self.addCleanup(waiters.wait_for_volume_resource_status, - self.volumes_client, - self.volume['id'], 'available') - self.addCleanup(self.volumes_client.detach_volume, self.volume['id']) - volume = self.volumes_client.show_volume(self.volume['id'])['volume'] - self.assertIn('attachments', volume) - attachment = volume['attachments'][0] - - self.assertEqual('/dev/%s' % - CONF.compute.volume_device_name, - attachment['device']) - self.assertEqual(server['id'], attachment['server_id']) - self.assertEqual(self.volume['id'], attachment['id']) - self.assertEqual(self.volume['id'], attachment['volume_id']) - - @decorators.idempotent_id('d8f1ca95-3d5b-44a3-b8ca-909691c9532d') - @test.services('image') - def test_volume_upload(self): - # NOTE(gfidente): the volume uploaded in Glance comes from setUpClass, - # it is shared with the other tests. After it is uploaded in Glance, - # there is no way to delete it from Cinder, so we delete it from Glance - # using the Glance images_client and from Cinder via tearDownClass. - image_name = data_utils.rand_name(self.__class__.__name__ + '-Image') - body = self.volumes_client.upload_volume( - self.volume['id'], image_name=image_name, - disk_format=CONF.volume.disk_format)['os-volume_upload_image'] - image_id = body["image_id"] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.images_client.delete_image, - image_id) - waiters.wait_for_image_status(self.images_client, image_id, 'active') - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'available') - - @decorators.idempotent_id('92c4ef64-51b2-40c0-9f7e-4749fbaaba33') - def test_reserve_unreserve_volume(self): - # Mark volume as reserved. - self.volumes_client.reserve_volume(self.volume['id']) - # To get the volume info - body = self.volumes_client.show_volume(self.volume['id'])['volume'] - self.assertIn('attaching', body['status']) - # Unmark volume as reserved. - self.volumes_client.unreserve_volume(self.volume['id']) - # To get the volume info - body = self.volumes_client.show_volume(self.volume['id'])['volume'] - self.assertIn('available', body['status']) - - @decorators.idempotent_id('fff74e1e-5bd3-4b33-9ea9-24c103bc3f59') - def test_volume_readonly_update(self): - for readonly in [True, False]: - # Update volume readonly - self.volumes_client.update_volume_readonly(self.volume['id'], - readonly=readonly) - # Get Volume information - fetched_volume = self.volumes_client.show_volume( - self.volume['id'])['volume'] - # NOTE(masayukig): 'readonly' is "True" or "False" in the current - # cinder implementation. So we need to cast boolean values to str - # to compare here. - self.assertEqual(str(readonly), - fetched_volume['metadata']['readonly']) diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py deleted file mode 100644 index 1f91db67d..000000000 --- a/tempest/api/volume/test_volumes_backup.py +++ /dev/null @@ -1,178 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools -from testtools import matchers - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class VolumesBackupsTest(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesBackupsTest, cls).skip_checks() - if not CONF.volume_feature_enabled.backup: - raise cls.skipException("Cinder backup feature disabled") - - def restore_backup(self, backup_id): - # Restore a backup - restored_volume = self.backups_client.restore_backup( - backup_id)['restore'] - - # Delete backup - self.addCleanup(self.volumes_client.delete_volume, - restored_volume['volume_id']) - self.assertEqual(backup_id, restored_volume['backup_id']) - waiters.wait_for_volume_resource_status(self.backups_client, - backup_id, 'available') - waiters.wait_for_volume_resource_status(self.volumes_client, - restored_volume['volume_id'], - 'available') - return restored_volume - - @testtools.skipIf(CONF.volume.storage_protocol == 'ceph', - 'ceph does not support arbitrary container names') - @decorators.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6') - def test_volume_backup_create_get_detailed_list_restore_delete(self): - # Create a volume with metadata - metadata = {"vol-meta1": "value1", - "vol-meta2": "value2", - "vol-meta3": "value3"} - volume = self.create_volume(metadata=metadata) - self.addCleanup(self.volumes_client.delete_volume, - volume['id']) - - # Create a backup - backup_name = data_utils.rand_name( - self.__class__.__name__ + '-Backup') - description = data_utils.rand_name("volume-backup-description") - backup = self.create_backup(volume_id=volume['id'], - name=backup_name, - description=description, - container='container') - self.assertEqual(backup_name, backup['name']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - # Get a given backup - backup = self.backups_client.show_backup(backup['id'])['backup'] - self.assertEqual(backup_name, backup['name']) - self.assertEqual(description, backup['description']) - self.assertEqual('container', backup['container']) - - # Get all backups with detail - backups = self.backups_client.list_backups( - detail=True)['backups'] - self.assertIn((backup['name'], backup['id']), - [(m['name'], m['id']) for m in backups]) - - restored_volume = self.restore_backup(backup['id']) - - restored_volume_metadata = self.volumes_client.show_volume( - restored_volume['volume_id'])['volume']['metadata'] - - # Verify the backups has been restored successfully - # with the metadata of the source volume. - self.assertThat(restored_volume_metadata.items(), - matchers.ContainsAll(metadata.items())) - - @decorators.idempotent_id('07af8f6d-80af-44c9-a5dc-c8427b1b62e6') - @test.services('compute') - def test_backup_create_attached_volume(self): - """Test backup create using force flag. - - Cinder allows to create a volume backup, whether the volume status - is "available" or "in-use". - """ - # Create a server - volume = self.create_volume() - self.addCleanup(self.volumes_client.delete_volume, - volume['id']) - server = self.create_server() - # Attach volume to instance - self.attach_volume(server['id'], volume['id']) - # Create backup using force flag - backup_name = data_utils.rand_name( - self.__class__.__name__ + '-Backup') - backup = self.create_backup(volume_id=volume['id'], - name=backup_name, force=True) - self.assertEqual(backup_name, backup['name']) - - @decorators.idempotent_id('2a8ba340-dff2-4511-9db7-646f07156b15') - @test.services('image') - def test_bootable_volume_backup_and_restore(self): - # Create volume from image - img_uuid = CONF.compute.image_ref - volume = self.create_volume(imageRef=img_uuid) - - volume_details = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual('true', volume_details['bootable']) - - # Create a backup - backup = self.create_backup(volume_id=volume['id']) - - # Restore the backup - restored_volume_id = self.restore_backup(backup['id'])['volume_id'] - - # Verify the restored backup volume is bootable - restored_volume_info = self.volumes_client.show_volume( - restored_volume_id)['volume'] - - self.assertEqual('true', restored_volume_info['bootable']) - - -class VolumesBackupsV39Test(base.BaseVolumeTest): - - _api_version = 3 - min_microversion = '3.9' - max_microversion = 'latest' - - @classmethod - def skip_checks(cls): - super(VolumesBackupsV39Test, cls).skip_checks() - if not CONF.volume_feature_enabled.backup: - raise cls.skipException("Cinder backup feature disabled") - - @decorators.idempotent_id('9b374cbc-be5f-4d37-8848-7efb8a873dcc') - def test_update_backup(self): - # Create volume and backup - volume = self.create_volume() - backup = self.create_backup(volume_id=volume['id']) - - # Update backup and assert response body for update_backup method - update_kwargs = { - 'name': data_utils.rand_name(self.__class__.__name__ + '-Backup'), - 'description': data_utils.rand_name("volume-backup-description") - } - update_backup = self.backups_client.update_backup( - backup['id'], **update_kwargs)['backup'] - self.assertEqual(backup['id'], update_backup['id']) - self.assertEqual(update_kwargs['name'], update_backup['name']) - self.assertIn('links', update_backup) - - # Assert response body for show_backup method - retrieved_backup = self.backups_client.show_backup( - backup['id'])['backup'] - for key in update_kwargs: - self.assertEqual(update_kwargs[key], retrieved_backup[key]) diff --git a/tempest/api/volume/test_volumes_clone.py b/tempest/api/volume/test_volumes_clone.py deleted file mode 100644 index 927bfa5a2..000000000 --- a/tempest/api/volume/test_volumes_clone.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest import test - - -CONF = config.CONF - - -class VolumesCloneTest(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesCloneTest, cls).skip_checks() - if not CONF.volume_feature_enabled.clone: - raise cls.skipException("Cinder volume clones are disabled") - - def _verify_volume_clone(self, source_volume, cloned_volume, - bootable='false', extra_size=0): - - cloned_vol_details = self.volumes_client.show_volume( - cloned_volume['id'])['volume'] - - self.assertEqual(source_volume['id'], - cloned_vol_details['source_volid']) - self.assertEqual(source_volume['size'] + extra_size, - cloned_vol_details['size']) - self.assertEqual(bootable, cloned_vol_details['bootable']) - - @decorators.idempotent_id('9adae371-a257-43a5-9555-dc7c88e66e0e') - def test_create_from_volume(self): - # Creates a volume from another volume passing a size different from - # the source volume. - src_size = CONF.volume.volume_size - - src_vol = self.create_volume(size=src_size) - # Destination volume bigger than source - dst_vol = self.create_volume(source_volid=src_vol['id'], - size=src_size + 1) - - self._verify_volume_clone(src_vol, dst_vol, extra_size=1) - - @decorators.idempotent_id('cbbcd7c6-5a6c-481a-97ac-ca55ab715d16') - @test.services('image') - def test_create_from_bootable_volume(self): - # Create volume from image - img_uuid = CONF.compute.image_ref - src_vol = self.create_volume(imageRef=img_uuid) - - # Create a volume from the bootable volume - cloned_vol = self.create_volume(source_volid=src_vol['id']) - - self._verify_volume_clone(src_vol, cloned_vol, bootable='true') diff --git a/tempest/api/volume/test_volumes_clone_negative.py b/tempest/api/volume/test_volumes_clone_negative.py deleted file mode 100644 index bba7a0bb8..000000000 --- a/tempest/api/volume/test_volumes_clone_negative.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class VolumesCloneNegativeTest(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesCloneNegativeTest, cls).skip_checks() - if not CONF.volume_feature_enabled.clone: - raise cls.skipException("Cinder volume clones are disabled") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9adae371-a257-43a5-459a-dc7c88e66e0e') - def test_create_from_volume_decreasing_size(self): - # Creates a volume from another volume passing a size different from - # the source volume. - src_size = CONF.volume.volume_size + 1 - src_vol = self.create_volume(size=src_size) - - # Destination volume smaller than source - self.assertRaises(exceptions.BadRequest, - self.volumes_client.create_volume, - size=src_size - 1, - source_volid=src_vol['id']) diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py deleted file mode 100644 index 1eb76a06a..000000000 --- a/tempest/api/volume/test_volumes_extend.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesExtendTest(base.BaseVolumeTest): - - @decorators.idempotent_id('9a36df71-a257-43a5-9555-dc7c88e66e0e') - def test_volume_extend(self): - # Extend Volume Test. - volume = self.create_volume() - extend_size = volume['size'] + 1 - self.volumes_client.extend_volume(volume['id'], - new_size=extend_size) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - volume = self.volumes_client.show_volume(volume['id'])['volume'] - self.assertEqual(volume['size'], extend_size) - - @decorators.idempotent_id('86be1cba-2640-11e5-9c82-635fb964c912') - @testtools.skipUnless(CONF.volume_feature_enabled.snapshot, - "Cinder volume snapshots are disabled") - @decorators.skip_because(bug='1687044') - def test_volume_extend_when_volume_has_snapshot(self): - volume = self.create_volume() - self.create_snapshot(volume['id']) - - extend_size = volume['size'] + 1 - self.volumes_client.extend_volume(volume['id'], new_size=extend_size) - - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - resized_volume = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual(extend_size, resized_volume['size']) diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py deleted file mode 100644 index ec9a0dd9f..000000000 --- a/tempest/api/volume/test_volumes_get.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools -from testtools import matchers - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class VolumesGetTest(base.BaseVolumeTest): - - def _volume_create_get_update_delete(self, **kwargs): - # Create a volume, Get it's details and Delete the volume - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - metadata = {'Type': 'Test'} - # Create a volume - kwargs['name'] = v_name - kwargs['metadata'] = metadata - volume = self.volumes_client.create_volume(**kwargs)['volume'] - self.assertIn('id', volume) - self.addCleanup(self.delete_volume, self.volumes_client, volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - self.assertIn('name', volume) - self.assertEqual(volume['name'], v_name, - "The created volume name is not equal " - "to the requested name") - - # Get Volume information - fetched_volume = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual(v_name, - fetched_volume['name'], - 'The fetched Volume name is different ' - 'from the created Volume') - self.assertEqual(volume['id'], - fetched_volume['id'], - 'The fetched Volume id is different ' - 'from the created Volume') - self.assertThat(fetched_volume['metadata'].items(), - matchers.ContainsAll(metadata.items()), - 'The fetched Volume metadata misses data ' - 'from the created Volume') - - if 'imageRef' in kwargs: - self.assertEqual('true', fetched_volume['bootable']) - else: - self.assertEqual('false', fetched_volume['bootable']) - - # Update Volume - # Test volume update when display_name is same with original value - params = {'name': v_name} - self.volumes_client.update_volume(volume['id'], **params) - # Test volume update when display_name is new - new_v_name = data_utils.rand_name( - self.__class__.__name__ + '-new-Volume') - new_desc = 'This is the new description of volume' - params = {'name': new_v_name, - 'description': new_desc} - update_volume = self.volumes_client.update_volume( - volume['id'], **params)['volume'] - # Assert response body for update_volume method - self.assertEqual(new_v_name, update_volume['name']) - self.assertEqual(new_desc, update_volume['description']) - # Assert response body for show_volume method - updated_volume = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual(volume['id'], updated_volume['id']) - self.assertEqual(new_v_name, updated_volume['name']) - self.assertEqual(new_desc, updated_volume['description']) - self.assertThat(updated_volume['metadata'].items(), - matchers.ContainsAll(metadata.items()), - 'The fetched Volume metadata misses data ' - 'from the created Volume') - - # Test volume create when display_name is none and display_description - # contains specific characters, - # then test volume update if display_name is duplicated - new_v_desc = data_utils.rand_name('@#$%^* description') - params = {'description': new_v_desc, - 'availability_zone': volume['availability_zone'], - 'size': CONF.volume.volume_size} - new_volume = self.volumes_client.create_volume(**params)['volume'] - self.assertIn('id', new_volume) - self.addCleanup(self.delete_volume, self.volumes_client, - new_volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - new_volume['id'], 'available') - - params = {'name': volume['name'], - 'description': volume['description']} - self.volumes_client.update_volume(new_volume['id'], **params) - - if 'imageRef' in kwargs: - self.assertEqual('true', updated_volume['bootable']) - else: - self.assertEqual('false', updated_volume['bootable']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('27fb0e9f-fb64-41dd-8bdb-1ffa762f0d51') - def test_volume_create_get_update_delete(self): - self._volume_create_get_update_delete(size=CONF.volume.volume_size) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('54a01030-c7fc-447c-86ee-c1182beae638') - @test.services('image') - def test_volume_create_get_update_delete_from_image(self): - image = self.images_client.show_image(CONF.compute.image_ref) - min_disk = image['min_disk'] - disk_size = max(min_disk, CONF.volume.volume_size) - self._volume_create_get_update_delete( - imageRef=CONF.compute.image_ref, size=disk_size) - - @decorators.idempotent_id('3f591b4a-7dc6-444c-bd51-77469506b3a1') - @testtools.skipUnless(CONF.volume_feature_enabled.clone, - 'Cinder volume clones are disabled') - def test_volume_create_get_update_delete_as_clone(self): - origin = self.create_volume() - self._volume_create_get_update_delete(source_volid=origin['id'], - size=CONF.volume.volume_size) - - -class VolumesSummaryTest(base.BaseVolumeTest): - - _api_version = 3 - min_microversion = '3.12' - max_microversion = 'latest' - - @decorators.idempotent_id('c4f2431e-4920-4736-9e00-4040386b6feb') - def test_show_volume_summary(self): - volume_summary = \ - self.volumes_client.show_volume_summary()['volume-summary'] - for key in ['total_size', 'total_count']: - self.assertIn(key, volume_summary) diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py deleted file mode 100644 index 8593d3a8e..000000000 --- a/tempest/api/volume/test_volumes_list.py +++ /dev/null @@ -1,380 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import operator -import random - -from six.moves.urllib import parse -from testtools import matchers - -from tempest.api.volume import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class VolumesListTestJSON(base.BaseVolumeTest): - # NOTE: This test creates a number of 1G volumes. To run successfully, - # ensure that the backing file for the volume group that Nova uses - # has space for at least 3 1G volumes! - # If you are running a Devstack environment, ensure that the - # VOLUME_BACKING_FILE_SIZE is at least 4G in your localrc - - VOLUME_FIELDS = ('id', 'name') - - def assertVolumesIn(self, fetched_list, expected_list, fields=None): - """Check out the list. - - This function is aim at check out whether all of the volumes in - expected_list are in fetched_list. - """ - if fields: - fieldsgetter = operator.itemgetter(*fields) - expected_list = map(fieldsgetter, expected_list) - fetched_list = [fieldsgetter(item) for item in fetched_list] - - missing_vols = [v for v in expected_list if v not in fetched_list] - if not missing_vols: - return - - def str_vol(vol): - return "%s:%s" % (vol['id'], vol[self.name]) - - raw_msg = "Could not find volumes %s in expected list %s; fetched %s" - self.fail(raw_msg % ([str_vol(v) for v in missing_vols], - [str_vol(v) for v in expected_list], - [str_vol(v) for v in fetched_list])) - - @classmethod - def resource_setup(cls): - super(VolumesListTestJSON, cls).resource_setup() - cls.name = cls.VOLUME_FIELDS[1] - - existing_volumes = cls.volumes_client.list_volumes()['volumes'] - cls.volume_id_list = [vol['id'] for vol in existing_volumes] - - # Create 3 test volumes - cls.volume_list = [] - cls.metadata = {'Type': 'work'} - for _ in range(3): - volume = cls.create_volume(metadata=cls.metadata) - volume = cls.volumes_client.show_volume(volume['id'])['volume'] - cls.volume_list.append(volume) - cls.volume_id_list.append(volume['id']) - - def _list_by_param_value_and_assert(self, params, with_detail=False): - """list or list_details with given params and validates result""" - if with_detail: - fetched_vol_list = \ - self.volumes_client.list_volumes(detail=True, - params=params)['volumes'] - else: - fetched_vol_list = self.volumes_client.list_volumes( - params=params)['volumes'] - - # Validating params of fetched volumes - if with_detail: - for volume in fetched_vol_list: - for key in params: - msg = "Failed to list volumes %s by %s" % \ - ('details' if with_detail else '', key) - if key == 'metadata': - self.assertThat( - volume[key].items(), - matchers.ContainsAll(params[key].items()), - msg) - else: - self.assertEqual(params[key], volume[key], msg) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('0b6ddd39-b948-471f-8038-4787978747c4') - def test_volume_list(self): - # Get a list of Volumes - # Fetch all volumes - fetched_list = self.volumes_client.list_volumes()['volumes'] - self.assertVolumesIn(fetched_list, self.volume_list, - fields=self.VOLUME_FIELDS) - - @decorators.idempotent_id('adcbb5a7-5ad8-4b61-bd10-5380e111a877') - def test_volume_list_with_details(self): - # Get a list of Volumes with details - # Fetch all Volumes - fetched_list = self.volumes_client.list_volumes(detail=True)['volumes'] - self.assertVolumesIn(fetched_list, self.volume_list) - - @decorators.idempotent_id('a28e8da4-0b56-472f-87a8-0f4d3f819c02') - def test_volume_list_by_name(self): - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - params = {self.name: volume[self.name]} - fetched_vol = self.volumes_client.list_volumes( - params=params)['volumes'] - self.assertEqual(1, len(fetched_vol), str(fetched_vol)) - self.assertEqual(fetched_vol[0][self.name], - volume[self.name]) - - @decorators.idempotent_id('2de3a6d4-12aa-403b-a8f2-fdeb42a89623') - def test_volume_list_details_by_name(self): - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - params = {self.name: volume[self.name]} - fetched_vol = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - self.assertEqual(1, len(fetched_vol), str(fetched_vol)) - self.assertEqual(fetched_vol[0][self.name], - volume[self.name]) - - @decorators.idempotent_id('39654e13-734c-4dab-95ce-7613bf8407ce') - def test_volumes_list_by_status(self): - params = {'status': 'available'} - fetched_list = self.volumes_client.list_volumes( - params=params)['volumes'] - self._list_by_param_value_and_assert(params) - self.assertVolumesIn(fetched_list, self.volume_list, - fields=self.VOLUME_FIELDS) - - @decorators.idempotent_id('2943f712-71ec-482a-bf49-d5ca06216b9f') - def test_volumes_list_details_by_status(self): - params = {'status': 'available'} - fetched_list = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - for volume in fetched_list: - self.assertEqual('available', volume['status']) - self.assertVolumesIn(fetched_list, self.volume_list) - - @decorators.idempotent_id('2016a942-3020-40d7-95ce-7613bf8407ce') - def test_volumes_list_by_bootable(self): - """Check out volumes. - - This test function is aim at check out whether all of the volumes - in volume_list are not a bootable volume. - """ - params = {'bootable': 'false'} - fetched_list = self.volumes_client.list_volumes( - params=params)['volumes'] - self._list_by_param_value_and_assert(params) - self.assertVolumesIn(fetched_list, self.volume_list, - fields=self.VOLUME_FIELDS) - - @decorators.idempotent_id('2016a939-72ec-482a-bf49-d5ca06216b9f') - def test_volumes_list_details_by_bootable(self): - params = {'bootable': 'false'} - fetched_list = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - for volume in fetched_list: - self.assertEqual('false', volume['bootable']) - self.assertVolumesIn(fetched_list, self.volume_list) - - @decorators.idempotent_id('c0cfa863-3020-40d7-b587-e35f597d5d87') - def test_volumes_list_by_availability_zone(self): - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - zone = volume['availability_zone'] - params = {'availability_zone': zone} - fetched_list = self.volumes_client.list_volumes( - params=params)['volumes'] - self._list_by_param_value_and_assert(params) - self.assertVolumesIn(fetched_list, self.volume_list, - fields=self.VOLUME_FIELDS) - - @decorators.idempotent_id('e1b80d13-94f0-4ba2-a40e-386af29f8db1') - def test_volumes_list_details_by_availability_zone(self): - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - zone = volume['availability_zone'] - params = {'availability_zone': zone} - fetched_list = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - for volume in fetched_list: - self.assertEqual(zone, volume['availability_zone']) - self.assertVolumesIn(fetched_list, self.volume_list) - - @decorators.idempotent_id('b5ebea1b-0603-40a0-bb41-15fcd0a53214') - def test_volume_list_with_param_metadata(self): - # Test to list volumes when metadata param is given - params = {'metadata': self.metadata} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('1ca92d3c-4a8e-4b43-93f5-e4c7fb3b291d') - def test_volume_list_with_detail_param_metadata(self): - # Test to list volumes details when metadata param is given - params = {'metadata': self.metadata} - self._list_by_param_value_and_assert(params, with_detail=True) - - @decorators.idempotent_id('777c87c1-2fc4-4883-8b8e-5c0b951d1ec8') - def test_volume_list_param_display_name_and_status(self): - # Test to list volume when display name and status param is given - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - params = {self.name: volume[self.name], - 'status': 'available'} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('856ab8ca-6009-4c37-b691-be1065528ad4') - def test_volume_list_with_detail_param_display_name_and_status(self): - # Test to list volume when name and status param is given - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - params = {self.name: volume[self.name], - 'status': 'available'} - self._list_by_param_value_and_assert(params, with_detail=True) - - @decorators.idempotent_id('2a7064eb-b9c3-429b-b888-33928fc5edd3') - def test_volume_list_details_with_multiple_params(self): - # List volumes detail using combined condition - def _list_details_with_multiple_params(limit=2, - status='available', - sort_dir='asc', - sort_key='id'): - params = {'limit': limit, - 'status': status, - 'sort_dir': sort_dir, - 'sort_key': sort_key - } - fetched_volume = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - self.assertEqual(limit, len(fetched_volume), - "The count of volumes is %s, expected:%s " % - (len(fetched_volume), limit)) - self.assertEqual(status, fetched_volume[0]['status']) - self.assertEqual(status, fetched_volume[1]['status']) - val0 = fetched_volume[0][sort_key] - val1 = fetched_volume[1][sort_key] - if sort_dir == 'asc': - self.assertLess(val0, val1, - "list is not in asc order with sort_key: %s." - " %s" % (sort_key, fetched_volume)) - elif sort_dir == 'desc': - self.assertGreater(val0, val1, - "list is not in desc order with sort_key: " - "%s. %s" % (sort_key, fetched_volume)) - - _list_details_with_multiple_params() - _list_details_with_multiple_params(sort_dir='desc') - - def _test_pagination(self, resource, ids=None, limit=1, **kwargs): - """Check list pagination functionality for a resource. - - This method requests the list of resources and follows pagination - links. - - If an iterable is supplied in ids it will check that all ids are - retrieved and that only those are listed, that we will get a next - link for an empty page if the number of items is divisible by used - limit (this is expected behavior). - - We can specify number of items per request using limit argument. - """ - - # Get list method for the type of resource from the client - client = getattr(self, resource + '_client') - method = getattr(client, 'list_' + resource) - - # Include limit in params for list request - params = kwargs.pop('params', {}) - params['limit'] = limit - - # Store remaining items we are expecting from list - if ids is not None: - remaining = list(ids) - else: - remaining = None - - # Mark that the current iteration is not from a 'next' link - next = None - - while True: - # Get a list page - response = method(params=params, **kwargs) - - # If we have to check ids - if remaining is not None: - # Confirm we receive expected number of elements - num_expected = min(len(remaining), limit) - self.assertEqual(num_expected, len(response[resource]), - 'Requested %(#expect)d but got %(#received)d ' - % {'#expect': num_expected, - '#received': len(response[resource])}) - - # For each received element - for element in response[resource]: - element_id = element['id'] - # Check it's one of expected ids - self.assertIn(element_id, - ids, - 'Id %(id)s is not in expected ids %(ids)s' % - {'id': element_id, 'ids': ids}) - # If not in remaining, we have received it twice - self.assertIn(element_id, - remaining, - 'Id %s was received twice' % element_id) - # We no longer expect it - remaining.remove(element_id) - - # If the current iteration is from a 'next' link, check that the - # absolute url is the same as the one used for this request - if next: - self.assertEqual(next, response.response['content-location']) - - # Get next from response - next = None - for link in response.get(resource + '_links', ()): - if link['rel'] == 'next': - next = link['href'] - break - - # Check if we have next and we shouldn't or the other way around - if remaining is not None: - if remaining or (num_expected and len(ids) % limit == 0): - self.assertIsNotNone(next, 'Missing link to next page') - else: - self.assertIsNone(next, 'Unexpected link to next page') - - # If we can follow to the next page, get params from url to make - # request in the form of a relative URL - if next: - params = parse.urlparse(next).query - - # If cannot follow make sure it's because we have finished - else: - self.assertEmpty(remaining or [], - 'No more pages reported, but still ' - 'missing ids %s' % remaining) - break - - @decorators.idempotent_id('e9138a2c-f67b-4796-8efa-635c196d01de') - def test_volume_list_details_pagination(self): - self._test_pagination('volumes', ids=self.volume_id_list, detail=True) - - @decorators.idempotent_id('af55e775-8e4b-4feb-8719-215c43b0238c') - def test_volume_list_pagination(self): - self._test_pagination('volumes', ids=self.volume_id_list, detail=False) - - @decorators.idempotent_id('46eff077-100b-427f-914e-3db2abcdb7e2') - def test_volume_list_with_detail_param_marker(self): - # Choosing a random volume from a list of volumes for 'marker' - # parameter - marker = random.choice(self.volume_id_list) - - # Though Cinder volumes are returned sorted by ID by default - # this is implicit. Let make this explicit in case Cinder - # folks change their minds. - params = {'marker': marker, 'sort': 'id:asc'} - - # Running volume list using marker parameter - vol_with_marker = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - - expected_volumes_id = { - id for id in self.volume_id_list if id > marker - } - - self.assertEqual( - expected_volumes_id, {v['id'] for v in vol_with_marker} - ) diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py deleted file mode 100644 index 4e19e620f..000000000 --- a/tempest/api/volume/test_volumes_negative.py +++ /dev/null @@ -1,322 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class VolumesNegativeTest(base.BaseVolumeTest): - - @classmethod - def resource_setup(cls): - super(VolumesNegativeTest, cls).resource_setup() - - # Create a test shared instance and volume for attach/detach tests - cls.volume = cls.create_volume() - cls.mountpoint = "/dev/vdc" - - def create_image(self): - # Create image - image_name = data_utils.rand_name(self.__class__.__name__ + "-image") - image = self.images_client.create_image( - name=image_name, - container_format=CONF.image.container_formats[0], - disk_format=CONF.image.disk_formats[0], - visibility='private', - min_disk=CONF.volume.volume_size + 1) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.images_client.delete_image, image['id']) - - # Upload image with 1KB data - image_file = six.BytesIO(data_utils.random_bytes()) - self.images_client.store_image_file(image['id'], image_file) - waiters.wait_for_image_status(self.images_client, - image['id'], 'active') - return image - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f131c586-9448-44a4-a8b0-54ca838aa43e') - def test_volume_get_nonexistent_volume_id(self): - # Should not be able to get a non-existent volume - self.assertRaises(lib_exc.NotFound, self.volumes_client.show_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('555efa6e-efcd-44ef-8a3b-4a7ca4837a29') - def test_volume_delete_nonexistent_volume_id(self): - # Should not be able to delete a non-existent Volume - self.assertRaises(lib_exc.NotFound, self.volumes_client.delete_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1ed83a8a-682d-4dfb-a30e-ee63ffd6c049') - def test_create_volume_with_invalid_size(self): - # Should not be able to create volume with invalid size in request - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, size='#$%') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9387686f-334f-4d31-a439-33494b9e2683') - def test_create_volume_without_passing_size(self): - # Should not be able to create volume without passing size - # in request - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, size='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('41331caa-eaf4-4001-869d-bc18c1869360') - def test_create_volume_with_size_zero(self): - # Should not be able to create volume with size zero - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, size='0') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8b472729-9eba-446e-a83b-916bdb34bef7') - def test_create_volume_with_size_negative(self): - # Should not be able to create volume with size negative - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, size='-1') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('10254ed8-3849-454e-862e-3ab8e6aa01d2') - def test_create_volume_with_nonexistent_volume_type(self): - # Should not be able to create volume with non-existent volume type - self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume, - size='1', volume_type=data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0c36f6ae-4604-4017-b0a9-34fdc63096f9') - def test_create_volume_with_nonexistent_snapshot_id(self): - # Should not be able to create volume with non-existent snapshot - self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume, - size='1', snapshot_id=data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('47c73e08-4be8-45bb-bfdf-0c4e79b88344') - def test_create_volume_with_nonexistent_source_volid(self): - # Should not be able to create volume with non-existent source volume - self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume, - size='1', source_volid=data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0186422c-999a-480e-a026-6a665744c30c') - def test_update_volume_with_nonexistent_volume_id(self): - self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume, - volume_id=data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e66e40d6-65e6-4e75-bdc7-636792fa152d') - def test_update_volume_with_invalid_volume_id(self): - self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume, - volume_id=data_utils.rand_name('invalid')) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('72aeca85-57a5-4c1f-9057-f320f9ea575b') - def test_update_volume_with_empty_volume_id(self): - self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume, - volume_id='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('30799cfd-7ee4-446c-b66c-45b383ed211b') - def test_get_invalid_volume_id(self): - # Should not be able to get volume with invalid id - self.assertRaises(lib_exc.NotFound, self.volumes_client.show_volume, - data_utils.rand_name('invalid')) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c6c3db06-29ad-4e91-beb0-2ab195fe49e3') - def test_get_volume_without_passing_volume_id(self): - # Should not be able to get volume when empty ID is passed - self.assertRaises(lib_exc.NotFound, - self.volumes_client.show_volume, '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1f035827-7c32-4019-9240-b4ec2dbd9dfd') - def test_delete_invalid_volume_id(self): - # Should not be able to delete volume when invalid ID is passed - self.assertRaises(lib_exc.NotFound, self.volumes_client.delete_volume, - data_utils.rand_name('invalid')) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('441a1550-5d44-4b30-af0f-a6d402f52026') - def test_delete_volume_without_passing_volume_id(self): - # Should not be able to delete volume when empty ID is passed - self.assertRaises(lib_exc.NotFound, - self.volumes_client.delete_volume, '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f5e56b0a-5d02-43c1-a2a7-c9b792c2e3f6') - @test.services('compute') - def test_attach_volumes_with_nonexistent_volume_id(self): - server = self.create_server() - - self.assertRaises(lib_exc.NotFound, - self.volumes_client.attach_volume, - data_utils.rand_uuid(), - instance_uuid=server['id'], - mountpoint=self.mountpoint) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9f9c24e4-011d-46b5-b992-952140ce237a') - def test_detach_volumes_with_invalid_volume_id(self): - self.assertRaises(lib_exc.NotFound, - self.volumes_client.detach_volume, - 'xxx') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e0c75c74-ee34-41a9-9288-2a2051452854') - def test_volume_extend_with_size_smaller_than_original_size(self): - # Extend volume with smaller size than original size. - extend_size = 0 - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.extend_volume, - self.volume['id'], new_size=extend_size) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5d0b480d-e833-439f-8a5a-96ad2ed6f22f') - def test_volume_extend_with_non_number_size(self): - # Extend volume when size is non number. - extend_size = 'abc' - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.extend_volume, - self.volume['id'], new_size=extend_size) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('355218f1-8991-400a-a6bb-971239287d92') - def test_volume_extend_with_None_size(self): - # Extend volume with None size. - extend_size = None - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.extend_volume, - self.volume['id'], new_size=extend_size) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8f05a943-013c-4063-ac71-7baf561e82eb') - def test_volume_extend_with_nonexistent_volume_id(self): - # Extend volume size when volume is nonexistent. - extend_size = self.volume['size'] + 1 - self.assertRaises(lib_exc.NotFound, self.volumes_client.extend_volume, - data_utils.rand_uuid(), new_size=extend_size) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('aff8ba64-6d6f-4f2e-bc33-41a08ee9f115') - def test_volume_extend_without_passing_volume_id(self): - # Extend volume size when passing volume id is None. - extend_size = self.volume['size'] + 1 - self.assertRaises(lib_exc.NotFound, self.volumes_client.extend_volume, - None, new_size=extend_size) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ac6084c0-0546-45f9-b284-38a367e0e0e2') - def test_reserve_volume_with_nonexistent_volume_id(self): - self.assertRaises(lib_exc.NotFound, - self.volumes_client.reserve_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('eb467654-3dc1-4a72-9b46-47c29d22654c') - def test_unreserve_volume_with_nonexistent_volume_id(self): - self.assertRaises(lib_exc.NotFound, - self.volumes_client.unreserve_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('449c4ed2-ecdd-47bb-98dc-072aeccf158c') - def test_reserve_volume_with_negative_volume_status(self): - # Mark volume as reserved. - self.volumes_client.reserve_volume(self.volume['id']) - # Mark volume which is marked as reserved before - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.reserve_volume, - self.volume['id']) - # Unmark volume as reserved. - self.volumes_client.unreserve_volume(self.volume['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0f4aa809-8c7b-418f-8fb3-84c7a5dfc52f') - def test_list_volumes_with_nonexistent_name(self): - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - params = {'name': v_name} - fetched_volume = self.volumes_client.list_volumes( - params=params)['volumes'] - self.assertEmpty(fetched_volume) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9ca17820-a0e7-4cbd-a7fa-f4468735e359') - def test_list_volumes_detail_with_nonexistent_name(self): - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - params = {'name': v_name} - fetched_volume = \ - self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - self.assertEmpty(fetched_volume) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('143b279b-7522-466b-81be-34a87d564a7c') - def test_list_volumes_with_invalid_status(self): - params = {'status': 'null'} - fetched_volume = self.volumes_client.list_volumes( - params=params)['volumes'] - self.assertEmpty(fetched_volume) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ba94b27b-be3f-496c-a00e-0283b373fa75') - def test_list_volumes_detail_with_invalid_status(self): - params = {'status': 'null'} - fetched_volume = \ - self.volumes_client.list_volumes(detail=True, - params=params)['volumes'] - self.assertEmpty(fetched_volume) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5b810c91-0ad1-47ce-aee8-615f789be78f') - @test.services('image') - def test_create_volume_from_image_with_decreasing_size(self): - # Create image - image = self.create_image() - - # Note(jeremyZ): To shorten the test time (uploading a big size image - # is time-consuming), here just consider the scenario that volume size - # is smaller than the min_disk of image. - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, - size=CONF.volume.volume_size, - imageRef=image['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d15e7f35-2cfc-48c8-9418-c8223a89bcbb') - @test.services('image') - def test_create_volume_from_deactivated_image(self): - # Create image - image = self.create_image() - - # Deactivate the image - self.images_client.deactivate_image(image['id']) - body = self.images_client.show_image(image['id']) - self.assertEqual("deactivated", body['status']) - # Try creating a volume from deactivated image - self.assertRaises(lib_exc.BadRequest, - self.create_volume, - imageRef=image['id']) diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py deleted file mode 100644 index e68ab7e2a..000000000 --- a/tempest/api/volume/test_volumes_snapshots.py +++ /dev/null @@ -1,165 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools -from testtools import matchers - -from tempest.api.volume import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class VolumesSnapshotTestJSON(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesSnapshotTestJSON, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder volume snapshots are disabled") - - @classmethod - def resource_setup(cls): - super(VolumesSnapshotTestJSON, cls).resource_setup() - cls.volume_origin = cls.create_volume() - - @decorators.idempotent_id('8567b54c-4455-446d-a1cf-651ddeaa3ff2') - @test.services('compute') - def test_snapshot_create_delete_with_volume_in_use(self): - # Create a test instance - server = self.create_server() - self.attach_volume(server['id'], self.volume_origin['id']) - - # Snapshot a volume which attached to an instance with force=False - self.assertRaises(lib_exc.BadRequest, self.create_snapshot, - self.volume_origin['id'], force=False) - - # Snapshot a volume attached to an instance - snapshot1 = self.create_snapshot(self.volume_origin['id'], force=True) - snapshot2 = self.create_snapshot(self.volume_origin['id'], force=True) - snapshot3 = self.create_snapshot(self.volume_origin['id'], force=True) - - # Delete the snapshots. Some snapshot implementations can take - # different paths according to order they are deleted. - self.delete_snapshot(snapshot1['id']) - self.delete_snapshot(snapshot3['id']) - self.delete_snapshot(snapshot2['id']) - - @decorators.idempotent_id('5210a1de-85a0-11e6-bb21-641c676a5d61') - @test.services('compute') - def test_snapshot_create_offline_delete_online(self): - - # Create a snapshot while it is not attached - snapshot1 = self.create_snapshot(self.volume_origin['id']) - - # Create a server and attach it - server = self.create_server() - self.attach_volume(server['id'], self.volume_origin['id']) - - # Now that the volume is attached, create another snapshots - snapshot2 = self.create_snapshot(self.volume_origin['id'], force=True) - snapshot3 = self.create_snapshot(self.volume_origin['id'], force=True) - - # Delete the snapshots. Some snapshot implementations can take - # different paths according to order they are deleted. - self.delete_snapshot(snapshot3['id']) - self.delete_snapshot(snapshot1['id']) - self.delete_snapshot(snapshot2['id']) - - @decorators.idempotent_id('2a8abbe4-d871-46db-b049-c41f5af8216e') - def test_snapshot_create_get_list_update_delete(self): - # Create a snapshot with metadata - metadata = {"snap-meta1": "value1", - "snap-meta2": "value2", - "snap-meta3": "value3"} - snapshot = self.create_snapshot(self.volume_origin['id'], - metadata=metadata) - - # Get the snap and check for some of its details - snap_get = self.snapshots_client.show_snapshot( - snapshot['id'])['snapshot'] - self.assertEqual(self.volume_origin['id'], - snap_get['volume_id'], - "Referred volume origin mismatch") - self.assertEqual(self.volume_origin['size'], snap_get['size']) - - # Verify snapshot metadata - self.assertThat(snap_get['metadata'].items(), - matchers.ContainsAll(metadata.items())) - - # Compare also with the output from the list action - tracking_data = (snapshot['id'], snapshot['name']) - snaps_list = self.snapshots_client.list_snapshots()['snapshots'] - snaps_data = [(f['id'], f['name']) for f in snaps_list] - self.assertIn(tracking_data, snaps_data) - - # Updates snapshot with new values - new_s_name = data_utils.rand_name( - self.__class__.__name__ + '-new-snap') - new_desc = 'This is the new description of snapshot.' - params = {'name': new_s_name, - 'description': new_desc} - update_snapshot = self.snapshots_client.update_snapshot( - snapshot['id'], **params)['snapshot'] - # Assert response body for update_snapshot method - self.assertEqual(new_s_name, update_snapshot['name']) - self.assertEqual(new_desc, update_snapshot['description']) - # Assert response body for show_snapshot method - updated_snapshot = self.snapshots_client.show_snapshot( - snapshot['id'])['snapshot'] - self.assertEqual(new_s_name, updated_snapshot['name']) - self.assertEqual(new_desc, updated_snapshot['description']) - - # Delete the snapshot - self.delete_snapshot(snapshot['id']) - - @decorators.idempotent_id('677863d1-3142-456d-b6ac-9924f667a7f4') - def test_volume_from_snapshot(self): - # Creates a volume from a snapshot passing a size - # different from the source - src_size = CONF.volume.volume_size - - src_vol = self.create_volume(size=src_size) - src_snap = self.create_snapshot(src_vol['id']) - # Destination volume bigger than source snapshot - dst_vol = self.create_volume(snapshot_id=src_snap['id'], - size=src_size + 1) - # NOTE(zhufl): dst_vol is created based on snapshot, so dst_vol - # should be deleted before deleting snapshot, otherwise deleting - # snapshot will end with status 'error-deleting'. This depends on - # the implementation mechanism of vendors, generally speaking, - # some verdors will use "virtual disk clone" which will promote - # disk clone speed, and in this situation the "disk clone" - # is just a relationship between volume and snapshot. - self.addCleanup(self.delete_volume, self.volumes_client, dst_vol['id']) - - volume = self.volumes_client.show_volume(dst_vol['id'])['volume'] - # Should allow - self.assertEqual(volume['snapshot_id'], src_snap['id']) - self.assertEqual(volume['size'], src_size + 1) - - @decorators.idempotent_id('bbcfa285-af7f-479e-8c1a-8c34fc16543c') - @testtools.skipUnless(CONF.volume_feature_enabled.backup, - "Cinder backup is disabled") - def test_snapshot_backup(self): - # Create a snapshot - snapshot = self.create_snapshot(volume_id=self.volume_origin['id']) - - backup = self.create_backup(volume_id=self.volume_origin['id'], - snapshot_id=snapshot['id']) - backup_info = self.backups_client.show_backup(backup['id'])['backup'] - self.assertEqual(self.volume_origin['id'], backup_info['volume_id']) - self.assertEqual(snapshot['id'], backup_info['snapshot_id']) diff --git a/tempest/api/volume/test_volumes_snapshots_list.py b/tempest/api/volume/test_volumes_snapshots_list.py deleted file mode 100644 index 507df1faa..000000000 --- a/tempest/api/volume/test_volumes_snapshots_list.py +++ /dev/null @@ -1,160 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesSnapshotListTestJSON(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesSnapshotListTestJSON, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder volume snapshots are disabled") - - @classmethod - def resource_setup(cls): - super(VolumesSnapshotListTestJSON, cls).resource_setup() - cls.snapshot_id_list = [] - volume_origin = cls.create_volume() - - # Create snapshots with params - for _ in range(3): - snapshot = cls.create_snapshot(volume_origin['id']) - cls.snapshot_id_list.append(snapshot['id']) - cls.snapshot = snapshot - - def _list_by_param_values_and_assert(self, with_detail=False, **params): - """list or list_details with given params and validates result.""" - - fetched_snap_list = self.snapshots_client.list_snapshots( - detail=with_detail, **params)['snapshots'] - - # Validating params of fetched snapshots - for snap in fetched_snap_list: - for key in params: - msg = "Failed to list snapshots %s by %s" % \ - ('details' if with_detail else '', key) - self.assertEqual(params[key], snap[key], msg) - - def _list_snapshots_by_param_limit(self, limit, expected_elements): - """list snapshots by limit param""" - # Get snapshots list using limit parameter - fetched_snap_list = self.snapshots_client.list_snapshots( - limit=limit)['snapshots'] - # Validating filtered snapshots length equals to expected_elements - self.assertEqual(expected_elements, len(fetched_snap_list)) - - @decorators.idempotent_id('59f41f43-aebf-48a9-ab5d-d76340fab32b') - def test_snapshots_list_with_params(self): - """list snapshots with params.""" - # Verify list snapshots by display_name filter - params = {'name': self.snapshot['name']} - self._list_by_param_values_and_assert(**params) - - # Verify list snapshots by status filter - params = {'status': 'available'} - self._list_by_param_values_and_assert(**params) - - # Verify list snapshots by status and display name filter - params = {'status': 'available', - 'name': self.snapshot['name']} - self._list_by_param_values_and_assert(**params) - - @decorators.idempotent_id('220a1022-1fcd-4a74-a7bd-6b859156cda2') - def test_snapshots_list_details_with_params(self): - """list snapshot details with params.""" - # Verify list snapshot details by display_name filter - params = {'name': self.snapshot['name']} - self._list_by_param_values_and_assert(with_detail=True, **params) - # Verify list snapshot details by status filter - params = {'status': 'available'} - self._list_by_param_values_and_assert(with_detail=True, **params) - # Verify list snapshot details by status and display name filter - params = {'status': 'available', - 'name': self.snapshot['name']} - self._list_by_param_values_and_assert(with_detail=True, **params) - - @decorators.idempotent_id('db4d8e0a-7a2e-41cc-a712-961f6844e896') - def test_snapshot_list_param_limit(self): - # List returns limited elements - self._list_snapshots_by_param_limit(limit=1, expected_elements=1) - - @decorators.idempotent_id('a1427f61-420e-48a5-b6e3-0b394fa95400') - def test_snapshot_list_param_limit_equals_infinite(self): - # List returns all elements when request limit exceeded - # snapshots number - snap_list = self.snapshots_client.list_snapshots()['snapshots'] - self._list_snapshots_by_param_limit(limit=100000, - expected_elements=len(snap_list)) - - @decorators.idempotent_id('e3b44b7f-ae87-45b5-8a8c-66110eb24d0a') - def test_snapshot_list_param_limit_equals_zero(self): - # List returns zero elements - self._list_snapshots_by_param_limit(limit=0, expected_elements=0) - - def _list_snapshots_param_sort(self, sort_key, sort_dir): - """list snapshots by sort param""" - snap_list = self.snapshots_client.list_snapshots( - sort_key=sort_key, sort_dir=sort_dir)['snapshots'] - self.assertNotEmpty(snap_list) - if sort_key is 'display_name': - sort_key = 'name' - # Note: On Cinder API, 'display_name' works as a sort key - # on a request, a volume name appears as 'name' on the response. - # So Tempest needs to change the key name here for this inconsistent - # API behavior. - sorted_list = [snapshot[sort_key] for snapshot in snap_list] - msg = 'The list of snapshots was not sorted correctly.' - self.assertEqual(sorted(sorted_list, reverse=(sort_dir == 'desc')), - sorted_list, msg) - - @decorators.idempotent_id('c5513ada-64c1-4d28-83b9-af3307ec1388') - def test_snapshot_list_param_sort_id_asc(self): - self._list_snapshots_param_sort(sort_key='id', sort_dir='asc') - - @decorators.idempotent_id('8a7fe058-0b41-402a-8afd-2dbc5a4a718b') - def test_snapshot_list_param_sort_id_desc(self): - self._list_snapshots_param_sort(sort_key='id', sort_dir='desc') - - @decorators.idempotent_id('4052c3a0-2415-440a-a8cc-305a875331b0') - def test_snapshot_list_param_sort_created_at_asc(self): - self._list_snapshots_param_sort(sort_key='created_at', sort_dir='asc') - - @decorators.idempotent_id('dcbbe24a-f3c0-4ec8-9274-55d48db8d1cf') - def test_snapshot_list_param_sort_created_at_desc(self): - self._list_snapshots_param_sort(sort_key='created_at', sort_dir='desc') - - @decorators.idempotent_id('d58b5fed-0c37-42d3-8c5d-39014ac13c00') - def test_snapshot_list_param_sort_name_asc(self): - self._list_snapshots_param_sort(sort_key='display_name', - sort_dir='asc') - - @decorators.idempotent_id('96ba6f4d-1f18-47e1-b4bc-76edc6c21250') - def test_snapshot_list_param_sort_name_desc(self): - self._list_snapshots_param_sort(sort_key='display_name', - sort_dir='desc') - - @decorators.idempotent_id('05489dde-44bc-4961-a1f5-3ce7ee7824f7') - def test_snapshot_list_param_marker(self): - # The list of snapshots should end before the provided marker - params = {'marker': self.snapshot_id_list[1]} - snap_list = self.snapshots_client.list_snapshots(**params)['snapshots'] - fetched_list_id = [snap['id'] for snap in snap_list] - # Verify the list of snapshots ends before the provided - # marker(second snapshot), therefore only the first snapshot - # should displayed. - self.assertEqual(self.snapshot_id_list[:1], fetched_list_id) diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py deleted file mode 100644 index ea5f03685..000000000 --- a/tempest/api/volume/test_volumes_snapshots_negative.py +++ /dev/null @@ -1,83 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.volume import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class VolumesSnapshotNegativeTestJSON(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesSnapshotNegativeTestJSON, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder volume snapshots are disabled") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e3e466af-70ab-4f4b-a967-ab04e3532ea7') - def test_create_snapshot_with_nonexistent_volume_id(self): - # Create a snapshot with nonexistent volume id - s_name = data_utils.rand_name(self.__class__.__name__ + '-snap') - self.assertRaises(lib_exc.NotFound, - self.snapshots_client.create_snapshot, - volume_id=data_utils.rand_uuid(), - display_name=s_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bb9da53e-d335-4309-9c15-7e76fd5e4d6d') - def test_create_snapshot_without_passing_volume_id(self): - # Create a snapshot without passing volume id - s_name = data_utils.rand_name(self.__class__.__name__ + '-snap') - self.assertRaises(lib_exc.NotFound, - self.snapshots_client.create_snapshot, - volume_id=None, display_name=s_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('677863d1-34f9-456d-b6ac-9924f667a7f4') - def test_volume_from_snapshot_decreasing_size(self): - # Creates a volume a snapshot passing a size different from the source - src_size = CONF.volume.volume_size + 1 - - src_vol = self.create_volume(size=src_size) - src_snap = self.create_snapshot(src_vol['id']) - - # Destination volume smaller than source - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, - size=src_size - 1, - snapshot_id=src_snap['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8fd92339-e22f-4591-86b4-1e2215372a40') - def test_list_snapshot_invalid_param_limit(self): - self.assertRaises(lib_exc.BadRequest, - self.snapshots_client.list_snapshots, - limit='invalid') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('27b5f37f-bf69-4e8c-986e-c44f3d6819b8') - def test_list_snapshots_invalid_param_sort(self): - self.assertRaises(lib_exc.BadRequest, - self.snapshots_client.list_snapshots, - sort_key='invalid') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b68deeda-ca79-4a32-81af-5c51179e553a') - def test_list_snapshots_invalid_param_marker(self): - self.assertRaises(lib_exc.NotFound, - self.snapshots_client.list_snapshots, - marker=data_utils.rand_uuid()) diff --git a/tempest/clients.py b/tempest/clients.py deleted file mode 100644 index 85c2242fc..000000000 --- a/tempest/clients.py +++ /dev/null @@ -1,316 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest import config -from tempest.lib import auth -from tempest.lib import exceptions as lib_exc -from tempest.lib.services import clients -from tempest.services import object_storage - -CONF = config.CONF - - -class Manager(clients.ServiceClients): - """Top level manager for OpenStack tempest clients""" - - default_params = config.service_client_config() - - def __init__(self, credentials, scope='project'): - """Initialization of Manager class. - - Setup all services clients and make them available for tests cases. - :param credentials: type Credentials or TestResources - :param scope: default scope for tokens produced by the auth provider - """ - _, identity_uri = get_auth_provider_class(credentials) - super(Manager, self).__init__( - credentials=credentials, identity_uri=identity_uri, scope=scope, - region=CONF.identity.region) - # TODO(andreaf) When clients are initialised without the right - # parameters available, the calls below will trigger a KeyError. - # We should catch that and raise a better error. - self._set_compute_clients() - self._set_identity_clients() - self._set_volume_clients() - self._set_object_storage_clients() - self._set_image_clients() - self._set_network_clients() - - def _set_network_clients(self): - self.network_agents_client = self.network.AgentsClient() - self.network_extensions_client = self.network.ExtensionsClient() - self.networks_client = self.network.NetworksClient() - self.subnetpools_client = self.network.SubnetpoolsClient() - self.subnets_client = self.network.SubnetsClient() - self.ports_client = self.network.PortsClient() - self.network_quotas_client = self.network.QuotasClient() - self.floating_ips_client = self.network.FloatingIPsClient() - self.metering_labels_client = self.network.MeteringLabelsClient() - self.metering_label_rules_client = ( - self.network.MeteringLabelRulesClient()) - self.routers_client = self.network.RoutersClient() - self.security_group_rules_client = ( - self.network.SecurityGroupRulesClient()) - self.security_groups_client = self.network.SecurityGroupsClient() - self.network_versions_client = self.network.NetworkVersionsClient() - self.service_providers_client = self.network.ServiceProvidersClient() - self.tags_client = self.network.TagsClient() - - def _set_image_clients(self): - if CONF.service_available.glance: - self.image_client = self.image_v1.ImagesClient() - self.image_member_client = self.image_v1.ImageMembersClient() - self.image_client_v2 = self.image_v2.ImagesClient() - self.image_member_client_v2 = self.image_v2.ImageMembersClient() - self.namespaces_client = self.image_v2.NamespacesClient() - self.resource_types_client = self.image_v2.ResourceTypesClient() - self.namespace_objects_client = \ - self.image_v2.NamespaceObjectsClient() - self.schemas_client = self.image_v2.SchemasClient() - self.namespace_properties_client = \ - self.image_v2.NamespacePropertiesClient() - self.namespace_tags_client = \ - self.image_v2.NamespaceTagsClient() - self.image_versions_client = \ - self.image_v2.VersionsClient() - - def _set_compute_clients(self): - self.agents_client = self.compute.AgentsClient() - self.compute_networks_client = self.compute.NetworksClient() - self.migrations_client = self.compute.MigrationsClient() - self.security_group_default_rules_client = ( - self.compute.SecurityGroupDefaultRulesClient()) - self.certificates_client = self.compute.CertificatesClient() - eip = CONF.compute_feature_enabled.enable_instance_password - self.servers_client = self.compute.ServersClient( - enable_instance_password=eip) - self.server_groups_client = self.compute.ServerGroupsClient() - self.limits_client = self.compute.LimitsClient() - self.compute_images_client = self.compute.ImagesClient() - self.keypairs_client = self.compute.KeyPairsClient() - self.quotas_client = self.compute.QuotasClient() - self.quota_classes_client = self.compute.QuotaClassesClient() - self.flavors_client = self.compute.FlavorsClient() - self.extensions_client = self.compute.ExtensionsClient() - self.floating_ip_pools_client = self.compute.FloatingIPPoolsClient() - self.floating_ips_bulk_client = self.compute.FloatingIPsBulkClient() - self.compute_floating_ips_client = self.compute.FloatingIPsClient() - self.compute_security_group_rules_client = ( - self.compute.SecurityGroupRulesClient()) - self.compute_security_groups_client = ( - self.compute.SecurityGroupsClient()) - self.interfaces_client = self.compute.InterfacesClient() - self.fixed_ips_client = self.compute.FixedIPsClient() - self.availability_zone_client = self.compute.AvailabilityZoneClient() - self.aggregates_client = self.compute.AggregatesClient() - self.services_client = self.compute.ServicesClient() - self.tenant_usages_client = self.compute.TenantUsagesClient() - self.hosts_client = self.compute.HostsClient() - self.hypervisor_client = self.compute.HypervisorClient() - self.instance_usages_audit_log_client = ( - self.compute.InstanceUsagesAuditLogClient()) - self.tenant_networks_client = self.compute.TenantNetworksClient() - - # NOTE: The following client needs special timeout values because - # the API is a proxy for the other component. - params_volume = { - 'build_interval': CONF.volume.build_interval, - 'build_timeout': CONF.volume.build_timeout - } - self.volumes_extensions_client = self.compute.VolumesClient( - **params_volume) - self.compute_versions_client = self.compute.VersionsClient( - **params_volume) - self.snapshots_extensions_client = self.compute.SnapshotsClient( - **params_volume) - - def _set_identity_clients(self): - # Clients below use the admin endpoint type of Keystone API v2 - params_v2_admin = { - 'endpoint_type': CONF.identity.v2_admin_endpoint_type} - self.endpoints_client = self.identity_v2.EndpointsClient( - **params_v2_admin) - self.identity_client = self.identity_v2.IdentityClient( - **params_v2_admin) - self.tenants_client = self.identity_v2.TenantsClient( - **params_v2_admin) - self.roles_client = self.identity_v2.RolesClient(**params_v2_admin) - self.users_client = self.identity_v2.UsersClient(**params_v2_admin) - self.identity_services_client = self.identity_v2.ServicesClient( - **params_v2_admin) - - # Clients below use the public endpoint type of Keystone API v2 - params_v2_public = { - 'endpoint_type': CONF.identity.v2_public_endpoint_type} - self.identity_public_client = self.identity_v2.IdentityClient( - **params_v2_public) - self.tenants_public_client = self.identity_v2.TenantsClient( - **params_v2_public) - self.users_public_client = self.identity_v2.UsersClient( - **params_v2_public) - - # Clients below use the endpoint type of Keystone API v3, which is set - # in endpoint_type - params_v3 = {'endpoint_type': CONF.identity.v3_endpoint_type} - self.domains_client = self.identity_v3.DomainsClient(**params_v3) - self.identity_v3_client = self.identity_v3.IdentityClient(**params_v3) - self.trusts_client = self.identity_v3.TrustsClient(**params_v3) - self.users_v3_client = self.identity_v3.UsersClient(**params_v3) - self.endpoints_v3_client = self.identity_v3.EndPointsClient( - **params_v3) - self.roles_v3_client = self.identity_v3.RolesClient(**params_v3) - self.inherited_roles_client = self.identity_v3.InheritedRolesClient( - **params_v3) - self.role_assignments_client = self.identity_v3.RoleAssignmentsClient( - **params_v3) - self.identity_services_v3_client = self.identity_v3.ServicesClient( - **params_v3) - self.policies_client = self.identity_v3.PoliciesClient(**params_v3) - self.projects_client = self.identity_v3.ProjectsClient(**params_v3) - self.regions_client = self.identity_v3.RegionsClient(**params_v3) - self.credentials_client = self.identity_v3.CredentialsClient( - **params_v3) - self.groups_client = self.identity_v3.GroupsClient(**params_v3) - self.identity_versions_v3_client = self.identity_v3.VersionsClient( - **params_v3) - self.oauth_consumers_client = self.identity_v3.OAUTHConsumerClient( - **params_v3) - self.oauth_token_client = self.identity_v3.OAUTHTokenClient( - **params_v3) - self.domain_config_client = self.identity_v3.DomainConfigurationClient( - **params_v3) - self.endpoint_filter_client = \ - self.identity_v3.EndPointsFilterClient(**params_v3) - self.endpoint_groups_client = self.identity_v3.EndPointGroupsClient( - **params_v3) - self.catalog_client = self.identity_v3.CatalogClient(**params_v3) - - # Token clients do not use the catalog. They only need default_params. - # They read auth_url, so they should only be set if the corresponding - # API version is marked as enabled - if CONF.identity_feature_enabled.api_v2: - if CONF.identity.uri: - self.token_client = self.identity_v2.TokenClient( - auth_url=CONF.identity.uri) - else: - msg = 'Identity v2 API enabled, but no identity.uri set' - raise lib_exc.InvalidConfiguration(msg) - if CONF.identity_feature_enabled.api_v3: - if CONF.identity.uri_v3: - self.token_v3_client = self.identity_v3.V3TokenClient( - auth_url=CONF.identity.uri_v3) - else: - msg = 'Identity v3 API enabled, but no identity.uri_v3 set' - raise lib_exc.InvalidConfiguration(msg) - - def _set_volume_clients(self): - - if CONF.volume_feature_enabled.api_v1: - self.backups_client = self.volume_v1.BackupsClient() - self.encryption_types_client = \ - self.volume_v1.EncryptionTypesClient() - self.snapshots_client = self.volume_v1.SnapshotsClient() - self.volume_availability_zone_client = \ - self.volume_v1.AvailabilityZoneClient() - self.volume_hosts_client = self.volume_v1.HostsClient() - self.volume_limits_client = self.volume_v1.LimitsClient() - self.volume_qos_client = self.volume_v1.QosSpecsClient() - self.volume_quotas_client = self.volume_v1.QuotasClient() - self.volume_services_client = self.volume_v1.ServicesClient() - self.volume_types_client = self.volume_v1.TypesClient() - self.volumes_client = self.volume_v1.VolumesClient() - self.volumes_extension_client = self.volume_v1.ExtensionsClient() - - if CONF.volume_feature_enabled.api_v2: - self.backups_v2_client = self.volume_v2.BackupsClient() - self.encryption_types_v2_client = \ - self.volume_v2.EncryptionTypesClient() - self.snapshot_manage_v2_client = \ - self.volume_v2.SnapshotManageClient() - self.snapshots_v2_client = self.volume_v2.SnapshotsClient() - self.volume_capabilities_v2_client = \ - self.volume_v2.CapabilitiesClient() - self.volume_manage_v2_client = self.volume_v2.VolumeManageClient() - self.volume_qos_v2_client = self.volume_v2.QosSpecsClient() - self.volume_services_v2_client = self.volume_v2.ServicesClient() - self.volume_types_v2_client = self.volume_v2.TypesClient() - self.volume_hosts_v2_client = self.volume_v2.HostsClient() - self.volume_quotas_v2_client = self.volume_v2.QuotasClient() - self.volume_quota_classes_v2_client = \ - self.volume_v2.QuotaClassesClient() - self.volume_scheduler_stats_v2_client = \ - self.volume_v2.SchedulerStatsClient() - self.volume_transfers_v2_client = \ - self.volume_v2.TransfersClient() - self.volume_v2_availability_zone_client = \ - self.volume_v2.AvailabilityZoneClient() - self.volume_v2_limits_client = self.volume_v2.LimitsClient() - self.volumes_v2_client = self.volume_v2.VolumesClient() - self.volumes_v2_extension_client = \ - self.volume_v2.ExtensionsClient() - - # Set default client for users that don't need explicit version - self.volumes_client_latest = self.volumes_v2_client - - if CONF.volume_feature_enabled.api_v3: - self.backups_v3_client = self.volume_v3.BackupsClient() - self.group_types_v3_client = self.volume_v3.GroupTypesClient() - self.groups_v3_client = self.volume_v3.GroupsClient() - self.volume_v3_messages_client = self.volume_v3.MessagesClient() - self.volume_v3_versions_client = self.volume_v3.VersionsClient() - self.volumes_v3_client = self.volume_v3.VolumesClient() - - # Set default client for users that don't need explicit version - self.volumes_client_latest = self.volumes_v3_client - - def _set_object_storage_clients(self): - # NOTE(andreaf) Load configuration from config. Once object storage - # is in lib, configuration will be pulled directly from the registry - # and this will not be required anymore. - params = config.service_client_config('object-storage') - - self.account_client = object_storage.AccountClient(self.auth_provider, - **params) - self.bulk_client = object_storage.BulkMiddlewareClient( - self.auth_provider, **params) - self.capabilities_client = object_storage.CapabilitiesClient( - self.auth_provider, **params) - self.container_client = object_storage.ContainerClient( - self.auth_provider, **params) - self.object_client = object_storage.ObjectClient(self.auth_provider, - **params) - - -def get_auth_provider_class(credentials): - if isinstance(credentials, auth.KeystoneV3Credentials): - return auth.KeystoneV3AuthProvider, CONF.identity.uri_v3 - else: - return auth.KeystoneV2AuthProvider, CONF.identity.uri - - -def get_auth_provider(credentials, pre_auth=False, scope='project'): - # kwargs for auth provider match the common ones used by service clients - default_params = config.service_client_config() - if credentials is None: - raise lib_exc.InvalidCredentials( - 'Credentials must be specified') - auth_provider_class, auth_url = get_auth_provider_class( - credentials) - _auth_provider = auth_provider_class(credentials, auth_url, - scope=scope, - **default_params) - if pre_auth: - _auth_provider.set_auth() - return _auth_provider diff --git a/tempest/cmd/__init__.py b/tempest/cmd/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py deleted file mode 100755 index 8636405b4..000000000 --- a/tempest/cmd/account_generator.py +++ /dev/null @@ -1,310 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2015 Mirantis, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Utility for creating **accounts.yaml** file for concurrent test runs. -Creates one primary user, one alt user, one swift admin, one stack owner -and one admin (optionally) for each concurrent thread. The utility creates -user for each tenant. The **accounts.yaml** file will be valid and contain -credentials for created users, so each user will be in separate tenant and -have the username, tenant_name, password and roles. - -**Usage:** ``tempest account-generator [-h] [OPTIONS] accounts_file.yaml``. - -Positional Arguments --------------------- -**accounts_file.yaml** (Required) Provide an output accounts yaml file. Utility -creates a .yaml file in the directory where the command is ran. The appropriate -name for the file is *accounts.yaml* and it should be placed in *tempest/etc* -directory. - -Authentication --------------- - -Account generator creates users and tenants so it needs the admin credentials -of your cloud to operate properly. The corresponding info can be given either -through CLI options or environment variables. - -You're probably familiar with these, but just to remind: - -======== ======================== ==================== -Param CLI Environment Variable -======== ======================== ==================== -Username --os-username OS_USERNAME -Password --os-password OS_PASSWORD -Project --os-project-name OS_PROJECT_NAME -Tenant --os-tenant-name (depr.) OS_TENANT_NAME -Domain --os-domain-name OS_DOMAIN_NAME -======== ======================== ==================== - -Optional Arguments ------------------- -**-h**, **--help** (Optional) Shows help message with the description of -utility and its arguments, and exits. - -**c /etc/tempest.conf**, **--config-file /etc/tempest.conf** (Optional) Path to -tempest config file. - -**--os-username ** (Optional) Name used for authentication with -the OpenStack Identity service. Defaults to env[OS_USERNAME]. Note: User should -have permissions to create new user accounts and tenants. - -**--os-password ** (Optional) Password used for authentication -with the OpenStack Identity service. Defaults to env[OS_PASSWORD]. - -**--os-project-name ** (Optional) Project to request -authorization on. Defaults to env[OS_PROJECT_NAME]. - -**--os-tenant-name ** (Optional, deprecated) Tenant to -request authorization on. Defaults to env[OS_TENANT_NAME]. - -**--os-domain-name ** (Optional) Domain the user and project -belong to. Defaults to env[OS_DOMAIN_NAME]. - -**--tag TAG** (Optional) Resources tag. Each created resource (user, project) -will have the prefix with the given TAG in its name. Using tag is recommended -for the further using, cleaning resources. - -**-r CONCURRENCY**, **--concurrency CONCURRENCY** (Required) Concurrency count -(default: 1). The number of accounts required can be estimated as -CONCURRENCY x 2. Each user provided in *accounts.yaml* file will be in -a different tenant. This is required to provide isolation between test for -running in parallel. - -**--with-admin** (Optional) Creates admin for each concurrent group -(default: False). - -**-i VERSION**, **--identity-version VERSION** (Optional) Provisions accounts -using the specified version of the identity API. (default: '3'). - -To see help on specific argument, please do: ``tempest account-generator -[OPTIONS] -h``. -""" -import argparse -import os -import traceback - -from cliff import command -from oslo_log import log as logging -import yaml - -from tempest.common import credentials_factory -from tempest import config -from tempest.lib.common import dynamic_creds - - -LOG = None -CONF = config.CONF -DESCRIPTION = ('Create accounts.yaml file for concurrent test runs.%s' - 'One primary user, one alt user, ' - 'one swift admin, one stack owner ' - 'and one admin (optionally) will be created ' - 'for each concurrent thread.' % os.linesep) - - -def setup_logging(): - global LOG - logging.setup(CONF, __name__) - LOG = logging.getLogger(__name__) - - -def get_credential_provider(opts): - identity_version = "".join(['v', str(opts.identity_version)]) - # NOTE(andreaf) For now tempest.conf controls whether resources will - # actually be created. Once we remove the dependency from tempest.conf - # we will need extra CLI option(s) to control this. - network_resources = {'router': True, - 'network': True, - 'subnet': True, - 'dhcp': True} - admin_creds_dict = {'username': opts.os_username, - 'password': opts.os_password} - _project_name = opts.os_project_name or opts.os_tenant_name - if opts.identity_version == 3: - admin_creds_dict['project_name'] = _project_name - admin_creds_dict['domain_name'] = opts.os_domain_name or 'Default' - elif opts.identity_version == 2: - admin_creds_dict['tenant_name'] = _project_name - admin_creds = credentials_factory.get_credentials( - fill_in=False, identity_version=identity_version, **admin_creds_dict) - return dynamic_creds.DynamicCredentialProvider( - name=opts.tag, - network_resources=network_resources, - **credentials_factory.get_dynamic_provider_params( - identity_version, admin_creds=admin_creds)) - - -def generate_resources(cred_provider, admin): - # Create the list of resources to be provisioned for each process - # NOTE(andreaf) get_credentials expects a string for types or a list for - # roles. Adding all required inputs to the spec list. - spec = ['primary', 'alt'] - if CONF.service_available.swift: - spec.append([CONF.object_storage.operator_role]) - spec.append([CONF.object_storage.reseller_admin_role]) - if CONF.service_available.heat: - spec.append([CONF.orchestration.stack_owner_role, - CONF.object_storage.operator_role]) - if admin: - spec.append('admin') - resources = [] - for cred_type in spec: - resources.append((cred_type, cred_provider.get_credentials( - credential_type=cred_type))) - return resources - - -def dump_accounts(resources, identity_version, account_file): - accounts = [] - for resource in resources: - cred_type, test_resource = resource - account = { - 'username': test_resource.username, - 'password': test_resource.password - } - if identity_version == 3: - account['project_name'] = test_resource.project_name - account['domain_name'] = test_resource.domain_name - else: - account['project_name'] = test_resource.tenant_name - - # If the spec includes 'admin' credentials are defined via type, - # else they are defined via list of roles. - if cred_type == 'admin': - account['types'] = [cred_type] - elif cred_type not in ['primary', 'alt']: - account['roles'] = cred_type - - if test_resource.network: - account['resources'] = {} - if test_resource.network: - account['resources']['network'] = test_resource.network['name'] - accounts.append(account) - if os.path.exists(account_file): - os.rename(account_file, '.'.join((account_file, 'bak'))) - with open(account_file, 'w') as f: - yaml.safe_dump(accounts, f, default_flow_style=False) - LOG.info('%s generated successfully!', account_file) - - -def _parser_add_args(parser): - parser.add_argument('-c', '--config-file', - metavar='/etc/tempest.conf', - help='path to tempest config file') - parser.add_argument('--os-username', - metavar='', - default=os.environ.get('OS_USERNAME'), - help='User should have permissions ' - 'to create new user accounts and ' - 'tenants. Defaults to env[OS_USERNAME].') - parser.add_argument('--os-password', - metavar='', - default=os.environ.get('OS_PASSWORD'), - help='Defaults to env[OS_PASSWORD].') - parser.add_argument('--os-project-name', - metavar='', - default=os.environ.get('OS_PROJECT_NAME'), - help='Defaults to env[OS_PROJECT_NAME].') - parser.add_argument('--os-tenant-name', - metavar='', - default=os.environ.get('OS_TENANT_NAME'), - help='Defaults to env[OS_TENANT_NAME].') - parser.add_argument('--os-domain-name', - metavar='', - default=os.environ.get('OS_DOMAIN_NAME'), - help='Defaults to env[OS_DOMAIN_NAME].') - parser.add_argument('--tag', - default='', - required=False, - dest='tag', - help='Resources tag') - parser.add_argument('-r', '--concurrency', - default=1, - type=int, - required=False, - dest='concurrency', - help='Concurrency count') - parser.add_argument('--with-admin', - action='store_true', - dest='admin', - help='Creates admin for each concurrent group') - parser.add_argument('-i', '--identity-version', - default=3, - choices=[2, 3], - type=int, - required=False, - dest='identity_version', - help='Version of the Identity API to use') - parser.add_argument('accounts', - metavar='accounts_file.yaml', - help='Output accounts yaml file') - - -def get_options(): - usage_string = ('tempest account-generator [-h] ...\n\n' - 'To see help on specific argument, do:\n' - 'tempest account-generator -h') - parser = argparse.ArgumentParser( - description=DESCRIPTION, - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - usage=usage_string - ) - - _parser_add_args(parser) - opts = parser.parse_args() - return opts - - -class TempestAccountGenerator(command.Command): - - def get_parser(self, prog_name): - parser = super(TempestAccountGenerator, self).get_parser(prog_name) - _parser_add_args(parser) - return parser - - def take_action(self, parsed_args): - try: - main(parsed_args) - except Exception: - LOG.exception("Failure generating test accounts.") - traceback.print_exc() - raise - - def get_description(self): - return DESCRIPTION - - -def main(opts=None): - setup_logging() - if not opts: - LOG.warning("Use of: 'tempest-account-generator' is deprecated, " - "please use: 'tempest account-generator'") - opts = get_options() - if opts.config_file: - config.CONF.set_config_path(opts.config_file) - if opts.os_tenant_name: - LOG.warning("'os-tenant-name' and 'OS_TENANT_NAME' are both " - "deprecated, please use 'os-project-name' or " - "'OS_PROJECT_NAME' instead") - resources = [] - for count in range(opts.concurrency): - # Use N different cred_providers to obtain different sets of creds - cred_provider = get_credential_provider(opts) - resources.extend(generate_resources(cred_provider, opts.admin)) - dump_accounts(resources, opts.identity_version, opts.accounts) - -if __name__ == "__main__": - main() diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py deleted file mode 100644 index ac73cbfa9..000000000 --- a/tempest/cmd/cleanup.py +++ /dev/null @@ -1,317 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2014 Dell Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Utility for cleaning up environment after Tempest test run - -**Usage:** ``tempest cleanup [--help] [OPTIONS]`` - -If run with no arguments, ``tempest cleanup`` will query your OpenStack -deployment and build a list of resources to delete and destroy them. This list -will exclude the resources from ``saved_state.json`` and will include the -configured admin account if the ``--delete-tempest-conf-objects`` flag is -specified. By default the admin project is not deleted and the admin user -specified in ``tempest.conf`` is never deleted. - -Example Run ------------ - -**WARNING: If step 1 is skipped in the example below, the cleanup procedure -may delete resources that existed in the cloud before the test run. This -may cause an unwanted destruction of cloud resources, so use caution with -this command.** - -``$ tempest cleanup --init-saved-state`` - -``$ # Actual running of Tempest tests`` - -``$ tempest cleanup`` - -Runtime Arguments ------------------ - -**--init-saved-state**: Initializes the saved state of the OpenStack deployment -and will output a ``saved_state.json`` file containing resources from your -deployment that will be preserved from the cleanup command. This should be -done prior to running Tempest tests. - -**--delete-tempest-conf-objects**: If option is present, then the command will -delete the admin project in addition to the resources associated with them on -clean up. If option is not present, the command will delete the resources -associated with the Tempest and alternate Tempest users and projects but will -not delete the projects themselves. - -**--dry-run**: Creates a report (``./dry_run.json``) of the projects that will -be cleaned up (in the ``_tenants_to_clean`` dictionary [1]_) and the global -objects that will be removed (domains, flavors, images, roles, projects, -and users). Once the cleanup command is executed (e.g. run without -parameters), running it again with **--dry-run** should yield an empty report. - -**--help**: Print the help text for the command and parameters. - -.. [1] The ``_tenants_to_clean`` dictionary in ``dry_run.json`` lists the - projects that ``tempest cleanup`` will loop through to delete child - objects, but the command will, by default, not delete the projects - themselves. This may differ from the ``tenants`` list as you can clean - the Tempest and alternate Tempest users and projects but they will not be - deleted unless the **--delete-tempest-conf-objects** flag is used to - force their deletion. - -""" -import sys -import traceback - -from cliff import command -from oslo_log import log as logging -from oslo_serialization import jsonutils as json - -from tempest import clients -from tempest.cmd import cleanup_service -from tempest.common import credentials_factory as credentials -from tempest.common import identity -from tempest import config - -SAVED_STATE_JSON = "saved_state.json" -DRY_RUN_JSON = "dry_run.json" -LOG = logging.getLogger(__name__) -CONF = config.CONF - - -class TempestCleanup(command.Command): - - def take_action(self, parsed_args): - try: - self.init(parsed_args) - if not parsed_args.init_saved_state: - self._cleanup() - except Exception: - LOG.exception("Failure during cleanup") - traceback.print_exc() - raise - - def init(self, parsed_args): - cleanup_service.init_conf() - self.options = parsed_args - self.admin_mgr = credentials.AdminManager() - self.dry_run_data = {} - self.json_data = {} - - self.admin_id = "" - self.admin_role_id = "" - self.admin_tenant_id = "" - self._init_admin_ids() - - self.admin_role_added = [] - - # available services - self.tenant_services = cleanup_service.get_tenant_cleanup_services() - self.global_services = cleanup_service.get_global_cleanup_services() - - if parsed_args.init_saved_state: - self._init_state() - return - - self._load_json() - - def _cleanup(self): - print("Begin cleanup") - is_dry_run = self.options.dry_run - is_preserve = not self.options.delete_tempest_conf_objects - is_save_state = False - - if is_dry_run: - self.dry_run_data["_tenants_to_clean"] = {} - - admin_mgr = self.admin_mgr - # Always cleanup tempest and alt tempest tenants unless - # they are in saved state json. Therefore is_preserve is False - kwargs = {'data': self.dry_run_data, - 'is_dry_run': is_dry_run, - 'saved_state_json': self.json_data, - 'is_preserve': False, - 'is_save_state': is_save_state} - tenant_service = cleanup_service.TenantService(admin_mgr, **kwargs) - tenants = tenant_service.list() - print("Process %s tenants" % len(tenants)) - - # Loop through list of tenants and clean them up. - for tenant in tenants: - self._add_admin(tenant['id']) - self._clean_tenant(tenant) - - kwargs = {'data': self.dry_run_data, - 'is_dry_run': is_dry_run, - 'saved_state_json': self.json_data, - 'is_preserve': is_preserve, - 'is_save_state': is_save_state} - for service in self.global_services: - svc = service(admin_mgr, **kwargs) - svc.run() - - if is_dry_run: - with open(DRY_RUN_JSON, 'w+') as f: - f.write(json.dumps(self.dry_run_data, sort_keys=True, - indent=2, separators=(',', ': '))) - - self._remove_admin_user_roles() - - def _remove_admin_user_roles(self): - tenant_ids = self.admin_role_added - LOG.debug("Removing admin user roles where needed for tenants: %s", - tenant_ids) - for tenant_id in tenant_ids: - self._remove_admin_role(tenant_id) - - def _clean_tenant(self, tenant): - print("Cleaning tenant: %s " % tenant['name']) - is_dry_run = self.options.dry_run - dry_run_data = self.dry_run_data - is_preserve = not self.options.delete_tempest_conf_objects - tenant_id = tenant['id'] - tenant_name = tenant['name'] - tenant_data = None - if is_dry_run: - tenant_data = dry_run_data["_tenants_to_clean"][tenant_id] = {} - tenant_data['name'] = tenant_name - - kwargs = {"username": CONF.auth.admin_username, - "password": CONF.auth.admin_password, - "tenant_name": tenant['name']} - mgr = clients.Manager(credentials=credentials.get_credentials( - **kwargs)) - kwargs = {'data': tenant_data, - 'is_dry_run': is_dry_run, - 'saved_state_json': None, - 'is_preserve': is_preserve, - 'is_save_state': False, - 'tenant_id': tenant_id} - for service in self.tenant_services: - svc = service(mgr, **kwargs) - svc.run() - - def _init_admin_ids(self): - tn_cl = self.admin_mgr.tenants_client - rl_cl = self.admin_mgr.roles_client - - tenant = identity.get_tenant_by_name(tn_cl, - CONF.auth.admin_project_name) - self.admin_tenant_id = tenant['id'] - - user = identity.get_user_by_username(tn_cl, self.admin_tenant_id, - CONF.auth.admin_username) - self.admin_id = user['id'] - - roles = rl_cl.list_roles()['roles'] - for role in roles: - if role['name'] == CONF.identity.admin_role: - self.admin_role_id = role['id'] - break - - def get_parser(self, prog_name): - parser = super(TempestCleanup, self).get_parser(prog_name) - parser.add_argument('--init-saved-state', action="store_true", - dest='init_saved_state', default=False, - help="Creates JSON file: " + SAVED_STATE_JSON + - ", representing the current state of your " - "deployment, specifically object types " - "tempest creates and destroys during a run. " - "You must run with this flag prior to " - "executing cleanup in normal mode, which is with " - "no arguments.") - parser.add_argument('--delete-tempest-conf-objects', - action="store_true", - dest='delete_tempest_conf_objects', - default=False, - help="Force deletion of the tempest and " - "alternate tempest users and tenants.") - parser.add_argument('--dry-run', action="store_true", - dest='dry_run', default=False, - help="Generate JSON file:" + DRY_RUN_JSON + - ", that reports the objects that would have " - "been deleted had a full cleanup been run.") - return parser - - def get_description(self): - return 'Cleanup after tempest run' - - def _add_admin(self, tenant_id): - rl_cl = self.admin_mgr.roles_client - needs_role = True - roles = rl_cl.list_user_roles_on_project(tenant_id, - self.admin_id)['roles'] - for role in roles: - if role['id'] == self.admin_role_id: - needs_role = False - LOG.debug("User already had admin privilege for this tenant") - if needs_role: - LOG.debug("Adding admin privilege for : %s", tenant_id) - rl_cl.create_user_role_on_project(tenant_id, self.admin_id, - self.admin_role_id) - self.admin_role_added.append(tenant_id) - - def _remove_admin_role(self, tenant_id): - LOG.debug("Remove admin user role for tenant: %s", tenant_id) - # Must initialize AdminManager for each user role - # Otherwise authentication exception is thrown, weird - id_cl = credentials.AdminManager().identity_client - if (self._tenant_exists(tenant_id)): - try: - id_cl.delete_role_from_user_on_project(tenant_id, - self.admin_id, - self.admin_role_id) - except Exception as ex: - LOG.exception("Failed removing role from tenant which still" - "exists, exception: %s", ex) - - def _tenant_exists(self, tenant_id): - tn_cl = self.admin_mgr.tenants_client - try: - t = tn_cl.show_tenant(tenant_id) - LOG.debug("Tenant is: %s", str(t)) - return True - except Exception as ex: - LOG.debug("Tenant no longer exists? %s", ex) - return False - - def _init_state(self): - print("Initializing saved state.") - data = {} - admin_mgr = self.admin_mgr - kwargs = {'data': data, - 'is_dry_run': False, - 'saved_state_json': data, - 'is_preserve': False, - 'is_save_state': True} - for service in self.global_services: - svc = service(admin_mgr, **kwargs) - svc.run() - - with open(SAVED_STATE_JSON, 'w+') as f: - f.write(json.dumps(data, - sort_keys=True, indent=2, separators=(',', ': '))) - - def _load_json(self): - try: - with open(SAVED_STATE_JSON) as json_file: - self.json_data = json.load(json_file) - - except IOError as ex: - LOG.exception("Failed loading saved state, please be sure you" - " have first run cleanup with --init-saved-state " - "flag prior to running tempest. Exception: %s", ex) - sys.exit(ex) - except Exception as ex: - LOG.exception("Exception parsing saved state json : %s", ex) - sys.exit(ex) diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py deleted file mode 100644 index 11cd4bb6b..000000000 --- a/tempest/cmd/cleanup_service.py +++ /dev/null @@ -1,990 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2015 Dell Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging - -from tempest.common import credentials_factory as credentials -from tempest.common import identity -from tempest.common.utils import net_info -from tempest import config -from tempest import test - -LOG = logging.getLogger(__name__) -CONF = config.CONF - -CONF_FLAVORS = None -CONF_IMAGES = None -CONF_NETWORKS = [] -CONF_PRIV_NETWORK_NAME = None -CONF_PUB_NETWORK = None -CONF_PUB_ROUTER = None -CONF_TENANTS = None -CONF_USERS = None - -IS_CINDER = None -IS_GLANCE = None -IS_HEAT = None -IS_NEUTRON = None -IS_NOVA = None - - -def init_conf(): - global CONF_FLAVORS - global CONF_IMAGES - global CONF_NETWORKS - global CONF_PRIV_NETWORK - global CONF_PRIV_NETWORK_NAME - global CONF_PUB_NETWORK - global CONF_PUB_ROUTER - global CONF_TENANTS - global CONF_USERS - global IS_CINDER - global IS_GLANCE - global IS_HEAT - global IS_NEUTRON - global IS_NOVA - - IS_CINDER = CONF.service_available.cinder - IS_GLANCE = CONF.service_available.glance - IS_HEAT = CONF.service_available.heat - IS_NEUTRON = CONF.service_available.neutron - IS_NOVA = CONF.service_available.nova - - CONF_FLAVORS = [CONF.compute.flavor_ref, CONF.compute.flavor_ref_alt] - CONF_IMAGES = [CONF.compute.image_ref, CONF.compute.image_ref_alt] - CONF_PRIV_NETWORK_NAME = CONF.compute.fixed_network_name - CONF_PUB_NETWORK = CONF.network.public_network_id - CONF_PUB_ROUTER = CONF.network.public_router_id - CONF_TENANTS = [CONF.auth.admin_project_name] - CONF_USERS = [CONF.auth.admin_username] - - if IS_NEUTRON: - CONF_PRIV_NETWORK = _get_network_id(CONF.compute.fixed_network_name, - CONF.auth.admin_project_name) - CONF_NETWORKS = [CONF_PUB_NETWORK, CONF_PRIV_NETWORK] - - -def _get_network_id(net_name, project_name): - am = credentials.AdminManager() - net_cl = am.networks_client - tn_cl = am.tenants_client - - networks = net_cl.list_networks() - tenant = identity.get_tenant_by_name(tn_cl, project_name) - t_id = tenant['id'] - n_id = None - for net in networks['networks']: - if (net['tenant_id'] == t_id and net['name'] == net_name): - n_id = net['id'] - break - return n_id - - -class BaseService(object): - def __init__(self, kwargs): - self.client = None - for key, value in kwargs.items(): - setattr(self, key, value) - - self.tenant_filter = {} - if hasattr(self, 'tenant_id'): - self.tenant_filter['tenant_id'] = self.tenant_id - - def _filter_by_tenant_id(self, item_list): - if (item_list is None - or not item_list - or not hasattr(self, 'tenant_id') - or self.tenant_id is None - or 'tenant_id' not in item_list[0]): - return item_list - - return [item for item in item_list - if item['tenant_id'] == self.tenant_id] - - def list(self): - pass - - def delete(self): - pass - - def dry_run(self): - pass - - def save_state(self): - pass - - def run(self): - if self.is_dry_run: - self.dry_run() - elif self.is_save_state: - self.save_state() - else: - self.delete() - - -class SnapshotService(BaseService): - - def __init__(self, manager, **kwargs): - super(SnapshotService, self).__init__(kwargs) - self.client = manager.snapshots_client - - def list(self): - client = self.client - snaps = client.list_snapshots()['snapshots'] - LOG.debug("List count, %s Snapshots", len(snaps)) - return snaps - - def delete(self): - snaps = self.list() - client = self.client - for snap in snaps: - try: - client.delete_snapshot(snap['id']) - except Exception: - LOG.exception("Delete Snapshot exception.") - - def dry_run(self): - snaps = self.list() - self.data['snapshots'] = snaps - - -class ServerService(BaseService): - def __init__(self, manager, **kwargs): - super(ServerService, self).__init__(kwargs) - self.client = manager.servers_client - self.server_groups_client = manager.server_groups_client - - def list(self): - client = self.client - servers_body = client.list_servers() - servers = servers_body['servers'] - LOG.debug("List count, %s Servers", len(servers)) - return servers - - def delete(self): - client = self.client - servers = self.list() - for server in servers: - try: - client.delete_server(server['id']) - except Exception: - LOG.exception("Delete Server exception.") - - def dry_run(self): - servers = self.list() - self.data['servers'] = servers - - -class ServerGroupService(ServerService): - - def list(self): - client = self.server_groups_client - sgs = client.list_server_groups()['server_groups'] - LOG.debug("List count, %s Server Groups", len(sgs)) - return sgs - - def delete(self): - client = self.client - sgs = self.list() - for sg in sgs: - try: - client.delete_server_group(sg['id']) - except Exception: - LOG.exception("Delete Server Group exception.") - - def dry_run(self): - sgs = self.list() - self.data['server_groups'] = sgs - - -class StackService(BaseService): - def __init__(self, manager, **kwargs): - super(StackService, self).__init__(kwargs) - params = config.service_client_config('orchestration') - self.client = manager.orchestration.OrchestrationClient( - manager.auth_provider, **params) - - def list(self): - client = self.client - stacks = client.list_stacks()['stacks'] - LOG.debug("List count, %s Stacks", len(stacks)) - return stacks - - def delete(self): - client = self.client - stacks = self.list() - for stack in stacks: - try: - client.delete_stack(stack['id']) - except Exception: - LOG.exception("Delete Stack exception.") - - def dry_run(self): - stacks = self.list() - self.data['stacks'] = stacks - - -class KeyPairService(BaseService): - def __init__(self, manager, **kwargs): - super(KeyPairService, self).__init__(kwargs) - self.client = manager.keypairs_client - - def list(self): - client = self.client - keypairs = client.list_keypairs()['keypairs'] - LOG.debug("List count, %s Keypairs", len(keypairs)) - return keypairs - - def delete(self): - client = self.client - keypairs = self.list() - for k in keypairs: - try: - name = k['keypair']['name'] - client.delete_keypair(name) - except Exception: - LOG.exception("Delete Keypairs exception.") - - def dry_run(self): - keypairs = self.list() - self.data['keypairs'] = keypairs - - -class SecurityGroupService(BaseService): - def __init__(self, manager, **kwargs): - super(SecurityGroupService, self).__init__(kwargs) - self.client = manager.compute_security_groups_client - - def list(self): - client = self.client - secgrps = client.list_security_groups()['security_groups'] - secgrp_del = [grp for grp in secgrps if grp['name'] != 'default'] - LOG.debug("List count, %s Security Groups", len(secgrp_del)) - return secgrp_del - - def delete(self): - client = self.client - secgrp_del = self.list() - for g in secgrp_del: - try: - client.delete_security_group(g['id']) - except Exception: - LOG.exception("Delete Security Groups exception.") - - def dry_run(self): - secgrp_del = self.list() - self.data['security_groups'] = secgrp_del - - -class FloatingIpService(BaseService): - def __init__(self, manager, **kwargs): - super(FloatingIpService, self).__init__(kwargs) - self.client = manager.compute_floating_ips_client - - def list(self): - client = self.client - floating_ips = client.list_floating_ips()['floating_ips'] - LOG.debug("List count, %s Floating IPs", len(floating_ips)) - return floating_ips - - def delete(self): - client = self.client - floating_ips = self.list() - for f in floating_ips: - try: - client.delete_floating_ip(f['id']) - except Exception: - LOG.exception("Delete Floating IPs exception.") - - def dry_run(self): - floating_ips = self.list() - self.data['floating_ips'] = floating_ips - - -class VolumeService(BaseService): - def __init__(self, manager, **kwargs): - super(VolumeService, self).__init__(kwargs) - self.client = manager.volumes_client - - def list(self): - client = self.client - vols = client.list_volumes()['volumes'] - LOG.debug("List count, %s Volumes", len(vols)) - return vols - - def delete(self): - client = self.client - vols = self.list() - for v in vols: - try: - client.delete_volume(v['id']) - except Exception: - LOG.exception("Delete Volume exception.") - - def dry_run(self): - vols = self.list() - self.data['volumes'] = vols - - -class VolumeQuotaService(BaseService): - def __init__(self, manager, **kwargs): - super(VolumeQuotaService, self).__init__(kwargs) - self.client = manager.volume_quotas_client - - def delete(self): - client = self.client - try: - client.delete_quota_set(self.tenant_id) - except Exception: - LOG.exception("Delete Volume Quotas exception.") - - def dry_run(self): - quotas = self.client.show_quota_set( - self.tenant_id, params={'usage': True})['quota_set'] - self.data['volume_quotas'] = quotas - - -class NovaQuotaService(BaseService): - def __init__(self, manager, **kwargs): - super(NovaQuotaService, self).__init__(kwargs) - self.client = manager.quotas_client - self.limits_client = manager.limits_client - - def delete(self): - client = self.client - try: - client.delete_quota_set(self.tenant_id) - except Exception: - LOG.exception("Delete Quotas exception.") - - def dry_run(self): - client = self.limits_client - quotas = client.show_limits()['limits'] - self.data['compute_quotas'] = quotas['absolute'] - - -# Begin network service classes -class NetworkService(BaseService): - def __init__(self, manager, **kwargs): - super(NetworkService, self).__init__(kwargs) - self.networks_client = manager.networks_client - self.subnets_client = manager.subnets_client - self.ports_client = manager.ports_client - self.floating_ips_client = manager.floating_ips_client - self.metering_labels_client = manager.metering_labels_client - self.metering_label_rules_client = manager.metering_label_rules_client - self.security_groups_client = manager.security_groups_client - self.routers_client = manager.routers_client - - def _filter_by_conf_networks(self, item_list): - if not item_list or not all(('network_id' in i for i in item_list)): - return item_list - - return [item for item in item_list if item['network_id'] - not in CONF_NETWORKS] - - def list(self): - client = self.networks_client - networks = client.list_networks(**self.tenant_filter) - networks = networks['networks'] - # filter out networks declared in tempest.conf - if self.is_preserve: - networks = [network for network in networks - if network['id'] not in CONF_NETWORKS] - LOG.debug("List count, %s Networks", networks) - return networks - - def delete(self): - client = self.networks_client - networks = self.list() - for n in networks: - try: - client.delete_network(n['id']) - except Exception: - LOG.exception("Delete Network exception.") - - def dry_run(self): - networks = self.list() - self.data['networks'] = networks - - -class NetworkFloatingIpService(NetworkService): - - def list(self): - client = self.floating_ips_client - flips = client.list_floatingips(**self.tenant_filter) - flips = flips['floatingips'] - LOG.debug("List count, %s Network Floating IPs", len(flips)) - return flips - - def delete(self): - client = self.client - flips = self.list() - for flip in flips: - try: - client.delete_floatingip(flip['id']) - except Exception: - LOG.exception("Delete Network Floating IP exception.") - - def dry_run(self): - flips = self.list() - self.data['floating_ips'] = flips - - -class NetworkRouterService(NetworkService): - - def list(self): - client = self.routers_client - routers = client.list_routers(**self.tenant_filter) - routers = routers['routers'] - if self.is_preserve: - routers = [router for router in routers - if router['id'] != CONF_PUB_ROUTER] - - LOG.debug("List count, %s Routers", len(routers)) - return routers - - def delete(self): - client = self.routers_client - ports_client = self.ports_client - routers = self.list() - for router in routers: - try: - rid = router['id'] - ports = [port for port - in ports_client.list_ports(device_id=rid)['ports'] - if net_info.is_router_interface_port(port)] - for port in ports: - client.remove_router_interface(rid, port_id=port['id']) - client.delete_router(rid) - except Exception: - LOG.exception("Delete Router exception.") - - def dry_run(self): - routers = self.list() - self.data['routers'] = routers - - -class NetworkHealthMonitorService(NetworkService): - - def list(self): - client = self.client - hms = client.list_health_monitors() - hms = hms['health_monitors'] - hms = self._filter_by_tenant_id(hms) - LOG.debug("List count, %s Health Monitors", len(hms)) - return hms - - def delete(self): - client = self.client - hms = self.list() - for hm in hms: - try: - client.delete_health_monitor(hm['id']) - except Exception: - LOG.exception("Delete Health Monitor exception.") - - def dry_run(self): - hms = self.list() - self.data['health_monitors'] = hms - - -class NetworkMemberService(NetworkService): - - def list(self): - client = self.client - members = client.list_members() - members = members['members'] - members = self._filter_by_tenant_id(members) - LOG.debug("List count, %s Members", len(members)) - return members - - def delete(self): - client = self.client - members = self.list() - for member in members: - try: - client.delete_member(member['id']) - except Exception: - LOG.exception("Delete Member exception.") - - def dry_run(self): - members = self.list() - self.data['members'] = members - - -class NetworkVipService(NetworkService): - - def list(self): - client = self.client - vips = client.list_vips() - vips = vips['vips'] - vips = self._filter_by_tenant_id(vips) - LOG.debug("List count, %s VIPs", len(vips)) - return vips - - def delete(self): - client = self.client - vips = self.list() - for vip in vips: - try: - client.delete_vip(vip['id']) - except Exception: - LOG.exception("Delete VIP exception.") - - def dry_run(self): - vips = self.list() - self.data['vips'] = vips - - -class NetworkPoolService(NetworkService): - - def list(self): - client = self.client - pools = client.list_pools() - pools = pools['pools'] - pools = self._filter_by_tenant_id(pools) - LOG.debug("List count, %s Pools", len(pools)) - return pools - - def delete(self): - client = self.client - pools = self.list() - for pool in pools: - try: - client.delete_pool(pool['id']) - except Exception: - LOG.exception("Delete Pool exception.") - - def dry_run(self): - pools = self.list() - self.data['pools'] = pools - - -class NetworkMeteringLabelRuleService(NetworkService): - - def list(self): - client = self.metering_label_rules_client - rules = client.list_metering_label_rules() - rules = rules['metering_label_rules'] - rules = self._filter_by_tenant_id(rules) - LOG.debug("List count, %s Metering Label Rules", len(rules)) - return rules - - def delete(self): - client = self.metering_label_rules_client - rules = self.list() - for rule in rules: - try: - client.delete_metering_label_rule(rule['id']) - except Exception: - LOG.exception("Delete Metering Label Rule exception.") - - def dry_run(self): - rules = self.list() - self.data['rules'] = rules - - -class NetworkMeteringLabelService(NetworkService): - - def list(self): - client = self.metering_labels_client - labels = client.list_metering_labels() - labels = labels['metering_labels'] - labels = self._filter_by_tenant_id(labels) - LOG.debug("List count, %s Metering Labels", len(labels)) - return labels - - def delete(self): - client = self.metering_labels_client - labels = self.list() - for label in labels: - try: - client.delete_metering_label(label['id']) - except Exception: - LOG.exception("Delete Metering Label exception.") - - def dry_run(self): - labels = self.list() - self.data['labels'] = labels - - -class NetworkPortService(NetworkService): - - def list(self): - client = self.ports_client - ports = [port for port in - client.list_ports(**self.tenant_filter)['ports'] - if port["device_owner"] == "" or - port["device_owner"].startswith("compute:")] - - if self.is_preserve: - ports = self._filter_by_conf_networks(ports) - - LOG.debug("List count, %s Ports", len(ports)) - return ports - - def delete(self): - client = self.ports_client - ports = self.list() - for port in ports: - try: - client.delete_port(port['id']) - except Exception: - LOG.exception("Delete Port exception.") - - def dry_run(self): - ports = self.list() - self.data['ports'] = ports - - -class NetworkSecGroupService(NetworkService): - def list(self): - client = self.security_groups_client - filter = self.tenant_filter - # cannot delete default sec group so never show it. - secgroups = [secgroup for secgroup in - client.list_security_groups(**filter)['security_groups'] - if secgroup['name'] != 'default'] - - if self.is_preserve: - secgroups = self._filter_by_conf_networks(secgroups) - LOG.debug("List count, %s security_groups", len(secgroups)) - return secgroups - - def delete(self): - client = self.client - secgroups = self.list() - for secgroup in secgroups: - try: - client.delete_secgroup(secgroup['id']) - except Exception: - LOG.exception("Delete security_group exception.") - - def dry_run(self): - secgroups = self.list() - self.data['secgroups'] = secgroups - - -class NetworkSubnetService(NetworkService): - - def list(self): - client = self.subnets_client - subnets = client.list_subnets(**self.tenant_filter) - subnets = subnets['subnets'] - if self.is_preserve: - subnets = self._filter_by_conf_networks(subnets) - LOG.debug("List count, %s Subnets", len(subnets)) - return subnets - - def delete(self): - client = self.subnets_client - subnets = self.list() - for subnet in subnets: - try: - client.delete_subnet(subnet['id']) - except Exception: - LOG.exception("Delete Subnet exception.") - - def dry_run(self): - subnets = self.list() - self.data['subnets'] = subnets - - -# begin global services -class FlavorService(BaseService): - def __init__(self, manager, **kwargs): - super(FlavorService, self).__init__(kwargs) - self.client = manager.flavors_client - - def list(self): - client = self.client - flavors = client.list_flavors({"is_public": None})['flavors'] - if not self.is_save_state: - # recreate list removing saved flavors - flavors = [flavor for flavor in flavors if flavor['id'] - not in self.saved_state_json['flavors'].keys()] - - if self.is_preserve: - flavors = [flavor for flavor in flavors - if flavor['id'] not in CONF_FLAVORS] - LOG.debug("List count, %s Flavors after reconcile", len(flavors)) - return flavors - - def delete(self): - client = self.client - flavors = self.list() - for flavor in flavors: - try: - client.delete_flavor(flavor['id']) - except Exception: - LOG.exception("Delete Flavor exception.") - - def dry_run(self): - flavors = self.list() - self.data['flavors'] = flavors - - def save_state(self): - flavors = self.list() - self.data['flavors'] = {} - for flavor in flavors: - self.data['flavors'][flavor['id']] = flavor['name'] - - -class ImageService(BaseService): - def __init__(self, manager, **kwargs): - super(ImageService, self).__init__(kwargs) - self.client = manager.compute_images_client - - def list(self): - client = self.client - images = client.list_images({"all_tenants": True})['images'] - if not self.is_save_state: - images = [image for image in images if image['id'] - not in self.saved_state_json['images'].keys()] - if self.is_preserve: - images = [image for image in images - if image['id'] not in CONF_IMAGES] - LOG.debug("List count, %s Images after reconcile", len(images)) - return images - - def delete(self): - client = self.client - images = self.list() - for image in images: - try: - client.delete_image(image['id']) - except Exception: - LOG.exception("Delete Image exception.") - - def dry_run(self): - images = self.list() - self.data['images'] = images - - def save_state(self): - self.data['images'] = {} - images = self.list() - for image in images: - self.data['images'][image['id']] = image['name'] - - -class IdentityService(BaseService): - def __init__(self, manager, **kwargs): - super(IdentityService, self).__init__(kwargs) - self.client = manager.identity_client - - -class UserService(BaseService): - - def __init__(self, manager, **kwargs): - super(UserService, self).__init__(kwargs) - self.client = manager.users_client - - def list(self): - users = self.client.list_users()['users'] - - if not self.is_save_state: - users = [user for user in users if user['id'] - not in self.saved_state_json['users'].keys()] - - if self.is_preserve: - users = [user for user in users if user['name'] - not in CONF_USERS] - - elif not self.is_save_state: # Never delete admin user - users = [user for user in users if user['name'] != - CONF.auth.admin_username] - - LOG.debug("List count, %s Users after reconcile", len(users)) - return users - - def delete(self): - users = self.list() - for user in users: - try: - self.client.delete_user(user['id']) - except Exception: - LOG.exception("Delete User exception.") - - def dry_run(self): - users = self.list() - self.data['users'] = users - - def save_state(self): - users = self.list() - self.data['users'] = {} - for user in users: - self.data['users'][user['id']] = user['name'] - - -class RoleService(BaseService): - - def __init__(self, manager, **kwargs): - super(RoleService, self).__init__(kwargs) - self.client = manager.roles_client - - def list(self): - try: - roles = self.client.list_roles()['roles'] - # reconcile roles with saved state and never list admin role - if not self.is_save_state: - roles = [role for role in roles if - (role['id'] not in - self.saved_state_json['roles'].keys() - and role['name'] != CONF.identity.admin_role)] - LOG.debug("List count, %s Roles after reconcile", len(roles)) - return roles - except Exception: - LOG.exception("Cannot retrieve Roles.") - return [] - - def delete(self): - roles = self.list() - for role in roles: - try: - self.client.delete_role(role['id']) - except Exception: - LOG.exception("Delete Role exception.") - - def dry_run(self): - roles = self.list() - self.data['roles'] = roles - - def save_state(self): - roles = self.list() - self.data['roles'] = {} - for role in roles: - self.data['roles'][role['id']] = role['name'] - - -class TenantService(BaseService): - - def __init__(self, manager, **kwargs): - super(TenantService, self).__init__(kwargs) - self.client = manager.tenants_client - - def list(self): - tenants = self.client.list_tenants()['tenants'] - if not self.is_save_state: - tenants = [tenant for tenant in tenants if (tenant['id'] - not in self.saved_state_json['tenants'].keys() - and tenant['name'] != CONF.auth.admin_project_name)] - - if self.is_preserve: - tenants = [tenant for tenant in tenants if tenant['name'] - not in CONF_TENANTS] - - LOG.debug("List count, %s Tenants after reconcile", len(tenants)) - return tenants - - def delete(self): - tenants = self.list() - for tenant in tenants: - try: - self.client.delete_tenant(tenant['id']) - except Exception: - LOG.exception("Delete Tenant exception.") - - def dry_run(self): - tenants = self.list() - self.data['tenants'] = tenants - - def save_state(self): - tenants = self.list() - self.data['tenants'] = {} - for tenant in tenants: - self.data['tenants'][tenant['id']] = tenant['name'] - - -class DomainService(BaseService): - - def __init__(self, manager, **kwargs): - super(DomainService, self).__init__(kwargs) - self.client = manager.domains_client - - def list(self): - client = self.client - domains = client.list_domains()['domains'] - if not self.is_save_state: - domains = [domain for domain in domains if domain['id'] - not in self.saved_state_json['domains'].keys()] - - LOG.debug("List count, %s Domains after reconcile", len(domains)) - return domains - - def delete(self): - client = self.client - domains = self.list() - for domain in domains: - try: - client.update_domain(domain['id'], enabled=False) - client.delete_domain(domain['id']) - except Exception: - LOG.exception("Delete Domain exception.") - - def dry_run(self): - domains = self.list() - self.data['domains'] = domains - - def save_state(self): - domains = self.list() - self.data['domains'] = {} - for domain in domains: - self.data['domains'][domain['id']] = domain['name'] - - -def get_tenant_cleanup_services(): - tenant_services = [] - # TODO(gmann): Tempest should provide some plugin hook for cleanup - # script extension to plugin tests also. - if IS_NOVA: - tenant_services.append(ServerService) - tenant_services.append(KeyPairService) - tenant_services.append(SecurityGroupService) - tenant_services.append(ServerGroupService) - if not IS_NEUTRON: - tenant_services.append(FloatingIpService) - tenant_services.append(NovaQuotaService) - if IS_HEAT: - tenant_services.append(StackService) - if IS_NEUTRON: - tenant_services.append(NetworkFloatingIpService) - if test.is_extension_enabled('metering', 'network'): - tenant_services.append(NetworkMeteringLabelRuleService) - tenant_services.append(NetworkMeteringLabelService) - tenant_services.append(NetworkRouterService) - tenant_services.append(NetworkPortService) - tenant_services.append(NetworkSubnetService) - tenant_services.append(NetworkService) - tenant_services.append(NetworkSecGroupService) - if IS_CINDER: - tenant_services.append(SnapshotService) - tenant_services.append(VolumeService) - tenant_services.append(VolumeQuotaService) - return tenant_services - - -def get_global_cleanup_services(): - global_services = [] - if IS_NOVA: - global_services.append(FlavorService) - if IS_GLANCE: - global_services.append(ImageService) - global_services.append(UserService) - global_services.append(TenantService) - global_services.append(DomainService) - global_services.append(RoleService) - return global_services diff --git a/tempest/cmd/config-generator.tempest.conf b/tempest/cmd/config-generator.tempest.conf deleted file mode 100644 index b8f16d92d..000000000 --- a/tempest/cmd/config-generator.tempest.conf +++ /dev/null @@ -1,5 +0,0 @@ -[DEFAULT] -output_file = etc/tempest.conf.sample -namespace = tempest.config -namespace = oslo.concurrency -namespace = oslo.log diff --git a/tempest/cmd/init.py b/tempest/cmd/init.py deleted file mode 100644 index 7634d9e1a..000000000 --- a/tempest/cmd/init.py +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import shutil -import sys - -from cliff import command -from oslo_config import generator -from oslo_log import log as logging -from six import moves -from testrepository import commands - -from tempest.cmd import workspace - -LOG = logging.getLogger(__name__) - -TESTR_CONF = """[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \\ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \\ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-500} \\ - ${PYTHON:-python} -m subunit.run discover -t %s %s $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list -group_regex=([^\.]*\.)* -""" - - -def get_tempest_default_config_dir(): - """Get default config directory of tempest - - There are 3 dirs that get tried in priority order. First is /etc/tempest, - if that doesn't exist it looks for a tempest dir in the XDG_CONFIG_HOME - dir (defaulting to ~/.config/tempest) and last it tries for a - ~/.tempest/etc directory. If none of these exist a ~/.tempest/etc - directory will be created. - - :return: default config dir - """ - global_conf_dir = '/etc/tempest' - xdg_config = os.environ.get('XDG_CONFIG_HOME', - os.path.expanduser('~/.config')) - user_xdg_global_path = os.path.join(xdg_config, 'tempest') - user_global_path = os.path.join(os.path.expanduser('~'), '.tempest/etc') - if os.path.isdir(global_conf_dir): - return global_conf_dir - elif os.path.isdir(user_xdg_global_path): - return user_xdg_global_path - elif os.path.isdir(user_global_path): - return user_global_path - else: - os.makedirs(user_global_path) - return user_global_path - - -class TempestInit(command.Command): - """Setup a local working environment for running tempest""" - - def get_parser(self, prog_name): - parser = super(TempestInit, self).get_parser(prog_name) - parser.add_argument('dir', nargs='?', default=os.getcwd(), - help="The path to the workspace directory. If you " - "omit this argument, the workspace directory is " - "your current directory") - parser.add_argument('--config-dir', '-c', default=None) - parser.add_argument('--show-global-config-dir', '-s', - action='store_true', dest='show_global_dir', - help="Print the global config dir location, " - "then exit") - parser.add_argument('--name', help="The workspace name", default=None) - parser.add_argument('--workspace-path', default=None, - help="The path to the workspace file, the default " - "is ~/.tempest/workspace.yaml") - return parser - - def generate_testr_conf(self, local_path): - testr_conf_path = os.path.join(local_path, '.testr.conf') - top_level_path = os.path.dirname(os.path.dirname(__file__)) - discover_path = os.path.join(top_level_path, 'test_discover') - testr_conf = TESTR_CONF % (top_level_path, discover_path) - with open(testr_conf_path, 'w+') as testr_conf_file: - testr_conf_file.write(testr_conf) - - def get_configparser(self, conf_path): - config_parse = moves.configparser.ConfigParser() - config_parse.optionxform = str - # get any existing values if a config file already exists - if os.path.isfile(conf_path): - # use read() for Python 2 and 3 compatibility - config_parse.read(conf_path) - return config_parse - - def update_local_conf(self, conf_path, lock_dir, log_dir): - config_parse = self.get_configparser(conf_path) - # Set local lock_dir in tempest conf - if not config_parse.has_section('oslo_concurrency'): - config_parse.add_section('oslo_concurrency') - config_parse.set('oslo_concurrency', 'lock_path', lock_dir) - # Set local log_dir in tempest conf - config_parse.set('DEFAULT', 'log_dir', log_dir) - # Set default log filename to tempest.log - config_parse.set('DEFAULT', 'log_file', 'tempest.log') - - # write out a new file with the updated configurations - with open(conf_path, 'w+') as conf_file: - config_parse.write(conf_file) - - def copy_config(self, etc_dir, config_dir): - if os.path.isdir(config_dir): - shutil.copytree(config_dir, etc_dir) - else: - LOG.warning("Global config dir %s can't be found", config_dir) - - def generate_sample_config(self, local_dir): - conf_generator = os.path.join(os.path.dirname(__file__), - 'config-generator.tempest.conf') - output_file = os.path.join(local_dir, 'etc/tempest.conf.sample') - if os.path.isfile(conf_generator): - generator.main(['--config-file', conf_generator, '--output-file', - output_file]) - else: - LOG.warning("Skipping sample config generation because global " - "config file %s can't be found", conf_generator) - - def create_working_dir(self, local_dir, config_dir): - # make sure we are working with abspath however tempest init is called - local_dir = os.path.abspath(local_dir) - # Create local dir if missing - if not os.path.isdir(local_dir): - LOG.debug('Creating local working dir: %s', local_dir) - os.mkdir(local_dir) - elif not os.listdir(local_dir) == []: - raise OSError("Directory you are trying to initialize already " - "exists and is not empty: %s" % local_dir) - - lock_dir = os.path.join(local_dir, 'tempest_lock') - etc_dir = os.path.join(local_dir, 'etc') - config_path = os.path.join(etc_dir, 'tempest.conf') - log_dir = os.path.join(local_dir, 'logs') - testr_dir = os.path.join(local_dir, '.testrepository') - # Create lock dir - if not os.path.isdir(lock_dir): - LOG.debug('Creating lock dir: %s', lock_dir) - os.mkdir(lock_dir) - # Create log dir - if not os.path.isdir(log_dir): - LOG.debug('Creating log dir: %s', log_dir) - os.mkdir(log_dir) - # Create and copy local etc dir - self.copy_config(etc_dir, config_dir) - # Generate the sample config file - self.generate_sample_config(local_dir) - # Update local confs to reflect local paths - self.update_local_conf(config_path, lock_dir, log_dir) - # Generate a testr conf file - self.generate_testr_conf(local_dir) - # setup local testr working dir - if not os.path.isdir(testr_dir): - commands.run_argv(['testr', 'init', '-d', local_dir], sys.stdin, - sys.stdout, sys.stderr) - - def take_action(self, parsed_args): - workspace_manager = workspace.WorkspaceManager( - parsed_args.workspace_path) - name = parsed_args.name or parsed_args.dir.split(os.path.sep)[-1] - config_dir = parsed_args.config_dir or get_tempest_default_config_dir() - if parsed_args.show_global_dir: - print("Global config dir is located at: %s" % config_dir) - sys.exit(0) - self.create_working_dir(parsed_args.dir, config_dir) - workspace_manager.register_new_workspace( - name, parsed_args.dir, init=True) diff --git a/tempest/cmd/list_plugins.py b/tempest/cmd/list_plugins.py deleted file mode 100644 index 86732da54..000000000 --- a/tempest/cmd/list_plugins.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python - -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Utility for listing all currently installed Tempest plugins. - -**Usage:** ``tempest list-plugins``. -""" - -from cliff import command -import prettytable - -from tempest.test_discover import plugins as plg - - -class TempestListPlugins(command.Command): - def take_action(self, parsed_args): - self._list_plugins() - - def get_description(self): - return 'List all tempest plugins' - - def _list_plugins(self): - plugins = plg.TempestTestPluginManager() - - output = prettytable.PrettyTable(["Name", "EntryPoint"]) - for plugin in plugins.ext_plugins.extensions: - output.add_row([ - plugin.name, plugin.entry_point_target]) - - print(output) diff --git a/tempest/cmd/main.py b/tempest/cmd/main.py deleted file mode 100644 index 1090c41b1..000000000 --- a/tempest/cmd/main.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2015 Dell Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import sys - -from cliff import app -from cliff import commandmanager -from oslo_log import log as logging -from pbr import version - - -class Main(app.App): - - log = logging.getLogger(__name__) - - def __init__(self): - super(Main, self).__init__( - description='Tempest cli application', - version=version.VersionInfo('tempest').version_string_with_vcs(), - command_manager=commandmanager.CommandManager('tempest.cm'), - deferred_help=True, - ) - - def initialize_app(self, argv): - self.log.debug('tempest initialize_app') - - def prepare_to_run_command(self, cmd): - self.log.debug('prepare_to_run_command %s', cmd.__class__.__name__) - - def clean_up(self, cmd, result, err): - self.log.debug('tempest clean_up %s', cmd.__class__.__name__) - if err: - self.log.debug('tempest got an error: %s', err) - - -def main(argv=sys.argv[1:]): - the_app = Main() - return the_app.run(argv) - - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py deleted file mode 100644 index 350dd0bde..000000000 --- a/tempest/cmd/run.py +++ /dev/null @@ -1,350 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Runs tempest tests - -This command is used for running the tempest tests - -Test Selection -============== -Tempest run has several options: - - * **--regex/-r**: This is a selection regex like what testr uses. It will run - any tests that match on re.match() with the regex - * **--smoke/-s**: Run all the tests tagged as smoke - -There are also the **--blacklist-file** and **--whitelist-file** options that -let you pass a filepath to tempest run with the file format being a line -separated regex, with '#' used to signify the start of a comment on a line. -For example:: - - # Regex file - ^regex1 # Match these tests - .*regex2 # Match those tests - -The blacklist file will be used to construct a negative lookahead regex and -the whitelist file will simply OR all the regexes in the file. The whitelist -and blacklist file options are mutually exclusive so you can't use them -together. However, you can combine either with a normal regex or the *--smoke* -flag. When used with a blacklist file the generated regex will be combined to -something like:: - - ^((?!black_regex1|black_regex2).)*$cli_regex1 - -When combined with a whitelist file all the regexes from the file and the CLI -regexes will be ORed. - -You can also use the **--list-tests** option in conjunction with selection -arguments to list which tests will be run. - -Test Execution -============== -There are several options to control how the tests are executed. By default -tempest will run in parallel with a worker for each CPU present on the machine. -If you want to adjust the number of workers use the **--concurrency** option -and if you want to run tests serially use **--serial/-t** - -Running with Workspaces ------------------------ -Tempest run enables you to run your tempest tests from any setup tempest -workspace it relies on you having setup a tempest workspace with either the -``tempest init`` or ``tempest workspace`` commands. Then using the -``--workspace`` CLI option you can specify which one of your workspaces you -want to run tempest from. Using this option you don't have to run Tempest -directly with you current working directory being the workspace, Tempest will -take care of managing everything to be executed from there. - -Running from Anywhere ---------------------- -Tempest run provides you with an option to execute tempest from anywhere on -your system. You are required to provide a config file in this case with the -``--config-file`` option. When run tempest will create a .testrepository -directory and a .testr.conf file in your current working directory. This way -you can use testr commands directly to inspect the state of the previous run. - -Test Output -=========== -By default tempest run's output to STDOUT will be generated using the -subunit-trace output filter. But, if you would prefer a subunit v2 stream be -output to STDOUT use the **--subunit** flag - -Combining Runs -============== - -There are certain situations in which you want to split a single run of tempest -across 2 executions of tempest run. (for example to run part of the tests -serially and others in parallel) To accomplish this but still treat the results -as a single run you can leverage the **--combine** option which will append -the current run's results with the previous runs. -""" - -import io -import os -import sys -import tempfile -import threading - -from cliff import command -from os_testr import regex_builder -from os_testr import subunit_trace -from oslo_serialization import jsonutils as json -import six -from testrepository.commands import run_argv - -from tempest.cmd import cleanup_service -from tempest.cmd import init -from tempest.cmd import workspace -from tempest.common import credentials_factory as credentials -from tempest import config - - -CONF = config.CONF -SAVED_STATE_JSON = "saved_state.json" - - -class TempestRun(command.Command): - - def _set_env(self, config_file=None): - if config_file: - CONF.set_config_path(os.path.abspath(config_file)) - # NOTE(mtreinish): This is needed so that testr doesn't gobble up any - # stacktraces on failure. - if 'TESTR_PDB' in os.environ: - return - else: - os.environ["TESTR_PDB"] = "" - # NOTE(dims): most of our .testr.conf try to test for PYTHON - # environment variable and fall back to "python", under python3 - # if it does not exist. we should set it to the python3 executable - # to deal with this situation better for now. - if six.PY3 and 'PYTHON' not in os.environ: - os.environ['PYTHON'] = sys.executable - - def _create_testrepository(self): - if not os.path.isdir('.testrepository'): - returncode = run_argv(['testr', 'init'], sys.stdin, sys.stdout, - sys.stderr) - if returncode: - sys.exit(returncode) - - def _create_testr_conf(self): - top_level_path = os.path.dirname(os.path.dirname(__file__)) - discover_path = os.path.join(top_level_path, 'test_discover') - file_contents = init.TESTR_CONF % (top_level_path, discover_path) - with open('.testr.conf', 'w+') as testr_conf_file: - testr_conf_file.write(file_contents) - - def take_action(self, parsed_args): - returncode = 0 - if parsed_args.config_file: - self._set_env(parsed_args.config_file) - else: - self._set_env() - # Workspace execution mode - if parsed_args.workspace: - workspace_mgr = workspace.WorkspaceManager( - parsed_args.workspace_path) - path = workspace_mgr.get_workspace(parsed_args.workspace) - if not path: - sys.exit( - "The %r workspace isn't registered in " - "%r. Use 'tempest init' to " - "register the workspace." % - (parsed_args.workspace, workspace_mgr.path)) - os.chdir(path) - # NOTE(mtreinish): tempest init should create a .testrepository dir - # but since workspaces can be imported let's sanity check and - # ensure that one is created - self._create_testrepository() - # Local execution mode - elif os.path.isfile('.testr.conf'): - # If you're running in local execution mode and there is not a - # testrepository dir create one - self._create_testrepository() - # local execution with config file mode - elif parsed_args.config_file: - self._create_testr_conf() - self._create_testrepository() - else: - print("No .testr.conf file was found for local execution") - sys.exit(2) - if parsed_args.state: - self._init_state() - else: - pass - - if parsed_args.combine: - temp_stream = tempfile.NamedTemporaryFile() - return_code = run_argv(['tempest', 'last', '--subunit'], sys.stdin, - temp_stream, sys.stderr) - if return_code > 0: - sys.exit(return_code) - - regex = self._build_regex(parsed_args) - if parsed_args.list_tests: - argv = ['tempest', 'list-tests', regex] - returncode = run_argv(argv, sys.stdin, sys.stdout, sys.stderr) - else: - options = self._build_options(parsed_args) - returncode = self._run(regex, options) - if returncode > 0: - sys.exit(returncode) - - if parsed_args.combine: - return_code = run_argv(['tempest', 'last', '--subunit'], sys.stdin, - temp_stream, sys.stderr) - if return_code > 0: - sys.exit(return_code) - returncode = run_argv(['tempest', 'load', temp_stream.name], - sys.stdin, sys.stdout, sys.stderr) - sys.exit(returncode) - - def get_description(self): - return 'Run tempest' - - def _init_state(self): - print("Initializing saved state.") - data = {} - self.global_services = cleanup_service.get_global_cleanup_services() - self.admin_mgr = credentials.AdminManager() - admin_mgr = self.admin_mgr - kwargs = {'data': data, - 'is_dry_run': False, - 'saved_state_json': data, - 'is_preserve': False, - 'is_save_state': True} - for service in self.global_services: - svc = service(admin_mgr, **kwargs) - svc.run() - - with open(SAVED_STATE_JSON, 'w+') as f: - f.write(json.dumps(data, - sort_keys=True, indent=2, separators=(',', ': '))) - - def get_parser(self, prog_name): - parser = super(TempestRun, self).get_parser(prog_name) - parser = self._add_args(parser) - return parser - - def _add_args(self, parser): - # workspace args - parser.add_argument('--workspace', default=None, - help='Name of tempest workspace to use for running' - ' tests. You can see a list of workspaces ' - 'with tempest workspace list') - parser.add_argument('--workspace-path', default=None, - dest='workspace_path', - help="The path to the workspace file, the default " - "is ~/.tempest/workspace.yaml") - # Configuration flags - parser.add_argument('--config-file', default=None, dest='config_file', - help='Configuration file to run tempest with') - # test selection args - regex = parser.add_mutually_exclusive_group() - regex.add_argument('--smoke', '-s', action='store_true', - help="Run the smoke tests only") - regex.add_argument('--regex', '-r', default='', - help='A normal testr selection regex used to ' - 'specify a subset of tests to run') - list_selector = parser.add_mutually_exclusive_group() - list_selector.add_argument('--whitelist-file', '--whitelist_file', - help="Path to a whitelist file, this file " - "contains a separate regex on each " - "newline.") - list_selector.add_argument('--blacklist-file', '--blacklist_file', - help='Path to a blacklist file, this file ' - 'contains a separate regex exclude on ' - 'each newline') - # list only args - parser.add_argument('--list-tests', '-l', action='store_true', - help='List tests', - default=False) - # execution args - parser.add_argument('--concurrency', '-w', - help="The number of workers to use, defaults to " - "the number of cpus") - parallel = parser.add_mutually_exclusive_group() - parallel.add_argument('--parallel', dest='parallel', - action='store_true', - help='Run tests in parallel (this is the' - ' default)') - parallel.add_argument('--serial', '-t', dest='parallel', - action='store_false', - help='Run tests serially') - parser.add_argument('--save-state', dest='state', - action='store_true', - help="To save the state of the cloud before " - "running tempest.") - # output args - parser.add_argument("--subunit", action='store_true', - help='Enable subunit v2 output') - parser.add_argument("--combine", action='store_true', - help='Combine the output of this run with the ' - "previous run's as a combined stream in the " - "testr repository after it finish") - - parser.set_defaults(parallel=True) - return parser - - def _build_regex(self, parsed_args): - regex = '' - if parsed_args.smoke: - regex = 'smoke' - elif parsed_args.regex: - regex = parsed_args.regex - if parsed_args.whitelist_file or parsed_args.blacklist_file: - regex = regex_builder.construct_regex(parsed_args.blacklist_file, - parsed_args.whitelist_file, - regex, False) - return regex - - def _build_options(self, parsed_args): - options = [] - if parsed_args.subunit: - options.append("--subunit") - if parsed_args.parallel: - options.append("--parallel") - if parsed_args.concurrency: - options.append("--concurrency=%s" % parsed_args.concurrency) - return options - - def _run(self, regex, options): - returncode = 0 - argv = ['tempest', 'run', regex] + options - if '--subunit' in options: - returncode = run_argv(argv, sys.stdin, sys.stdout, sys.stderr) - else: - argv.append('--subunit') - stdin = io.StringIO() - stdout_r, stdout_w = os.pipe() - subunit_w = os.fdopen(stdout_w, 'wt') - subunit_r = os.fdopen(stdout_r) - returncodes = {} - - def run_argv_thread(): - returncodes['testr'] = run_argv(argv, stdin, subunit_w, - sys.stderr) - subunit_w.close() - - run_thread = threading.Thread(target=run_argv_thread) - run_thread.start() - returncodes['subunit-trace'] = subunit_trace.trace( - subunit_r, sys.stdout, post_fails=True, print_failures=True) - run_thread.join() - subunit_r.close() - # python version of pipefail - if returncodes['testr']: - returncode = returncodes['testr'] - elif returncodes['subunit-trace']: - returncode = returncodes['subunit-trace'] - return returncode diff --git a/tempest/cmd/subunit_describe_calls.py b/tempest/cmd/subunit_describe_calls.py deleted file mode 100644 index 8ee305582..000000000 --- a/tempest/cmd/subunit_describe_calls.py +++ /dev/null @@ -1,317 +0,0 @@ -# Copyright 2016 Rackspace -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -subunit-describe-calls is a parser for subunit streams to determine what REST -API calls are made inside of a test and in what order they are called. - -Runtime Arguments ------------------ - -**--subunit, -s**: (Optional) The path to the subunit file being parsed, -defaults to stdin - -**--non-subunit-name, -n**: (Optional) The file_name that the logs are being -stored in - -**--output-file, -o**: (Optional) The path where the JSON output will be -written to. This contains more information than is present in stdout. - -**--ports, -p**: (Optional) The path to a JSON file describing the ports being -used by different services - -Usage ------ - -subunit-describe-calls will take in either stdin subunit v1 or v2 stream or a -file path which contains either a subunit v1 or v2 stream passed via the ---subunit parameter. This is then parsed checking for details contained in the -file_bytes of the --non-subunit-name parameter (the default is pythonlogging -which is what Tempest uses to store logs). By default the OpenStack Kilo -release port defaults (http://bit.ly/22jpF5P) are used unless a file is -provided via the --ports option. The resulting output is dumped in JSON output -to the path provided in the --output-file option. - -Ports file JSON structure -^^^^^^^^^^^^^^^^^^^^^^^^^ -:: - - { - "": "", - ... - } - - -Output file JSON structure -^^^^^^^^^^^^^^^^^^^^^^^^^^ -:: - - { - "full_test_name[with_id_and_tags]": [ - { - "name": "The ClassName.MethodName that made the call", - "verb": "HTTP Verb", - "service": "Name of the service", - "url": "A shortened version of the URL called", - "status_code": "The status code of the response", - "request_headers": "The headers of the request", - "request_body": "The body of the request", - "response_headers": "The headers of the response", - "response_body": "The body of the response" - } - ] - } -""" -import argparse -import collections -import io -import json -import os -import re -import sys - -import subunit -import testtools - - -class UrlParser(testtools.TestResult): - uuid_re = re.compile(r'(^|[^0-9a-f])[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-' - '[0-9a-f]{4}-[0-9a-f]{12}([^0-9a-f]|$)') - id_re = re.compile(r'(^|[^0-9a-z])[0-9a-z]{8}[0-9a-z]{4}[0-9a-z]{4}' - '[0-9a-z]{4}[0-9a-z]{12}([^0-9a-z]|$)') - ip_re = re.compile(r'(^|[^0-9])[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]' - '{1,3}([^0-9]|$)') - url_re = re.compile(r'.*INFO.*Request \((?P.*)\): (?P[\d]{3}) ' - '(?P\w*) (?P.*) .*') - port_re = re.compile(r'.*:(?P\d+).*') - path_re = re.compile(r'http[s]?://[^/]*/(?P.*)') - request_re = re.compile(r'.* Request - Headers: (?P.*)') - response_re = re.compile(r'.* Response - Headers: (?P.*)') - body_re = re.compile(r'.*Body: (?P.*)') - - # Based on mitaka defaults: - # http://docs.openstack.org/mitaka/config-reference/ - # firewalls-default-ports.html - services = { - "8776": "Block Storage", - "8774": "Nova", - "8773": "Nova-API", "8775": "Nova-API", - "8386": "Sahara", - "35357": "Keystone", "5000": "Keystone", - "9292": "Glance", "9191": "Glance", - "9696": "Neutron", - "6000": "Swift", "6001": "Swift", "6002": "Swift", - "8004": "Heat", "8000": "Heat", "8003": "Heat", - "8777": "Ceilometer", - "80": "Horizon", - "8080": "Swift", - "443": "SSL", - "873": "rsync", - "3260": "iSCSI", - "3306": "MySQL", - "5672": "AMQP"} - - def __init__(self, services=None): - super(UrlParser, self).__init__() - self.test_logs = {} - self.services = services or self.services - - def addSuccess(self, test, details=None): - output = test.shortDescription() or test.id() - calls = self.parse_details(details) - self.test_logs.update({output: calls}) - - def addSkip(self, test, err, details=None): - output = test.shortDescription() or test.id() - calls = self.parse_details(details) - self.test_logs.update({output: calls}) - - def addError(self, test, err, details=None): - output = test.shortDescription() or test.id() - calls = self.parse_details(details) - self.test_logs.update({output: calls}) - - def addFailure(self, test, err, details=None): - output = test.shortDescription() or test.id() - calls = self.parse_details(details) - self.test_logs.update({output: calls}) - - def stopTestRun(self): - super(UrlParser, self).stopTestRun() - - def startTestRun(self): - super(UrlParser, self).startTestRun() - - def parse_details(self, details): - if details is None: - return - - calls = [] - for _, detail in details.items(): - in_request = False - in_response = False - current_call = {} - for line in detail.as_text().split("\n"): - url_match = self.url_re.match(line) - request_match = self.request_re.match(line) - response_match = self.response_re.match(line) - body_match = self.body_re.match(line) - - if url_match is not None: - if current_call != {}: - calls.append(current_call.copy()) - current_call = {} - in_request, in_response = False, False - current_call.update({ - "name": url_match.group("name"), - "verb": url_match.group("verb"), - "status_code": url_match.group("code"), - "service": self.get_service(url_match.group("url")), - "url": self.url_path(url_match.group("url"))}) - elif request_match is not None: - in_request, in_response = True, False - current_call.update( - {"request_headers": request_match.group("headers")}) - elif in_request and body_match is not None: - in_request = False - current_call.update( - {"request_body": body_match.group( - "body")}) - elif response_match is not None: - in_request, in_response = False, True - current_call.update( - {"response_headers": response_match.group( - "headers")}) - elif in_response and body_match is not None: - in_response = False - current_call.update( - {"response_body": body_match.group("body")}) - if current_call != {}: - calls.append(current_call.copy()) - - return calls - - def get_service(self, url): - match = self.port_re.match(url) - if match is not None: - return self.services.get(match.group("port"), "Unknown") - return "Unknown" - - def url_path(self, url): - match = self.path_re.match(url) - if match is not None: - path = match.group("path") - path = self.uuid_re.sub(r'\1\2', path) - path = self.ip_re.sub(r'\1\2', path) - path = self.id_re.sub(r'\1\2', path) - return path - return url - - -class FileAccumulator(testtools.StreamResult): - - def __init__(self, non_subunit_name='pythonlogging'): - super(FileAccumulator, self).__init__() - self.route_codes = collections.defaultdict(io.BytesIO) - self.non_subunit_name = non_subunit_name - - def status(self, **kwargs): - if kwargs.get('file_name') != self.non_subunit_name: - return - file_bytes = kwargs.get('file_bytes') - if not file_bytes: - return - route_code = kwargs.get('route_code') - stream = self.route_codes[route_code] - stream.write(file_bytes) - - -class ArgumentParser(argparse.ArgumentParser): - def __init__(self): - desc = "Outputs all HTTP calls a given test made that were logged." - super(ArgumentParser, self).__init__(description=desc) - - self.prog = "subunit-describe-calls" - - self.add_argument( - "-s", "--subunit", metavar="", - nargs="?", type=argparse.FileType('rb'), default=sys.stdin, - help="The path to the subunit output file.") - - self.add_argument( - "-n", "--non-subunit-name", metavar="", - default="pythonlogging", - help="The name used in subunit to describe the file contents.") - - self.add_argument( - "-o", "--output-file", metavar="", default=None, - help="The output file name for the json.") - - self.add_argument( - "-p", "--ports", metavar="", default=None, - help="A JSON file describing the ports for each service.") - - -def parse(stream, non_subunit_name, ports): - if ports is not None and os.path.exists(ports): - ports = json.loads(open(ports).read()) - - url_parser = UrlParser(ports) - suite = subunit.ByteStreamToStreamResult( - stream, non_subunit_name=non_subunit_name) - result = testtools.StreamToExtendedDecorator(url_parser) - accumulator = FileAccumulator(non_subunit_name) - result = testtools.StreamResultRouter(result) - result.add_rule(accumulator, 'test_id', test_id=None) - result.startTestRun() - suite.run(result) - - for bytes_io in accumulator.route_codes.values(): # v1 processing - bytes_io.seek(0) - suite = subunit.ProtocolTestCase(bytes_io) - suite.run(url_parser) - result.stopTestRun() - - return url_parser - - -def output(url_parser, output_file): - if output_file is not None: - with open(output_file, "w") as outfile: - outfile.write(json.dumps(url_parser.test_logs)) - return - - for test_name in url_parser.test_logs: - items = url_parser.test_logs[test_name] - sys.stdout.write('{0}\n'.format(test_name)) - if not items: - sys.stdout.write('\n') - continue - for item in items: - sys.stdout.write('\t- {0} {1} request for {2} to {3}\n'.format( - item.get('status_code'), item.get('verb'), - item.get('service'), item.get('url'))) - sys.stdout.write('\n') - - -def entry_point(): - cl_args = ArgumentParser().parse_args() - parser = parse(cl_args.subunit, cl_args.non_subunit_name, cl_args.ports) - output(parser, cl_args.output_file) - - -if __name__ == "__main__": - entry_point() diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py deleted file mode 100644 index 8e71ecca1..000000000 --- a/tempest/cmd/verify_tempest_config.py +++ /dev/null @@ -1,428 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import os -import re -import sys -import traceback - -from cliff import command -from oslo_log import log as logging -from oslo_serialization import jsonutils as json -from six import moves -from six.moves.urllib import parse as urlparse - -from tempest import clients -from tempest.common import credentials_factory as credentials -from tempest import config -import tempest.lib.common.http - - -CONF = config.CONF -CONF_PARSER = None - -LOG = logging.getLogger(__name__) - - -def _get_config_file(): - default_config_dir = os.path.join(os.path.abspath( - os.path.dirname(os.path.dirname(os.path.dirname(__file__)))), "etc") - default_config_file = "tempest.conf" - - conf_dir = os.environ.get('TEMPEST_CONFIG_DIR', default_config_dir) - conf_file = os.environ.get('TEMPEST_CONFIG', default_config_file) - path = os.path.join(conf_dir, conf_file) - fd = open(path, 'r+') - return fd - - -def change_option(option, group, value): - if not CONF_PARSER.has_section(group): - CONF_PARSER.add_section(group) - CONF_PARSER.set(group, option, str(value)) - - -def print_and_or_update(option, group, value, update): - print('Config option %s in group %s should be changed to: %s' - % (option, group, value)) - if update: - change_option(option, group, value) - - -def contains_version(prefix, versions): - return any([x for x in versions if x.startswith(prefix)]) - - -def verify_glance_api_versions(os, update): - # Check glance api versions - _, versions = os.image_client.get_versions() - if CONF.image_feature_enabled.api_v1 != contains_version('v1.', versions): - print_and_or_update('api_v1', 'image-feature-enabled', - not CONF.image_feature_enabled.api_v1, update) - if CONF.image_feature_enabled.api_v2 != contains_version('v2.', versions): - print_and_or_update('api_v2', 'image-feature-enabled', - not CONF.image_feature_enabled.api_v2, update) - - -def _remove_version_project(url_path): - # The regex matches strings like /v2.0, /v3/, /v2.1/project-id/ - return re.sub(r'/v\d+(\.\d+)?(/[^/]+)?', '', url_path) - - -def _get_unversioned_endpoint(base_url): - endpoint_parts = urlparse.urlparse(base_url) - new_path = _remove_version_project(endpoint_parts.path) - endpoint_parts = endpoint_parts._replace(path=new_path) - endpoint = urlparse.urlunparse(endpoint_parts) - return endpoint - - -def _get_api_versions(os, service): - client_dict = { - 'nova': os.servers_client, - 'keystone': os.identity_client, - 'cinder': os.volumes_client_latest, - } - if service != 'keystone' and service != 'cinder': - # Since keystone and cinder may be listening on a path, - # do not remove the path. - client_dict[service].skip_path() - endpoint = _get_unversioned_endpoint(client_dict[service].base_url) - - http = tempest.lib.common.http.ClosingHttp( - CONF.identity.disable_ssl_certificate_validation, - CONF.identity.ca_certificates_file) - - __, body = http.request(endpoint, 'GET') - client_dict[service].reset_path() - try: - body = json.loads(body) - except ValueError: - LOG.error( - 'Failed to get a JSON response from unversioned endpoint %s ' - '(versioned endpoint was %s). Response is:\n%s', - endpoint, client_dict[service].base_url, body[:100]) - raise - if service == 'keystone': - versions = map(lambda x: x['id'], body['versions']['values']) - else: - versions = map(lambda x: x['id'], body['versions']) - return list(versions) - - -def verify_keystone_api_versions(os, update): - # Check keystone api versions - versions = _get_api_versions(os, 'keystone') - if (CONF.identity_feature_enabled.api_v2 != - contains_version('v2.', versions)): - print_and_or_update('api_v2', 'identity-feature-enabled', - not CONF.identity_feature_enabled.api_v2, update) - if (CONF.identity_feature_enabled.api_v3 != - contains_version('v3.', versions)): - print_and_or_update('api_v3', 'identity-feature-enabled', - not CONF.identity_feature_enabled.api_v3, update) - - -def verify_cinder_api_versions(os, update): - # Check cinder api versions - versions = _get_api_versions(os, 'cinder') - if (CONF.volume_feature_enabled.api_v1 != - contains_version('v1.', versions)): - print_and_or_update('api_v1', 'volume-feature-enabled', - not CONF.volume_feature_enabled.api_v1, update) - if (CONF.volume_feature_enabled.api_v2 != - contains_version('v2.', versions)): - print_and_or_update('api_v2', 'volume-feature-enabled', - not CONF.volume_feature_enabled.api_v2, update) - if (CONF.volume_feature_enabled.api_v3 != - contains_version('v3.', versions)): - print_and_or_update('api_v3', 'volume-feature-enabled', - not CONF.volume_feature_enabled.api_v3, update) - - -def verify_api_versions(os, service, update): - verify = { - 'cinder': verify_cinder_api_versions, - 'glance': verify_glance_api_versions, - 'keystone': verify_keystone_api_versions, - } - if service not in verify: - return - verify[service](os, update) - - -def get_extension_client(os, service): - extensions_client = { - 'nova': os.extensions_client, - 'neutron': os.network_extensions_client, - 'swift': os.capabilities_client, - # NOTE: Cinder v3 API is current and v2 and v1 are deprecated. - # V3 extension API is the same as v2, so we reuse the v2 client - # for v3 API also. - 'cinder': os.volumes_v2_extension_client, - } - - if service not in extensions_client: - print('No tempest extensions client for %s' % service) - sys.exit(1) - return extensions_client[service] - - -def get_enabled_extensions(service): - extensions_options = { - 'nova': CONF.compute_feature_enabled.api_extensions, - 'cinder': CONF.volume_feature_enabled.api_extensions, - 'neutron': CONF.network_feature_enabled.api_extensions, - 'swift': CONF.object_storage_feature_enabled.discoverable_apis, - } - if service not in extensions_options: - print('No supported extensions list option for %s' % service) - sys.exit(1) - return extensions_options[service] - - -def verify_extensions(os, service, results): - extensions_client = get_extension_client(os, service) - if service != 'swift': - resp = extensions_client.list_extensions() - else: - resp = extensions_client.list_capabilities() - # For Nova, Cinder and Neutron we use the alias name rather than the - # 'name' field because the alias is considered to be the canonical - # name. - if isinstance(resp, dict): - if service == 'swift': - # Remove Swift general information from extensions list - resp.pop('swift') - extensions = resp.keys() - else: - extensions = map(lambda x: x['alias'], resp['extensions']) - - else: - extensions = map(lambda x: x['alias'], resp) - extensions = list(extensions) - if not results.get(service): - results[service] = {} - extensions_opt = get_enabled_extensions(service) - if extensions_opt[0] == 'all': - results[service]['extensions'] = extensions - return results - # Verify that all configured extensions are actually enabled - for extension in extensions_opt: - results[service][extension] = extension in extensions - # Verify that there aren't additional extensions enabled that aren't - # specified in the config list - for extension in extensions: - if extension not in extensions_opt: - results[service][extension] = False - return results - - -def display_results(results, update, replace): - update_dict = { - 'swift': 'object-storage-feature-enabled', - 'nova': 'compute-feature-enabled', - 'cinder': 'volume-feature-enabled', - 'neutron': 'network-feature-enabled', - } - for service in results: - # If all extensions are specified as being enabled there is no way to - # verify this so we just assume this to be true - if results[service].get('extensions'): - if replace: - output_list = results[service].get('extensions') - else: - output_list = ['all'] - else: - extension_list = get_enabled_extensions(service) - output_list = [] - for extension in results[service]: - if not results[service][extension]: - if extension in extension_list: - print("%s extension: %s should not be included in the " - "list of enabled extensions" % (service, - extension)) - else: - print("%s extension: %s should be included in the list" - " of enabled extensions" % (service, extension)) - output_list.append(extension) - else: - output_list.append(extension) - if update: - # Sort List - output_list.sort() - # Convert list to a string - output_string = ', '.join(output_list) - if service == 'swift': - change_option('discoverable_apis', update_dict[service], - output_string) - else: - change_option('api_extensions', update_dict[service], - output_string) - - -def check_service_availability(os, update): - services = [] - avail_services = [] - codename_match = { - 'volume': 'cinder', - 'network': 'neutron', - 'image': 'glance', - 'object_storage': 'swift', - 'compute': 'nova', - 'orchestration': 'heat', - 'baremetal': 'ironic', - 'identity': 'keystone', - } - # Get catalog list for endpoints to use for validation - _token, auth_data = os.auth_provider.get_auth() - if os.auth_version == 'v2': - catalog_key = 'serviceCatalog' - else: - catalog_key = 'catalog' - for entry in auth_data[catalog_key]: - services.append(entry['type']) - # Pull all catalog types from config file and compare against endpoint list - for cfgname in dir(CONF._config): - cfg = getattr(CONF, cfgname) - catalog_type = getattr(cfg, 'catalog_type', None) - if not catalog_type: - continue - else: - if cfgname == 'identity': - # Keystone is a required service for tempest - continue - if catalog_type not in services: - if getattr(CONF.service_available, codename_match[cfgname]): - print('Endpoint type %s not found either disable service ' - '%s or fix the catalog_type in the config file' % ( - catalog_type, codename_match[cfgname])) - if update: - change_option(codename_match[cfgname], - 'service_available', False) - else: - if not getattr(CONF.service_available, - codename_match[cfgname]): - print('Endpoint type %s is available, service %s should be' - ' set as available in the config file.' % ( - catalog_type, codename_match[cfgname])) - if update: - change_option(codename_match[cfgname], - 'service_available', True) - # If we are going to enable this we should allow - # extension checks. - avail_services.append(codename_match[cfgname]) - else: - avail_services.append(codename_match[cfgname]) - return avail_services - - -def _parser_add_args(parser): - parser.add_argument('-u', '--update', action='store_true', - help='Update the config file with results from api ' - 'queries. This assumes whatever is set in the ' - 'config file is incorrect. In the case of ' - 'endpoint checks where it could either be the ' - 'incorrect catalog type or the service available ' - 'option the service available option is assumed ' - 'to be incorrect and is thus changed') - parser.add_argument('-o', '--output', - help="Output file to write an updated config file to. " - "This has to be a separate file from the " - "original config file. If one isn't specified " - "with -u the new config file will be printed to " - "STDOUT") - parser.add_argument('-r', '--replace-ext', action='store_true', - help="If specified the all option will be replaced " - "with a full list of extensions") - - -def parse_args(): - parser = argparse.ArgumentParser() - _parser_add_args(parser) - opts = parser.parse_args() - return opts - - -def main(opts=None): - print('Running config verification...') - if opts is None: - print("Use of: 'verify-tempest-config' is deprecated, " - "please use: 'tempest verify-config'") - opts = parse_args() - update = opts.update - replace = opts.replace_ext - global CONF_PARSER - - if update: - conf_file = _get_config_file() - CONF_PARSER = moves.configparser.ConfigParser() - CONF_PARSER.optionxform = str - CONF_PARSER.readfp(conf_file) - - # Indicate not to create network resources as part of getting credentials - net_resources = { - 'network': False, - 'router': False, - 'subnet': False, - 'dhcp': False - } - icreds = credentials.get_credentials_provider( - 'verify_tempest_config', network_resources=net_resources) - try: - os = clients.Manager(icreds.get_primary_creds().credentials) - services = check_service_availability(os, update) - results = {} - for service in ['nova', 'cinder', 'neutron', 'swift']: - if service not in services: - continue - results = verify_extensions(os, service, results) - - # Verify API versions of all services in the keystone catalog and - # keystone itself. - services.append('keystone') - for service in services: - verify_api_versions(os, service, update) - - display_results(results, update, replace) - if update: - conf_file.close() - if opts.output: - with open(opts.output, 'w+') as outfile: - CONF_PARSER.write(outfile) - finally: - icreds.clear_creds() - - -class TempestVerifyConfig(command.Command): - """Verify your current tempest configuration""" - - def get_parser(self, prog_name): - parser = super(TempestVerifyConfig, self).get_parser(prog_name) - _parser_add_args(parser) - return parser - - def take_action(self, parsed_args): - try: - main(parsed_args) - except Exception: - LOG.exception("Failure verifying configuration.") - traceback.print_exc() - raise - -if __name__ == "__main__": - main() diff --git a/tempest/cmd/workspace.py b/tempest/cmd/workspace.py deleted file mode 100644 index 8166b4f8c..000000000 --- a/tempest/cmd/workspace.py +++ /dev/null @@ -1,262 +0,0 @@ -# Copyright 2016 Rackspace -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Manages Tempest workspaces - -This command is used for managing tempest workspaces - -Commands -======== - -list ----- -Outputs the name and path of all known tempest workspaces - -register --------- -Registers a new tempest workspace via a given --name and --path - -rename ------- -Renames a tempest workspace from --old-name to --new-name - -move ----- -Changes the path of a given tempest workspace --name to --path - -remove ------- -Deletes the entry for a given tempest workspace --name - ---rmdir Deletes the given tempest workspace directory - -General Options -=============== - - **--workspace_path**: Allows the user to specify a different location for the - workspace.yaml file containing the workspace definitions - instead of ~/.tempest/workspace.yaml -""" - -import os -import shutil -import sys - -from cliff import command -from cliff import lister -from oslo_concurrency import lockutils -import yaml - -from tempest import config - -CONF = config.CONF - - -class WorkspaceManager(object): - def __init__(self, path=None): - lockutils.get_lock_path(CONF) - self.path = path or os.path.join( - os.path.expanduser("~"), ".tempest", "workspace.yaml") - if not os.path.isdir(os.path.dirname(self.path)): - os.makedirs(self.path.rsplit(os.path.sep, 1)[0]) - self.workspaces = {} - - @lockutils.synchronized('workspaces', external=True) - def get_workspace(self, name): - """Returns the workspace that has the given name - - If the workspace isn't registered then `None` is returned. - """ - self._populate() - return self.workspaces.get(name) - - @lockutils.synchronized('workspaces', external=True) - def rename_workspace(self, old_name, new_name): - self._populate() - self._name_exists(old_name) - self._workspace_name_exists(new_name) - self.workspaces[new_name] = self.workspaces.pop(old_name) - self._write_file() - - @lockutils.synchronized('workspaces', external=True) - def move_workspace(self, name, path): - self._populate() - path = os.path.abspath(os.path.expanduser(path)) - self._name_exists(name) - self._validate_path(path) - self.workspaces[name] = path - self._write_file() - - def _name_exists(self, name): - if name not in self.workspaces: - print("A workspace was not found with name: {0}".format(name)) - sys.exit(1) - - @lockutils.synchronized('workspaces', external=True) - def remove_workspace_entry(self, name): - self._populate() - self._name_exists(name) - workspace_path = self.workspaces.pop(name) - self._write_file() - return workspace_path - - @lockutils.synchronized('workspaces', external=True) - def remove_workspace_directory(self, workspace_path): - shutil.rmtree(workspace_path) - - @lockutils.synchronized('workspaces', external=True) - def list_workspaces(self): - self._populate() - self._validate_workspaces() - return self.workspaces - - def _workspace_name_exists(self, name): - if name in self.workspaces: - print("A workspace already exists with name: {0}.".format( - name)) - sys.exit(1) - - def _validate_path(self, path): - if not os.path.exists(path): - print("Path does not exist.") - sys.exit(1) - - @lockutils.synchronized('workspaces', external=True) - def register_new_workspace(self, name, path, init=False): - """Adds the new workspace and writes out the new workspace config""" - self._populate() - path = os.path.abspath(os.path.expanduser(path)) - # This only happens when register is called from outside of init - if not init: - self._validate_path(path) - self._workspace_name_exists(name) - self.workspaces[name] = path - self._write_file() - - def _validate_workspaces(self): - if self.workspaces is not None: - self.workspaces = {n: p for n, p in self.workspaces.items() - if os.path.exists(p)} - self._write_file() - - def _write_file(self): - with open(self.path, 'w') as f: - f.write(yaml.dump(self.workspaces)) - - def _populate(self): - if not os.path.isfile(self.path): - return - with open(self.path, 'r') as f: - self.workspaces = yaml.safe_load(f) or {} - - -def add_global_arguments(parser): - parser.add_argument( - '--workspace-path', required=False, default=None, - help="The path to the workspace file, the default is " - "~/.tempest/workspace.yaml") - return parser - - -class TempestWorkspaceRegister(command.Command): - def get_description(self): - return ('Registers a new tempest workspace via a given ' - '--name and --path') - - def get_parser(self, prog_name): - parser = super(TempestWorkspaceRegister, self).get_parser(prog_name) - add_global_arguments(parser) - parser.add_argument('--name', required=True) - parser.add_argument('--path', required=True) - - return parser - - def take_action(self, parsed_args): - self.manager = WorkspaceManager(parsed_args.workspace_path) - self.manager.register_new_workspace(parsed_args.name, parsed_args.path) - sys.exit(0) - - -class TempestWorkspaceRename(command.Command): - def get_description(self): - return 'Renames a tempest workspace from --old-name to --new-name' - - def get_parser(self, prog_name): - parser = super(TempestWorkspaceRename, self).get_parser(prog_name) - add_global_arguments(parser) - parser.add_argument('--old-name', required=True) - parser.add_argument('--new-name', required=True) - - return parser - - def take_action(self, parsed_args): - self.manager = WorkspaceManager(parsed_args.workspace_path) - self.manager.rename_workspace( - parsed_args.old_name, parsed_args.new_name) - sys.exit(0) - - -class TempestWorkspaceMove(command.Command): - def get_description(self): - return 'Changes the path of a given tempest workspace --name to --path' - - def get_parser(self, prog_name): - parser = super(TempestWorkspaceMove, self).get_parser(prog_name) - add_global_arguments(parser) - parser.add_argument('--name', required=True) - parser.add_argument('--path', required=True) - - return parser - - def take_action(self, parsed_args): - self.manager = WorkspaceManager(parsed_args.workspace_path) - self.manager.move_workspace(parsed_args.name, parsed_args.path) - sys.exit(0) - - -class TempestWorkspaceRemove(command.Command): - def get_description(self): - return 'Deletes the entry for a given tempest workspace --name' - - def get_parser(self, prog_name): - parser = super(TempestWorkspaceRemove, self).get_parser(prog_name) - add_global_arguments(parser) - parser.add_argument('--name', required=True) - parser.add_argument('--rmdir', action='store_true', - help='Deletes the given workspace directory') - - return parser - - def take_action(self, parsed_args): - self.manager = WorkspaceManager(parsed_args.workspace_path) - workspace_path = self.manager.remove_workspace_entry(parsed_args.name) - if parsed_args.rmdir: - self.manager.remove_workspace_directory(workspace_path) - sys.exit(0) - - -class TempestWorkspaceList(lister.Lister): - def get_description(self): - return 'Outputs the name and path of all known tempest workspaces' - - def get_parser(self, prog_name): - parser = super(TempestWorkspaceList, self).get_parser(prog_name) - add_global_arguments(parser) - return parser - - def take_action(self, parsed_args): - self.manager = WorkspaceManager(parsed_args.workspace_path) - return (("Name", "Path"), - ((n, p) for n, p in self.manager.list_workspaces().items())) diff --git a/tempest/common/__init__.py b/tempest/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/common/compute.py b/tempest/common/compute.py deleted file mode 100644 index e3fbfb8b3..000000000 --- a/tempest/common/compute.py +++ /dev/null @@ -1,363 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import base64 -import socket -import ssl -import struct -import textwrap - -import six -from six.moves.urllib import parse as urlparse - -from oslo_log import log as logging -from oslo_utils import excutils - -from tempest.common import waiters -from tempest import config -from tempest.lib.common import fixed_network -from tempest.lib.common import rest_client -from tempest.lib.common.utils import data_utils - -if six.PY2: - ord_func = ord -else: - ord_func = int - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -def create_test_server(clients, validatable=False, validation_resources=None, - tenant_network=None, wait_until=None, - volume_backed=False, name=None, flavor=None, - image_id=None, **kwargs): - """Common wrapper utility returning a test server. - - This method is a common wrapper returning a test server that can be - pingable or sshable. - - :param clients: Client manager which provides OpenStack Tempest clients. - :param validatable: Whether the server will be pingable or sshable. - :param validation_resources: Resources created for the connection to the - server. Include a keypair, a security group and an IP. - :param tenant_network: Tenant network to be used for creating a server. - :param wait_until: Server status to wait for the server to reach after - its creation. - :param volume_backed: Whether the server is volume backed or not. - If this is true, a volume will be created and - create server will be requested with - 'block_device_mapping_v2' populated with below - values: - -------------------------------------------- - bd_map_v2 = [{ - 'uuid': volume['volume']['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'boot_index': 0, - 'delete_on_termination': True}] - kwargs['block_device_mapping_v2'] = bd_map_v2 - --------------------------------------------- - If server needs to be booted from volume with other - combination of bdm inputs than mentioned above, then - pass the bdm inputs explicitly as kwargs and image_id - as empty string (''). - :param name: Name of the server to be provisioned. If not defined a random - string ending with '-instance' will be generated. - :param flavor: Flavor of the server to be provisioned. If not defined, - CONF.compute.flavor_ref will be used instead. - :param image_id: ID of the image to be used to provision the server. If not - defined, CONF.compute.image_ref will be used instead. - :returns: a tuple - """ - - # TODO(jlanoux) add support of wait_until PINGABLE/SSHABLE - - if name is None: - name = data_utils.rand_name(__name__ + "-instance") - if flavor is None: - flavor = CONF.compute.flavor_ref - if image_id is None: - image_id = CONF.compute.image_ref - - kwargs = fixed_network.set_networks_kwarg( - tenant_network, kwargs) or {} - - multiple_create_request = (max(kwargs.get('min_count', 0), - kwargs.get('max_count', 0)) > 1) - - if CONF.validation.run_validation and validatable: - # As a first implementation, multiple pingable or sshable servers will - # not be supported - if multiple_create_request: - msg = ("Multiple pingable or sshable servers not supported at " - "this stage.") - raise ValueError(msg) - - if 'security_groups' in kwargs: - kwargs['security_groups'].append( - {'name': validation_resources['security_group']['name']}) - else: - try: - kwargs['security_groups'] = [ - {'name': validation_resources['security_group']['name']}] - except KeyError: - LOG.debug("No security group provided.") - - if 'key_name' not in kwargs: - try: - kwargs['key_name'] = validation_resources['keypair']['name'] - except KeyError: - LOG.debug("No key provided.") - - if CONF.validation.connect_method == 'floating': - if wait_until is None: - wait_until = 'ACTIVE' - - if 'user_data' not in kwargs: - # If nothing overrides the default user data script then run - # a simple script on the host to print networking info. This is - # to aid in debugging ssh failures. - script = ''' - #!/bin/sh - echo "Printing {user} user authorized keys" - cat ~{user}/.ssh/authorized_keys || true - '''.format(user=CONF.validation.image_ssh_user) - script_clean = textwrap.dedent(script).lstrip().encode('utf8') - script_b64 = base64.b64encode(script_clean) - kwargs['user_data'] = script_b64 - - if volume_backed: - volume_name = data_utils.rand_name(__name__ + '-volume') - volumes_client = clients.volumes_v2_client - params = {'name': volume_name, - 'imageRef': image_id, - 'size': CONF.volume.volume_size} - volume = volumes_client.create_volume(**params) - waiters.wait_for_volume_resource_status(volumes_client, - volume['volume']['id'], - 'available') - - bd_map_v2 = [{ - 'uuid': volume['volume']['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'boot_index': 0, - 'delete_on_termination': True}] - kwargs['block_device_mapping_v2'] = bd_map_v2 - - # Since this is boot from volume an image does not need - # to be specified. - image_id = '' - - body = clients.servers_client.create_server(name=name, imageRef=image_id, - flavorRef=flavor, - **kwargs) - - # handle the case of multiple servers - if multiple_create_request: - # Get servers created which name match with name param. - body_servers = clients.servers_client.list_servers() - servers = \ - [s for s in body_servers['servers'] if s['name'].startswith(name)] - else: - body = rest_client.ResponseBody(body.response, body['server']) - servers = [body] - - # The name of the method to associate a floating IP to as server is too - # long for PEP8 compliance so: - assoc = clients.compute_floating_ips_client.associate_floating_ip_to_server - - if wait_until: - for server in servers: - try: - waiters.wait_for_server_status( - clients.servers_client, server['id'], wait_until) - - # Multiple validatable servers are not supported for now. Their - # creation will fail with the condition above (l.58). - if CONF.validation.run_validation and validatable: - if CONF.validation.connect_method == 'floating': - assoc(floating_ip=validation_resources[ - 'floating_ip']['ip'], - server_id=servers[0]['id']) - - except Exception: - with excutils.save_and_reraise_exception(): - for server in servers: - try: - clients.servers_client.delete_server( - server['id']) - except Exception: - LOG.exception('Deleting server %s failed', - server['id']) - for server in servers: - # NOTE(artom) If the servers were booted with volumes - # and with delete_on_termination=False we need to wait - # for the servers to go away before proceeding with - # cleanup, otherwise we'll attempt to delete the - # volumes while they're still attached to servers that - # are in the process of being deleted. - try: - waiters.wait_for_server_termination( - clients.servers_client, server['id']) - except Exception: - LOG.exception('Server %s failed to delete in time', - server['id']) - - return body, servers - - -def shelve_server(servers_client, server_id, force_shelve_offload=False): - """Common wrapper utility to shelve server. - - This method is a common wrapper to make server in 'SHELVED' - or 'SHELVED_OFFLOADED' state. - - :param servers_clients: Compute servers client instance. - :param server_id: Server to make in shelve state - :param force_shelve_offload: Forcefully offload shelve server if it - is configured not to offload server - automatically after offload time. - """ - servers_client.shelve_server(server_id) - - offload_time = CONF.compute.shelved_offload_time - if offload_time >= 0: - waiters.wait_for_server_status(servers_client, server_id, - 'SHELVED_OFFLOADED', - extra_timeout=offload_time) - else: - waiters.wait_for_server_status(servers_client, server_id, 'SHELVED') - if force_shelve_offload: - servers_client.shelve_offload_server(server_id) - waiters.wait_for_server_status(servers_client, server_id, - 'SHELVED_OFFLOADED') - - -def create_websocket(url): - url = urlparse.urlparse(url) - if url.scheme == 'https': - client_socket = ssl.wrap_socket(socket.socket(socket.AF_INET, - socket.SOCK_STREAM)) - else: - client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - client_socket.connect((url.hostname, url.port)) - # Turn the Socket into a WebSocket to do the communication - return _WebSocket(client_socket, url) - - -class _WebSocket(object): - def __init__(self, client_socket, url): - """Contructor for the WebSocket wrapper to the socket.""" - self._socket = client_socket - # cached stream for early frames. - self.cached_stream = b'' - # Upgrade the HTTP connection to a WebSocket - self._upgrade(url) - - def _recv(self, recv_size): - """Wrapper to receive data from the cached stream or socket.""" - if recv_size <= 0: - return None - - data_from_cached = b'' - data_from_socket = b'' - if len(self.cached_stream) > 0: - read_from_cached = min(len(self.cached_stream), recv_size) - data_from_cached += self.cached_stream[:read_from_cached] - self.cached_stream = self.cached_stream[read_from_cached:] - recv_size -= read_from_cached - if recv_size > 0: - data_from_socket = self._socket.recv(recv_size) - return data_from_cached + data_from_socket - - def receive_frame(self): - """Wrapper for receiving data to parse the WebSocket frame format""" - # We need to loop until we either get some bytes back in the frame - # or no data was received (meaning the socket was closed). This is - # done to handle the case where we get back some empty frames - while True: - header = self._recv(2) - # If we didn't receive any data, just return None - if not header: - return None - # We will make the assumption that we are only dealing with - # frames less than 125 bytes here (for the negotiation) and - # that only the 2nd byte contains the length, and since the - # server doesn't do masking, we can just read the data length - if ord_func(header[1]) & 127 > 0: - return self._recv(ord_func(header[1]) & 127) - - def send_frame(self, data): - """Wrapper for sending data to add in the WebSocket frame format.""" - frame_bytes = list() - # For the first byte, want to say we are sending binary data (130) - frame_bytes.append(130) - # Only sending negotiation data so don't need to worry about > 125 - # We do need to add the bit that says we are masking the data - frame_bytes.append(len(data) | 128) - # We don't really care about providing a random mask for security - # So we will just hard-code a value since a test program - mask = [7, 2, 1, 9] - for i in range(len(mask)): - frame_bytes.append(mask[i]) - # Mask each of the actual data bytes that we are going to send - for i in range(len(data)): - frame_bytes.append(ord_func(data[i]) ^ mask[i % 4]) - # Convert our integer list to a binary array of bytes - frame_bytes = struct.pack('!%iB' % len(frame_bytes), * frame_bytes) - self._socket.sendall(frame_bytes) - - def close(self): - """Helper method to close the connection.""" - # Close down the real socket connection and exit the test program - if self._socket is not None: - self._socket.shutdown(1) - self._socket.close() - self._socket = None - - def _upgrade(self, url): - """Upgrade the HTTP connection to a WebSocket and verify.""" - # The real request goes to the /websockify URI always - reqdata = 'GET /websockify HTTP/1.1\r\n' - reqdata += 'Host: %s:%s\r\n' % (url.hostname, url.port) - # Tell the HTTP Server to Upgrade the connection to a WebSocket - reqdata += 'Upgrade: websocket\r\nConnection: Upgrade\r\n' - # The token=xxx is sent as a Cookie not in the URI - reqdata += 'Cookie: %s\r\n' % url.query - # Use a hard-coded WebSocket key since a test program - reqdata += 'Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n' - reqdata += 'Sec-WebSocket-Version: 13\r\n' - # We are choosing to use binary even though browser may do Base64 - reqdata += 'Sec-WebSocket-Protocol: binary\r\n\r\n' - # Send the HTTP GET request and get the response back - self._socket.sendall(reqdata.encode('utf8')) - self.response = data = self._socket.recv(4096) - # Loop through & concatenate all of the data in the response body - end_loc = self.response.find(b'\r\n\r\n') - while data and end_loc < 0: - data = self._socket.recv(4096) - self.response += data - end_loc = self.response.find(b'\r\n\r\n') - - if len(self.response) > end_loc + 4: - # In case some frames (e.g. the first RFP negotiation) have - # arrived, cache it for next reading. - self.cached_stream = self.response[end_loc + 4:] - # ensure response ends with '\r\n\r\n'. - self.response = self.response[:end_loc + 4] diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py deleted file mode 100644 index fd875be2d..000000000 --- a/tempest/common/credentials_factory.py +++ /dev/null @@ -1,314 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_concurrency import lockutils - -from tempest import clients -from tempest import config -from tempest.lib import auth -from tempest.lib.common import dynamic_creds -from tempest.lib.common import preprov_creds -from tempest.lib import exceptions - -CONF = config.CONF - - -"""This module provides factories of credential and credential providers - -Credentials providers and clients are (going to be) part of tempest.lib, -and so they may not hold any dependency to tempest configuration. - -Methods in this module collect the relevant configuration details and pass -them to credentials providers and clients, so that test can have easy -access to these features. - -Client managers with hard-coded configured credentials are also moved here, -to avoid circular dependencies.""" - -# === Credential Providers - - -# Subset of the parameters of credential providers that depend on configuration -def _get_common_provider_params(identity_version): - if identity_version == 'v3': - identity_uri = CONF.identity.uri_v3 - elif identity_version == 'v2': - identity_uri = CONF.identity.uri - return { - 'identity_version': identity_version, - 'identity_uri': identity_uri, - 'credentials_domain': CONF.auth.default_credentials_domain_name, - 'admin_role': CONF.identity.admin_role - } - - -def get_dynamic_provider_params(identity_version, admin_creds=None): - """Dynamic provider parameters setup from config - - This helper returns a dict of parameter that can be used to initialise - a `DynamicCredentialProvider` according to tempest configuration. - Parameters that are not configuration specific (name, network_resources) - are not returned. - - :param identity_version: 'v2' or 'v3' - :param admin_creds: An object of type `auth.Credentials`. If None, it - is built from the configuration file as well. - :returns A dict with the parameters - """ - _common_params = _get_common_provider_params(identity_version) - admin_creds = admin_creds or get_configured_admin_credentials( - fill_in=True, identity_version=identity_version) - if identity_version == 'v3': - endpoint_type = CONF.identity.v3_endpoint_type - elif identity_version == 'v2': - endpoint_type = CONF.identity.v2_admin_endpoint_type - return dict(_common_params, **dict([ - ('admin_creds', admin_creds), - ('identity_admin_domain_scope', CONF.identity.admin_domain_scope), - ('identity_admin_role', CONF.identity.admin_role), - ('extra_roles', CONF.auth.tempest_roles), - ('neutron_available', CONF.service_available.neutron), - ('project_network_cidr', CONF.network.project_network_cidr), - ('project_network_mask_bits', CONF.network.project_network_mask_bits), - ('public_network_id', CONF.network.public_network_id), - ('create_networks', (CONF.auth.create_isolated_networks and not - CONF.network.shared_physical_network)), - ('resource_prefix', CONF.resources_prefix), - ('identity_admin_endpoint_type', endpoint_type) - ])) - - -def get_preprov_provider_params(identity_version): - """Pre-provisioned provider parameters setup from config - - This helper returns a dict of parameter that can be used to initialise - a `PreProvisionedCredentialProvider` according to tempest configuration. - Parameters that are not configuration specific (name) are not returned. - - :param identity_version: 'v2' or 'v3' - :returns A dict with the parameters - """ - _common_params = _get_common_provider_params(identity_version) - reseller_admin_role = CONF.object_storage.reseller_admin_role - return dict(_common_params, **dict([ - ('accounts_lock_dir', lockutils.get_lock_path(CONF)), - ('test_accounts_file', CONF.auth.test_accounts_file), - ('object_storage_operator_role', CONF.object_storage.operator_role), - ('object_storage_reseller_admin_role', reseller_admin_role) - ])) - - -def get_credentials_provider(name, network_resources=None, - force_tenant_isolation=False, - identity_version=None): - """Return the right implementation of CredentialProvider based on config - - This helper returns the right implementation of CredentialProvider based on - config and on the value of force_tenant_isolation. - - :param name: When provided, it makes it possible to associate credential - artifacts back to the owner (test class). - :param network_resources: Dictionary of network resources to be allocated - for each test account. Only valid for the dynamic - credentials provider. - :param force_tenant_isolation: Always return a `DynamicCredentialProvider`, - regardless of the configuration. - :param identity_version: Use the specified identity API version, regardless - of the configuration. Valid values are 'v2', 'v3'. - """ - # If a test requires a new account to work, it can have it via forcing - # dynamic credentials. A new account will be produced only for that test. - # In case admin credentials are not available for the account creation, - # the test should be skipped else it would fail. - identity_version = identity_version or CONF.identity.auth_version - if CONF.auth.use_dynamic_credentials or force_tenant_isolation: - return dynamic_creds.DynamicCredentialProvider( - name=name, - network_resources=network_resources, - **get_dynamic_provider_params(identity_version)) - else: - if CONF.auth.test_accounts_file: - # Most params are not relevant for pre-created accounts - return preprov_creds.PreProvisionedCredentialProvider( - name=name, - **get_preprov_provider_params(identity_version)) - else: - raise exceptions.InvalidConfiguration( - 'A valid credential provider is needed') - - -def is_admin_available(identity_version): - """Helper to check for admin credentials - - Helper function to check if a set of admin credentials is available so we - can do a single call from skip_checks. - This helper depends on identity_version as there may be admin credentials - available for v2 but not for v3. - - :param identity_version: 'v2' or 'v3' - """ - is_admin = True - # If dynamic credentials is enabled admin will be available - if CONF.auth.use_dynamic_credentials: - return is_admin - # Check whether test accounts file has the admin specified or not - elif CONF.auth.test_accounts_file: - check_accounts = preprov_creds.PreProvisionedCredentialProvider( - name='check_admin', - **get_preprov_provider_params(identity_version)) - if not check_accounts.admin_available(): - is_admin = False - else: - try: - get_configured_admin_credentials(fill_in=False, - identity_version=identity_version) - except exceptions.InvalidConfiguration: - is_admin = False - return is_admin - - -def is_alt_available(identity_version): - """Helper to check for alt credentials - - Helper function to check if a second set of credentials is available (aka - alt credentials) so we can do a single call from skip_checks. - This helper depends on identity_version as there may be alt credentials - available for v2 but not for v3. - - :param identity_version: 'v2' or 'v3' - """ - # If dynamic credentials is enabled alt will be available - if CONF.auth.use_dynamic_credentials: - return True - # Check whether test accounts file has the admin specified or not - if CONF.auth.test_accounts_file: - check_accounts = preprov_creds.PreProvisionedCredentialProvider( - name='check_alt', - **get_preprov_provider_params(identity_version)) - else: - raise exceptions.InvalidConfiguration( - 'A valid credential provider is needed') - - try: - if not check_accounts.is_multi_user(): - return False - else: - return True - except exceptions.InvalidConfiguration: - return False - -# === Credentials - -# Type of credentials available from configuration -CREDENTIAL_TYPES = { - 'identity_admin': ('auth', 'admin'), - 'user': ('identity', None), - 'alt_user': ('identity', 'alt') -} - -DEFAULT_PARAMS = { - 'disable_ssl_certificate_validation': - CONF.identity.disable_ssl_certificate_validation, - 'ca_certs': CONF.identity.ca_certificates_file, - 'trace_requests': CONF.debug.trace_requests -} - - -def get_configured_admin_credentials(fill_in=True, identity_version=None): - """Get admin credentials from the config file - - Read credentials from configuration, builds a Credentials object based on - the specified or configured version - - :param fill_in: If True, a request to the Token API is submitted, and the - credential object is filled in with all names and IDs from - the token API response. - :param identity_version: The identity version to talk to and the type of - credentials object to be created. 'v2' or 'v3'. - :returns: An object of a sub-type of `auth.Credentials` - """ - identity_version = identity_version or CONF.identity.auth_version - - if identity_version not in ('v2', 'v3'): - raise exceptions.InvalidConfiguration( - 'Unsupported auth version: %s' % identity_version) - - conf_attributes = ['username', 'password', - 'project_name'] - - if identity_version == 'v3': - conf_attributes.append('domain_name') - # Read the parts of credentials from config - params = DEFAULT_PARAMS.copy() - for attr in conf_attributes: - params[attr] = getattr(CONF.auth, 'admin_' + attr) - # Build and validate credentials. We are reading configured credentials, - # so validate them even if fill_in is False - credentials = get_credentials(fill_in=fill_in, - identity_version=identity_version, **params) - if not fill_in: - if not credentials.is_valid(): - msg = ("The admin credentials are incorrectly set in the config " - "file for identity version %s. Double check that all " - "required values are assigned.") - raise exceptions.InvalidConfiguration(msg % identity_version) - return credentials - - -# Wrapper around auth.get_credentials to use the configured identity version -# if none is specified -def get_credentials(fill_in=True, identity_version=None, **kwargs): - """Get credentials from dict based on config - - Wrapper around auth.get_credentials to use the configured identity version - if none is specified. - - :param fill_in: If True, a request to the Token API is submitted, and the - credential object is filled in with all names and IDs from - the token API response. - :param identity_version: The identity version to talk to and the type of - credentials object to be created. 'v2' or 'v3'. - :param kwargs: Attributes to be used to build the Credentials object. - :returns: An object of a sub-type of `auth.Credentials` - """ - params = dict(DEFAULT_PARAMS, **kwargs) - identity_version = identity_version or CONF.identity.auth_version - # In case of "v3" add the domain from config if not specified - # To honour the "default_credentials_domain_name", if not domain - # field is specified at all, add it the credential dict. - if identity_version == 'v3': - domain_fields = set(x for x in auth.KeystoneV3Credentials.ATTRIBUTES - if 'domain' in x) - if not domain_fields.intersection(kwargs.keys()): - domain_name = CONF.auth.default_credentials_domain_name - # NOTE(andreaf) Setting domain_name implicitly sets user and - # project domain names, if they are None - params['domain_name'] = domain_name - - auth_url = CONF.identity.uri_v3 - else: - auth_url = CONF.identity.uri - return auth.get_credentials(auth_url, - fill_in=fill_in, - identity_version=identity_version, - **params) - -# === Credential / client managers - - -class AdminManager(clients.Manager): - """Manager that uses admin credentials for its managed client objects""" - - def __init__(self): - super(AdminManager, self).__init__( - credentials=get_configured_admin_credentials()) diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py deleted file mode 100644 index ed11b21ef..000000000 --- a/tempest/common/custom_matchers.py +++ /dev/null @@ -1,319 +0,0 @@ -# Copyright 2013 NTT Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import re - -from testtools import helpers - - -class ExistsAllResponseHeaders(object): - """Specific matcher to check the existence of Swift's response headers - - This matcher checks the existence of common headers for each HTTP method - or the target, which means account, container or object. - When checking the existence of 'specific' headers such as - X-Account-Meta-* or X-Object-Manifest for example, those headers must be - checked in each test code. - """ - - def __init__(self, target, method, policies=None): - """Initialization of ExistsAllResponseHeaders - - param: target Account/Container/Object - param: method PUT/GET/HEAD/DELETE/COPY/POST - """ - self.target = target - self.method = method - self.policies = policies or [] - - def _content_length_required(self, resp): - # Verify whether given HTTP response must contain content-length. - # Take into account the exceptions defined in RFC 7230. - if resp.status in range(100, 200) or resp.status == 204: - return False - - return True - - def match(self, actual): - """Check headers - - param: actual HTTP response object containing headers and status - """ - # Check common headers for all HTTP methods. - # - # Please note that for 1xx and 204 responses Content-Length presence - # is not checked intensionally. According to RFC 7230 a server MUST - # NOT send the header in such responses. Thus, clients should not - # depend on this header. However, the standard does not require them - # to validate the server's behavior. We leverage that to not refuse - # any implementation violating it like Swift [1] or some versions of - # Ceph RadosGW [2]. - # [1] https://bugs.launchpad.net/swift/+bug/1537811 - # [2] http://tracker.ceph.com/issues/13582 - if ('content-length' not in actual and - self._content_length_required(actual)): - return NonExistentHeader('content-length') - if 'content-type' not in actual: - return NonExistentHeader('content-type') - if 'x-trans-id' not in actual: - return NonExistentHeader('x-trans-id') - if 'date' not in actual: - return NonExistentHeader('date') - - # Check headers for a specific method or target - if self.method == 'GET' or self.method == 'HEAD': - if 'x-timestamp' not in actual: - return NonExistentHeader('x-timestamp') - if 'accept-ranges' not in actual: - return NonExistentHeader('accept-ranges') - if self.target == 'Account': - if 'x-account-bytes-used' not in actual: - return NonExistentHeader('x-account-bytes-used') - if 'x-account-container-count' not in actual: - return NonExistentHeader('x-account-container-count') - if 'x-account-object-count' not in actual: - return NonExistentHeader('x-account-object-count') - if int(actual['x-account-container-count']) > 0: - acct_header = "x-account-storage-policy-" - matched_policy_count = 0 - - # Loop through the policies and look for account - # usage data. There should be at least 1 set - for policy in self.policies: - front_header = acct_header + policy['name'].lower() - - usage_policies = [ - front_header + '-bytes-used', - front_header + '-object-count', - front_header + '-container-count' - ] - - # There should be 3 usage values for a give storage - # policy in an account bytes, object count, and - # container count - policy_hdrs = sum(1 for use_hdr in usage_policies - if use_hdr in actual) - - # If there are less than 3 headers here then 1 is - # missing, let's figure out which one and report - if policy_hdrs == 3: - matched_policy_count = matched_policy_count + 1 - else: - if policy_hdrs > 0 and policy_hdrs < 3: - for use_hdr in usage_policies: - if use_hdr not in actual: - return NonExistentHeader(use_hdr) - - # Only flag an error if actual policies have been read and - # no usage has been found - if self.policies and matched_policy_count == 0: - return GenericError("No storage policy usage headers") - - elif self.target == 'Container': - if 'x-container-bytes-used' not in actual: - return NonExistentHeader('x-container-bytes-used') - if 'x-container-object-count' not in actual: - return NonExistentHeader('x-container-object-count') - if 'x-storage-policy' not in actual: - return NonExistentHeader('x-storage-policy') - else: - policy_name = actual['x-storage-policy'] - - # loop through the policies and ensure that - # the value in the container header matches - # one of the storage policies - for policy in self.policies: - if policy['name'] == policy_name: - break - else: - # Ensure that there are actual policies stored - if self.policies: - return InvalidHeaderValue('x-storage-policy', - policy_name) - elif self.target == 'Object': - if 'etag' not in actual: - return NonExistentHeader('etag') - if 'last-modified' not in actual: - return NonExistentHeader('last-modified') - elif self.method == 'PUT': - if self.target == 'Object': - if 'etag' not in actual: - return NonExistentHeader('etag') - if 'last-modified' not in actual: - return NonExistentHeader('last-modified') - elif self.method == 'COPY': - if self.target == 'Object': - if 'etag' not in actual: - return NonExistentHeader('etag') - if 'last-modified' not in actual: - return NonExistentHeader('last-modified') - if 'x-copied-from' not in actual: - return NonExistentHeader('x-copied-from') - if 'x-copied-from-last-modified' not in actual: - return NonExistentHeader('x-copied-from-last-modified') - - return None - - -class GenericError(object): - """Informs an error message of a generic error during header evaluation""" - - def __init__(self, body): - self.body = body - - def describe(self): - return "%s" % self.body - - def get_details(self): - return {} - - -class NonExistentHeader(object): - """Informs an error message in the case of missing a certain header""" - - def __init__(self, header): - self.header = header - - def describe(self): - return "%s header does not exist" % self.header - - def get_details(self): - return {} - - -class InvalidHeaderValue(object): - """Informs an error message when a header contains a bad value""" - - def __init__(self, header, value): - self.header = header - self.value = value - - def describe(self): - return "InvalidValue (%s, %s)" % (self.header, self.value) - - def get_details(self): - return {} - - -class AreAllWellFormatted(object): - """Specific matcher to check the correctness of formats of values - - This matcher checks the format of values of response headers. - When checking the format of values of 'specific' headers such as - X-Account-Meta-* or X-Object-Manifest for example, those values must be - checked in each test code. - """ - - def match(self, actual): - for key, value in actual.items(): - if key in ('content-length', 'x-account-bytes-used', - 'x-account-container-count', 'x-account-object-count', - 'x-container-bytes-used', 'x-container-object-count')\ - and not value.isdigit(): - return InvalidFormat(key, value) - elif key in ('content-type', 'date', 'last-modified', - 'x-copied-from-last-modified') and not value: - return InvalidFormat(key, value) - elif key == 'x-timestamp' and not re.match("^\d+\.?\d*\Z", value): - return InvalidFormat(key, value) - elif key == 'x-copied-from' and not re.match("\S+/\S+", value): - return InvalidFormat(key, value) - elif key == 'x-trans-id' and \ - not re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*", value): - return InvalidFormat(key, value) - elif key == 'accept-ranges' and not value == 'bytes': - return InvalidFormat(key, value) - elif key == 'etag' and not value.isalnum(): - return InvalidFormat(key, value) - elif key == 'transfer-encoding' and not value == 'chunked': - return InvalidFormat(key, value) - - return None - - -class InvalidFormat(object): - """Informs an error message if a format of a certain header is invalid""" - - def __init__(self, key, value): - self.key = key - self.value = value - - def describe(self): - return "InvalidFormat (%s, %s)" % (self.key, self.value) - - def get_details(self): - return {} - - -class MatchesDictExceptForKeys(object): - """Matches two dictionaries. - - Verifies all items are equals except for those identified by a list of keys - """ - - def __init__(self, expected, excluded_keys=None): - self.expected = expected - self.excluded_keys = excluded_keys if excluded_keys is not None else [] - - def match(self, actual): - filtered_expected = helpers.dict_subtract(self.expected, - self.excluded_keys) - filtered_actual = helpers.dict_subtract(actual, - self.excluded_keys) - if filtered_actual != filtered_expected: - return DictMismatch(filtered_expected, filtered_actual) - - -class DictMismatch(object): - """Mismatch between two dicts describes deltas""" - - def __init__(self, expected, actual): - self.expected = expected - self.actual = actual - self.intersect = set(self.expected) & set(self.actual) - self.symmetric_diff = set(self.expected) ^ set(self.actual) - - def _format_dict(self, dict_to_format): - # Ensure the error string dict is printed in a set order - # NOTE(mtreinish): needed to ensure a deterministic error msg for - # testing. Otherwise the error message will be dependent on the - # dict ordering. - dict_string = "{" - for key in sorted(dict_to_format): - dict_string += "'%s': %s, " % (key, dict_to_format[key]) - dict_string = dict_string[:-2] + '}' - return dict_string - - def describe(self): - msg = "" - if self.symmetric_diff: - only_expected = helpers.dict_subtract(self.expected, self.actual) - only_actual = helpers.dict_subtract(self.actual, self.expected) - if only_expected: - msg += "Only in expected:\n %s\n" % self._format_dict( - only_expected) - if only_actual: - msg += "Only in actual:\n %s\n" % self._format_dict( - only_actual) - diff_set = set(o for o in self.intersect if - self.expected[o] != self.actual[o]) - if diff_set: - msg += "Differences:\n" - for o in diff_set: - msg += " %s: expected %s, actual %s\n" % ( - o, self.expected[o], self.actual[o]) - return msg - - def get_details(self): - return {} diff --git a/tempest/common/identity.py b/tempest/common/identity.py deleted file mode 100644 index 469defed3..000000000 --- a/tempest/common/identity.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2015 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib import exceptions as lib_exc - - -def get_tenant_by_name(client, tenant_name): - tenants = client.list_tenants()['tenants'] - for tenant in tenants: - if tenant['name'] == tenant_name: - return tenant - raise lib_exc.NotFound('No such tenant(%s) in %s' % (tenant_name, tenants)) - - -def get_user_by_username(client, tenant_id, username): - users = client.list_tenant_users(tenant_id)['users'] - for user in users: - if user['name'] == username: - return user - raise lib_exc.NotFound('No such user(%s) in %s' % (username, users)) diff --git a/tempest/common/image.py b/tempest/common/image.py deleted file mode 100644 index 3618f7e13..000000000 --- a/tempest/common/image.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2016 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - - -def get_image_meta_from_headers(resp): - meta = {'properties': {}} - for key in resp.response: - value = resp.response[key] - if key.startswith('x-image-meta-property-'): - _key = key[22:] - meta['properties'][_key] = value - elif key.startswith('x-image-meta-'): - _key = key[13:] - meta[_key] = value - - for key in ['is_public', 'protected', 'deleted']: - if key in meta: - meta[key] = meta[key].strip().lower() in ('t', 'true', 'yes', '1') - - for key in ['size', 'min_ram', 'min_disk']: - if key in meta: - try: - meta[key] = int(meta[key]) - except ValueError: - pass - return meta - - -def image_meta_to_headers(**metadata): - headers = {} - fields_copy = copy.deepcopy(metadata) - - copy_from = fields_copy.pop('copy_from', None) - purge = fields_copy.pop('purge_props', None) - - if purge is not None: - headers['x-glance-registry-purge-props'] = purge - - if copy_from is not None: - headers['x-glance-api-copy-from'] = copy_from - - for key, value in fields_copy.pop('properties', {}).items(): - headers['x-image-meta-property-%s' % key] = str(value) - - for key, value in fields_copy.pop('api', {}).items(): - headers['x-glance-api-property-%s' % key] = str(value) - - for key, value in fields_copy.items(): - headers['x-image-meta-%s' % key] = str(value) - - return headers diff --git a/tempest/common/tempest_fixtures.py b/tempest/common/tempest_fixtures.py deleted file mode 100644 index d416857ae..000000000 --- a/tempest/common/tempest_fixtures.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_concurrency.fixture import lockutils - - -class LockFixture(lockutils.LockFixture): - def __init__(self, name): - super(LockFixture, self).__init__(name, 'tempest-') diff --git a/tempest/common/utils/__init__.py b/tempest/common/utils/__init__.py deleted file mode 100644 index 84e31d0d4..000000000 --- a/tempest/common/utils/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from functools import partial - -from tempest import config -from tempest.lib.common.utils import data_utils as lib_data_utils - -CONF = config.CONF - - -class DataUtils(object): - def __getattr__(self, attr): - - if attr == 'rand_name': - # NOTE(flwang): This is a proxy to generate a random name that - # includes a random number and a prefix if one is configured in - # CONF.resources_prefix - attr_obj = partial(lib_data_utils.rand_name, - prefix=CONF.resources_prefix) - else: - attr_obj = getattr(lib_data_utils, attr) - - self.__dict__[attr] = attr_obj - return attr_obj - -data_utils = DataUtils() diff --git a/tempest/common/utils/linux/__init__.py b/tempest/common/utils/linux/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py deleted file mode 100644 index 99a628eed..000000000 --- a/tempest/common/utils/linux/remote_client.py +++ /dev/null @@ -1,157 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import re -import time - -from oslo_log import log as logging - -from tempest import config -from tempest.lib.common.utils.linux import remote_client -import tempest.lib.exceptions - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class RemoteClient(remote_client.RemoteClient): - - # TODO(oomichi): Make this class deprecated after migrating - # necessary methods to tempest.lib and cleaning - # unnecessary methods up from this class. - def __init__(self, ip_address, username, password=None, pkey=None, - server=None, servers_client=None): - """Executes commands in a VM over ssh - - :param ip_address: IP address to ssh to - :param username: ssh username - :param password: ssh password (optional) - :param pkey: ssh public key (optional) - :param server: server dict, used for debugging purposes - :param servers_client: servers client, used for debugging purposes - """ - super(RemoteClient, self).__init__( - ip_address, username, password=password, pkey=pkey, - server=server, servers_client=servers_client, - ssh_timeout=CONF.validation.ssh_timeout, - connect_timeout=CONF.validation.connect_timeout, - console_output_enabled=CONF.compute_feature_enabled.console_output, - ssh_shell_prologue=CONF.validation.ssh_shell_prologue, - ping_count=CONF.validation.ping_count, - ping_size=CONF.validation.ping_size) - - # Note that this method will not work on SLES11 guests, as they do - # not support the TYPE column on lsblk - def get_disks(self): - # Select root disk devices as shown by lsblk - command = 'lsblk -lb --nodeps' - output = self.exec_command(command) - selected = [] - pos = None - for l in output.splitlines(): - if pos is None and l.find("TYPE") > 0: - pos = l.find("TYPE") - # Show header line too - selected.append(l) - # lsblk lists disk type in a column right-aligned with TYPE - elif pos is not None and pos > 0 and l[pos:pos + 4] == "disk": - selected.append(l) - - if selected: - return "\n".join(selected) - else: - msg = "'TYPE' column is requred but the output doesn't have it: " - raise tempest.lib.exceptions.TempestException(msg + output) - - def get_boot_time(self): - cmd = 'cut -f1 -d. /proc/uptime' - boot_secs = self.exec_command(cmd) - boot_time = time.time() - int(boot_secs) - return time.localtime(boot_time) - - def write_to_console(self, message): - message = re.sub("([$\\`])", "\\\\\\\\\\1", message) - # usually to /dev/ttyS0 - cmd = 'sudo sh -c "echo \\"%s\\" >/dev/console"' % message - return self.exec_command(cmd) - - def get_mac_address(self, nic=""): - show_nic = "show {nic} ".format(nic=nic) if nic else "" - cmd = "ip addr %s| awk '/ether/ {print $2}'" % show_nic - return self.exec_command(cmd).strip().lower() - - def get_nic_name_by_mac(self, address): - cmd = "ip -o link | awk '/%s/ {print $2}'" % address - nic = self.exec_command(cmd) - return nic.strip().strip(":").split('@')[0].lower() - - def get_nic_name_by_ip(self, address): - cmd = "ip -o addr | awk '/%s/ {print $2}'" % address - nic = self.exec_command(cmd) - return nic.strip().strip(":").split('@')[0].lower() - - def get_dns_servers(self): - cmd = 'cat /etc/resolv.conf' - resolve_file = self.exec_command(cmd).strip().split('\n') - entries = (l.split() for l in resolve_file) - dns_servers = [l[1] for l in entries - if len(l) and l[0] == 'nameserver'] - return dns_servers - - def _renew_lease_udhcpc(self, fixed_ip=None): - """Renews DHCP lease via udhcpc client. """ - file_path = '/var/run/udhcpc.' - nic_name = self.get_nic_name_by_ip(fixed_ip) - pid = self.exec_command('cat {path}{nic}.pid'. - format(path=file_path, nic=nic_name)) - pid = pid.strip() - cmd = 'sudo /bin/kill -{sig} {pid}'.format(pid=pid, sig='USR1') - self.exec_command(cmd) - - def _renew_lease_dhclient(self, fixed_ip=None): - """Renews DHCP lease via dhclient client. """ - cmd = "sudo /sbin/dhclient -r && sudo /sbin/dhclient" - self.exec_command(cmd) - - def renew_lease(self, fixed_ip=None, dhcp_client='udhcpc'): - """Wrapper method for renewing DHCP lease via given client - - Supporting: - * udhcpc - * dhclient - """ - # TODO(yfried): add support for dhcpcd - supported_clients = ['udhcpc', 'dhclient'] - if dhcp_client not in supported_clients: - raise tempest.lib.exceptions.InvalidConfiguration( - '%s DHCP client unsupported' % dhcp_client) - if dhcp_client == 'udhcpc' and not fixed_ip: - raise ValueError("need to set 'fixed_ip' for udhcpc client") - return getattr(self, '_renew_lease_' + dhcp_client)(fixed_ip=fixed_ip) - - def mount(self, dev_name, mount_path='/mnt'): - cmd_mount = 'sudo mount /dev/%s %s' % (dev_name, mount_path) - self.exec_command(cmd_mount) - - def umount(self, mount_path='/mnt'): - self.exec_command('sudo umount %s' % mount_path) - - def make_fs(self, dev_name, fs='ext4'): - cmd_mkfs = 'sudo /usr/sbin/mke2fs -t %s /dev/%s' % (fs, dev_name) - try: - self.exec_command(cmd_mkfs) - except tempest.lib.exceptions.SSHExecCommandFailed: - LOG.error("Couldn't mke2fs") - cmd_why = 'sudo ls -lR /dev' - LOG.info("Contents of /dev: %s", self.exec_command(cmd_why)) - raise diff --git a/tempest/common/utils/net_info.py b/tempest/common/utils/net_info.py deleted file mode 100644 index 9b0a08377..000000000 --- a/tempest/common/utils/net_info.py +++ /dev/null @@ -1,25 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import re - -RE_OWNER = re.compile('^network:.*router_.*interface.*') - - -def _is_owner_router_interface(owner): - return bool(RE_OWNER.match(owner)) - - -def is_router_interface_port(port): - """Based on the port attributes determines is it a router interface.""" - return _is_owner_router_interface(port['device_owner']) diff --git a/tempest/common/utils/net_utils.py b/tempest/common/utils/net_utils.py deleted file mode 100644 index 867b3dd02..000000000 --- a/tempest/common/utils/net_utils.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2016 Hewlett Packard Enterprise Development Company -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr - -from tempest.lib import exceptions as lib_exc - - -def get_unused_ip_addresses(ports_client, subnets_client, - network_id, subnet_id, count): - - """Return a list with the specified number of unused IP addresses - - This method uses the given ports_client to find the specified number of - unused IP addresses on the given subnet using the supplied subnets_client - """ - - ports = ports_client.list_ports(network_id=network_id)['ports'] - subnet = subnets_client.show_subnet(subnet_id) - ip_net = netaddr.IPNetwork(subnet['subnet']['cidr']) - subnet_set = netaddr.IPSet(ip_net.iter_hosts()) - alloc_set = netaddr.IPSet() - - # prune out any addresses already allocated to existing ports - for port in ports: - for fixed_ip in port.get('fixed_ips'): - alloc_set.add(fixed_ip['ip_address']) - - # exclude gateway_ip of subnet - gateway_ip = subnet['subnet']['gateway_ip'] - if gateway_ip: - alloc_set.add(gateway_ip) - - av_set = subnet_set - alloc_set - addrs = [] - for cidr in reversed(av_set.iter_cidrs()): - for ip in reversed(cidr): - addrs.append(str(ip)) - if len(addrs) == count: - return addrs - msg = "Insufficient IP addresses available" - raise lib_exc.BadRequest(message=msg) - - -def get_ping_payload_size(mtu, ip_version): - """Return the maximum size of ping payload that will fit into MTU.""" - if not mtu: - return None - if ip_version == 4: - ip_header = 20 - icmp_header = 8 - else: - ip_header = 40 - icmp_header = 4 - res = mtu - ip_header - icmp_header - if res < 0: - raise lib_exc.BadRequest( - message='MTU = %(mtu)d is too low for IPv%(ip_version)d' % { - 'mtu': mtu, - 'ip_version': ip_version, - }) - return res diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py deleted file mode 100644 index 9e83a073b..000000000 --- a/tempest/common/validation_resources.py +++ /dev/null @@ -1,154 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_log import log as logging - -from tempest import config - -from tempest.lib.common.utils import data_utils -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -def _create_neutron_sec_group_rules(os, sec_group): - sec_group_rules_client = os.security_group_rules_client - ethertype = 'IPv4' - if CONF.validation.ip_version_for_ssh == 6: - ethertype = 'IPv6' - - sec_group_rules_client.create_security_group_rule( - security_group_id=sec_group['id'], - protocol='tcp', - ethertype=ethertype, - port_range_min=22, - port_range_max=22, - direction='ingress') - sec_group_rules_client.create_security_group_rule( - security_group_id=sec_group['id'], - protocol='icmp', - ethertype=ethertype, - direction='ingress') - - -def create_ssh_security_group(os, add_rule=False): - security_groups_client = os.compute_security_groups_client - security_group_rules_client = os.compute_security_group_rules_client - sg_name = data_utils.rand_name('securitygroup-') - sg_description = data_utils.rand_name('description-') - security_group = security_groups_client.create_security_group( - name=sg_name, description=sg_description)['security_group'] - if add_rule: - if CONF.service_available.neutron: - _create_neutron_sec_group_rules(os, security_group) - else: - security_group_rules_client.create_security_group_rule( - parent_group_id=security_group['id'], ip_protocol='tcp', - from_port=22, to_port=22) - security_group_rules_client.create_security_group_rule( - parent_group_id=security_group['id'], ip_protocol='icmp', - from_port=-1, to_port=-1) - LOG.debug("SSH Validation resource security group with tcp and icmp " - "rules %s created", sg_name) - return security_group - - -def create_validation_resources(os, validation_resources=None): - # Create and Return the validation resources required to validate a VM - validation_data = {} - if validation_resources: - if validation_resources['keypair']: - keypair_name = data_utils.rand_name('keypair') - validation_data.update(os.keypairs_client.create_keypair( - name=keypair_name)) - LOG.debug("Validation resource key %s created", keypair_name) - add_rule = False - if validation_resources['security_group']: - if validation_resources['security_group_rules']: - add_rule = True - validation_data['security_group'] = \ - create_ssh_security_group(os, add_rule) - if validation_resources['floating_ip']: - if CONF.service_available.neutron: - floatingip = os.floating_ips_client.create_floatingip( - floating_network_id=CONF.network.public_network_id) - # validation_resources['floating_ip'] has historically looked - # like a compute API POST /os-floating-ips response, so we need - # to mangle it a bit for a Neutron response with different - # fields. - validation_data['floating_ip'] = floatingip['floatingip'] - validation_data['floating_ip']['ip'] = ( - floatingip['floatingip']['floating_ip_address']) - else: - # NOTE(mriedem): The os-floating-ips compute API was deprecated - # in the 2.36 microversion. Any tests for CRUD operations on - # floating IPs using the compute API should be capped at 2.35. - validation_data.update( - os.compute_floating_ips_client.create_floating_ip( - pool=CONF.network.floating_network_name)) - return validation_data - - -def clear_validation_resources(os, validation_data=None): - # Cleanup the vm validation resources - has_exception = None - if validation_data: - if 'keypair' in validation_data: - keypair_client = os.keypairs_client - keypair_name = validation_data['keypair']['name'] - try: - keypair_client.delete_keypair(keypair_name) - except lib_exc.NotFound: - LOG.warning( - "Keypair %s is not found when attempting to delete", - keypair_name - ) - except Exception as exc: - LOG.exception('Exception raised while deleting key %s', - keypair_name) - if not has_exception: - has_exception = exc - if 'security_group' in validation_data: - security_group_client = os.compute_security_groups_client - sec_id = validation_data['security_group']['id'] - try: - security_group_client.delete_security_group(sec_id) - security_group_client.wait_for_resource_deletion(sec_id) - except lib_exc.NotFound: - LOG.warning("Security group %s is not found when attempting " - "to delete", sec_id) - except lib_exc.Conflict as exc: - LOG.exception('Conflict while deleting security ' - 'group %s VM might not be deleted', sec_id) - if not has_exception: - has_exception = exc - except Exception as exc: - LOG.exception('Exception raised while deleting security ' - 'group %s', sec_id) - if not has_exception: - has_exception = exc - if 'floating_ip' in validation_data: - floating_client = os.compute_floating_ips_client - fip_id = validation_data['floating_ip']['id'] - try: - floating_client.delete_floating_ip(fip_id) - except lib_exc.NotFound: - LOG.warning('Floating ip %s not found while attempting to ' - 'delete', fip_id) - except Exception as exc: - LOG.exception('Exception raised while deleting ip %s', fip_id) - if not has_exception: - has_exception = exc - if has_exception: - raise has_exception diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py deleted file mode 100644 index cf187e6bf..000000000 --- a/tempest/common/waiters.py +++ /dev/null @@ -1,288 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import re -import time - -from oslo_log import log as logging - -from tempest.common import image as common_image -from tempest import config -from tempest import exceptions -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.image.v1 import images_client as images_v1_client - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -def _get_task_state(body): - return body.get('OS-EXT-STS:task_state', None) - - -# NOTE(afazekas): This function needs to know a token and a subject. -def wait_for_server_status(client, server_id, status, ready_wait=True, - extra_timeout=0, raise_on_error=True): - """Waits for a server to reach a given status.""" - - # NOTE(afazekas): UNKNOWN status possible on ERROR - # or in a very early stage. - body = client.show_server(server_id)['server'] - old_status = server_status = body['status'] - old_task_state = task_state = _get_task_state(body) - start_time = int(time.time()) - timeout = client.build_timeout + extra_timeout - while True: - # NOTE(afazekas): Now the BUILD status only reached - # between the UNKNOWN->ACTIVE transition. - # TODO(afazekas): enumerate and validate the stable status set - if status == 'BUILD' and server_status != 'UNKNOWN': - return - if server_status == status: - if ready_wait: - if status == 'BUILD': - return - # NOTE(afazekas): The instance is in "ready for action state" - # when no task in progress - if task_state is None: - # without state api extension 3 sec usually enough - time.sleep(CONF.compute.ready_wait) - return - else: - return - - time.sleep(client.build_interval) - body = client.show_server(server_id)['server'] - server_status = body['status'] - task_state = _get_task_state(body) - if (server_status != old_status) or (task_state != old_task_state): - LOG.info('State transition "%s" ==> "%s" after %d second wait', - '/'.join((old_status, str(old_task_state))), - '/'.join((server_status, str(task_state))), - time.time() - start_time) - if (server_status == 'ERROR') and raise_on_error: - if 'fault' in body: - raise exceptions.BuildErrorException(body['fault'], - server_id=server_id) - else: - raise exceptions.BuildErrorException(server_id=server_id) - - timed_out = int(time.time()) - start_time >= timeout - - if timed_out: - expected_task_state = 'None' if ready_wait else 'n/a' - message = ('Server %(server_id)s failed to reach %(status)s ' - 'status and task state "%(expected_task_state)s" ' - 'within the required time (%(timeout)s s).' % - {'server_id': server_id, - 'status': status, - 'expected_task_state': expected_task_state, - 'timeout': timeout}) - message += ' Current status: %s.' % server_status - message += ' Current task state: %s.' % task_state - caller = test_utils.find_test_caller() - if caller: - message = '(%s) %s' % (caller, message) - raise lib_exc.TimeoutException(message) - old_status = server_status - old_task_state = task_state - - -def wait_for_server_termination(client, server_id, ignore_error=False): - """Waits for server to reach termination.""" - try: - body = client.show_server(server_id)['server'] - except lib_exc.NotFound: - return - old_status = server_status = body['status'] - old_task_state = task_state = _get_task_state(body) - start_time = int(time.time()) - while True: - time.sleep(client.build_interval) - try: - body = client.show_server(server_id)['server'] - except lib_exc.NotFound: - return - server_status = body['status'] - task_state = _get_task_state(body) - if (server_status != old_status) or (task_state != old_task_state): - LOG.info('State transition "%s" ==> "%s" after %d second wait', - '/'.join((old_status, str(old_task_state))), - '/'.join((server_status, str(task_state))), - time.time() - start_time) - if server_status == 'ERROR' and not ignore_error: - raise lib_exc.DeleteErrorException(resource_id=server_id) - - if int(time.time()) - start_time >= client.build_timeout: - raise lib_exc.TimeoutException - old_status = server_status - old_task_state = task_state - - -def wait_for_image_status(client, image_id, status): - """Waits for an image to reach a given status. - - The client should have a show_image(image_id) method to get the image. - The client should also have build_interval and build_timeout attributes. - """ - if isinstance(client, images_v1_client.ImagesClient): - # The 'check_image' method is used here because the show_image method - # returns image details plus the image itself which is very expensive. - # The 'check_image' method returns just image details. - def _show_image_v1(image_id): - resp = client.check_image(image_id) - return common_image.get_image_meta_from_headers(resp) - - show_image = _show_image_v1 - else: - show_image = client.show_image - - current_status = 'An unknown status' - start = int(time.time()) - while int(time.time()) - start < client.build_timeout: - image = show_image(image_id) - # Compute image client returns response wrapped in 'image' element - # which is not the case with Glance image client. - if 'image' in image: - image = image['image'] - - current_status = image['status'] - if current_status == status: - return - if current_status.lower() == 'killed': - raise exceptions.ImageKilledException(image_id=image_id, - status=status) - if current_status.lower() == 'error': - raise exceptions.AddImageException(image_id=image_id) - - time.sleep(client.build_interval) - - message = ('Image %(image_id)s failed to reach %(status)s state ' - '(current state %(current_status)s) within the required ' - 'time (%(timeout)s s).' % {'image_id': image_id, - 'status': status, - 'current_status': current_status, - 'timeout': client.build_timeout}) - caller = test_utils.find_test_caller() - if caller: - message = '(%s) %s' % (caller, message) - raise lib_exc.TimeoutException(message) - - -def wait_for_volume_resource_status(client, resource_id, statuses): - """Waits for a volume resource to reach any of the specified statuses. - - This function is a common function for volume, snapshot and backup - resources. The function extracts the name of the desired resource from - the client class name of the resource. - """ - if not isinstance(statuses, list): - statuses = [statuses] - resource_name = re.findall(r'(Volume|Snapshot|Backup|Group)', - client.__class__.__name__)[0].lower() - show_resource = getattr(client, 'show_' + resource_name) - resource_status = show_resource(resource_id)[resource_name]['status'] - start = int(time.time()) - - while resource_status not in statuses: - time.sleep(client.build_interval) - resource_status = show_resource(resource_id)[ - '{}'.format(resource_name)]['status'] - if resource_status == 'error' and resource_status not in statuses: - raise exceptions.VolumeResourceBuildErrorException( - resource_name=resource_name, resource_id=resource_id) - if resource_name == 'volume' and resource_status == 'error_restoring': - raise exceptions.VolumeRestoreErrorException(volume_id=resource_id) - - if int(time.time()) - start >= client.build_timeout: - message = ('%s %s failed to reach %s status (current %s) ' - 'within the required time (%s s).' % - (resource_name, resource_id, statuses, resource_status, - client.build_timeout)) - raise lib_exc.TimeoutException(message) - - -def wait_for_volume_retype(client, volume_id, new_volume_type): - """Waits for a Volume to have a new volume type.""" - body = client.show_volume(volume_id)['volume'] - current_volume_type = body['volume_type'] - start = int(time.time()) - - while current_volume_type != new_volume_type: - time.sleep(client.build_interval) - body = client.show_volume(volume_id)['volume'] - current_volume_type = body['volume_type'] - - if int(time.time()) - start >= client.build_timeout: - message = ('Volume %s failed to reach %s volume type (current %s) ' - 'within the required time (%s s).' % - (volume_id, new_volume_type, current_volume_type, - client.build_timeout)) - raise lib_exc.TimeoutException(message) - - -def wait_for_qos_operations(client, qos_id, operation, args=None): - """Waits for a qos operations to be completed. - - NOTE : operation value is required for wait_for_qos_operations() - operation = 'qos-key' / 'disassociate' / 'disassociate-all' - args = keys[] when operation = 'qos-key' - args = volume-type-id disassociated when operation = 'disassociate' - args = None when operation = 'disassociate-all' - """ - start_time = int(time.time()) - while True: - if operation == 'qos-key-unset': - body = client.show_qos(qos_id)['qos_specs'] - if not any(key in body['specs'] for key in args): - return - elif operation == 'disassociate': - body = client.show_association_qos(qos_id)['qos_associations'] - if not any(args in body[i]['id'] for i in range(0, len(body))): - return - elif operation == 'disassociate-all': - body = client.show_association_qos(qos_id)['qos_associations'] - if not body: - return - else: - msg = (" operation value is either not defined or incorrect.") - raise lib_exc.UnprocessableEntity(msg) - - if int(time.time()) - start_time >= client.build_timeout: - raise lib_exc.TimeoutException - time.sleep(client.build_interval) - - -def wait_for_interface_status(client, server_id, port_id, status): - """Waits for an interface to reach a given status.""" - body = (client.show_interface(server_id, port_id) - ['interfaceAttachment']) - interface_status = body['port_state'] - start = int(time.time()) - - while(interface_status != status): - time.sleep(client.build_interval) - body = (client.show_interface(server_id, port_id) - ['interfaceAttachment']) - interface_status = body['port_state'] - - timed_out = int(time.time()) - start >= client.build_timeout - - if interface_status != status and timed_out: - message = ('Interface %s failed to reach %s status ' - '(current %s) within the required time (%s s).' % - (port_id, status, interface_status, - client.build_timeout)) - raise lib_exc.TimeoutException(message) - - return body diff --git a/tempest/config.py b/tempest/config.py deleted file mode 100644 index af9eefc0a..000000000 --- a/tempest/config.py +++ /dev/null @@ -1,1460 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from __future__ import print_function - -import functools -import os -import tempfile - -import debtcollector.removals -from oslo_concurrency import lockutils -from oslo_config import cfg -from oslo_log import log as logging -import testtools - -from tempest.lib import exceptions -from tempest.lib.services import clients -from tempest.test_discover import plugins - - -# TODO(marun) Replace use of oslo_config's global ConfigOpts -# (cfg.CONF) instance with a local instance (cfg.ConfigOpts()) once -# the cli tests move to the clients. The cli tests rely on oslo -# incubator modules that use the global cfg.CONF. -_CONF = cfg.CONF - - -def register_opt_group(conf, opt_group, options): - if opt_group: - conf.register_group(opt_group) - for opt in options: - conf.register_opt(opt, group=getattr(opt_group, 'name', None)) - - -auth_group = cfg.OptGroup(name='auth', - title="Options for authentication and credentials") - - -AuthGroup = [ - cfg.StrOpt('test_accounts_file', - help="Path to the yaml file that contains the list of " - "credentials to use for running tests. If used when " - "running in parallel you have to make sure sufficient " - "credentials are provided in the accounts file. For " - "example if no tests with roles are being run it requires " - "at least `2 * CONC` distinct accounts configured in " - " the `test_accounts_file`, with CONC == the " - "number of concurrent test processes."), - cfg.BoolOpt('use_dynamic_credentials', - default=True, - help="Allows test cases to create/destroy projects and " - "users. This option requires that OpenStack Identity " - "API admin credentials are known. If false, isolated " - "test cases and parallel execution, can still be " - "achieved configuring a list of test accounts", - deprecated_opts=[cfg.DeprecatedOpt('allow_tenant_isolation', - group='auth'), - cfg.DeprecatedOpt('allow_tenant_isolation', - group='compute'), - cfg.DeprecatedOpt('allow_tenant_isolation', - group='orchestration')]), - cfg.ListOpt('tempest_roles', - help="Roles to assign to all users created by tempest", - default=[]), - cfg.StrOpt('default_credentials_domain_name', - default='Default', - help="Default domain used when getting v3 credentials. " - "This is the name keystone uses for v2 compatibility.", - deprecated_opts=[cfg.DeprecatedOpt( - 'tenant_isolation_domain_name', - group='auth')]), - cfg.BoolOpt('create_isolated_networks', - default=True, - help="If use_dynamic_credentials is set to True and Neutron " - "is enabled Tempest will try to create a usable network, " - "subnet, and router when needed for each project it " - "creates. However in some neutron configurations, like " - "with VLAN provider networks, this doesn't work. So if " - "set to False the isolated networks will not be created"), - cfg.StrOpt('admin_username', - help="Username for an administrative user. This is needed for " - "authenticating requests made by project isolation to " - "create users and projects", - deprecated_group='identity'), - cfg.StrOpt('admin_project_name', - help="Project name to use for an administrative user. This is " - "needed for authenticating requests made by project " - "isolation to create users and projects", - deprecated_opts=[cfg.DeprecatedOpt('admin_tenant_name', - group='auth'), - cfg.DeprecatedOpt('admin_tenant_name', - group='identity')]), - cfg.StrOpt('admin_password', - help="Password to use for an administrative user. This is " - "needed for authenticating requests made by project " - "isolation to create users and projects", - secret=True, - deprecated_group='identity'), - cfg.StrOpt('admin_domain_name', - help="Admin domain name for authentication (Keystone V3)." - "The same domain applies to user and project", - deprecated_group='identity'), -] - -identity_group = cfg.OptGroup(name='identity', - title="Keystone Configuration Options") - -IdentityGroup = [ - cfg.StrOpt('catalog_type', - default='identity', - help="Catalog type of the Identity service."), - cfg.BoolOpt('disable_ssl_certificate_validation', - default=False, - help="Set to True if using self-signed SSL certificates."), - cfg.StrOpt('ca_certificates_file', - default=None, - help='Specify a CA bundle file to use in verifying a ' - 'TLS (https) server certificate.'), - cfg.StrOpt('uri', - help="Full URI of the OpenStack Identity API (Keystone), v2"), - cfg.StrOpt('uri_v3', - help='Full URI of the OpenStack Identity API (Keystone), v3'), - cfg.StrOpt('auth_version', - default='v3', - help="Identity API version to be used for authentication " - "for API tests."), - cfg.StrOpt('region', - default='RegionOne', - help="The identity region name to use. Also used as the other " - "services' region name unless they are set explicitly. " - "If no such region is found in the service catalog, the " - "first found one is used."), - cfg.StrOpt('v2_admin_endpoint_type', - default='adminURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The admin endpoint type to use for OpenStack Identity " - "(Keystone) API v2"), - cfg.StrOpt('v2_public_endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The public endpoint type to use for OpenStack Identity " - "(Keystone) API v2", - deprecated_opts=[cfg.DeprecatedOpt('endpoint_type', - group='identity')]), - cfg.StrOpt('v3_endpoint_type', - default='adminURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for OpenStack Identity " - "(Keystone) API v3. The default value adminURL is " - "deprecated and will be modified to publicURL in " - "the next release."), - cfg.StrOpt('admin_role', - default='admin', - help="Role required to administrate keystone."), - cfg.StrOpt('default_domain_id', - default='default', - help="ID of the default domain"), - cfg.BoolOpt('admin_domain_scope', - default=False, - help="Whether keystone identity v3 policy required " - "a domain scoped token to use admin APIs"), - # Security Compliance (PCI-DSS) - cfg.IntOpt('user_lockout_failure_attempts', - default=2, - help="The number of unsuccessful login attempts the user is " - "allowed before having the account locked."), - cfg.IntOpt('user_lockout_duration', - default=5, - help="The number of seconds a user account will remain " - "locked."), - cfg.IntOpt('user_unique_last_password_count', - default=2, - help="The number of passwords for a user that must be unique " - "before an old password can be reused."), -] - -service_clients_group = cfg.OptGroup(name='service-clients', - title="Service Clients Options") - -ServiceClientsGroup = [ - cfg.IntOpt('http_timeout', - default=60, - help='Timeout in seconds to wait for the http request to ' - 'return'), -] - -identity_feature_group = cfg.OptGroup(name='identity-feature-enabled', - title='Enabled Identity Features') - -IdentityFeatureGroup = [ - cfg.BoolOpt('trust', - default=True, - help='Does the identity service have delegation and ' - 'impersonation enabled'), - cfg.BoolOpt('api_v2', - default=True, - help='Is the v2 identity API enabled'), - cfg.BoolOpt('api_v2_admin', - default=True, - help="Is the v2 identity admin API available? This setting " - "only applies if api_v2 is set to True."), - cfg.BoolOpt('api_v3', - default=True, - help='Is the v3 identity API enabled'), - cfg.ListOpt('api_extensions', - default=['all'], - help="A list of enabled identity extensions with a special " - "entry all which indicates every extension is enabled. " - "Empty list indicates all extensions are disabled. " - "To get the list of extensions run: 'keystone discover'"), - # TODO(rodrigods): This is a feature flag for bug 1590578 which is fixed - # in Newton and Ocata. This option can be removed after Mitaka is end of - # life. - cfg.BoolOpt('forbid_global_implied_dsr', - default=False, - help='Does the environment forbid global roles implying ' - 'domain specific ones?', - deprecated_for_removal=True, - deprecated_reason="This feature flag was introduced to " - "support testing of old OpenStack versions, " - "which are not supported anymore"), - cfg.BoolOpt('security_compliance', - default=False, - help='Does the environment have the security compliance ' - 'settings enabled?') -] - -compute_group = cfg.OptGroup(name='compute', - title='Compute Service Options') - -ComputeGroup = [ - cfg.StrOpt('image_ref', - help="Valid primary image reference to be used in tests. " - "This is a required option"), - cfg.StrOpt('image_ref_alt', - help="Valid secondary image reference to be used in tests. " - "This is a required option, but if only one image is " - "available duplicate the value of image_ref above"), - cfg.StrOpt('flavor_ref', - default="1", - help="Valid primary flavor to use in tests."), - cfg.StrOpt('flavor_ref_alt', - default="2", - help='Valid secondary flavor to be used in tests.'), - cfg.IntOpt('build_interval', - default=1, - help="Time in seconds between build status checks."), - cfg.IntOpt('build_timeout', - default=300, - help="Timeout in seconds to wait for an instance to build. " - "Other services that do not define build_timeout will " - "inherit this value."), - cfg.IntOpt('ready_wait', - default=0, - help="Additional wait time for clean state, when there is " - "no OS-EXT-STS extension available"), - cfg.StrOpt('fixed_network_name', - help="Name of the fixed network that is visible to all test " - "projects. If multiple networks are available for a " - "project, this is the network which will be used for " - "creating servers if tempest does not create a network or " - "a network is not specified elsewhere. It may be used for " - "ssh validation only if floating IPs are disabled."), - cfg.StrOpt('catalog_type', - default='compute', - help="Catalog type of the Compute service."), - cfg.StrOpt('region', - default='', - help="The compute region name to use. If empty, the value " - "of identity.region is used instead. If no such region " - "is found in the service catalog, the first found one is " - "used."), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the compute service."), - cfg.StrOpt('volume_device_name', - default='vdb', - help="Expected device name when a volume is attached to " - "an instance. Not all hypervisors guarantee that they " - "will respect the user defined device name, tests may " - "fail if inappropriate device name is set."), - cfg.IntOpt('shelved_offload_time', - default=0, - help='Time in seconds before a shelved instance is eligible ' - 'for removing from a host. -1 never offload, 0 offload ' - 'when shelved. This time should be the same as the time ' - 'of nova.conf, and some tests will run for as long as the ' - 'time.'), - cfg.IntOpt('min_compute_nodes', - default=1, - help=('The minimum number of compute nodes expected. This will ' - 'be utilized by some multinode specific tests to ensure ' - 'that requests match the expected size of the cluster ' - 'you are testing with.')), - cfg.StrOpt('hypervisor_type', - default=None, - help="Hypervisor type of the test target on heterogeneous " - "compute environment. The value can be 'QEMU', 'xen' or " - "something."), - cfg.StrOpt('min_microversion', - default=None, - help="Lower version of the test target microversion range. " - "The format is 'X.Y', where 'X' and 'Y' are int values. " - "Tempest selects tests based on the range between " - "min_microversion and max_microversion. " - "If both values are not specified, Tempest avoids tests " - "which require a microversion. Valid values are string " - "with format 'X.Y' or string 'latest'"), - cfg.StrOpt('max_microversion', - default=None, - help="Upper version of the test target microversion range. " - "The format is 'X.Y', where 'X' and 'Y' are int values. " - "Tempest selects tests based on the range between " - "min_microversion and max_microversion. " - "If both values are not specified, Tempest avoids tests " - "which require a microversion. Valid values are string " - "with format 'X.Y' or string 'latest'"), -] - -compute_features_group = cfg.OptGroup(name='compute-feature-enabled', - title="Enabled Compute Service Features") - -ComputeFeaturesGroup = [ - cfg.BoolOpt('disk_config', - default=True, - help="If false, skip disk config tests"), - cfg.ListOpt('api_extensions', - default=['all'], - help='A list of enabled compute extensions with a special ' - 'entry all which indicates every extension is enabled. ' - 'Each extension should be specified with alias name. ' - 'Empty list indicates all extensions are disabled', - deprecated_for_removal=True, - deprecated_reason='The Nova extensions API and mechanism ' - 'is deprecated. This option will be ' - 'removed when all releases supported ' - 'by tempest no longer contain the Nova ' - 'extensions API and mechanism.'), - cfg.BoolOpt('change_password', - default=False, - help="Does the test environment support changing the admin " - "password?"), - cfg.BoolOpt('console_output', - default=True, - help="Does the test environment support obtaining instance " - "serial console output?"), - cfg.BoolOpt('resize', - default=False, - help="Does the test environment support resizing? When you " - "enable this feature, 'flavor_ref_alt' should be set and " - "it should refer to a larger flavor than 'flavor_ref' " - "one."), - cfg.BoolOpt('pause', - default=True, - help="Does the test environment support pausing?"), - cfg.BoolOpt('shelve', - default=True, - help="Does the test environment support shelving/unshelving?"), - cfg.BoolOpt('suspend', - default=True, - help="Does the test environment support suspend/resume?"), - cfg.BoolOpt('cold_migration', - default=True, - help="Does the test environment support cold migration?"), - cfg.BoolOpt('live_migration', - default=True, - help="Does the test environment support live migration?"), - cfg.BoolOpt('live_migrate_back_and_forth', - default=False, - help="Does the test environment support live migrating " - "VM back and forth between different versions of " - "nova-compute?"), - cfg.BoolOpt('metadata_service', - default=True, - help="Does the test environment support metadata service? " - "Ignored unless validation.run_validation=true."), - cfg.BoolOpt('block_migration_for_live_migration', - default=False, - help="Does the test environment use block devices for live " - "migration"), - cfg.BoolOpt('block_migrate_cinder_iscsi', - default=False, - help="Does the test environment support block migration with " - "Cinder iSCSI volumes. Note: libvirt >= 1.2.17 is required " - "to support this if using the libvirt compute driver."), - cfg.BoolOpt('vnc_console', - default=False, - help='Enable VNC console. This configuration value should ' - 'be same as [nova.vnc]->vnc_enabled in nova.conf'), - cfg.BoolOpt('spice_console', - default=False, - help='Enable Spice console. This configuration value should ' - 'be same as [nova.spice]->enabled in nova.conf'), - cfg.BoolOpt('rdp_console', - default=False, - help='Enable RDP console. This configuration value should ' - 'be same as [nova.rdp]->enabled in nova.conf'), - cfg.BoolOpt('serial_console', - default=False, - help='Enable serial console. This configuration value ' - 'should be the same as [nova.serial_console]->enabled ' - 'in nova.conf'), - cfg.BoolOpt('rescue', - default=True, - help='Does the test environment support instance rescue ' - 'mode?'), - cfg.BoolOpt('enable_instance_password', - default=True, - help='Enables returning of the instance password by the ' - 'relevant server API calls such as create, rebuild ' - 'or rescue. This configuration value should be same as ' - 'nova.conf: DEFAULT.enable_instance_password'), - cfg.BoolOpt('interface_attach', - default=True, - help='Does the test environment support dynamic network ' - 'interface attachment?'), - cfg.BoolOpt('snapshot', - default=True, - help='Does the test environment support creating snapshot ' - 'images of running instances?'), - cfg.BoolOpt('nova_cert', - default=False, - help='Does the test environment have the nova cert running?', - deprecated_for_removal=True, - deprecated_reason="On Nova side, the nova-cert service is " - "deprecated and the service will be removed " - "as early as Ocata."), - cfg.BoolOpt('personality', - default=False, - help='Does the test environment support server personality'), - cfg.BoolOpt('attach_encrypted_volume', - default=True, - help='Does the test environment support attaching an ' - 'encrypted volume to a running server instance? This may ' - 'depend on the combination of compute_driver in nova and ' - 'the volume_driver(s) in cinder.'), - cfg.BoolOpt('config_drive', - default=True, - help='Enable special configuration drive with metadata.'), - cfg.ListOpt('scheduler_available_filters', - default=['all'], - help="A list of enabled filters that nova will accept as hints" - " to the scheduler when creating a server. A special " - "entry 'all' indicates all filters that are included " - "with nova are enabled. Empty list indicates all filters " - "are disabled. The full list of available filters is in " - "nova.conf: DEFAULT.scheduler_available_filters. If the " - "default value is overridden in nova.conf by the test " - "environment (which means that a different set of " - "filters is enabled than what is included in Nova by " - "default) then, this option must be configured to " - "contain the same filters that Nova uses in the test " - "environment."), - cfg.BoolOpt('swap_volume', - default=False, - help='Does the test environment support in-place swapping of ' - 'volumes attached to a server instance?'), -] - - -image_group = cfg.OptGroup(name='image', - title="Image Service Options") - -ImageGroup = [ - cfg.StrOpt('catalog_type', - default='image', - help='Catalog type of the Image service.'), - cfg.StrOpt('region', - default='', - help="The image region name to use. If empty, the value " - "of identity.region is used instead. If no such region " - "is found in the service catalog, the first found one is " - "used."), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the image service."), - cfg.StrOpt('http_image', - default='http://download.cirros-cloud.net/0.3.1/' - 'cirros-0.3.1-x86_64-uec.tar.gz', - help='http accessible image'), - cfg.IntOpt('build_timeout', - default=300, - help="Timeout in seconds to wait for an image to " - "become available."), - cfg.IntOpt('build_interval', - default=1, - help="Time in seconds between image operation status " - "checks."), - cfg.ListOpt('container_formats', - default=['ami', 'ari', 'aki', 'bare', 'ovf', 'ova'], - help="A list of image's container formats " - "users can specify."), - cfg.ListOpt('disk_formats', - default=['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', - 'vdi', 'iso', 'vhdx'], - help="A list of image's disk formats " - "users can specify.") -] - -image_feature_group = cfg.OptGroup(name='image-feature-enabled', - title='Enabled image service features') - -ImageFeaturesGroup = [ - cfg.BoolOpt('api_v2', - default=True, - help="Is the v2 image API enabled", - deprecated_for_removal=True, - deprecated_reason='Glance v1 APIs are deprecated and v2 APIs ' - 'are current one. In future, Tempest will ' - 'test v2 APIs only so this config option ' - 'will be removed.'), - cfg.BoolOpt('api_v1', - default=True, - help="Is the v1 image API enabled", - deprecated_for_removal=True, - deprecated_reason='Glance v1 APIs are deprecated and v2 APIs ' - 'are current one. In future, Tempest will ' - 'test v2 APIs only so this config option ' - 'will be removed.'), - cfg.BoolOpt('deactivate_image', - default=False, - help="Is the deactivate-image feature enabled." - " The feature has been integrated since Kilo.", - deprecated_for_removal=True, - deprecated_reason="All supported versions of OpenStack now " - "support the 'deactivate_image' feature"), -] - -network_group = cfg.OptGroup(name='network', - title='Network Service Options') - -NetworkGroup = [ - cfg.StrOpt('catalog_type', - default='network', - help='Catalog type of the Neutron service.'), - cfg.StrOpt('region', - default='', - help="The network region name to use. If empty, the value " - "of identity.region is used instead. If no such region " - "is found in the service catalog, the first found one is " - "used."), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the network service."), - cfg.StrOpt('project_network_cidr', - default="10.100.0.0/16", - help="The cidr block to allocate project ipv4 subnets from"), - cfg.IntOpt('project_network_mask_bits', - default=28, - help="The mask bits for project ipv4 subnets"), - cfg.StrOpt('project_network_v6_cidr', - default="2003::/48", - help="The cidr block to allocate project ipv6 subnets from"), - cfg.IntOpt('project_network_v6_mask_bits', - default=64, - help="The mask bits for project ipv6 subnets"), - cfg.BoolOpt('project_networks_reachable', - default=False, - help="Whether project networks can be reached directly from " - "the test client. This must be set to True when the " - "'fixed' connect_method is selected."), - cfg.StrOpt('public_network_id', - default="", - help="Id of the public network that provides external " - "connectivity"), - cfg.StrOpt('floating_network_name', - help="Default floating network name. Used to allocate floating " - "IPs when neutron is enabled."), - cfg.StrOpt('public_router_id', - default="", - help="Id of the public router that provides external " - "connectivity. This should only be used when Neutron's " - "'allow_overlapping_ips' is set to 'False' in " - "neutron.conf. usually not needed past 'Grizzly' release"), - cfg.IntOpt('build_timeout', - default=300, - help="Timeout in seconds to wait for network operation to " - "complete."), - cfg.IntOpt('build_interval', - default=1, - help="Time in seconds between network operation status " - "checks."), - cfg.ListOpt('dns_servers', - default=["8.8.8.8", "8.8.4.4"], - help="List of dns servers which should be used" - " for subnet creation"), - cfg.StrOpt('port_vnic_type', - choices=[None, 'normal', 'direct', 'macvtap'], - help="vnic_type to use when Launching instances" - " with pre-configured ports." - " Supported ports are:" - " ['normal','direct','macvtap']"), - cfg.ListOpt('default_network', - default=["1.0.0.0/16", "2.0.0.0/16"], - help="List of ip pools" - " for subnetpools creation"), - cfg.BoolOpt('shared_physical_network', - default=False, - help="The environment does not support network separation " - "between tenants."), -] - -network_feature_group = cfg.OptGroup(name='network-feature-enabled', - title='Enabled network service features') - -NetworkFeaturesGroup = [ - cfg.BoolOpt('ipv6', - default=True, - help="Allow the execution of IPv6 tests"), - cfg.ListOpt('api_extensions', - default=['all'], - help="A list of enabled network extensions with a special " - "entry all which indicates every extension is enabled. " - "Empty list indicates all extensions are disabled. " - "To get the list of extensions run: 'neutron ext-list'"), - cfg.BoolOpt('ipv6_subnet_attributes', - default=False, - help="Allow the execution of IPv6 subnet tests that use " - "the extended IPv6 attributes ipv6_ra_mode " - "and ipv6_address_mode" - ), - cfg.BoolOpt('port_admin_state_change', - default=True, - help="Does the test environment support changing" - " port admin state"), - cfg.BoolOpt('port_security', - default=False, - help="Does the test environment support port security?"), - cfg.BoolOpt('floating_ips', - default=True, - help='Does the test environment support floating_ips') -] - -validation_group = cfg.OptGroup(name='validation', - title='SSH Validation options') - -ValidationGroup = [ - cfg.BoolOpt('run_validation', - default=False, - help='Enable ssh on created servers and creation of additional' - ' validation resources to enable remote access'), - cfg.BoolOpt('security_group', - default=True, - help='Enable/disable security groups.'), - cfg.BoolOpt('security_group_rules', - default=True, - help='Enable/disable security group rules.'), - cfg.StrOpt('connect_method', - default='floating', - choices=['fixed', 'floating'], - help='Default IP type used for validation: ' - '-fixed: uses the first IP belonging to the fixed network ' - '-floating: creates and uses a floating IP'), - cfg.StrOpt('auth_method', - default='keypair', - choices=['keypair'], - help='Default authentication method to the instance. ' - 'Only ssh via keypair is supported for now. ' - 'Additional methods will be handled in a separate spec.'), - cfg.IntOpt('ip_version_for_ssh', - default=4, - help='Default IP version for ssh connections.'), - cfg.IntOpt('ping_timeout', - default=120, - help='Timeout in seconds to wait for ping to succeed.'), - cfg.IntOpt('connect_timeout', - default=60, - help='Timeout in seconds to wait for the TCP connection to be ' - 'successful.'), - cfg.IntOpt('ssh_timeout', - default=300, - help='Timeout in seconds to wait for the ssh banner.'), - cfg.StrOpt('image_ssh_user', - default="root", - help="User name used to authenticate to an instance."), - cfg.StrOpt('image_ssh_password', - default="password", - help="Password used to authenticate to an instance."), - cfg.StrOpt('ssh_shell_prologue', - default="set -eu -o pipefail; PATH=$$PATH:/sbin;", - help="Shell fragments to use before executing a command " - "when sshing to a guest."), - cfg.IntOpt('ping_size', - default=56, - help="The packet size for ping packets originating " - "from remote linux hosts"), - cfg.IntOpt('ping_count', - default=1, - help="The number of ping packets originating from remote " - "linux hosts"), - cfg.StrOpt('floating_ip_range', - default='10.0.0.0/29', - help='Unallocated floating IP range, which will be used to ' - 'test the floating IP bulk feature for CRUD operation. ' - 'This block must not overlap an existing floating IP ' - 'pool.'), - cfg.StrOpt('network_for_ssh', - default='public', - help="Network used for SSH connections. Ignored if " - "connect_method=floating."), -] - -volume_group = cfg.OptGroup(name='volume', - title='Block Storage Options') - -VolumeGroup = [ - cfg.IntOpt('build_interval', - default=1, - help='Time in seconds between volume availability checks.'), - cfg.IntOpt('build_timeout', - default=300, - help='Timeout in seconds to wait for a volume to become ' - 'available.'), - cfg.StrOpt('catalog_type', - default='volume', - help="Catalog type of the Volume Service"), - cfg.StrOpt('region', - default='', - help="The volume region name to use. If empty, the value " - "of identity.region is used instead. If no such region " - "is found in the service catalog, the first found one is " - "used."), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the volume service."), - cfg.ListOpt('backend_names', - default=['BACKEND_1', 'BACKEND_2'], - help='A list of backend names separated by comma. ' - 'The backend name must be declared in cinder.conf'), - cfg.StrOpt('storage_protocol', - default='iSCSI', - help='Backend protocol to target when creating volume types'), - cfg.StrOpt('vendor_name', - default='Open Source', - help='Backend vendor to target when creating volume types'), - cfg.StrOpt('disk_format', - default='raw', - help='Disk format to use when copying a volume to image'), - cfg.IntOpt('volume_size', - default=1, - help='Default size in GB for volumes created by volumes tests'), - cfg.ListOpt('manage_volume_ref', - default=['source-name', 'volume-%s'], - help="A reference to existing volume for volume manage. " - "It contains two elements, the first is ref type " - "(like 'source-name', 'source-id', etc), the second is " - "volume name template used in storage backend"), - cfg.ListOpt('manage_snapshot_ref', - default=['source-name', '_snapshot-%s'], - help="A reference to existing snapshot for snapshot manage. " - "It contains two elements, the first is ref type " - "(like 'source-name', 'source-id', etc), the second is " - "snapshot name template used in storage backend"), - cfg.StrOpt('min_microversion', - default=None, - help="Lower version of the test target microversion range. " - "The format is 'X.Y', where 'X' and 'Y' are int values. " - "Tempest selects tests based on the range between " - "min_microversion and max_microversion. " - "If both values are not specified, Tempest avoids tests " - "which require a microversion. Valid values are string " - "with format 'X.Y' or string 'latest'",), - cfg.StrOpt('max_microversion', - default=None, - help="Upper version of the test target microversion range. " - "The format is 'X.Y', where 'X' and 'Y' are int values. " - "Tempest selects tests based on the range between " - "min_microversion and max_microversion. " - "If both values are not specified, Tempest avoids tests " - "which require a microversion. Valid values are string " - "with format 'X.Y' or string 'latest'",), -] - -volume_feature_group = cfg.OptGroup(name='volume-feature-enabled', - title='Enabled Cinder Features') - -VolumeFeaturesGroup = [ - cfg.BoolOpt('multi_backend', - default=False, - help="Runs Cinder multi-backend test (requires 2 backends)"), - cfg.BoolOpt('backup', - default=True, - help='Runs Cinder volumes backup test'), - cfg.BoolOpt('snapshot', - default=True, - help='Runs Cinder volume snapshot test'), - cfg.BoolOpt('clone', - default=True, - help='Runs Cinder volume clone test'), - cfg.BoolOpt('manage_snapshot', - default=False, - help='Runs Cinder manage snapshot tests'), - cfg.BoolOpt('manage_volume', - default=False, - help='Runs Cinder manage volume tests'), - cfg.ListOpt('api_extensions', - default=['all'], - help='A list of enabled volume extensions with a special ' - 'entry all which indicates every extension is enabled. ' - 'Empty list indicates all extensions are disabled'), - cfg.BoolOpt('api_v1', - default=False, - help="Is the v1 volume API enabled", - deprecated_for_removal=True, - deprecated_reason="The v1 volume API has been deprecated " - "since Juno release, and the API will be " - "removed."), - cfg.BoolOpt('api_v2', - default=True, - help="Is the v2 volume API enabled"), - cfg.BoolOpt('api_v3', - default=True, - help="Is the v3 volume API enabled") -] - - -object_storage_group = cfg.OptGroup(name='object-storage', - title='Object Storage Service Options') - -ObjectStoreGroup = [ - cfg.StrOpt('catalog_type', - default='object-store', - help="Catalog type of the Object-Storage service."), - cfg.StrOpt('region', - default='', - help="The object-storage region name to use. If empty, the " - "value of identity.region is used instead. If no such " - "region is found in the service catalog, the first found " - "one is used."), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the object-store service."), - cfg.IntOpt('container_sync_timeout', - default=600, - help="Number of seconds to time on waiting for a container " - "to container synchronization complete."), - cfg.IntOpt('container_sync_interval', - default=5, - help="Number of seconds to wait while looping to check the " - "status of a container to container synchronization"), - cfg.StrOpt('operator_role', - default='Member', - help="Role to add to users created for swift tests to " - "enable creating containers"), - cfg.StrOpt('reseller_admin_role', - default='ResellerAdmin', - help="User role that has reseller admin"), - cfg.StrOpt('realm_name', - default='realm1', - help="Name of sync realm. A sync realm is a set of clusters " - "that have agreed to allow container syncing with each " - "other. Set the same realm name as Swift's " - "container-sync-realms.conf"), - cfg.StrOpt('cluster_name', - default='name1', - help="One name of cluster which is set in the realm whose name " - "is set in 'realm_name' item in this file. Set the " - "same cluster name as Swift's container-sync-realms.conf"), -] - -object_storage_feature_group = cfg.OptGroup( - name='object-storage-feature-enabled', - title='Enabled object-storage features') - -ObjectStoreFeaturesGroup = [ - cfg.ListOpt('discoverable_apis', - default=['all'], - help="A list of the enabled optional discoverable apis. " - "A single entry, all, indicates that all of these " - "features are expected to be enabled"), - cfg.BoolOpt('container_sync', - default=True, - help="Execute (old style) container-sync tests"), - cfg.BoolOpt('object_versioning', - default=True, - help="Execute object-versioning tests"), - cfg.BoolOpt('discoverability', - default=True, - help="Execute discoverability tests"), -] - -orchestration_group = cfg.OptGroup(name='orchestration', - title='Orchestration Service Options') - -OrchestrationGroup = [ - cfg.StrOpt('catalog_type', - default='orchestration', - help="Catalog type of the Orchestration service.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.StrOpt('region', - default='', - help="The orchestration region name to use. If empty, the " - "value of identity.region is used instead. If no such " - "region is found in the service catalog, the first found " - "one is used.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the orchestration service.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.StrOpt('stack_owner_role', default='heat_stack_owner', - help='Role required for users to be able to manage stacks', - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.IntOpt('build_interval', - default=1, - help="Time in seconds between build status checks.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.IntOpt('build_timeout', - default=1200, - help="Timeout in seconds to wait for a stack to build.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.StrOpt('instance_type', - default='m1.micro', - help="Instance type for tests. Needs to be big enough for a " - "full OS plus the test workload", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.StrOpt('keypair_name', - help="Name of existing keypair to launch servers with.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.IntOpt('max_template_size', - default=524288, - help="Value must match heat configuration of the same name.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.IntOpt('max_resources_per_stack', - default=1000, - help="Value must match heat configuration of the same name.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), -] - - -scenario_group = cfg.OptGroup(name='scenario', title='Scenario Test Options') - -ScenarioGroup = [ - cfg.StrOpt('img_dir', - default='/opt/stack/new/devstack/files/images/' - 'cirros-0.3.1-x86_64-uec', - help='Directory containing image files', - deprecated_for_removal=True), - cfg.StrOpt('img_file', deprecated_name='qcow2_img_file', - default='cirros-0.3.1-x86_64-disk.img', - help='Image file name'), - cfg.StrOpt('img_disk_format', - default='qcow2', - help='Image disk format'), - cfg.StrOpt('img_container_format', - default='bare', - help='Image container format'), - cfg.DictOpt('img_properties', help='Glance image properties. ' - 'Use for custom images which require them'), - cfg.StrOpt('ami_img_file', - default='cirros-0.3.1-x86_64-blank.img', - help='AMI image file name', - deprecated_for_removal=True), - cfg.StrOpt('ari_img_file', - default='cirros-0.3.1-x86_64-initrd', - help='ARI image file name', - deprecated_for_removal=True), - cfg.StrOpt('aki_img_file', - default='cirros-0.3.1-x86_64-vmlinuz', - help='AKI image file name', - deprecated_for_removal=True), - # TODO(yfried): add support for dhcpcd - cfg.StrOpt('dhcp_client', - default='udhcpc', - choices=["udhcpc", "dhclient", ""], - help='DHCP client used by images to renew DCHP lease. ' - 'If left empty, update operation will be skipped. ' - 'Supported clients: "udhcpc", "dhclient"') -] - - -service_available_group = cfg.OptGroup(name="service_available", - title="Available OpenStack Services") - -ServiceAvailableGroup = [ - cfg.BoolOpt('cinder', - default=True, - help="Whether or not cinder is expected to be available"), - cfg.BoolOpt('neutron', - default=False, - help="Whether or not neutron is expected to be available"), - cfg.BoolOpt('glance', - default=True, - help="Whether or not glance is expected to be available"), - cfg.BoolOpt('swift', - default=True, - help="Whether or not swift is expected to be available"), - cfg.BoolOpt('nova', - default=True, - help="Whether or not nova is expected to be available"), - cfg.BoolOpt('heat', - default=False, - help="Whether or not Heat is expected to be available", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), -] - -debug_group = cfg.OptGroup(name="debug", - title="Debug System") - -DebugGroup = [ - cfg.StrOpt('trace_requests', - default='', - help="""A regex to determine which requests should be traced. - -This is a regex to match the caller for rest client requests to be able to -selectively trace calls out of specific classes and methods. It largely -exists for test development, and is not expected to be used in a real deploy -of tempest. This will be matched against the discovered ClassName:method -in the test environment. - -Expected values for this field are: - - * ClassName:test_method_name - traces one test_method - * ClassName:setUp(Class) - traces specific setup functions - * ClassName:tearDown(Class) - traces specific teardown functions - * ClassName:_run_cleanups - traces the cleanup functions - -If nothing is specified, this feature is not enabled. To trace everything -specify .* as the regex. -""") -] - -DefaultGroup = [ - cfg.StrOpt('resources_prefix', - default='tempest', - help="Prefix to be added when generating the name for " - "test resources. It can be used to discover all " - "resources associated with a specific test run when " - "running tempest on a real-life cloud", - deprecated_for_removal=True, - deprecated_reason="It is enough to add 'tempest' as this " - "prefix to ideintify resources which are " - "created by Tempest and no projects set " - "this option on OpenStack dev community."), - cfg.BoolOpt('pause_teardown', - default=False, - help="""Whether to pause a test in global teardown. - -The best use case is investigating used resources of one test. -A test can be run as follows: - $ ostestr --pdb TEST_ID -or - $ python -m testtools.run TEST_ID"""), -] - -_opts = [ - (auth_group, AuthGroup), - (compute_group, ComputeGroup), - (compute_features_group, ComputeFeaturesGroup), - (identity_group, IdentityGroup), - (service_clients_group, ServiceClientsGroup), - (identity_feature_group, IdentityFeatureGroup), - (image_group, ImageGroup), - (image_feature_group, ImageFeaturesGroup), - (network_group, NetworkGroup), - (network_feature_group, NetworkFeaturesGroup), - (validation_group, ValidationGroup), - (volume_group, VolumeGroup), - (volume_feature_group, VolumeFeaturesGroup), - (object_storage_group, ObjectStoreGroup), - (object_storage_feature_group, ObjectStoreFeaturesGroup), - (orchestration_group, OrchestrationGroup), - (scenario_group, ScenarioGroup), - (service_available_group, ServiceAvailableGroup), - (debug_group, DebugGroup), - (None, DefaultGroup) -] - - -def register_opts(): - ext_plugins = plugins.TempestTestPluginManager() - # Register in-tree tempest config options - for g, o in _opts: - register_opt_group(_CONF, g, o) - # Call external plugin config option registration - ext_plugins.register_plugin_opts(_CONF) - - -def list_opts(): - """Return a list of oslo.config options available. - - The purpose of this is to allow tools like the Oslo sample config file - generator to discover the options exposed to users. - """ - ext_plugins = plugins.TempestTestPluginManager() - # Make a shallow copy of the options list that can be - # extended by plugins. Send back the group object - # to allow group help text to be generated. - opt_list = [(g, o) for g, o in _opts] - opt_list.extend(ext_plugins.get_plugin_options_list()) - return opt_list - - -# this should never be called outside of this class -class TempestConfigPrivate(object): - """Provides OpenStack configuration information.""" - - DEFAULT_CONFIG_DIR = os.path.join(os.getcwd(), "etc") - - DEFAULT_CONFIG_FILE = "tempest.conf" - - def __getattr__(self, attr): - # Handles config options from the default group - return getattr(_CONF, attr) - - def _set_attrs(self): - # This methods ensures that config options in Tempest as well as - # in Tempest plugins can be accessed via: - # CONF.. - # where: - # normalised_group_name = group_name.replace('-', '_') - # Attributes are set at __init__ time *only* for known option groups - self.auth = _CONF.auth - self.compute = _CONF.compute - self.compute_feature_enabled = _CONF['compute-feature-enabled'] - self.identity = _CONF.identity - self.service_clients = _CONF['service-clients'] - self.identity_feature_enabled = _CONF['identity-feature-enabled'] - self.image = _CONF.image - self.image_feature_enabled = _CONF['image-feature-enabled'] - self.network = _CONF.network - self.network_feature_enabled = _CONF['network-feature-enabled'] - self.validation = _CONF.validation - self.volume = _CONF.volume - self.volume_feature_enabled = _CONF['volume-feature-enabled'] - self.object_storage = _CONF['object-storage'] - self.object_storage_feature_enabled = _CONF[ - 'object-storage-feature-enabled'] - self.orchestration = _CONF.orchestration - self.scenario = _CONF.scenario - self.service_available = _CONF.service_available - self.debug = _CONF.debug - logging.tempest_set_log_file('tempest.log') - # Setting attributes for plugins - # NOTE(andreaf) Plugins have no access to the TempestConfigPrivate - # instance at discovery time, so they have no way of setting these - # aliases themselves. - ext_plugins = plugins.TempestTestPluginManager() - for group, _ in ext_plugins.get_plugin_options_list(): - if isinstance(group, cfg.OptGroup): - # If we have an OptGroup - group_name = group.name - group_dest = group.dest - else: - # If we have a group name as a string - group_name = group - group_dest = group.replace('-', '_') - # NOTE(andreaf) We can set the attribute safely here since in - # case of name conflict we would not have reached this point. - setattr(self, group_dest, _CONF[group_name]) - - def __init__(self, parse_conf=True, config_path=None): - """Initialize a configuration from a conf directory and conf file.""" - super(TempestConfigPrivate, self).__init__() - config_files = [] - failsafe_path = "/etc/tempest/" + self.DEFAULT_CONFIG_FILE - - if config_path: - path = config_path - else: - # Environment variables override defaults... - conf_dir = os.environ.get('TEMPEST_CONFIG_DIR', - self.DEFAULT_CONFIG_DIR) - conf_file = os.environ.get('TEMPEST_CONFIG', - self.DEFAULT_CONFIG_FILE) - - path = os.path.join(conf_dir, conf_file) - - if not os.path.isfile(path): - path = failsafe_path - - # only parse the config file if we expect one to exist. This is needed - # to remove an issue with the config file up to date checker. - if parse_conf: - config_files.append(path) - logging.register_options(_CONF) - if os.path.isfile(path): - _CONF([], project='tempest', default_config_files=config_files) - else: - _CONF([], project='tempest') - - logging_cfg_path = "%s/logging.conf" % os.path.dirname(path) - if ((not hasattr(_CONF, 'log_config_append') or - _CONF.log_config_append is None) and - os.path.isfile(logging_cfg_path)): - # if logging conf is in place we need to set log_config_append - _CONF.log_config_append = logging_cfg_path - - logging.setup(_CONF, 'tempest') - LOG = logging.getLogger('tempest') - LOG.info("Using tempest config file %s", path) - register_opts() - self._set_attrs() - if parse_conf: - _CONF.log_opt_values(LOG, logging.DEBUG) - - -class TempestConfigProxy(object): - _config = None - _path = None - - _extra_log_defaults = [ - ('paramiko.transport', logging.INFO), - ('requests.packages.urllib3.connectionpool', logging.WARN), - ] - - def _fix_log_levels(self): - """Tweak the oslo log defaults.""" - for name, level in self._extra_log_defaults: - logging.getLogger(name).logger.setLevel(level) - - def __getattr__(self, attr): - if not self._config: - self._fix_log_levels() - lock_dir = os.path.join(tempfile.gettempdir(), 'tempest-lock') - lockutils.set_defaults(lock_dir) - self._config = TempestConfigPrivate(config_path=self._path) - - # Pushing tempest internal service client configuration to the - # service clients register. Doing this in the config module ensures - # that the configuration is available by the time we register the - # service clients. - # NOTE(andreaf) This has to be done at the time the first - # attribute is accessed, to ensure all plugins have been already - # loaded, options registered, and _config is set. - _register_tempest_service_clients() - - # Registering service clients and pushing their configuration to - # the service clients register. Doing this in the config module - # ensures that the configuration is available by the time we - # discover tests from plugins. - plugins.TempestTestPluginManager()._register_service_clients() - - return getattr(self._config, attr) - - def set_config_path(self, path): - self._path = path - - -CONF = TempestConfigProxy() - - -@debtcollector.removals.remove( - message='use testtools.skipUnless instead', removal_version='Queens') -def skip_unless_config(*args): - """Decorator to raise a skip if a config opt doesn't exist or is False - - :param str group: The first arg, the option group to check - :param str name: The second arg, the option name to check - :param str msg: Optional third arg, the skip msg to use if a skip is raised - :raises testtools.TestCaseskipException: If the specified config option - doesn't exist or it exists and evaluates to False - """ - def decorator(f): - group = args[0] - name = args[1] - - @functools.wraps(f) - def wrapper(self, *func_args, **func_kwargs): - if not hasattr(CONF, group): - msg = "Config group %s doesn't exist" % group - raise testtools.TestCase.skipException(msg) - - conf_group = getattr(CONF, group) - if not hasattr(conf_group, name): - msg = "Config option %s.%s doesn't exist" % (group, - name) - raise testtools.TestCase.skipException(msg) - - value = getattr(conf_group, name) - if not value: - if len(args) == 3: - msg = args[2] - else: - msg = "Config option %s.%s is false" % (group, - name) - raise testtools.TestCase.skipException(msg) - return f(self, *func_args, **func_kwargs) - return wrapper - return decorator - - -@debtcollector.removals.remove( - message='use testtools.skipIf instead', removal_version='Queens') -def skip_if_config(*args): - """Raise a skipException if a config exists and is True - - :param str group: The first arg, the option group to check - :param str name: The second arg, the option name to check - :param str msg: Optional third arg, the skip msg to use if a skip is raised - :raises testtools.TestCase.skipException: If the specified config option - exists and evaluates to True - """ - def decorator(f): - group = args[0] - name = args[1] - - @functools.wraps(f) - def wrapper(self, *func_args, **func_kwargs): - if hasattr(CONF, group): - conf_group = getattr(CONF, group) - if hasattr(conf_group, name): - value = getattr(conf_group, name) - if value: - if len(args) == 3: - msg = args[2] - else: - msg = "Config option %s.%s is false" % (group, - name) - raise testtools.TestCase.skipException(msg) - return f(self, *func_args, **func_kwargs) - return wrapper - return decorator - - -def service_client_config(service_client_name=None): - """Return a dict with the parameters to init service clients - - Extracts from CONF the settings specific to the service_client_name and - api_version, and formats them as dict ready to be passed to the service - clients __init__: - - * `region` (default to identity) - * `catalog_type` - * `endpoint_type` - * `build_timeout` (object-storage and identity default to compute) - * `build_interval` (object-storage and identity default to compute) - - The following common settings are always returned, even if - `service_client_name` is None: - - * `disable_ssl_certificate_validation` - * `ca_certs` - * `trace_requests` - * `http_timeout` - - The dict returned by this does not fit a few service clients: - - * The endpoint type is not returned for identity client, since it takes - three different values for v2 admin, v2 public and v3 - * The `ServersClient` from compute accepts an optional - `enable_instance_password` parameter, which is not returned. - * The `VolumesClient` for both v1 and v2 volume accept an optional - `default_volume_size` parameter, which is not returned. - * The `TokenClient` and `V3TokenClient` have a very different - interface, only auth_url is needed for them. - - :param service_client_name: str Name of the service. Supported values are - 'compute', 'identity', 'image', 'network', 'object-storage', 'volume' - :return: dictionary of __init__ parameters for the service clients - :rtype: dict - """ - _parameters = { - 'disable_ssl_certificate_validation': - CONF.identity.disable_ssl_certificate_validation, - 'ca_certs': CONF.identity.ca_certificates_file, - 'trace_requests': CONF.debug.trace_requests, - 'http_timeout': CONF.service_clients.http_timeout - } - - if service_client_name is None: - return _parameters - - # Get the group of options first, by normalising the service_group_name - # Services with a '-' in the name have an '_' in the option group name - config_group = service_client_name.replace('-', '_') - # NOTE(andreaf) Check if the config group exists. This allows for this - # helper to be used for settings from registered plugins as well - try: - options = getattr(CONF, config_group) - except cfg.NoSuchOptError: - # Option group not defined - raise exceptions.UnknownServiceClient(services=service_client_name) - # Set endpoint_type - # Identity uses different settings depending on API version, so do not - # return the endpoint at all. - if service_client_name != 'identity': - _parameters['endpoint_type'] = getattr(options, 'endpoint_type') - # Set build_* - # Object storage and identity groups do not have conf settings for - # build_* parameters, and we default to compute in any case - for setting in ['build_timeout', 'build_interval']: - if not hasattr(options, setting) or not getattr(options, setting): - _parameters[setting] = getattr(CONF.compute, setting) - else: - _parameters[setting] = getattr(options, setting) - # Set region - # If a service client does not define region or region is not set - # default to the identity region - if not hasattr(options, 'region') or not getattr(options, 'region'): - _parameters['region'] = CONF.identity.region - else: - _parameters['region'] = getattr(options, 'region') - # Set service - _parameters['service'] = getattr(options, 'catalog_type') - return _parameters - - -def _register_tempest_service_clients(): - # Register tempest own service clients using the same mechanism used - # for external plugins. - # The configuration data is pushed to the registry so that automatic - # configuration of tempest own service clients is possible both for - # tempest as well as for the plugins. - service_clients = clients.tempest_modules() - registry = clients.ClientsRegistry() - all_clients = [] - for service_client in service_clients: - module = service_clients[service_client] - configs = service_client.split('.')[0] - service_client_data = dict( - name=service_client.replace('.', '_'), - service_version=service_client, - module_path=module.__name__, - client_names=module.__all__, - **service_client_config(configs) - ) - all_clients.append(service_client_data) - # NOTE(andreaf) Internal service clients do not actually belong - # to a plugin, so using '__tempest__' to indicate a virtual plugin - # which holds internal service clients. - registry.register_service_client('__tempest__', all_clients) diff --git a/tempest/exceptions.py b/tempest/exceptions.py deleted file mode 100644 index b5b2d71cf..000000000 --- a/tempest/exceptions.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.lib import exceptions - - -class BuildErrorException(exceptions.TempestException): - message = "Server %(server_id)s failed to build and is in ERROR status" - - -class SnapshotNotFoundException(exceptions.TempestException): - message = "Server snapshot image %(image_id)s not found." - - -class ImageKilledException(exceptions.TempestException): - message = "Image %(image_id)s 'killed' while waiting for '%(status)s'" - - -class AddImageException(exceptions.TempestException): - message = "Image %(image_id)s failed to become ACTIVE in the allotted time" - - -class VolumeResourceBuildErrorException(exceptions.TempestException): - message = ("%(resource_name)s %(resource_id)s failed to build and is in " - "ERROR status") - - -class VolumeRestoreErrorException(exceptions.TempestException): - message = "Volume %(volume_id)s failed to restore and is in ERROR status" - - -class StackBuildErrorException(exceptions.TempestException): - message = ("Stack %(stack_identifier)s is in %(stack_status)s status " - "due to '%(stack_status_reason)s'") - - -class ServerUnreachable(exceptions.TempestException): - message = ("Server %(server_id)s is not reachable via " - "the configured network") - - -class RFCViolation(exceptions.RestClientException): - message = "RFC Violation" diff --git a/tempest/hacking/__init__.py b/tempest/hacking/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py deleted file mode 100644 index 067da09a5..000000000 --- a/tempest/hacking/checks.py +++ /dev/null @@ -1,311 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import re - -import pep8 - - -PYTHON_CLIENTS = ['cinder', 'glance', 'keystone', 'nova', 'swift', 'neutron', - 'ironic', 'heat', 'sahara'] - -PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS)) -TEST_DEFINITION = re.compile(r'^\s*def test.*') -SETUP_TEARDOWN_CLASS_DEFINITION = re.compile(r'^\s+def (setUp|tearDown)Class') -SCENARIO_DECORATOR = re.compile(r'\s*@.*services\((.*)\)') -VI_HEADER_RE = re.compile(r"^#\s+vim?:.+") -RAND_NAME_HYPHEN_RE = re.compile(r".*rand_name\(.+[\-\_][\"\']\)") -mutable_default_args = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])") -TESTTOOLS_SKIP_DECORATOR = re.compile(r'\s*@testtools\.skip\((.*)\)') -METHOD = re.compile(r"^ def .+") -METHOD_GET_RESOURCE = re.compile(r"^\s*def (list|show)\_.+") -METHOD_DELETE_RESOURCE = re.compile(r"^\s*def delete_.+") -CLASS = re.compile(r"^class .+") - - -def import_no_clients_in_api_and_scenario_tests(physical_line, filename): - """Check for client imports from tempest/api & tempest/scenario tests - - T102: Cannot import OpenStack python clients - """ - - if "tempest/api" in filename or "tempest/scenario" in filename: - res = PYTHON_CLIENT_RE.match(physical_line) - if res: - return (physical_line.find(res.group(1)), - ("T102: python clients import not allowed" - " in tempest/api/* or tempest/scenario/* tests")) - - -def scenario_tests_need_service_tags(physical_line, filename, - previous_logical): - """Check that scenario tests have service tags - - T104: Scenario tests require a services decorator - """ - - if 'tempest/scenario/' in filename and '/test_' in filename: - if TEST_DEFINITION.match(physical_line): - if not SCENARIO_DECORATOR.match(previous_logical): - return (physical_line.find('def'), - "T104: Scenario tests require a service decorator") - - -def no_setup_teardown_class_for_tests(physical_line, filename): - - if pep8.noqa(physical_line): - return - - if 'tempest/test.py' in filename or 'tempest/lib/' in filename: - return - - if SETUP_TEARDOWN_CLASS_DEFINITION.match(physical_line): - return (physical_line.find('def'), - "T105: (setUp|tearDown)Class can not be used in tests") - - -def no_vi_headers(physical_line, line_number, lines): - """Check for vi editor configuration in source files. - - By default vi modelines can only appear in the first or - last 5 lines of a source file. - - T106 - """ - # NOTE(gilliard): line_number is 1-indexed - if line_number <= 5 or line_number > len(lines) - 5: - if VI_HEADER_RE.match(physical_line): - return 0, "T106: Don't put vi configuration in source files" - - -def service_tags_not_in_module_path(physical_line, filename): - """Check that a service tag isn't in the module path - - A service tag should only be added if the service name isn't already in - the module path. - - T107 - """ - # NOTE(mtreinish) Scenario tests always need service tags, but subdirs are - # created for services like heat which would cause false negatives for - # those tests, so just exclude the scenario tests. - if 'tempest/scenario' not in filename: - matches = SCENARIO_DECORATOR.match(physical_line) - if matches: - services = matches.group(1).split(',') - for service in services: - service_name = service.strip().strip("'") - modulepath = os.path.split(filename)[0] - if service_name in modulepath: - return (physical_line.find(service_name), - "T107: service tag should not be in path") - - -def no_hyphen_at_end_of_rand_name(logical_line, filename): - """Check no hyphen at the end of rand_name() argument - - T108 - """ - msg = "T108: hyphen should not be specified at the end of rand_name()" - if RAND_NAME_HYPHEN_RE.match(logical_line): - return 0, msg - - -def no_mutable_default_args(logical_line): - """Check that mutable object isn't used as default argument - - N322: Method's default argument shouldn't be mutable - """ - msg = "N322: Method's default argument shouldn't be mutable!" - if mutable_default_args.match(logical_line): - yield (0, msg) - - -def no_testtools_skip_decorator(logical_line): - """Check that methods do not have the testtools.skip decorator - - T109 - """ - if TESTTOOLS_SKIP_DECORATOR.match(logical_line): - yield (0, "T109: Cannot use testtools.skip decorator; instead use " - "decorators.skip_because from tempest.lib") - - -def _common_service_clients_check(logical_line, physical_line, filename, - ignored_list_file=None): - if not re.match('tempest/(lib/)?services/.*', filename): - return False - - if ignored_list_file is not None: - ignored_list = [] - with open('tempest/hacking/' + ignored_list_file) as f: - for line in f: - ignored_list.append(line.strip()) - - if filename in ignored_list: - return False - - if not METHOD.match(physical_line): - return False - - if pep8.noqa(physical_line): - return False - - return True - - -def get_resources_on_service_clients(logical_line, physical_line, filename, - line_number, lines): - """Check that service client names of GET should be consistent - - T110 - """ - if not _common_service_clients_check(logical_line, physical_line, - filename, 'ignored_list_T110.txt'): - return - - for line in lines[line_number:]: - if METHOD.match(line) or CLASS.match(line): - # the end of a method - return - - if 'self.get(' not in line and ('self.show_resource(' not in line and - 'self.list_resources(' not in line): - continue - - if METHOD_GET_RESOURCE.match(logical_line): - return - - msg = ("T110: [GET /resources] methods should be list_s" - " or show_") - yield (0, msg) - - -def delete_resources_on_service_clients(logical_line, physical_line, filename, - line_number, lines): - """Check that service client names of DELETE should be consistent - - T111 - """ - if not _common_service_clients_check(logical_line, physical_line, - filename, 'ignored_list_T111.txt'): - return - - for line in lines[line_number:]: - if METHOD.match(line) or CLASS.match(line): - # the end of a method - return - - if 'self.delete(' not in line and 'self.delete_resource(' not in line: - continue - - if METHOD_DELETE_RESOURCE.match(logical_line): - return - - msg = ("T111: [DELETE /resources/] methods should be " - "delete_") - yield (0, msg) - - -def dont_import_local_tempest_into_lib(logical_line, filename): - """Check that tempest.lib should not import local tempest code - - T112 - """ - if 'tempest/lib/' not in filename: - return - - if not ('from tempest' in logical_line - or 'import tempest' in logical_line): - return - - if ('from tempest.lib' in logical_line - or 'import tempest.lib' in logical_line): - return - - msg = ("T112: tempest.lib should not import local tempest code to avoid " - "circular dependency") - yield (0, msg) - - -def use_rand_uuid_instead_of_uuid4(logical_line, filename): - """Check that tests use data_utils.rand_uuid() instead of uuid.uuid4() - - T113 - """ - if 'tempest/lib/' in filename: - return - - if 'uuid.uuid4()' not in logical_line: - return - - msg = ("T113: Tests should use data_utils.rand_uuid()/rand_uuid_hex() " - "instead of uuid.uuid4()/uuid.uuid4().hex") - yield (0, msg) - - -def dont_use_config_in_tempest_lib(logical_line, filename): - """Check that tempest.lib doesn't use tempest config - - T114 - """ - - if 'tempest/lib/' not in filename: - return - - if ('tempest.config' in logical_line - or 'from tempest import config' in logical_line - or 'oslo_config' in logical_line): - msg = ('T114: tempest.lib can not have any dependency on tempest ' - 'config.') - yield(0, msg) - - -def dont_put_admin_tests_on_nonadmin_path(logical_line, physical_line, - filename): - """Check admin tests should exist under admin path - - T115 - """ - - if 'tempest/api/' not in filename: - return - - if pep8.noqa(physical_line): - return - - if not re.match('class .*Test.*\(.*Admin.*\):', logical_line): - return - - if not re.match('.\/tempest\/api\/.*\/admin\/.*', filename): - msg = 'T115: All admin tests should exist under admin path.' - yield(0, msg) - - -def factory(register): - register(import_no_clients_in_api_and_scenario_tests) - register(scenario_tests_need_service_tags) - register(no_setup_teardown_class_for_tests) - register(no_vi_headers) - register(service_tags_not_in_module_path) - register(no_hyphen_at_end_of_rand_name) - register(no_mutable_default_args) - register(no_testtools_skip_decorator) - register(get_resources_on_service_clients) - register(delete_resources_on_service_clients) - register(dont_import_local_tempest_into_lib) - register(dont_use_config_in_tempest_lib) - register(use_rand_uuid_instead_of_uuid4) - register(dont_put_admin_tests_on_nonadmin_path) diff --git a/tempest/hacking/ignored_list_T110.txt b/tempest/hacking/ignored_list_T110.txt deleted file mode 100644 index 0e7e894ca..000000000 --- a/tempest/hacking/ignored_list_T110.txt +++ /dev/null @@ -1 +0,0 @@ -./tempest/services/object_storage/object_client.py diff --git a/tempest/lib/__init__.py b/tempest/lib/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/__init__.py b/tempest/lib/api_schema/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/__init__.py b/tempest/lib/api_schema/response/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/__init__.py b/tempest/lib/api_schema/response/compute/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_1/__init__.py b/tempest/lib/api_schema/response/compute/v2_1/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_1/agents.py b/tempest/lib/api_schema/response/compute/v2_1/agents.py deleted file mode 100644 index 6f712b41e..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/agents.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -common_agent_info = { - 'type': 'object', - 'properties': { - 'agent_id': {'type': ['integer', 'string']}, - 'hypervisor': {'type': 'string'}, - 'os': {'type': 'string'}, - 'architecture': {'type': 'string'}, - 'version': {'type': 'string'}, - 'url': {'type': 'string', 'format': 'uri'}, - 'md5hash': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['agent_id', 'hypervisor', 'os', 'architecture', - 'version', 'url', 'md5hash'] -} - -list_agents = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'agents': { - 'type': 'array', - 'items': common_agent_info - } - }, - 'additionalProperties': False, - 'required': ['agents'] - } -} - -create_agent = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'agent': common_agent_info - }, - 'additionalProperties': False, - 'required': ['agent'] - } -} - -update_agent = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'agent': { - 'type': 'object', - 'properties': { - 'agent_id': {'type': ['integer', 'string']}, - 'version': {'type': 'string'}, - 'url': {'type': 'string', 'format': 'uri'}, - 'md5hash': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['agent_id', 'version', 'url', 'md5hash'] - } - }, - 'additionalProperties': False, - 'required': ['agent'] - } -} - -delete_agent = { - 'status_code': [200] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/aggregates.py b/tempest/lib/api_schema/response/compute/v2_1/aggregates.py deleted file mode 100644 index 3289a34a7..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/aggregates.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -# create-aggregate api doesn't have 'hosts' and 'metadata' attributes. -aggregate_for_create = { - 'type': 'object', - 'properties': { - 'availability_zone': {'type': ['string', 'null']}, - 'created_at': parameter_types.date_time, - 'deleted': {'type': 'boolean'}, - 'deleted_at': parameter_types.date_time_or_null, - 'id': {'type': 'integer'}, - 'name': {'type': 'string'}, - 'updated_at': parameter_types.date_time_or_null - }, - 'additionalProperties': False, - 'required': ['availability_zone', 'created_at', 'deleted', - 'deleted_at', 'id', 'name', 'updated_at'], -} - -common_aggregate_info = copy.deepcopy(aggregate_for_create) -common_aggregate_info['properties'].update({ - 'hosts': {'type': 'array'}, - 'metadata': {'type': 'object'} -}) -common_aggregate_info['required'].extend(['hosts', 'metadata']) - -list_aggregates = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'aggregates': { - 'type': 'array', - 'items': common_aggregate_info - } - }, - 'additionalProperties': False, - 'required': ['aggregates'], - } -} - -get_aggregate = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'aggregate': common_aggregate_info - }, - 'additionalProperties': False, - 'required': ['aggregate'], - } -} - -aggregate_set_metadata = get_aggregate -# The 'updated_at' attribute of 'update_aggregate' can't be null. -update_aggregate = copy.deepcopy(get_aggregate) -update_aggregate['response_body']['properties']['aggregate']['properties'][ - 'updated_at'] = parameter_types.date_time - -delete_aggregate = { - 'status_code': [200] -} - -create_aggregate = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'aggregate': aggregate_for_create - }, - 'additionalProperties': False, - 'required': ['aggregate'], - } -} - -aggregate_add_remove_host = get_aggregate diff --git a/tempest/lib/api_schema/response/compute/v2_1/availability_zone.py b/tempest/lib/api_schema/response/compute/v2_1/availability_zone.py deleted file mode 100644 index 0dc28c378..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/availability_zone.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - - -base = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'availabilityZoneInfo': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'zoneName': {'type': 'string'}, - 'zoneState': { - 'type': 'object', - 'properties': { - 'available': {'type': 'boolean'} - }, - 'additionalProperties': False, - 'required': ['available'] - }, - # NOTE: Here is the difference between detail and - # non-detail. - 'hosts': {'type': 'null'} - }, - 'additionalProperties': False, - 'required': ['zoneName', 'zoneState', 'hosts'] - } - } - }, - 'additionalProperties': False, - 'required': ['availabilityZoneInfo'] - } -} - -detail = { - 'type': ['object', 'null'], - 'patternProperties': { - # NOTE: Here is for a hostname - '^[a-zA-Z0-9-_.]+$': { - 'type': 'object', - 'patternProperties': { - # NOTE: Here is for a service name - '^.*$': { - 'type': 'object', - 'properties': { - 'available': {'type': 'boolean'}, - 'active': {'type': 'boolean'}, - 'updated_at': parameter_types.date_time_or_null - }, - 'additionalProperties': False, - 'required': ['available', 'active', 'updated_at'] - } - } - } - } -} - -list_availability_zone_list = copy.deepcopy(base) - -list_availability_zone_list_detail = copy.deepcopy(base) -list_availability_zone_list_detail['response_body']['properties'][ - 'availabilityZoneInfo']['items']['properties']['hosts'] = detail diff --git a/tempest/lib/api_schema/response/compute/v2_1/baremetal_nodes.py b/tempest/lib/api_schema/response/compute/v2_1/baremetal_nodes.py deleted file mode 100644 index d1ee87728..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/baremetal_nodes.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -node = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'interfaces': {'type': 'array'}, - 'host': {'type': 'string'}, - 'task_state': {'type': ['string', 'null']}, - 'cpus': {'type': ['integer', 'string']}, - 'memory_mb': {'type': ['integer', 'string']}, - 'disk_gb': {'type': ['integer', 'string']}, - }, - 'additionalProperties': False, - 'required': ['id', 'interfaces', 'host', 'task_state', 'cpus', 'memory_mb', - 'disk_gb'] -} - -list_baremetal_nodes = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'nodes': { - 'type': 'array', - 'items': node - } - }, - 'additionalProperties': False, - 'required': ['nodes'] - } -} - -baremetal_node = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'node': node - }, - 'additionalProperties': False, - 'required': ['node'] - } -} -get_baremetal_node = copy.deepcopy(baremetal_node) -get_baremetal_node['response_body']['properties']['node'][ - 'properties'].update({'instance_uuid': {'type': ['string', 'null']}}) -get_baremetal_node['response_body']['properties']['node'][ - 'required'].append('instance_uuid') diff --git a/tempest/lib/api_schema/response/compute/v2_1/certificates.py b/tempest/lib/api_schema/response/compute/v2_1/certificates.py deleted file mode 100644 index 4e7cbe4d2..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/certificates.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -_common_schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'certificate': { - 'type': 'object', - 'properties': { - 'data': {'type': 'string'}, - 'private_key': {'type': 'string'}, - }, - 'additionalProperties': False, - 'required': ['data', 'private_key'] - } - }, - 'additionalProperties': False, - 'required': ['certificate'] - } -} - -get_certificate = copy.deepcopy(_common_schema) -get_certificate['response_body']['properties']['certificate'][ - 'properties']['private_key'].update({'type': 'null'}) - -create_certificate = copy.deepcopy(_common_schema) diff --git a/tempest/lib/api_schema/response/compute/v2_1/extensions.py b/tempest/lib/api_schema/response/compute/v2_1/extensions.py deleted file mode 100644 index b5962d752..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/extensions.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -list_extensions = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'extensions': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'updated': parameter_types.date_time, - 'name': {'type': 'string'}, - 'links': {'type': 'array'}, - 'namespace': { - 'type': 'string', - 'format': 'uri' - }, - 'alias': {'type': 'string'}, - 'description': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['updated', 'name', 'links', 'namespace', - 'alias', 'description'] - } - } - }, - 'additionalProperties': False, - 'required': ['extensions'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/fixed_ips.py b/tempest/lib/api_schema/response/compute/v2_1/fixed_ips.py deleted file mode 100644 index a653213f0..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/fixed_ips.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -get_fixed_ip = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'fixed_ip': { - 'type': 'object', - 'properties': { - 'address': parameter_types.ip_address, - 'cidr': {'type': 'string'}, - 'host': {'type': 'string'}, - 'hostname': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['address', 'cidr', 'host', 'hostname'] - } - }, - 'additionalProperties': False, - 'required': ['fixed_ip'] - } -} - -reserve_unreserve_fixed_ip = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/flavors.py b/tempest/lib/api_schema/response/compute/v2_1/flavors.py deleted file mode 100644 index 547d94d57..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/flavors.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -list_flavors = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'flavors': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'links': parameter_types.links, - 'id': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['name', 'links', 'id'] - } - }, - 'flavors_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): flavors_links attribute is not necessary - # to be present always So it is not 'required'. - 'required': ['flavors'] - } -} - -common_flavor_info = { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'links': parameter_types.links, - 'ram': {'type': 'integer'}, - 'vcpus': {'type': 'integer'}, - # 'swap' attributes comes as integer value but if it is empty - # it comes as "". So defining type of as string and integer. - 'swap': {'type': ['integer', 'string']}, - 'disk': {'type': 'integer'}, - 'id': {'type': 'string'}, - 'OS-FLV-DISABLED:disabled': {'type': 'boolean'}, - 'os-flavor-access:is_public': {'type': 'boolean'}, - 'rxtx_factor': {'type': 'number'}, - 'OS-FLV-EXT-DATA:ephemeral': {'type': 'integer'} - }, - 'additionalProperties': False, - # 'OS-FLV-DISABLED', 'os-flavor-access', 'rxtx_factor' and - # 'OS-FLV-EXT-DATA' are API extensions. So they are not 'required'. - 'required': ['name', 'links', 'ram', 'vcpus', 'swap', 'disk', 'id'] -} - -list_flavors_details = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'flavors': { - 'type': 'array', - 'items': common_flavor_info - }, - # NOTE(gmann): flavors_links attribute is not necessary - # to be present always So it is not 'required'. - 'flavors_links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['flavors'] - } -} - -unset_flavor_extra_specs = { - 'status_code': [200] -} - -create_get_flavor_details = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'flavor': common_flavor_info - }, - 'additionalProperties': False, - 'required': ['flavor'] - } -} - -delete_flavor = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/flavors_access.py b/tempest/lib/api_schema/response/compute/v2_1/flavors_access.py deleted file mode 100644 index a4d6af0d7..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/flavors_access.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -add_remove_list_flavor_access = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'flavor_access': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'flavor_id': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - }, - 'additionalProperties': False, - 'required': ['flavor_id', 'tenant_id'], - } - } - }, - 'additionalProperties': False, - 'required': ['flavor_access'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/flavors_extra_specs.py b/tempest/lib/api_schema/response/compute/v2_1/flavors_extra_specs.py deleted file mode 100644 index a438d4869..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/flavors_extra_specs.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -set_get_flavor_extra_specs = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'extra_specs': { - 'type': 'object', - 'patternProperties': { - '^[a-zA-Z0-9_\-\. :]+$': {'type': 'string'} - } - } - }, - 'additionalProperties': False, - 'required': ['extra_specs'] - } -} - -set_get_flavor_extra_specs_key = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'patternProperties': { - '^[a-zA-Z0-9_\-\. :]+$': {'type': 'string'} - } - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/floating_ips.py b/tempest/lib/api_schema/response/compute/v2_1/floating_ips.py deleted file mode 100644 index 0c665905f..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/floating_ips.py +++ /dev/null @@ -1,148 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -common_floating_ip_info = { - 'type': 'object', - 'properties': { - # NOTE: Now the type of 'id' is integer, but - # here allows 'string' also because we will be - # able to change it to 'uuid' in the future. - 'id': {'type': ['integer', 'string']}, - 'pool': {'type': ['string', 'null']}, - 'instance_id': {'type': ['string', 'null']}, - 'ip': parameter_types.ip_address, - 'fixed_ip': parameter_types.ip_address - }, - 'additionalProperties': False, - 'required': ['id', 'pool', 'instance_id', - 'ip', 'fixed_ip'], - -} -list_floating_ips = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ips': { - 'type': 'array', - 'items': common_floating_ip_info - }, - }, - 'additionalProperties': False, - 'required': ['floating_ips'], - } -} - -create_get_floating_ip = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ip': common_floating_ip_info - }, - 'additionalProperties': False, - 'required': ['floating_ip'], - } -} - -list_floating_ip_pools = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ip_pools': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['name'], - } - } - }, - 'additionalProperties': False, - 'required': ['floating_ip_pools'], - } -} - -add_remove_floating_ip = { - 'status_code': [202] -} - -create_floating_ips_bulk = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ips_bulk_create': { - 'type': 'object', - 'properties': { - 'interface': {'type': ['string', 'null']}, - 'ip_range': {'type': 'string'}, - 'pool': {'type': ['string', 'null']}, - }, - 'additionalProperties': False, - 'required': ['interface', 'ip_range', 'pool'], - } - }, - 'additionalProperties': False, - 'required': ['floating_ips_bulk_create'], - } -} - -delete_floating_ips_bulk = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ips_bulk_delete': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['floating_ips_bulk_delete'], - } -} - -list_floating_ips_bulk = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ip_info': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'address': parameter_types.ip_address, - 'instance_uuid': {'type': ['string', 'null']}, - 'interface': {'type': ['string', 'null']}, - 'pool': {'type': ['string', 'null']}, - 'project_id': {'type': ['string', 'null']}, - 'fixed_ip': parameter_types.ip_address - }, - 'additionalProperties': False, - # NOTE: fixed_ip is introduced after JUNO release, - # So it is not defined as 'required'. - 'required': ['address', 'instance_uuid', 'interface', - 'pool', 'project_id'], - } - } - }, - 'additionalProperties': False, - 'required': ['floating_ip_info'], - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/hosts.py b/tempest/lib/api_schema/response/compute/v2_1/hosts.py deleted file mode 100644 index cae343597..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/hosts.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - - -list_hosts = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hosts': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'host_name': {'type': 'string'}, - 'service': {'type': 'string'}, - 'zone': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['host_name', 'service', 'zone'] - } - } - }, - 'additionalProperties': False, - 'required': ['hosts'] - } -} - -get_host_detail = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'host': { - 'type': 'array', - 'item': { - 'type': 'object', - 'properties': { - 'resource': { - 'type': 'object', - 'properties': { - 'cpu': {'type': 'integer'}, - 'disk_gb': {'type': 'integer'}, - 'host': {'type': 'string'}, - 'memory_mb': {'type': 'integer'}, - 'project': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['cpu', 'disk_gb', 'host', - 'memory_mb', 'project'] - } - }, - 'additionalProperties': False, - 'required': ['resource'] - } - } - }, - 'additionalProperties': False, - 'required': ['host'] - } -} - -startup_host = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'host': {'type': 'string'}, - 'power_action': {'enum': ['startup']} - }, - 'additionalProperties': False, - 'required': ['host', 'power_action'] - } -} - -# The 'power_action' attribute of 'shutdown_host' API is 'shutdown' -shutdown_host = copy.deepcopy(startup_host) - -shutdown_host['response_body']['properties']['power_action'] = { - 'enum': ['shutdown'] -} - -# The 'power_action' attribute of 'reboot_host' API is 'reboot' -reboot_host = copy.deepcopy(startup_host) - -reboot_host['response_body']['properties']['power_action'] = { - 'enum': ['reboot'] -} - -update_host = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'host': {'type': 'string'}, - 'maintenance_mode': {'enum': ['on_maintenance', - 'off_maintenance']}, - 'status': {'enum': ['enabled', 'disabled']} - }, - 'additionalProperties': False, - 'anyOf': [ - {'required': ['host', 'status']}, - {'required': ['host', 'maintenance_mode']} - ] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/hypervisors.py b/tempest/lib/api_schema/response/compute/v2_1/hypervisors.py deleted file mode 100644 index d15b4f66a..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/hypervisors.py +++ /dev/null @@ -1,195 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -get_hypervisor_statistics = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hypervisor_statistics': { - 'type': 'object', - 'properties': { - 'count': {'type': 'integer'}, - 'current_workload': {'type': 'integer'}, - 'disk_available_least': {'type': ['integer', 'null']}, - 'free_disk_gb': {'type': 'integer'}, - 'free_ram_mb': {'type': 'integer'}, - 'local_gb': {'type': 'integer'}, - 'local_gb_used': {'type': 'integer'}, - 'memory_mb': {'type': 'integer'}, - 'memory_mb_used': {'type': 'integer'}, - 'running_vms': {'type': 'integer'}, - 'vcpus': {'type': 'integer'}, - 'vcpus_used': {'type': 'integer'} - }, - 'additionalProperties': False, - 'required': ['count', 'current_workload', - 'disk_available_least', 'free_disk_gb', - 'free_ram_mb', 'local_gb', 'local_gb_used', - 'memory_mb', 'memory_mb_used', 'running_vms', - 'vcpus', 'vcpus_used'] - } - }, - 'additionalProperties': False, - 'required': ['hypervisor_statistics'] - } -} - - -hypervisor_detail = { - 'type': 'object', - 'properties': { - 'status': {'type': 'string'}, - 'state': {'type': 'string'}, - 'cpu_info': {'type': 'string'}, - 'current_workload': {'type': 'integer'}, - 'disk_available_least': {'type': ['integer', 'null']}, - 'host_ip': parameter_types.ip_address, - 'free_disk_gb': {'type': 'integer'}, - 'free_ram_mb': {'type': 'integer'}, - 'hypervisor_hostname': {'type': 'string'}, - 'hypervisor_type': {'type': 'string'}, - 'hypervisor_version': {'type': 'integer'}, - 'id': {'type': ['integer', 'string']}, - 'local_gb': {'type': 'integer'}, - 'local_gb_used': {'type': 'integer'}, - 'memory_mb': {'type': 'integer'}, - 'memory_mb_used': {'type': 'integer'}, - 'running_vms': {'type': 'integer'}, - 'service': { - 'type': 'object', - 'properties': { - 'host': {'type': 'string'}, - 'id': {'type': ['integer', 'string']}, - 'disabled_reason': {'type': ['string', 'null']} - }, - 'additionalProperties': False, - 'required': ['host', 'id'] - }, - 'vcpus': {'type': 'integer'}, - 'vcpus_used': {'type': 'integer'} - }, - 'additionalProperties': False, - # NOTE: When loading os-hypervisor-status extension, - # a response contains status and state. So these params - # should not be required. - 'required': ['cpu_info', 'current_workload', - 'disk_available_least', 'host_ip', - 'free_disk_gb', 'free_ram_mb', - 'hypervisor_hostname', 'hypervisor_type', - 'hypervisor_version', 'id', 'local_gb', - 'local_gb_used', 'memory_mb', 'memory_mb_used', - 'running_vms', 'service', 'vcpus', 'vcpus_used'] -} - -list_hypervisors_detail = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hypervisors': { - 'type': 'array', - 'items': hypervisor_detail - } - }, - 'additionalProperties': False, - 'required': ['hypervisors'] - } -} - -get_hypervisor = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hypervisor': hypervisor_detail - }, - 'additionalProperties': False, - 'required': ['hypervisor'] - } -} - -list_search_hypervisors = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hypervisors': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'status': {'type': 'string'}, - 'state': {'type': 'string'}, - 'id': {'type': ['integer', 'string']}, - 'hypervisor_hostname': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE: When loading os-hypervisor-status extension, - # a response contains status and state. So these params - # should not be required. - 'required': ['id', 'hypervisor_hostname'] - } - } - }, - 'additionalProperties': False, - 'required': ['hypervisors'] - } -} - -get_hypervisor_uptime = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hypervisor': { - 'type': 'object', - 'properties': { - 'status': {'type': 'string'}, - 'state': {'type': 'string'}, - 'id': {'type': ['integer', 'string']}, - 'hypervisor_hostname': {'type': 'string'}, - 'uptime': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE: When loading os-hypervisor-status extension, - # a response contains status and state. So these params - # should not be required. - 'required': ['id', 'hypervisor_hostname', 'uptime'] - } - }, - 'additionalProperties': False, - 'required': ['hypervisor'] - } -} - -get_hypervisors_servers = copy.deepcopy(list_search_hypervisors) -get_hypervisors_servers['response_body']['properties']['hypervisors']['items'][ - 'properties']['servers'] = { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'uuid': {'type': 'string'}, - 'name': {'type': 'string'} - }, - 'additionalProperties': False, - } - } -# In V2 API, if there is no servers (VM) on the Hypervisor host then 'servers' -# attribute will not be present in response body So it is not 'required'. diff --git a/tempest/lib/api_schema/response/compute/v2_1/images.py b/tempest/lib/api_schema/response/compute/v2_1/images.py deleted file mode 100644 index 156ff4ac6..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/images.py +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -image_links = copy.deepcopy(parameter_types.links) -image_links['items']['properties'].update({'type': {'type': 'string'}}) - -image_status_enums = ['ACTIVE', 'SAVING', 'DELETED', 'ERROR', 'UNKNOWN'] - -common_image_schema = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'status': {'enum': image_status_enums}, - 'updated': parameter_types.date_time, - 'links': image_links, - 'name': {'type': ['string', 'null']}, - 'created': parameter_types.date_time, - 'minDisk': {'type': 'integer'}, - 'minRam': {'type': 'integer'}, - 'progress': {'type': 'integer'}, - 'metadata': {'type': 'object'}, - 'server': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links'] - }, - 'OS-EXT-IMG-SIZE:size': {'type': ['integer', 'null']}, - 'OS-DCF:diskConfig': {'type': 'string'} - }, - 'additionalProperties': False, - # 'server' attributes only comes in response body if image is - # associated with any server. 'OS-EXT-IMG-SIZE:size' & 'OS-DCF:diskConfig' - # are API extension, So those are not defined as 'required'. - 'required': ['id', 'status', 'updated', 'links', 'name', - 'created', 'minDisk', 'minRam', 'progress', - 'metadata'] -} - -get_image = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'image': common_image_schema - }, - 'additionalProperties': False, - 'required': ['image'] - } -} - -list_images = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'images': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': image_links, - 'name': {'type': ['string', 'null']} - }, - 'additionalProperties': False, - 'required': ['id', 'links', 'name'] - } - }, - 'images_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): images_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['images'] - } -} - -create_image = { - 'status_code': [202], - 'response_header': { - 'type': 'object', - 'properties': parameter_types.response_header - } -} -create_image['response_header']['properties'].update( - {'location': { - 'type': 'string', - 'format': 'uri'} - } -) -create_image['response_header']['required'] = ['location'] - -delete = { - 'status_code': [204] -} - -image_metadata = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'metadata': {'type': 'object'} - }, - 'additionalProperties': False, - 'required': ['metadata'] - } -} - -image_meta_item = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'meta': {'type': 'object'} - }, - 'additionalProperties': False, - 'required': ['meta'] - } -} - -list_images_details = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'images': { - 'type': 'array', - 'items': common_image_schema - }, - 'images_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): images_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['images'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/instance_usage_audit_logs.py b/tempest/lib/api_schema/response/compute/v2_1/instance_usage_audit_logs.py deleted file mode 100644 index 15224c5a0..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/instance_usage_audit_logs.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -common_instance_usage_audit_log = { - 'type': 'object', - 'properties': { - 'hosts_not_run': { - 'type': 'array', - 'items': {'type': 'string'} - }, - 'log': { - 'type': 'object', - 'patternProperties': { - # NOTE: Here is a host name. - '^.+$': { - 'type': 'object', - 'properties': { - 'state': {'type': 'string'}, - 'instances': {'type': 'integer'}, - 'errors': {'type': 'integer'}, - 'message': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['state', 'instances', 'errors', 'message'] - } - } - }, - 'num_hosts': {'type': 'integer'}, - 'num_hosts_done': {'type': 'integer'}, - 'num_hosts_not_run': {'type': 'integer'}, - 'num_hosts_running': {'type': 'integer'}, - 'overall_status': {'type': 'string'}, - 'period_beginning': {'type': 'string'}, - 'period_ending': {'type': 'string'}, - 'total_errors': {'type': 'integer'}, - 'total_instances': {'type': 'integer'} - }, - 'additionalProperties': False, - 'required': ['hosts_not_run', 'log', 'num_hosts', 'num_hosts_done', - 'num_hosts_not_run', 'num_hosts_running', 'overall_status', - 'period_beginning', 'period_ending', 'total_errors', - 'total_instances'] -} - -get_instance_usage_audit_log = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'instance_usage_audit_log': common_instance_usage_audit_log - }, - 'additionalProperties': False, - 'required': ['instance_usage_audit_log'] - } -} - -list_instance_usage_audit_log = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'instance_usage_audit_logs': common_instance_usage_audit_log - }, - 'additionalProperties': False, - 'required': ['instance_usage_audit_logs'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/interfaces.py b/tempest/lib/api_schema/response/compute/v2_1/interfaces.py deleted file mode 100644 index 99847502c..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/interfaces.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -interface_common_info = { - 'type': 'object', - 'properties': { - 'port_state': {'type': 'string'}, - 'fixed_ips': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'subnet_id': { - 'type': 'string', - 'format': 'uuid' - }, - 'ip_address': parameter_types.ip_address - }, - 'additionalProperties': False, - 'required': ['subnet_id', 'ip_address'] - } - }, - 'port_id': {'type': 'string', 'format': 'uuid'}, - 'net_id': {'type': 'string', 'format': 'uuid'}, - 'mac_addr': parameter_types.mac_address - }, - 'additionalProperties': False, - 'required': ['port_state', 'fixed_ips', 'port_id', 'net_id', 'mac_addr'] -} - -get_create_interfaces = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'interfaceAttachment': interface_common_info - }, - 'additionalProperties': False, - 'required': ['interfaceAttachment'] - } -} - -list_interfaces = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'interfaceAttachments': { - 'type': 'array', - 'items': interface_common_info - } - }, - 'additionalProperties': False, - 'required': ['interfaceAttachments'] - } -} - -delete_interface = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/keypairs.py b/tempest/lib/api_schema/response/compute/v2_1/keypairs.py deleted file mode 100644 index e7dcf791d..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/keypairs.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -get_keypair = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'keypair': { - 'type': 'object', - 'properties': { - 'public_key': {'type': 'string'}, - 'name': {'type': 'string'}, - 'fingerprint': {'type': 'string'}, - 'user_id': {'type': 'string'}, - 'deleted': {'type': 'boolean'}, - 'created_at': parameter_types.date_time, - 'updated_at': parameter_types.date_time_or_null, - 'deleted_at': parameter_types.date_time_or_null, - 'id': {'type': 'integer'} - - }, - 'additionalProperties': False, - 'required': ['public_key', 'name', 'fingerprint', 'user_id', - 'deleted', 'created_at', 'updated_at', - 'deleted_at', 'id'] - } - }, - 'additionalProperties': False, - 'required': ['keypair'] - } -} - -create_keypair = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'keypair': { - 'type': 'object', - 'properties': { - 'fingerprint': {'type': 'string'}, - 'name': {'type': 'string'}, - 'public_key': {'type': 'string'}, - 'user_id': {'type': 'string'}, - 'private_key': {'type': 'string'} - }, - 'additionalProperties': False, - # When create keypair API is being called with 'Public key' - # (Importing keypair) then, response body does not contain - # 'private_key' So it is not defined as 'required' - 'required': ['fingerprint', 'name', 'public_key', 'user_id'] - } - }, - 'additionalProperties': False, - 'required': ['keypair'] - } -} - -delete_keypair = { - 'status_code': [202], -} - -list_keypairs = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'keypairs': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'keypair': { - 'type': 'object', - 'properties': { - 'public_key': {'type': 'string'}, - 'name': {'type': 'string'}, - 'fingerprint': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['public_key', 'name', 'fingerprint'] - } - }, - 'additionalProperties': False, - 'required': ['keypair'] - } - } - }, - 'additionalProperties': False, - 'required': ['keypairs'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/limits.py b/tempest/lib/api_schema/response/compute/v2_1/limits.py deleted file mode 100644 index 81f175fa7..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/limits.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -get_limit = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'limits': { - 'type': 'object', - 'properties': { - 'absolute': { - 'type': 'object', - 'properties': { - 'maxTotalRAMSize': {'type': 'integer'}, - 'totalCoresUsed': {'type': 'integer'}, - 'maxTotalInstances': {'type': 'integer'}, - 'maxTotalFloatingIps': {'type': 'integer'}, - 'totalSecurityGroupsUsed': {'type': 'integer'}, - 'maxTotalCores': {'type': 'integer'}, - 'totalFloatingIpsUsed': {'type': 'integer'}, - 'maxSecurityGroups': {'type': 'integer'}, - 'maxServerMeta': {'type': 'integer'}, - 'maxPersonality': {'type': 'integer'}, - 'maxImageMeta': {'type': 'integer'}, - 'maxPersonalitySize': {'type': 'integer'}, - 'maxSecurityGroupRules': {'type': 'integer'}, - 'maxTotalKeypairs': {'type': 'integer'}, - 'totalRAMUsed': {'type': 'integer'}, - 'totalInstancesUsed': {'type': 'integer'}, - 'maxServerGroupMembers': {'type': 'integer'}, - 'maxServerGroups': {'type': 'integer'}, - 'totalServerGroupsUsed': {'type': 'integer'} - }, - 'additionalProperties': False, - # NOTE(gmann): maxServerGroupMembers, maxServerGroups - # and totalServerGroupsUsed are API extension, - # and some environments return a response without these - # attributes.So they are not 'required'. - 'required': ['maxImageMeta', - 'maxPersonality', - 'maxPersonalitySize', - 'maxSecurityGroupRules', - 'maxSecurityGroups', - 'maxServerMeta', - 'maxTotalCores', - 'maxTotalFloatingIps', - 'maxTotalInstances', - 'maxTotalKeypairs', - 'maxTotalRAMSize', - 'totalCoresUsed', - 'totalFloatingIpsUsed', - 'totalInstancesUsed', - 'totalRAMUsed', - 'totalSecurityGroupsUsed'] - }, - 'rate': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'limit': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'next-available': - {'type': 'string'}, - 'remaining': - {'type': 'integer'}, - 'unit': - {'type': 'string'}, - 'value': - {'type': 'integer'}, - 'verb': - {'type': 'string'} - }, - 'additionalProperties': False, - } - }, - 'regex': {'type': 'string'}, - 'uri': {'type': 'string'} - }, - 'additionalProperties': False, - } - } - }, - 'additionalProperties': False, - 'required': ['absolute', 'rate'] - } - }, - 'additionalProperties': False, - 'required': ['limits'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/migrations.py b/tempest/lib/api_schema/response/compute/v2_1/migrations.py deleted file mode 100644 index c50286d27..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/migrations.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -list_migrations = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'migrations': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'status': {'type': ['string', 'null']}, - 'instance_uuid': {'type': ['string', 'null']}, - 'source_node': {'type': ['string', 'null']}, - 'source_compute': {'type': ['string', 'null']}, - 'dest_node': {'type': ['string', 'null']}, - 'dest_compute': {'type': ['string', 'null']}, - 'dest_host': {'type': ['string', 'null']}, - 'old_instance_type_id': {'type': ['integer', 'null']}, - 'new_instance_type_id': {'type': ['integer', 'null']}, - 'created_at': parameter_types.date_time, - 'updated_at': parameter_types.date_time_or_null - }, - 'additionalProperties': False, - 'required': [ - 'id', 'status', 'instance_uuid', 'source_node', - 'source_compute', 'dest_node', 'dest_compute', - 'dest_host', 'old_instance_type_id', - 'new_instance_type_id', 'created_at', 'updated_at' - ] - } - } - }, - 'additionalProperties': False, - 'required': ['migrations'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py b/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py deleted file mode 100644 index a3c9099ea..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -links = { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'href': { - 'type': 'string', - 'format': 'uri' - }, - 'rel': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['href', 'rel'] - } -} - -mac_address = { - 'type': 'string', - 'pattern': '(?:[a-f0-9]{2}:){5}[a-f0-9]{2}' -} - -ip_address = { - 'oneOf': [ - { - 'type': 'string', - 'oneOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - }, - {'type': 'null'} - ] -} - -access_ip_v4 = { - 'type': 'string', - 'oneOf': [{'format': 'ipv4'}, {'enum': ['']}] -} - -access_ip_v6 = { - 'type': 'string', - 'oneOf': [{'format': 'ipv6'}, {'enum': ['']}] -} - -addresses = { - 'type': 'object', - 'patternProperties': { - # NOTE: Here is for 'private' or something. - '^[a-zA-Z0-9-_.]+$': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'version': {'type': 'integer'}, - 'addr': { - 'type': 'string', - 'oneOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - } - }, - 'additionalProperties': False, - 'required': ['version', 'addr'] - } - } - } -} - -date_time = { - 'type': 'string', - 'format': 'iso8601-date-time' -} - -date_time_or_null = { - 'type': ['string', 'null'], - 'format': 'iso8601-date-time' -} - -response_header = { - 'connection': {'type': 'string'}, - 'content-length': {'type': 'string'}, - 'content-type': {'type': 'string'}, - 'status': {'type': 'string'}, - 'x-compute-request-id': {'type': 'string'}, - 'vary': {'type': 'string'}, - 'x-openstack-nova-api-version': {'type': 'string'}, - # NOTE(gmann): Validating this as string only as this - # date in header is returned in different format than - # ISO 8601 date time format which is not consistent with - # other date-time format in nova. - # This API is already deprecated so not worth to fix - # on nova side. - 'date': { - 'type': 'string' - } -} - -power_state = { - 'type': 'integer', - # 0: NOSTATE - # 1: RUNNING - # 3: PAUSED - # 4: SHUTDOWN - # 6: CRASHED - # 7: SUSPENDED - 'enum': [0, 1, 3, 4, 6, 7] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/quota_classes.py b/tempest/lib/api_schema/response/compute/v2_1/quota_classes.py deleted file mode 100644 index 03d7f1281..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/quota_classes.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2014 IBM Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import quotas - -# NOTE(mriedem): os-quota-class-sets responses are the same as os-quota-sets -# except for the key in the response body is quota_class_set instead of -# quota_set, so update this copy of the schema from os-quota-sets. -get_quota_class_set = copy.deepcopy(quotas.get_quota_set) -get_quota_class_set['response_body']['properties']['quota_class_set'] = ( - get_quota_class_set['response_body']['properties'].pop('quota_set')) -get_quota_class_set['response_body']['required'] = ['quota_class_set'] - -update_quota_class_set = copy.deepcopy(quotas.update_quota_set) -update_quota_class_set['response_body']['properties']['quota_class_set'] = ( - update_quota_class_set['response_body']['properties'].pop('quota_set')) -update_quota_class_set['response_body']['required'] = ['quota_class_set'] diff --git a/tempest/lib/api_schema/response/compute/v2_1/quotas.py b/tempest/lib/api_schema/response/compute/v2_1/quotas.py deleted file mode 100644 index 44f5bdfd2..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/quotas.py +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -update_quota_set = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'quota_set': { - 'type': 'object', - 'properties': { - 'instances': {'type': 'integer'}, - 'cores': {'type': 'integer'}, - 'ram': {'type': 'integer'}, - 'floating_ips': {'type': 'integer'}, - 'fixed_ips': {'type': 'integer'}, - 'metadata_items': {'type': 'integer'}, - 'key_pairs': {'type': 'integer'}, - 'security_groups': {'type': 'integer'}, - 'security_group_rules': {'type': 'integer'}, - 'server_group_members': {'type': 'integer'}, - 'server_groups': {'type': 'integer'}, - 'injected_files': {'type': 'integer'}, - 'injected_file_content_bytes': {'type': 'integer'}, - 'injected_file_path_bytes': {'type': 'integer'} - }, - 'additionalProperties': False, - # NOTE: server_group_members and server_groups are represented - # when enabling quota_server_group extension. So they should - # not be required. - 'required': ['instances', 'cores', 'ram', - 'floating_ips', 'fixed_ips', - 'metadata_items', 'key_pairs', - 'security_groups', 'security_group_rules', - 'injected_files', 'injected_file_content_bytes', - 'injected_file_path_bytes'] - } - }, - 'additionalProperties': False, - 'required': ['quota_set'] - } -} - -get_quota_set = copy.deepcopy(update_quota_set) -get_quota_set['response_body']['properties']['quota_set']['properties'][ - 'id'] = {'type': 'string'} -get_quota_set['response_body']['properties']['quota_set']['required'].extend([ - 'id']) - -get_quota_set_details = copy.deepcopy(get_quota_set) -get_quota_set_details['response_body']['properties']['quota_set'][ - 'properties'] = { - 'id': {'type': 'string'}, - 'instances': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'cores': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'ram': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'floating_ips': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'fixed_ips': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'metadata_items': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'key_pairs': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'security_groups': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'security_group_rules': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'server_group_members': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'server_groups': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'injected_files': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'injected_file_content_bytes': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'injected_file_path_bytes': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - } -} - -delete_quota = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/security_group_default_rule.py b/tempest/lib/api_schema/response/compute/v2_1/security_group_default_rule.py deleted file mode 100644 index 2ec282698..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/security_group_default_rule.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -common_security_group_default_rule_info = { - 'type': 'object', - 'properties': { - 'from_port': {'type': 'integer'}, - 'id': {'type': 'integer'}, - 'ip_protocol': {'type': 'string'}, - 'ip_range': { - 'type': 'object', - 'properties': { - 'cidr': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['cidr'], - }, - 'to_port': {'type': 'integer'}, - }, - 'additionalProperties': False, - 'required': ['from_port', 'id', 'ip_protocol', 'ip_range', 'to_port'], -} - -create_get_security_group_default_rule = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'security_group_default_rule': - common_security_group_default_rule_info - }, - 'additionalProperties': False, - 'required': ['security_group_default_rule'] - } -} - -delete_security_group_default_rule = { - 'status_code': [204] -} - -list_security_group_default_rules = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'security_group_default_rules': { - 'type': 'array', - 'items': common_security_group_default_rule_info - } - }, - 'additionalProperties': False, - 'required': ['security_group_default_rules'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/security_groups.py b/tempest/lib/api_schema/response/compute/v2_1/security_groups.py deleted file mode 100644 index 5ed5a5c80..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/security_groups.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -common_security_group_rule = { - 'from_port': {'type': ['integer', 'null']}, - 'to_port': {'type': ['integer', 'null']}, - 'group': { - 'type': 'object', - 'properties': { - 'tenant_id': {'type': 'string'}, - 'name': {'type': 'string'} - }, - 'additionalProperties': False, - }, - 'ip_protocol': {'type': ['string', 'null']}, - # 'parent_group_id' can be UUID so defining it as 'string' also. - 'parent_group_id': {'type': ['string', 'integer', 'null']}, - 'ip_range': { - 'type': 'object', - 'properties': { - 'cidr': {'type': 'string'} - }, - 'additionalProperties': False, - # When optional argument is provided in request body - # like 'group_id' then, attribute 'cidr' does not - # comes in response body. So it is not 'required'. - }, - 'id': {'type': ['string', 'integer']} -} - -common_security_group = { - 'type': 'object', - 'properties': { - 'id': {'type': ['integer', 'string']}, - 'name': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - 'rules': { - 'type': 'array', - 'items': { - 'type': ['object', 'null'], - 'properties': common_security_group_rule, - 'additionalProperties': False, - } - }, - 'description': {'type': 'string'}, - }, - 'additionalProperties': False, - 'required': ['id', 'name', 'tenant_id', 'rules', 'description'], -} - -list_security_groups = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'security_groups': { - 'type': 'array', - 'items': common_security_group - } - }, - 'additionalProperties': False, - 'required': ['security_groups'] - } -} - -get_security_group = create_security_group = update_security_group = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'security_group': common_security_group - }, - 'additionalProperties': False, - 'required': ['security_group'] - } -} - -delete_security_group = { - 'status_code': [202] -} - -create_security_group_rule = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'security_group_rule': { - 'type': 'object', - 'properties': common_security_group_rule, - 'additionalProperties': False, - 'required': ['from_port', 'to_port', 'group', 'ip_protocol', - 'parent_group_id', 'id', 'ip_range'] - } - }, - 'additionalProperties': False, - 'required': ['security_group_rule'] - } -} - -delete_security_group_rule = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/servers.py b/tempest/lib/api_schema/response/compute/v2_1/servers.py deleted file mode 100644 index 2954de005..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/servers.py +++ /dev/null @@ -1,596 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -create_server = { - 'status_code': [202], - 'response_body': { - 'type': 'object', - 'properties': { - 'server': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'security_groups': {'type': 'array'}, - 'links': parameter_types.links, - 'OS-DCF:diskConfig': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE: OS-DCF:diskConfig & security_groups are API extension, - # and some environments return a response without these - # attributes.So they are not 'required'. - 'required': ['id', 'links'] - } - }, - 'additionalProperties': False, - 'required': ['server'] - } -} - -create_server_with_admin_pass = copy.deepcopy(create_server) -create_server_with_admin_pass['response_body']['properties']['server'][ - 'properties'].update({'adminPass': {'type': 'string'}}) -create_server_with_admin_pass['response_body']['properties']['server'][ - 'required'].append('adminPass') - -list_servers = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'servers': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links, - 'name': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['id', 'links', 'name'] - } - }, - 'servers_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): servers_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['servers'] - } -} - -delete_server = { - 'status_code': [204], -} - -common_show_server = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'name': {'type': 'string'}, - 'status': {'type': 'string'}, - 'image': {'oneOf': [ - {'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links']}, - {'type': ['string', 'null']} - ]}, - 'flavor': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - # NOTE(gmann): This will be empty object if there is no - # flavor info present in DB. This can happen when flavor info is - # deleted after server creation. - 'additionalProperties': False - }, - 'fault': { - 'type': 'object', - 'properties': { - 'code': {'type': 'integer'}, - 'created': {'type': 'string'}, - 'message': {'type': 'string'}, - 'details': {'type': 'string'}, - }, - 'additionalProperties': False, - # NOTE(gmann): 'details' is not necessary to be present - # in the 'fault'. So it is not defined as 'required'. - 'required': ['code', 'created', 'message'] - }, - 'user_id': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - 'created': parameter_types.date_time, - 'updated': parameter_types.date_time, - 'progress': {'type': 'integer'}, - 'metadata': {'type': 'object'}, - 'links': parameter_types.links, - 'addresses': parameter_types.addresses, - 'hostId': {'type': 'string'}, - 'OS-DCF:diskConfig': {'type': 'string'}, - 'accessIPv4': parameter_types.access_ip_v4, - 'accessIPv6': parameter_types.access_ip_v6 - }, - 'additionalProperties': False, - # NOTE(GMann): 'progress' attribute is present in the response - # only when server's status is one of the progress statuses - # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE") - # 'fault' attribute is present in the response - # only when server's status is one of the "ERROR", "DELETED". - # OS-DCF:diskConfig and accessIPv4/v6 are API - # extensions, and some environments return a response - # without these attributes.So these are not defined as 'required'. - 'required': ['id', 'name', 'status', 'image', 'flavor', - 'user_id', 'tenant_id', 'created', 'updated', - 'metadata', 'links', 'addresses', 'hostId'] -} - -update_server = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server': common_show_server - }, - 'additionalProperties': False, - 'required': ['server'] - } -} - -server_detail = copy.deepcopy(common_show_server) -server_detail['properties'].update({ - 'key_name': {'type': ['string', 'null']}, - 'security_groups': {'type': 'array'}, - - # NOTE: Non-admin users also can see "OS-SRV-USG" and "OS-EXT-AZ" - # attributes. - 'OS-SRV-USG:launched_at': {'type': ['string', 'null']}, - 'OS-SRV-USG:terminated_at': {'type': ['string', 'null']}, - 'OS-EXT-AZ:availability_zone': {'type': 'string'}, - - # NOTE: Admin users only can see "OS-EXT-STS" and "OS-EXT-SRV-ATTR" - # attributes. - 'OS-EXT-STS:task_state': {'type': ['string', 'null']}, - 'OS-EXT-STS:vm_state': {'type': 'string'}, - 'OS-EXT-STS:power_state': parameter_types.power_state, - 'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'}, - 'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']}, - 'os-extended-volumes:volumes_attached': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'} - }, - 'additionalProperties': False, - }, - }, - 'config_drive': {'type': 'string'} -}) -server_detail['properties']['addresses']['patternProperties'][ - '^[a-zA-Z0-9-_.]+$']['items']['properties'].update({ - 'OS-EXT-IPS:type': {'type': 'string'}, - 'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address}) -# NOTE(gmann): Update OS-EXT-IPS:type and OS-EXT-IPS-MAC:mac_addr -# attributes in server address. Those are API extension, -# and some environments return a response without -# these attributes. So they are not 'required'. - -get_server = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server': server_detail - }, - 'additionalProperties': False, - 'required': ['server'] - } -} - -list_servers_detail = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'servers': { - 'type': 'array', - 'items': server_detail - }, - 'servers_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): servers_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['servers'] - } -} - -rebuild_server = copy.deepcopy(update_server) -rebuild_server['status_code'] = [202] - -rebuild_server_with_admin_pass = copy.deepcopy(rebuild_server) -rebuild_server_with_admin_pass['response_body']['properties']['server'][ - 'properties'].update({'adminPass': {'type': 'string'}}) -rebuild_server_with_admin_pass['response_body']['properties']['server'][ - 'required'].append('adminPass') - -rescue_server = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'additionalProperties': False, - } -} - -rescue_server_with_admin_pass = copy.deepcopy(rescue_server) -rescue_server_with_admin_pass['response_body'].update( - {'properties': {'adminPass': {'type': 'string'}}}) -rescue_server_with_admin_pass['response_body'].update( - {'required': ['adminPass']}) - - -list_virtual_interfaces = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'virtual_interfaces': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'mac_address': parameter_types.mac_address, - 'OS-EXT-VIF-NET:net_id': {'type': 'string'} - }, - 'additionalProperties': False, - # 'OS-EXT-VIF-NET:net_id' is API extension So it is - # not defined as 'required' - 'required': ['id', 'mac_address'] - } - } - }, - 'additionalProperties': False, - 'required': ['virtual_interfaces'] - } -} - -common_attach_volume_info = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'device': {'type': ['string', 'null']}, - 'volumeId': {'type': 'string'}, - 'serverId': {'type': ['integer', 'string']} - }, - 'additionalProperties': False, - # 'device' is optional in response. - 'required': ['id', 'volumeId', 'serverId'] -} - -attach_volume = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'volumeAttachment': common_attach_volume_info - }, - 'additionalProperties': False, - 'required': ['volumeAttachment'] - } -} - -detach_volume = { - 'status_code': [202] -} - -show_volume_attachment = copy.deepcopy(attach_volume) -show_volume_attachment['response_body']['properties'][ - 'volumeAttachment']['properties'].update({'serverId': {'type': 'string'}}) - -list_volume_attachments = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'volumeAttachments': { - 'type': 'array', - 'items': common_attach_volume_info - } - }, - 'additionalProperties': False, - 'required': ['volumeAttachments'] - } -} -list_volume_attachments['response_body']['properties'][ - 'volumeAttachments']['items']['properties'].update( - {'serverId': {'type': 'string'}}) - -list_addresses_by_network = { - 'status_code': [200], - 'response_body': parameter_types.addresses -} - -list_addresses = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'addresses': parameter_types.addresses - }, - 'additionalProperties': False, - 'required': ['addresses'] - } -} - -common_server_group = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'name': {'type': 'string'}, - 'policies': { - 'type': 'array', - 'items': {'type': 'string'} - }, - # 'members' attribute contains the array of instance's UUID of - # instances present in server group - 'members': { - 'type': 'array', - 'items': {'type': 'string'} - }, - 'metadata': {'type': 'object'} - }, - 'additionalProperties': False, - 'required': ['id', 'name', 'policies', 'members', 'metadata'] -} - -create_show_server_group = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server_group': common_server_group - }, - 'additionalProperties': False, - 'required': ['server_group'] - } -} - -delete_server_group = { - 'status_code': [204] -} - -list_server_groups = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server_groups': { - 'type': 'array', - 'items': common_server_group - } - }, - 'additionalProperties': False, - 'required': ['server_groups'] - } -} - -instance_actions = { - 'type': 'object', - 'properties': { - 'action': {'type': 'string'}, - 'request_id': {'type': 'string'}, - 'user_id': {'type': 'string'}, - 'project_id': {'type': 'string'}, - 'start_time': parameter_types.date_time, - 'message': {'type': ['string', 'null']}, - 'instance_uuid': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['action', 'request_id', 'user_id', 'project_id', - 'start_time', 'message', 'instance_uuid'] -} - -instance_action_events = { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'event': {'type': 'string'}, - 'start_time': parameter_types.date_time, - # The finish_time, result and optionally traceback are all - # possibly None (null) until the event is actually finished. - # The traceback would only be set if there was an error, but - # when the event is complete both finish_time and result will - # be set. - 'finish_time': parameter_types.date_time_or_null, - 'result': {'type': ['string', 'null']}, - 'traceback': {'type': ['string', 'null']} - }, - 'additionalProperties': False, - 'required': ['event', 'start_time', 'finish_time', 'result', - 'traceback'] - } -} - -list_instance_actions = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'instanceActions': { - 'type': 'array', - 'items': instance_actions - } - }, - 'additionalProperties': False, - 'required': ['instanceActions'] - } -} - -instance_actions_with_events = copy.deepcopy(instance_actions) -instance_actions_with_events['properties'].update({ - 'events': instance_action_events}) -# 'events' does not come in response body always so it is not -# defined as 'required' - -show_instance_action = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'instanceAction': instance_actions_with_events - }, - 'additionalProperties': False, - 'required': ['instanceAction'] - } -} - -show_password = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'password': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['password'] - } -} - -get_vnc_console = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'console': { - 'type': 'object', - 'properties': { - 'type': {'type': 'string'}, - 'url': { - 'type': 'string', - 'format': 'uri' - } - }, - 'additionalProperties': False, - 'required': ['type', 'url'] - } - }, - 'additionalProperties': False, - 'required': ['console'] - } -} - -get_console_output = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'output': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['output'] - } -} - -set_server_metadata = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'metadata': { - 'type': 'object', - 'patternProperties': { - '^.+$': {'type': 'string'} - } - } - }, - 'additionalProperties': False, - 'required': ['metadata'] - } -} - -list_server_metadata = copy.deepcopy(set_server_metadata) - -update_server_metadata = copy.deepcopy(set_server_metadata) - -delete_server_metadata_item = { - 'status_code': [204] -} - -set_show_server_metadata_item = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'meta': { - 'type': 'object', - 'patternProperties': { - '^.+$': {'type': 'string'} - } - } - }, - 'additionalProperties': False, - 'required': ['meta'] - } -} - -server_actions_common_schema = { - 'status_code': [202] -} - -server_actions_delete_password = { - 'status_code': [204] -} - -server_actions_confirm_resize = copy.deepcopy( - server_actions_delete_password) - -update_attached_volume = { - 'status_code': [202] -} - -evacuate_server = { - 'status_code': [200] -} - -evacuate_server_with_admin_pass = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'adminPass': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['adminPass'] - } -} - -show_server_diagnostics = { - 'status_code': [200], - 'response_body': { - 'type': 'object' - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/services.py b/tempest/lib/api_schema/response/compute/v2_1/services.py deleted file mode 100644 index 3b58ece48..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/services.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -list_services = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'services': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': ['integer', 'string'], - 'pattern': '^[a-zA-Z!]*@[0-9]+$'}, - 'zone': {'type': 'string'}, - 'host': {'type': 'string'}, - 'state': {'type': 'string'}, - 'binary': {'type': 'string'}, - 'status': {'type': 'string'}, - 'updated_at': parameter_types.date_time_or_null, - 'disabled_reason': {'type': ['string', 'null']} - }, - 'additionalProperties': False, - 'required': ['id', 'zone', 'host', 'state', 'binary', - 'status', 'updated_at', 'disabled_reason'] - } - } - }, - 'additionalProperties': False, - 'required': ['services'] - } -} - -enable_disable_service = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'service': { - 'type': 'object', - 'properties': { - 'status': {'type': 'string'}, - 'binary': {'type': 'string'}, - 'host': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['status', 'binary', 'host'] - } - }, - 'additionalProperties': False, - 'required': ['service'] - } -} - -disable_log_reason = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'service': { - 'type': 'object', - 'properties': { - 'disabled_reason': {'type': 'string'}, - 'binary': {'type': 'string'}, - 'host': {'type': 'string'}, - 'status': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['disabled_reason', 'binary', 'host', 'status'] - } - }, - 'additionalProperties': False, - 'required': ['service'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/snapshots.py b/tempest/lib/api_schema/response/compute/v2_1/snapshots.py deleted file mode 100644 index 826f85413..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/snapshots.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2015 Fujitsu(fnst) Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -common_snapshot_info = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'volumeId': {'type': 'string'}, - 'status': {'type': 'string'}, - 'size': {'type': 'integer'}, - 'createdAt': parameter_types.date_time, - 'displayName': {'type': ['string', 'null']}, - 'displayDescription': {'type': ['string', 'null']} - }, - 'additionalProperties': False, - 'required': ['id', 'volumeId', 'status', 'size', - 'createdAt', 'displayName', 'displayDescription'] -} - -create_get_snapshot = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'snapshot': common_snapshot_info - }, - 'additionalProperties': False, - 'required': ['snapshot'] - } -} - -list_snapshots = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'snapshots': { - 'type': 'array', - 'items': common_snapshot_info - } - }, - 'additionalProperties': False, - 'required': ['snapshots'] - } -} - -delete_snapshot = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/tenant_networks.py b/tempest/lib/api_schema/response/compute/v2_1/tenant_networks.py deleted file mode 100644 index ddfab9619..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/tenant_networks.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -param_network = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'cidr': {'type': ['string', 'null']}, - 'label': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['id', 'cidr', 'label'] -} - - -list_tenant_networks = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'networks': { - 'type': 'array', - 'items': param_network - } - }, - 'additionalProperties': False, - 'required': ['networks'] - } -} - - -get_tenant_network = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'network': param_network - }, - 'additionalProperties': False, - 'required': ['network'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py b/tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py deleted file mode 100644 index b531d2e75..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -_server_usages = { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'ended_at': parameter_types.date_time_or_null, - 'flavor': {'type': 'string'}, - 'hours': {'type': 'number'}, - 'instance_id': {'type': 'string'}, - 'local_gb': {'type': 'integer'}, - 'memory_mb': {'type': 'integer'}, - 'name': {'type': 'string'}, - 'started_at': parameter_types.date_time, - 'state': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - 'uptime': {'type': 'integer'}, - 'vcpus': {'type': 'integer'}, - }, - 'required': ['ended_at', 'flavor', 'hours', 'instance_id', 'local_gb', - 'memory_mb', 'name', 'started_at', 'state', 'tenant_id', - 'uptime', 'vcpus'] - } -} - -_tenant_usage_list = { - 'type': 'object', - 'properties': { - 'server_usages': _server_usages, - 'start': parameter_types.date_time, - 'stop': parameter_types.date_time, - 'tenant_id': {'type': 'string'}, - 'total_hours': {'type': 'number'}, - 'total_local_gb_usage': {'type': 'number'}, - 'total_memory_mb_usage': {'type': 'number'}, - 'total_vcpus_usage': {'type': 'number'}, - }, - 'required': ['start', 'stop', 'tenant_id', - 'total_hours', 'total_local_gb_usage', - 'total_memory_mb_usage', 'total_vcpus_usage'] -} - -# 'required' of get_tenant is different from list_tenant's. -_tenant_usage_get = copy.deepcopy(_tenant_usage_list) -_tenant_usage_get['required'] = ['server_usages', 'start', 'stop', 'tenant_id', - 'total_hours', 'total_local_gb_usage', - 'total_memory_mb_usage', 'total_vcpus_usage'] - -list_tenant_usage = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'tenant_usages': { - 'type': 'array', - 'items': _tenant_usage_list - } - }, - 'required': ['tenant_usages'] - } -} - -get_tenant_usage = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'tenant_usage': _tenant_usage_get - }, - 'required': ['tenant_usage'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/versions.py b/tempest/lib/api_schema/response/compute/v2_1/versions.py deleted file mode 100644 index 7f5623928..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/versions.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - - -_version = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'href': {'type': 'string', 'format': 'uri'}, - 'rel': {'type': 'string'}, - 'type': {'type': 'string'}, - }, - 'required': ['href', 'rel'], - 'additionalProperties': False - } - }, - 'status': {'type': 'string'}, - 'updated': parameter_types.date_time, - 'version': {'type': 'string'}, - 'min_version': {'type': 'string'}, - 'media-types': { - 'type': 'array', - 'properties': { - 'base': {'type': 'string'}, - 'type': {'type': 'string'}, - } - }, - }, - # NOTE: version and min_version have been added since Kilo, - # so they should not be required. - # NOTE(sdague): media-types only shows up in single version requests. - 'required': ['id', 'links', 'status', 'updated'], - 'additionalProperties': False -} - -list_versions = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'versions': { - 'type': 'array', - 'items': _version - } - }, - 'required': ['versions'], - 'additionalProperties': False - } -} - - -_detail_get_version = copy.deepcopy(_version) -_detail_get_version['properties'].pop('min_version') -_detail_get_version['properties'].pop('version') -_detail_get_version['properties'].pop('updated') -_detail_get_version['properties']['media-types'] = { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'base': {'type': 'string'}, - 'type': {'type': 'string'} - } - } -} -_detail_get_version['required'] = ['id', 'links', 'status', 'media-types'] - -get_version = { - 'status_code': [300], - 'response_body': { - 'type': 'object', - 'properties': { - 'choices': { - 'type': 'array', - 'items': _detail_get_version - } - }, - 'required': ['choices'], - 'additionalProperties': False - } -} - -get_one_version = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'version': _version - }, - 'additionalProperties': False - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/volumes.py b/tempest/lib/api_schema/response/compute/v2_1/volumes.py deleted file mode 100644 index c35dae981..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/volumes.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -create_get_volume = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'volume': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'status': {'type': 'string'}, - 'displayName': {'type': ['string', 'null']}, - 'availabilityZone': {'type': 'string'}, - 'createdAt': parameter_types.date_time, - 'displayDescription': {'type': ['string', 'null']}, - 'volumeType': {'type': ['string', 'null']}, - 'snapshotId': {'type': ['string', 'null']}, - 'metadata': {'type': 'object'}, - 'size': {'type': 'integer'}, - 'attachments': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'device': {'type': 'string'}, - 'volumeId': {'type': 'string'}, - 'serverId': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE- If volume is not attached to any server - # then, 'attachments' attributes comes as array - # with empty objects "[{}]" due to that elements - # of 'attachments' cannot defined as 'required'. - # If it would come as empty array "[]" then, - # those elements can be defined as 'required'. - } - } - }, - 'additionalProperties': False, - 'required': ['id', 'status', 'displayName', 'availabilityZone', - 'createdAt', 'displayDescription', 'volumeType', - 'snapshotId', 'metadata', 'size', 'attachments'] - } - }, - 'additionalProperties': False, - 'required': ['volume'] - } -} - -list_volumes = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'volumes': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'status': {'type': 'string'}, - 'displayName': {'type': ['string', 'null']}, - 'availabilityZone': {'type': 'string'}, - 'createdAt': parameter_types.date_time, - 'displayDescription': {'type': ['string', 'null']}, - 'volumeType': {'type': ['string', 'null']}, - 'snapshotId': {'type': ['string', 'null']}, - 'metadata': {'type': 'object'}, - 'size': {'type': 'integer'}, - 'attachments': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'device': {'type': 'string'}, - 'volumeId': {'type': 'string'}, - 'serverId': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE- If volume is not attached to any server - # then, 'attachments' attributes comes as array - # with empty object "[{}]" due to that elements - # of 'attachments' cannot defined as 'required' - # If it would come as empty array "[]" then, - # those elements can be defined as 'required'. - } - } - }, - 'additionalProperties': False, - 'required': ['id', 'status', 'displayName', - 'availabilityZone', 'createdAt', - 'displayDescription', 'volumeType', - 'snapshotId', 'metadata', 'size', - 'attachments'] - } - } - }, - 'additionalProperties': False, - 'required': ['volumes'] - } -} - -delete_volume = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_11/__init__.py b/tempest/lib/api_schema/response/compute/v2_11/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_11/services.py b/tempest/lib/api_schema/response/compute/v2_11/services.py deleted file mode 100644 index 18b833bd2..000000000 --- a/tempest/lib/api_schema/response/compute/v2_11/services.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import services - - -list_services = copy.deepcopy(services.list_services) -list_services['response_body']['properties']['services']['items'][ - 'properties']['forced_down'] = {'type': 'boolean'} -list_services['response_body']['properties']['services']['items'][ - 'required'].append('forced_down') - -update_forced_down = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'service': { - 'type': 'object', - 'properties': { - 'binary': {'type': 'string'}, - 'host': {'type': 'string'}, - 'forced_down': {'type': 'boolean'} - }, - 'additionalProperties': False, - 'required': ['binary', 'host', 'forced_down'] - } - }, - 'additionalProperties': False, - 'required': ['service'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_13/__init__.py b/tempest/lib/api_schema/response/compute/v2_13/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_13/servers.py b/tempest/lib/api_schema/response/compute/v2_13/servers.py deleted file mode 100644 index a90f3e4f2..000000000 --- a/tempest/lib/api_schema/response/compute/v2_13/servers.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2017 NTT Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import servers - - -common_server_group = copy.deepcopy(servers.common_server_group) -common_server_group['properties']['project_id'] = {'type': 'string'} -common_server_group['properties']['user_id'] = {'type': 'string'} -common_server_group['required'].append('project_id') -common_server_group['required'].append('user_id') - -create_show_server_group = copy.deepcopy(servers.create_show_server_group) -create_show_server_group['response_body']['properties'][ - 'server_group'] = common_server_group - -delete_server_group = copy.deepcopy(servers.delete_server_group) - -list_server_groups = copy.deepcopy(servers.list_server_groups) -list_server_groups['response_body']['properties']['server_groups'][ - 'items'] = common_server_group diff --git a/tempest/lib/api_schema/response/compute/v2_16/__init__.py b/tempest/lib/api_schema/response/compute/v2_16/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_16/servers.py b/tempest/lib/api_schema/response/compute/v2_16/servers.py deleted file mode 100644 index 3eb658f4e..000000000 --- a/tempest/lib/api_schema/response/compute/v2_16/servers.py +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types -from tempest.lib.api_schema.response.compute.v2_9 import servers - -# Compute microversion 2.16: -# 1. New attributes in 'server' dict. -# 'host_status' - -server_detail = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'name': {'type': 'string'}, - 'status': {'type': 'string'}, - 'image': {'oneOf': [ - {'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links']}, - {'type': ['string', 'null']} - ]}, - 'flavor': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links'] - }, - 'fault': { - 'type': 'object', - 'properties': { - 'code': {'type': 'integer'}, - 'created': {'type': 'string'}, - 'message': {'type': 'string'}, - 'details': {'type': 'string'}, - }, - 'additionalProperties': False, - # NOTE(gmann): 'details' is not necessary to be present - # in the 'fault'. So it is not defined as 'required'. - 'required': ['code', 'created', 'message'] - }, - 'user_id': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - 'created': {'type': 'string'}, - 'updated': {'type': 'string'}, - 'progress': {'type': 'integer'}, - 'metadata': {'type': 'object'}, - 'links': parameter_types.links, - 'addresses': parameter_types.addresses, - 'hostId': {'type': 'string'}, - 'OS-DCF:diskConfig': {'type': 'string'}, - 'accessIPv4': parameter_types.access_ip_v4, - 'accessIPv6': parameter_types.access_ip_v6, - 'key_name': {'type': ['string', 'null']}, - 'security_groups': {'type': 'array'}, - 'OS-SRV-USG:launched_at': {'type': ['string', 'null']}, - 'OS-SRV-USG:terminated_at': {'type': ['string', 'null']}, - 'OS-EXT-AZ:availability_zone': {'type': 'string'}, - 'OS-EXT-STS:task_state': {'type': ['string', 'null']}, - 'OS-EXT-STS:vm_state': {'type': 'string'}, - 'OS-EXT-STS:power_state': parameter_types.power_state, - 'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'}, - 'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']}, - 'config_drive': {'type': 'string'}, - 'os-extended-volumes:volumes_attached': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'delete_on_termination': {'type': 'boolean'} - }, - 'additionalProperties': False, - }, - }, - 'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:launch_index': {'type': 'integer'}, - 'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:ramdisk_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:hostname': {'type': 'string'}, - 'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:user_data': {'type': ['string', 'null']}, - 'locked': {'type': 'boolean'}, - # NOTE(gmann): new attributes in version 2.16 - 'host_status': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE(gmann): 'progress' attribute is present in the response - # only when server's status is one of the progress statuses - # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE") - # 'fault' attribute is present in the response - # only when server's status is one of the "ERROR", "DELETED". - # OS-DCF:diskConfig and accessIPv4/v6 are API - # extensions, and some environments return a response - # without these attributes.So these are not defined as 'required'. - 'required': ['id', 'name', 'status', 'image', 'flavor', - 'user_id', 'tenant_id', 'created', 'updated', - 'metadata', 'links', 'addresses', 'hostId'] -} - -server_detail['properties']['addresses']['patternProperties'][ - '^[a-zA-Z0-9-_.]+$']['items']['properties'].update({ - 'OS-EXT-IPS:type': {'type': 'string'}, - 'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address}) -# NOTE(gmann)dd: Update OS-EXT-IPS:type and OS-EXT-IPS-MAC:mac_addr -# attributes in server address. Those are API extension, -# and some environments return a response without -# these attributes. So they are not 'required'. - -get_server = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server': server_detail - }, - 'additionalProperties': False, - 'required': ['server'] - } -} - -list_servers_detail = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'servers': { - 'type': 'array', - 'items': server_detail - }, - 'servers_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): servers_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['servers'] - } -} - -list_servers = copy.deepcopy(servers.list_servers) diff --git a/tempest/lib/api_schema/response/compute/v2_19/__init__.py b/tempest/lib/api_schema/response/compute/v2_19/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_19/servers.py b/tempest/lib/api_schema/response/compute/v2_19/servers.py deleted file mode 100644 index 05cc32c5b..000000000 --- a/tempest/lib/api_schema/response/compute/v2_19/servers.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import servers as serversv21 -from tempest.lib.api_schema.response.compute.v2_16 import servers \ - as serversv216 - -list_servers = copy.deepcopy(serversv216.list_servers) - -get_server = copy.deepcopy(serversv216.get_server) -get_server['response_body']['properties']['server'][ - 'properties'].update({'description': {'type': ['string', 'null']}}) -get_server['response_body']['properties']['server'][ - 'required'].append('description') - -list_servers_detail = copy.deepcopy(serversv216.list_servers_detail) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'properties'].update({'description': {'type': ['string', 'null']}}) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'required'].append('description') - -update_server = copy.deepcopy(serversv21.update_server) -update_server['response_body']['properties']['server'][ - 'properties'].update({'description': {'type': ['string', 'null']}}) -update_server['response_body']['properties']['server'][ - 'required'].append('description') - -rebuild_server = copy.deepcopy(serversv21.rebuild_server) -rebuild_server['response_body']['properties']['server'][ - 'properties'].update({'description': {'type': ['string', 'null']}}) -rebuild_server['response_body']['properties']['server'][ - 'required'].append('description') - -rebuild_server_with_admin_pass = copy.deepcopy( - serversv21.rebuild_server_with_admin_pass) -rebuild_server_with_admin_pass['response_body']['properties']['server'][ - 'properties'].update({'description': {'type': ['string', 'null']}}) -rebuild_server_with_admin_pass['response_body']['properties']['server'][ - 'required'].append('description') diff --git a/tempest/lib/api_schema/response/compute/v2_2/__init__.py b/tempest/lib/api_schema/response/compute/v2_2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_2/keypairs.py b/tempest/lib/api_schema/response/compute/v2_2/keypairs.py deleted file mode 100644 index 0bb7771c9..000000000 --- a/tempest/lib/api_schema/response/compute/v2_2/keypairs.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import keypairs - -get_keypair = copy.deepcopy(keypairs.get_keypair) -get_keypair['response_body']['properties']['keypair'][ - 'properties'].update({'type': {'type': 'string'}}) -get_keypair['response_body']['properties']['keypair'][ - 'required'].append('type') - -create_keypair = copy.deepcopy(keypairs.create_keypair) -create_keypair['status_code'] = [201] -create_keypair['response_body']['properties']['keypair'][ - 'properties'].update({'type': {'type': 'string'}}) -create_keypair['response_body']['properties']['keypair'][ - 'required'].append('type') - -delete_keypair = { - 'status_code': [204], -} - -list_keypairs = copy.deepcopy(keypairs.list_keypairs) -list_keypairs['response_body']['properties']['keypairs'][ - 'items']['properties']['keypair'][ - 'properties'].update({'type': {'type': 'string'}}) -list_keypairs['response_body']['properties']['keypairs'][ - 'items']['properties']['keypair']['required'].append('type') diff --git a/tempest/lib/api_schema/response/compute/v2_23/__init__.py b/tempest/lib/api_schema/response/compute/v2_23/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_23/migrations.py b/tempest/lib/api_schema/response/compute/v2_23/migrations.py deleted file mode 100644 index 3cd0f6ec1..000000000 --- a/tempest/lib/api_schema/response/compute/v2_23/migrations.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -# Compute microversion 2.23: -# New attributes in 'migrations' list. -# 'migration_type' -# 'links' - -list_migrations = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'migrations': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'status': {'type': ['string', 'null']}, - 'instance_uuid': {'type': ['string', 'null']}, - 'source_node': {'type': ['string', 'null']}, - 'source_compute': {'type': ['string', 'null']}, - 'dest_node': {'type': ['string', 'null']}, - 'dest_compute': {'type': ['string', 'null']}, - 'dest_host': {'type': ['string', 'null']}, - 'old_instance_type_id': {'type': ['integer', 'null']}, - 'new_instance_type_id': {'type': ['integer', 'null']}, - 'created_at': {'type': 'string'}, - 'updated_at': {'type': ['string', 'null']}, - # New attributes in version 2.23 - 'migration_type': {'type': ['string', 'null']}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': [ - 'id', 'status', 'instance_uuid', 'source_node', - 'source_compute', 'dest_node', 'dest_compute', - 'dest_host', 'old_instance_type_id', - 'new_instance_type_id', 'created_at', 'updated_at', - 'migration_type' - ] - } - } - }, - 'additionalProperties': False, - 'required': ['migrations'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_26/__init__.py b/tempest/lib/api_schema/response/compute/v2_26/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_26/servers.py b/tempest/lib/api_schema/response/compute/v2_26/servers.py deleted file mode 100644 index b03bdf6fa..000000000 --- a/tempest/lib/api_schema/response/compute/v2_26/servers.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2016 IBM Corp. -# Copyright 2017 AT&T Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import servers as servers21 -from tempest.lib.api_schema.response.compute.v2_19 import servers as servers219 - -# The 2.26 microversion changes the server GET and (detailed) LIST responses to -# include the server 'tags' which is just a list of strings. - -tag_items = { - 'type': 'array', - 'maxItems': 50, - 'items': { - 'type': 'string', - 'pattern': '^[^,/]*$', - 'maxLength': 60 - } -} - -get_server = copy.deepcopy(servers219.get_server) -get_server['response_body']['properties']['server'][ - 'properties'].update({'tags': tag_items}) -get_server['response_body']['properties']['server'][ - 'required'].append('tags') - -list_servers_detail = copy.deepcopy(servers219.list_servers_detail) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'properties'].update({'tags': tag_items}) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'required'].append('tags') - -# list response schema wasn't changed for v2.26 so use v2.1 - -list_servers = copy.deepcopy(servers21.list_servers) - -list_tags = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'tags': tag_items, - }, - 'additionalProperties': False, - 'required': ['tags'] - } -} - -update_all_tags = copy.deepcopy(list_tags) - -delete_all_tags = {'status_code': [204]} - -check_tag_existence = {'status_code': [204]} - -update_tag = { - 'status_code': [201, 204], - 'response_header': { - 'type': 'object', - 'properties': { - 'location': { - 'type': 'string' - } - }, - 'required': ['location'] - } -} - -delete_tag = {'status_code': [204]} diff --git a/tempest/lib/api_schema/response/compute/v2_3/__init__.py b/tempest/lib/api_schema/response/compute/v2_3/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_3/servers.py b/tempest/lib/api_schema/response/compute/v2_3/servers.py deleted file mode 100644 index f24103ea2..000000000 --- a/tempest/lib/api_schema/response/compute/v2_3/servers.py +++ /dev/null @@ -1,166 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types -from tempest.lib.api_schema.response.compute.v2_1 import servers - -# Compute microversion 2.3: -# 1. New attributes in 'os-extended-volumes:volumes_attached' dict. -# 'delete_on_termination' -# 2. New attributes in 'server' dict. -# 'OS-EXT-SRV-ATTR:reservation_id' -# 'OS-EXT-SRV-ATTR:launch_index' -# 'OS-EXT-SRV-ATTR:kernel_id' -# 'OS-EXT-SRV-ATTR:ramdisk_id' -# 'OS-EXT-SRV-ATTR:hostname' -# 'OS-EXT-SRV-ATTR:root_device_name' -# 'OS-EXT-SRV-ATTR:user_data' - -server_detail = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'name': {'type': 'string'}, - 'status': {'type': 'string'}, - 'image': {'oneOf': [ - {'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links']}, - {'type': ['string', 'null']} - ]}, - 'flavor': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links'] - }, - 'fault': { - 'type': 'object', - 'properties': { - 'code': {'type': 'integer'}, - 'created': {'type': 'string'}, - 'message': {'type': 'string'}, - 'details': {'type': 'string'}, - }, - 'additionalProperties': False, - # NOTE(gmann): 'details' is not necessary to be present - # in the 'fault'. So it is not defined as 'required'. - 'required': ['code', 'created', 'message'] - }, - 'user_id': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - 'created': {'type': 'string'}, - 'updated': {'type': 'string'}, - 'progress': {'type': 'integer'}, - 'metadata': {'type': 'object'}, - 'links': parameter_types.links, - 'addresses': parameter_types.addresses, - 'hostId': {'type': 'string'}, - 'OS-DCF:diskConfig': {'type': 'string'}, - 'accessIPv4': parameter_types.access_ip_v4, - 'accessIPv6': parameter_types.access_ip_v6, - 'key_name': {'type': ['string', 'null']}, - 'security_groups': {'type': 'array'}, - 'OS-SRV-USG:launched_at': {'type': ['string', 'null']}, - 'OS-SRV-USG:terminated_at': {'type': ['string', 'null']}, - 'OS-EXT-AZ:availability_zone': {'type': 'string'}, - 'OS-EXT-STS:task_state': {'type': ['string', 'null']}, - 'OS-EXT-STS:vm_state': {'type': 'string'}, - 'OS-EXT-STS:power_state': parameter_types.power_state, - 'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'}, - 'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']}, - 'config_drive': {'type': 'string'}, - # NOTE(gmann): new attributes in version 2.3 - 'os-extended-volumes:volumes_attached': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'delete_on_termination': {'type': 'boolean'} - }, - 'additionalProperties': False, - }, - }, - 'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:launch_index': {'type': 'integer'}, - 'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:ramdisk_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:hostname': {'type': 'string'}, - 'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:user_data': {'type': ['string', 'null']}, - }, - 'additionalProperties': False, - # NOTE(gmann): 'progress' attribute is present in the response - # only when server's status is one of the progress statuses - # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE") - # 'fault' attribute is present in the response - # only when server's status is one of the "ERROR", "DELETED". - # OS-DCF:diskConfig and accessIPv4/v6 are API - # extensions, and some environments return a response - # without these attributes.So these are not defined as 'required'. - 'required': ['id', 'name', 'status', 'image', 'flavor', - 'user_id', 'tenant_id', 'created', 'updated', - 'metadata', 'links', 'addresses', 'hostId'] -} - -server_detail['properties']['addresses']['patternProperties'][ - '^[a-zA-Z0-9-_.]+$']['items']['properties'].update({ - 'OS-EXT-IPS:type': {'type': 'string'}, - 'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address}) -# NOTE(gmann)dd: Update OS-EXT-IPS:type and OS-EXT-IPS-MAC:mac_addr -# attributes in server address. Those are API extension, -# and some environments return a response without -# these attributes. So they are not 'required'. - -get_server = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server': server_detail - }, - 'additionalProperties': False, - 'required': ['server'] - } -} - -list_servers_detail = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'servers': { - 'type': 'array', - 'items': server_detail - }, - 'servers_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): servers_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['servers'] - } -} - -list_servers = copy.deepcopy(servers.list_servers) diff --git a/tempest/lib/api_schema/response/compute/v2_47/__init__.py b/tempest/lib/api_schema/response/compute/v2_47/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_47/servers.py b/tempest/lib/api_schema/response/compute/v2_47/servers.py deleted file mode 100644 index 37a084f1c..000000000 --- a/tempest/lib/api_schema/response/compute/v2_47/servers.py +++ /dev/null @@ -1,39 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_26 import servers as servers226 - -flavor = { - 'type': 'object', - 'properties': { - 'original_name': {'type': 'string'}, - 'disk': {'type': 'integer'}, - 'ephemeral': {'type': 'integer'}, - 'ram': {'type': 'integer'}, - 'swap': {'type': 'integer'}, - 'vcpus': {'type': 'integer'}, - 'extra_specs': { - 'type': 'object', - 'patternProperties': { - '^[a-zA-Z0-9_\-\. :]+$': {'type': 'string'} - } - } - }, - 'additionalProperties': False, - 'required': ['original_name', 'disk', 'ephemeral', 'ram', 'swap', 'vcpus'] -} - -get_server = copy.deepcopy(servers226.get_server) -get_server['response_body']['properties']['server'][ - 'properties'].update({'flavor': flavor}) diff --git a/tempest/lib/api_schema/response/compute/v2_48/__init__.py b/tempest/lib/api_schema/response/compute/v2_48/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_48/servers.py b/tempest/lib/api_schema/response/compute/v2_48/servers.py deleted file mode 100644 index 59047583a..000000000 --- a/tempest/lib/api_schema/response/compute/v2_48/servers.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2017 Mirantis Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types -from tempest.lib.api_schema.response.compute.v2_47 import servers as servers247 - - -show_server_diagnostics = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'state': { - 'type': 'string', 'enum': [ - 'pending', 'running', 'paused', 'shutdown', 'crashed', - 'suspended'] - }, - 'driver': { - 'type': 'string', 'enum': [ - 'libvirt', 'xenapi', 'vmwareapi', 'ironic', 'hyperv'] - }, - 'hypervisor': {'type': ['string', 'null']}, - 'hypervisor_os': {'type': ['string', 'null']}, - 'uptime': {'type': ['integer', 'null']}, - 'config_drive': {'type': 'boolean'}, - 'num_cpus': {'type': 'integer'}, - 'num_nics': {'type': 'integer'}, - 'num_disks': {'type': 'integer'}, - 'memory_details': { - 'type': 'object', - 'properties': { - 'maximum': {'type': ['integer', 'null']}, - 'used': {'type': ['integer', 'null']} - }, - 'additionalProperties': False, - 'required': ['maximum', 'used'] - }, - 'cpu_details': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': ['integer', 'null']}, - 'time': {'type': ['integer', 'null']}, - 'utilisation': {'type': ['integer', 'null']} - }, - 'additionalProperties': False, - 'required': ['id', 'time', 'utilisation'] - } - }, - 'nic_details': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'mac_address': {'oneOf': [parameter_types.mac_address, - {'type': 'null'}]}, - 'rx_octets': {'type': ['integer', 'null']}, - 'rx_errors': {'type': ['integer', 'null']}, - 'rx_drop': {'type': ['integer', 'null']}, - 'rx_packets': {'type': ['integer', 'null']}, - 'rx_rate': {'type': ['integer', 'null']}, - 'tx_octets': {'type': ['integer', 'null']}, - 'tx_errors': {'type': ['integer', 'null']}, - 'tx_drop': {'type': ['integer', 'null']}, - 'tx_packets': {'type': ['integer', 'null']}, - 'tx_rate': {'type': ['integer', 'null']} - }, - 'additionalProperties': False, - 'required': ['mac_address', 'rx_octets', 'rx_errors', - 'rx_drop', - 'rx_packets', 'rx_rate', 'tx_octets', - 'tx_errors', - 'tx_drop', 'tx_packets', 'tx_rate'] - } - }, - 'disk_details': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'read_bytes': {'type': ['integer', 'null']}, - 'read_requests': {'type': ['integer', 'null']}, - 'write_bytes': {'type': ['integer', 'null']}, - 'write_requests': {'type': ['integer', 'null']}, - 'errors_count': {'type': ['integer', 'null']} - }, - 'additionalProperties': False, - 'required': ['read_bytes', 'read_requests', 'write_bytes', - 'write_requests', 'errors_count'] - } - } - }, - 'additionalProperties': False, - 'required': [ - 'state', 'driver', 'hypervisor', 'hypervisor_os', 'uptime', - 'config_drive', 'num_cpus', 'num_nics', 'num_disks', - 'memory_details', 'cpu_details', 'nic_details', 'disk_details'], - } -} - -get_server = copy.deepcopy(servers247.get_server) diff --git a/tempest/lib/api_schema/response/compute/v2_6/__init__.py b/tempest/lib/api_schema/response/compute/v2_6/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_6/servers.py b/tempest/lib/api_schema/response/compute/v2_6/servers.py deleted file mode 100644 index 29b3e8600..000000000 --- a/tempest/lib/api_schema/response/compute/v2_6/servers.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2016 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_3 import servers - -list_servers = copy.deepcopy(servers.list_servers) -get_server = copy.deepcopy(servers.get_server) -list_servers_detail = copy.deepcopy(servers.list_servers_detail) - -# NOTE: The consolidated remote console API got introduced with v2.6 -# with bp/consolidate-console-api. See Nova commit 578bafeda -get_remote_consoles = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'remote_console': { - 'type': 'object', - 'properties': { - 'protocol': {'enum': ['vnc', 'rdp', 'serial', 'spice']}, - 'type': {'enum': ['novnc', 'xpvnc', 'rdp-html5', - 'spice-html5', 'serial']}, - 'url': { - 'type': 'string', - 'format': 'uri' - } - }, - 'additionalProperties': False, - 'required': ['protocol', 'type', 'url'] - } - }, - 'additionalProperties': False, - 'required': ['remote_console'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_9/__init__.py b/tempest/lib/api_schema/response/compute/v2_9/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_9/servers.py b/tempest/lib/api_schema/response/compute/v2_9/servers.py deleted file mode 100644 index e260e48ce..000000000 --- a/tempest/lib/api_schema/response/compute/v2_9/servers.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.api_schema.response.compute.v2_6 import servers - -list_servers = copy.deepcopy(servers.list_servers) - -get_server = copy.deepcopy(servers.get_server) -get_server['response_body']['properties']['server'][ - 'properties'].update({'locked': {'type': 'boolean'}}) -get_server['response_body']['properties']['server'][ - 'required'].append('locked') - -list_servers_detail = copy.deepcopy(servers.list_servers_detail) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'properties'].update({'locked': {'type': 'boolean'}}) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'required'].append('locked') diff --git a/tempest/lib/api_schema/response/volume/__init__.py b/tempest/lib/api_schema/response/volume/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/volume/versions.py b/tempest/lib/api_schema/response/volume/versions.py deleted file mode 100644 index 2391a8c86..000000000 --- a/tempest/lib/api_schema/response/volume/versions.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -list_versions = { - 'status_code': [300], - 'response_body': { - 'type': 'object', - 'properties': { - 'versions': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'status': {'type': 'string'}, - 'updated': {'type': 'string'}, - 'id': {'type': 'string'}, - 'links': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'href': {'type': 'string', - 'format': 'uri'}, - 'rel': {'type': 'string'}, - 'type': {'type': 'string'}, - }, - 'required': ['href', 'rel'] - } - }, - 'min_version': {'type': 'string'}, - 'version': {'type': 'string'}, - 'media-types': { - 'type': 'array', - 'properties': { - 'base': {'type': 'string'}, - 'type': {'type': 'string'} - }, - 'required': ['base', 'type'] - } - }, - 'required': ['status', 'updated', 'id', 'links', - 'min_version', 'version', 'media-types'] - } - } - }, - 'required': ['versions'], - } -} diff --git a/tempest/lib/auth.py b/tempest/lib/auth.py deleted file mode 100644 index ab4308fed..000000000 --- a/tempest/lib/auth.py +++ /dev/null @@ -1,851 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# Copyright 2016 Rackspace Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc -import copy -import datetime -import re - -from oslo_log import log as logging -import six -from six.moves.urllib import parse as urlparse - -from tempest.lib import exceptions -from tempest.lib.services.identity.v2 import token_client as json_v2id -from tempest.lib.services.identity.v3 import token_client as json_v3id - -ISO8601_FLOAT_SECONDS = '%Y-%m-%dT%H:%M:%S.%fZ' -ISO8601_INT_SECONDS = '%Y-%m-%dT%H:%M:%SZ' -LOG = logging.getLogger(__name__) - - -def replace_version(url, new_version): - parts = urlparse.urlparse(url) - version_path = '/%s' % new_version - path, subs = re.subn(r'(^|/)+v\d+(?:\.\d+)?', - version_path, - parts.path, - count=1) - if not subs: - path = '%s%s' % (parts.path.rstrip('/'), version_path) - url = urlparse.urlunparse((parts.scheme, - parts.netloc, - path, - parts.params, - parts.query, - parts.fragment)) - return url - - -def apply_url_filters(url, filters): - if filters.get('api_version', None) is not None: - url = replace_version(url, filters['api_version']) - parts = urlparse.urlparse(url) - if filters.get('skip_path', None) is not None and parts.path != '': - url = urlparse.urlunparse((parts.scheme, - parts.netloc, - '/', - parts.params, - parts.query, - parts.fragment)) - - return url - - -@six.add_metaclass(abc.ABCMeta) -class AuthProvider(object): - """Provide authentication""" - - SCOPES = set(['project']) - - def __init__(self, credentials, scope='project'): - """Auth provider __init__ - - :param credentials: credentials for authentication - :param scope: the default scope to be used by the credential providers - when requesting a token. Valid values depend on the - AuthProvider class implementation, and are defined in - the set SCOPES. Default value is 'project'. - """ - if self.check_credentials(credentials): - self.credentials = credentials - else: - if isinstance(credentials, Credentials): - password = credentials.get('password') - message = "Credentials are: " + str(credentials) - if password is None: - message += " Password is not defined." - else: - message += " Password is defined." - raise exceptions.InvalidCredentials(message) - else: - raise TypeError("credentials object is of type %s, which is" - " not a valid Credentials object type." % - credentials.__class__.__name__) - self._scope = None - self.scope = scope - self.cache = None - self.alt_auth_data = None - self.alt_part = None - - def __str__(self): - return "Creds :{creds}, cached auth data: {cache}".format( - creds=self.credentials, cache=self.cache) - - @abc.abstractmethod - def _decorate_request(self, filters, method, url, headers=None, body=None, - auth_data=None): - """Decorate request with authentication data""" - return - - @abc.abstractmethod - def _get_auth(self): - return - - @abc.abstractmethod - def _fill_credentials(self, auth_data_body): - return - - def fill_credentials(self): - """Fill credentials object with data from auth""" - auth_data = self.get_auth() - self._fill_credentials(auth_data[1]) - return self.credentials - - @classmethod - def check_credentials(cls, credentials): - """Verify credentials are valid.""" - return isinstance(credentials, Credentials) and credentials.is_valid() - - @property - def auth_data(self): - """Auth data for set scope""" - return self.get_auth() - - @property - def scope(self): - """Scope used in auth requests""" - return self._scope - - @auth_data.deleter - def auth_data(self): - self.clear_auth() - - def get_auth(self): - """Returns auth from cache if available, else auth first""" - if self.cache is None or self.is_expired(self.cache): - self.set_auth() - return self.cache - - def set_auth(self): - """Forces setting auth. - - Forces setting auth, ignores cache if it exists. - Refills credentials. - """ - self.cache = self._get_auth() - self._fill_credentials(self.cache[1]) - - def clear_auth(self): - """Clear access cache - - Can be called to clear the access cache so that next request - will fetch a new token and base_url. - """ - self.cache = None - self.credentials.reset() - - @abc.abstractmethod - def is_expired(self, auth_data): - return - - def auth_request(self, method, url, headers=None, body=None, filters=None): - """Obtains auth data and decorates a request with that. - - :param method: HTTP method of the request - :param url: relative URL of the request (path) - :param headers: HTTP headers of the request - :param body: HTTP body in case of POST / PUT - :param filters: select a base URL out of the catalog - :return: a Tuple (url, headers, body) - """ - orig_req = dict(url=url, headers=headers, body=body) - - auth_url, auth_headers, auth_body = self._decorate_request( - filters, method, url, headers, body) - auth_req = dict(url=auth_url, headers=auth_headers, body=auth_body) - - # Overwrite part if the request if it has been requested - if self.alt_part is not None: - if self.alt_auth_data is not None: - alt_url, alt_headers, alt_body = self._decorate_request( - filters, method, url, headers, body, - auth_data=self.alt_auth_data) - alt_auth_req = dict(url=alt_url, headers=alt_headers, - body=alt_body) - if auth_req[self.alt_part] == alt_auth_req[self.alt_part]: - raise exceptions.BadAltAuth(part=self.alt_part) - auth_req[self.alt_part] = alt_auth_req[self.alt_part] - - else: - # If the requested part is not affected by auth, we are - # not altering auth as expected, raise an exception - if auth_req[self.alt_part] == orig_req[self.alt_part]: - raise exceptions.BadAltAuth(part=self.alt_part) - # If alt auth data is None, skip auth in the requested part - auth_req[self.alt_part] = orig_req[self.alt_part] - - # Next auth request will be normal, unless otherwise requested - self.reset_alt_auth_data() - - return auth_req['url'], auth_req['headers'], auth_req['body'] - - def reset_alt_auth_data(self): - """Configure auth provider to provide valid authentication data""" - self.alt_part = None - self.alt_auth_data = None - - def set_alt_auth_data(self, request_part, auth_data): - """Alternate auth data on next request - - Configure auth provider to provide alt authentication data - on a part of the *next* auth_request. If credentials are None, - set invalid data. - - :param request_part: request part to contain invalid auth: url, - headers, body - :param auth_data: alternative auth_data from which to get the - invalid data to be injected - """ - self.alt_part = request_part - self.alt_auth_data = auth_data - - @abc.abstractmethod - def base_url(self, filters, auth_data=None): - """Extracts the base_url based on provided filters""" - return - - @scope.setter - def scope(self, value): - """Set the scope to be used in token requests - - :param scope: scope to be used. If the scope is different, clear caches - """ - if value not in self.SCOPES: - raise exceptions.InvalidScope( - scope=value, auth_provider=self.__class__.__name__) - if value != self.scope: - self.clear_auth() - self._scope = value - - -class KeystoneAuthProvider(AuthProvider): - - EXPIRY_DATE_FORMATS = (ISO8601_FLOAT_SECONDS, ISO8601_INT_SECONDS) - - token_expiry_threshold = datetime.timedelta(seconds=60) - - def __init__(self, credentials, auth_url, - disable_ssl_certificate_validation=None, - ca_certs=None, trace_requests=None, scope='project', - http_timeout=None): - super(KeystoneAuthProvider, self).__init__(credentials, scope) - self.dscv = disable_ssl_certificate_validation - self.ca_certs = ca_certs - self.trace_requests = trace_requests - self.http_timeout = http_timeout - self.auth_url = auth_url - self.auth_client = self._auth_client(auth_url) - - def _decorate_request(self, filters, method, url, headers=None, body=None, - auth_data=None): - if auth_data is None: - auth_data = self.get_auth() - token, _ = auth_data - base_url = self.base_url(filters=filters, auth_data=auth_data) - # build authenticated request - # returns new request, it does not touch the original values - _headers = copy.deepcopy(headers) if headers is not None else {} - _headers['X-Auth-Token'] = str(token) - if url is None or url == "": - _url = base_url - else: - # Join base URL and url, and remove multiple contiguous slashes - _url = "/".join([base_url, url]) - parts = [x for x in urlparse.urlparse(_url)] - parts[2] = re.sub("/{2,}", "/", parts[2]) - _url = urlparse.urlunparse(parts) - # no change to method or body - return str(_url), _headers, body - - @abc.abstractmethod - def _auth_client(self): - return - - @abc.abstractmethod - def _auth_params(self): - """Auth parameters to be passed to the token request - - By default all fields available in Credentials are passed to the - token request. Scope may affect this. - """ - return - - def _get_auth(self): - # Bypasses the cache - auth_func = getattr(self.auth_client, 'get_token') - auth_params = self._auth_params() - - # returns token, auth_data - token, auth_data = auth_func(**auth_params) - return token, auth_data - - def _parse_expiry_time(self, expiry_string): - expiry = None - for date_format in self.EXPIRY_DATE_FORMATS: - try: - expiry = datetime.datetime.strptime( - expiry_string, date_format) - except ValueError: - pass - if expiry is None: - raise ValueError( - "time data '{data}' does not match any of the" - "expected formats: {formats}".format( - data=expiry_string, formats=self.EXPIRY_DATE_FORMATS)) - return expiry - - def get_token(self): - return self.get_auth()[0] - - -class KeystoneV2AuthProvider(KeystoneAuthProvider): - """Provides authentication based on the Identity V2 API - - The Keystone Identity V2 API defines both unscoped and project scoped - tokens. This auth provider only implements 'project'. - """ - - SCOPES = set(['project']) - - def _auth_client(self, auth_url): - return json_v2id.TokenClient( - auth_url, disable_ssl_certificate_validation=self.dscv, - ca_certs=self.ca_certs, trace_requests=self.trace_requests, - http_timeout=self.http_timeout) - - def _auth_params(self): - """Auth parameters to be passed to the token request - - All fields available in Credentials are passed to the token request. - """ - return dict( - user=self.credentials.username, - password=self.credentials.password, - tenant=self.credentials.tenant_name, - auth_data=True) - - def _fill_credentials(self, auth_data_body): - tenant = auth_data_body['token']['tenant'] - user = auth_data_body['user'] - if self.credentials.tenant_name is None: - self.credentials.tenant_name = tenant['name'] - if self.credentials.tenant_id is None: - self.credentials.tenant_id = tenant['id'] - if self.credentials.username is None: - self.credentials.username = user['name'] - if self.credentials.user_id is None: - self.credentials.user_id = user['id'] - - def base_url(self, filters, auth_data=None): - """Base URL from catalog - - :param filters: Used to filter results - - Filters can be: - - - service: service type name such as compute, image, etc. - - region: service region name - - name: service name, only if service exists - - endpoint_type: type of endpoint such as - adminURL, publicURL, internalURL - - api_version: the version of api used to replace catalog version - - skip_path: skips the suffix path of the url and uses base URL - - :rtype: string - :return: url with filters applied - """ - if auth_data is None: - auth_data = self.get_auth() - token, _auth_data = auth_data - service = filters.get('service') - region = filters.get('region') - name = filters.get('name') - endpoint_type = filters.get('endpoint_type', 'publicURL') - - if service is None: - raise exceptions.EndpointNotFound("No service provided") - - _base_url = None - for ep in _auth_data['serviceCatalog']: - if ep["type"] == service: - if name is not None and ep["name"] != name: - continue - for _ep in ep['endpoints']: - if region is not None and _ep['region'] == region: - _base_url = _ep.get(endpoint_type) - if not _base_url: - # No region or name matching, use the first - _base_url = ep['endpoints'][0].get(endpoint_type) - break - if _base_url is None: - raise exceptions.EndpointNotFound( - "service: %s, region: %s, endpoint_type: %s, name: %s" % - (service, region, endpoint_type, name)) - return apply_url_filters(_base_url, filters) - - def is_expired(self, auth_data): - _, access = auth_data - expiry = self._parse_expiry_time(access['token']['expires']) - return (expiry - self.token_expiry_threshold <= - datetime.datetime.utcnow()) - - -class KeystoneV3AuthProvider(KeystoneAuthProvider): - """Provides authentication based on the Identity V3 API""" - - SCOPES = set(['project', 'domain', 'unscoped', None]) - - def _auth_client(self, auth_url): - return json_v3id.V3TokenClient( - auth_url, disable_ssl_certificate_validation=self.dscv, - ca_certs=self.ca_certs, trace_requests=self.trace_requests, - http_timeout=self.http_timeout) - - def _auth_params(self): - """Auth parameters to be passed to the token request - - Fields available in Credentials are passed to the token request, - depending on the value of scope. Valid values for scope are: "project", - "domain". Any other string (e.g. "unscoped") or None will lead to an - unscoped token request. - """ - - auth_params = dict( - user_id=self.credentials.user_id, - username=self.credentials.username, - user_domain_id=self.credentials.user_domain_id, - user_domain_name=self.credentials.user_domain_name, - password=self.credentials.password, - auth_data=True) - - if self.scope == 'project': - auth_params.update( - project_domain_id=self.credentials.project_domain_id, - project_domain_name=self.credentials.project_domain_name, - project_id=self.credentials.project_id, - project_name=self.credentials.project_name) - - if self.scope == 'domain': - auth_params.update( - domain_id=self.credentials.domain_id, - domain_name=self.credentials.domain_name) - - return auth_params - - def _fill_credentials(self, auth_data_body): - # project or domain, depending on the scope - project = auth_data_body.get('project', None) - domain = auth_data_body.get('domain', None) - # user is always there - user = auth_data_body['user'] - # Set project fields - if project is not None: - if self.credentials.project_name is None: - self.credentials.project_name = project['name'] - if self.credentials.project_id is None: - self.credentials.project_id = project['id'] - if self.credentials.project_domain_id is None: - self.credentials.project_domain_id = project['domain']['id'] - if self.credentials.project_domain_name is None: - self.credentials.project_domain_name = ( - project['domain']['name']) - # Set domain fields - if domain is not None: - if self.credentials.domain_id is None: - self.credentials.domain_id = domain['id'] - if self.credentials.domain_name is None: - self.credentials.domain_name = domain['name'] - # Set user fields - if self.credentials.username is None: - self.credentials.username = user['name'] - if self.credentials.user_id is None: - self.credentials.user_id = user['id'] - if self.credentials.user_domain_id is None: - self.credentials.user_domain_id = user['domain']['id'] - if self.credentials.user_domain_name is None: - self.credentials.user_domain_name = user['domain']['name'] - - def base_url(self, filters, auth_data=None): - """Base URL from catalog - - If scope is not 'project', it may be that there is not catalog in - the auth_data. In such case, as long as the requested service is - 'identity', we can use the original auth URL to build the base_url. - - :param filters: Used to filter results - - Filters can be: - - - service: service type name such as compute, image, etc. - - region: service region name - - name: service name, only if service exists - - endpoint_type: type of endpoint such as - adminURL, publicURL, internalURL - - api_version: the version of api used to replace catalog version - - skip_path: skips the suffix path of the url and uses base URL - - :rtype: string - :return: url with filters applied - """ - if auth_data is None: - auth_data = self.get_auth() - token, _auth_data = auth_data - service = filters.get('service') - region = filters.get('region') - name = filters.get('name') - endpoint_type = filters.get('endpoint_type', 'public') - - if service is None: - raise exceptions.EndpointNotFound("No service provided") - - if 'URL' in endpoint_type: - endpoint_type = endpoint_type.replace('URL', '') - _base_url = None - catalog = _auth_data.get('catalog', []) - - # Select entries with matching service type - service_catalog = [ep for ep in catalog if ep['type'] == service] - if service_catalog: - if name is not None: - service_catalog = ( - [ep for ep in service_catalog if ep['name'] == name]) - if service_catalog: - service_catalog = service_catalog[0]['endpoints'] - else: - raise exceptions.EndpointNotFound(name) - else: - service_catalog = service_catalog[0]['endpoints'] - else: - if not catalog and service == 'identity': - # NOTE(andreaf) If there's no catalog at all and the service - # is identity, it's a valid use case. Having a non-empty - # catalog with no identity in it is not valid instead. - msg = ('Got an empty catalog. Scope: %s. ' - 'Falling back to configured URL for %s: %s') - LOG.debug(msg, self.scope, service, self.auth_url) - return apply_url_filters(self.auth_url, filters) - else: - # No matching service - msg = ('No matching service found in the catalog.\n' - 'Scope: %s, Credentials: %s\n' - 'Auth data: %s\n' - 'Service: %s, Region: %s, endpoint_type: %s\n' - 'Catalog: %s') - raise exceptions.EndpointNotFound(msg % ( - self.scope, self.credentials, _auth_data, service, region, - endpoint_type, catalog)) - # Filter by endpoint type (interface) - filtered_catalog = [ep for ep in service_catalog if - ep['interface'] == endpoint_type] - if not filtered_catalog: - # No matching type, keep all and try matching by region at least - filtered_catalog = service_catalog - # Filter by region - filtered_catalog = [ep for ep in filtered_catalog if - ep['region'] == region] - if not filtered_catalog: - # No matching region (or name), take the first endpoint - filtered_catalog = [service_catalog[0]] - # There should be only one match. If not take the first. - _base_url = filtered_catalog[0].get('url', None) - if _base_url is None: - raise exceptions.EndpointNotFound(service) - return apply_url_filters(_base_url, filters) - - def is_expired(self, auth_data): - _, access = auth_data - expiry = self._parse_expiry_time(access['expires_at']) - return (expiry - self.token_expiry_threshold <= - datetime.datetime.utcnow()) - - -def is_identity_version_supported(identity_version): - return identity_version in IDENTITY_VERSION - - -def get_credentials(auth_url, fill_in=True, identity_version='v2', - disable_ssl_certificate_validation=None, ca_certs=None, - trace_requests=None, http_timeout=None, **kwargs): - """Builds a credentials object based on the configured auth_version - - :param auth_url (string): Full URI of the OpenStack Identity API(Keystone) - which is used to fetch the token from Identity service. - :param fill_in (boolean): obtain a token and fill in all credential - details provided by the identity service. When fill_in is not - specified, credentials are not validated. Validation can be invoked - by invoking ``is_valid()`` - :param identity_version (string): identity API version is used to - select the matching auth provider and credentials class - :param disable_ssl_certificate_validation: whether to enforce SSL - certificate validation in SSL API requests to the auth system - :param ca_certs: CA certificate bundle for validation of certificates - in SSL API requests to the auth system - :param trace_requests: trace in log API requests to the auth system - :param http_timeout: timeout in seconds to wait for the http request to - return - :param kwargs (dict): Dict of credential key/value pairs - - Examples: - - Returns credentials from the provided parameters: - >>> get_credentials(username='foo', password='bar') - - Returns credentials including IDs: - >>> get_credentials(username='foo', password='bar', fill_in=True) - """ - if not is_identity_version_supported(identity_version): - raise exceptions.InvalidIdentityVersion( - identity_version=identity_version) - - credential_class, auth_provider_class = IDENTITY_VERSION.get( - identity_version) - - creds = credential_class(**kwargs) - # Fill in the credentials fields that were not specified - if fill_in: - dscv = disable_ssl_certificate_validation - auth_provider = auth_provider_class( - creds, auth_url, disable_ssl_certificate_validation=dscv, - ca_certs=ca_certs, trace_requests=trace_requests, - http_timeout=http_timeout) - creds = auth_provider.fill_credentials() - return creds - - -class Credentials(object): - """Set of credentials for accessing OpenStack services - - ATTRIBUTES: list of valid class attributes representing credentials. - """ - - ATTRIBUTES = [] - COLLISIONS = [] - - def __init__(self, **kwargs): - """Enforce the available attributes at init time (only). - - Additional attributes can still be set afterwards if tests need - to do so. - """ - self._initial = kwargs - self._apply_credentials(kwargs) - - def _apply_credentials(self, attr): - for (key1, key2) in self.COLLISIONS: - val1 = attr.get(key1) - val2 = attr.get(key2) - if val1 and val2 and val1 != val2: - msg = ('Cannot have conflicting values for %s and %s' % - (key1, key2)) - raise exceptions.InvalidCredentials(msg) - for key in attr: - if key in self.ATTRIBUTES: - setattr(self, key, attr[key]) - else: - msg = '%s is not a valid attr for %s' % (key, self.__class__) - raise exceptions.InvalidCredentials(msg) - - def __str__(self): - """Represent only attributes included in self.ATTRIBUTES""" - attrs = [attr for attr in self.ATTRIBUTES if attr is not 'password'] - _repr = dict((k, getattr(self, k)) for k in attrs) - return str(_repr) - - def __eq__(self, other): - """Credentials are equal if attributes in self.ATTRIBUTES are equal""" - return str(self) == str(other) - - def __ne__(self, other): - """Contrary to the __eq__""" - return not self.__eq__(other) - - def __getattr__(self, key): - # If an attribute is set, __getattr__ is not invoked - # If an attribute is not set, and it is a known one, return None - if key in self.ATTRIBUTES: - return None - else: - raise AttributeError - - def __delitem__(self, key): - # For backwards compatibility, support dict behaviour - if key in self.ATTRIBUTES: - delattr(self, key) - else: - raise AttributeError - - def get(self, item, default=None): - # In this patch act as dict for backward compatibility - try: - return getattr(self, item) - except AttributeError: - return default - - def get_init_attributes(self): - return self._initial.keys() - - def is_valid(self): - raise NotImplementedError - - def reset(self): - # First delete all known attributes - for key in self.ATTRIBUTES: - if getattr(self, key) is not None: - delattr(self, key) - # Then re-apply initial setup - self._apply_credentials(self._initial) - - -class KeystoneV2Credentials(Credentials): - - ATTRIBUTES = ['username', 'password', 'tenant_name', 'user_id', - 'tenant_id', 'project_id', 'project_name'] - COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')] - - def __str__(self): - """Represent only attributes included in self.ATTRIBUTES""" - attrs = [attr for attr in self.ATTRIBUTES if attr is not 'password'] - _repr = dict((k, getattr(self, k)) for k in attrs) - return str(_repr) - - def __setattr__(self, key, value): - # NOTE(andreaf) In order to ease the migration towards 'project' we - # support v2 credentials configured with 'project' and translate it - # to tenant on the fly. The original kwargs are stored for clients - # that may rely on them. We also set project when tenant is defined - # so clients can rely on project being part of credentials. - parent = super(KeystoneV2Credentials, self) - # for project_* set tenant only - if key == 'project_id': - parent.__setattr__('tenant_id', value) - elif key == 'project_name': - parent.__setattr__('tenant_name', value) - if key == 'tenant_id': - parent.__setattr__('project_id', value) - elif key == 'tenant_name': - parent.__setattr__('project_name', value) - # trigger default behaviour for all attributes - parent.__setattr__(key, value) - - def is_valid(self): - """Check of credentials (no API call) - - Minimum set of valid credentials, are username and password. - Tenant is optional. - """ - return None not in (self.username, self.password) - - -class KeystoneV3Credentials(Credentials): - """Credentials suitable for the Keystone Identity V3 API""" - - ATTRIBUTES = ['domain_id', 'domain_name', 'password', 'username', - 'project_domain_id', 'project_domain_name', 'project_id', - 'project_name', 'tenant_id', 'tenant_name', 'user_domain_id', - 'user_domain_name', 'user_id'] - COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')] - - def __setattr__(self, key, value): - parent = super(KeystoneV3Credentials, self) - # for tenant_* set both project and tenant - if key == 'tenant_id': - parent.__setattr__('project_id', value) - elif key == 'tenant_name': - parent.__setattr__('project_name', value) - # for project_* set both project and tenant - if key == 'project_id': - parent.__setattr__('tenant_id', value) - elif key == 'project_name': - parent.__setattr__('tenant_name', value) - # for *_domain_* set both user and project if not set yet - if key == 'user_domain_id': - if self.project_domain_id is None: - parent.__setattr__('project_domain_id', value) - if key == 'project_domain_id': - if self.user_domain_id is None: - parent.__setattr__('user_domain_id', value) - if key == 'user_domain_name': - if self.project_domain_name is None: - parent.__setattr__('project_domain_name', value) - if key == 'project_domain_name': - if self.user_domain_name is None: - parent.__setattr__('user_domain_name', value) - # support domain_name coming from config - if key == 'domain_name': - if self.user_domain_name is None: - parent.__setattr__('user_domain_name', value) - if self.project_domain_name is None: - parent.__setattr__('project_domain_name', value) - # finally trigger default behaviour for all attributes - parent.__setattr__(key, value) - - def is_valid(self): - """Check of credentials (no API call) - - Valid combinations of v3 credentials (excluding token) - - User id, password (optional domain) - - User name, password and its domain id/name - For the scope, valid combinations are: - - None - - Project id (optional domain) - - Project name and its domain id/name - - Domain id - - Domain name - """ - valid_user_domain = any( - [self.user_domain_id is not None, - self.user_domain_name is not None]) - valid_project_domain = any( - [self.project_domain_id is not None, - self.project_domain_name is not None]) - valid_user = any( - [self.user_id is not None, - self.username is not None and valid_user_domain]) - valid_project_scope = any( - [self.project_name is None and self.project_id is None, - self.project_id is not None, - self.project_name is not None and valid_project_domain]) - valid_domain_scope = any( - [self.domain_id is None and self.domain_name is None, - self.domain_id or self.domain_name]) - return all([self.password is not None, - valid_user, - valid_project_scope and valid_domain_scope]) - - -IDENTITY_VERSION = {'v2': (KeystoneV2Credentials, KeystoneV2AuthProvider), - 'v3': (KeystoneV3Credentials, KeystoneV3AuthProvider)} diff --git a/tempest/lib/base.py b/tempest/lib/base.py deleted file mode 100644 index 33a32eefc..000000000 --- a/tempest/lib/base.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os - -import fixtures -import testtools - - -class BaseTestCase(testtools.testcase.WithAttributes, testtools.TestCase): - setUpClassCalled = False - - # NOTE(sdague): log_format is defined inline here instead of using the oslo - # default because going through the config path recouples config to the - # stress tests too early, and depending on testr order will fail unit tests - log_format = ('%(asctime)s %(process)d %(levelname)-8s ' - '[%(name)s] %(message)s') - - @classmethod - def setUpClass(cls): - if hasattr(super(BaseTestCase, cls), 'setUpClass'): - super(BaseTestCase, cls).setUpClass() - cls.setUpClassCalled = True - - @classmethod - def tearDownClass(cls): - if hasattr(super(BaseTestCase, cls), 'tearDownClass'): - super(BaseTestCase, cls).tearDownClass() - - def setUp(self): - super(BaseTestCase, self).setUp() - if not self.setUpClassCalled: - raise RuntimeError("setUpClass does not calls the super's " - "setUpClass in the " - + self.__class__.__name__) - test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) - try: - test_timeout = int(test_timeout) - except ValueError: - test_timeout = 0 - if test_timeout > 0: - self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) - - if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or - os.environ.get('OS_STDOUT_CAPTURE') == '1'): - stdout = self.useFixture(fixtures.StringStream('stdout')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) - if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or - os.environ.get('OS_STDERR_CAPTURE') == '1'): - stderr = self.useFixture(fixtures.StringStream('stderr')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) - if (os.environ.get('OS_LOG_CAPTURE') != 'False' and - os.environ.get('OS_LOG_CAPTURE') != '0'): - self.useFixture(fixtures.LoggerFixture(nuke_handlers=False, - format=self.log_format, - level=None)) diff --git a/tempest/lib/cli/__init__.py b/tempest/lib/cli/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/cli/base.py b/tempest/lib/cli/base.py deleted file mode 100644 index 5468a7bcd..000000000 --- a/tempest/lib/cli/base.py +++ /dev/null @@ -1,416 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import shlex -import subprocess - -from oslo_log import log as logging -import six - -from tempest.lib import base -import tempest.lib.cli.output_parser -from tempest.lib import exceptions - - -LOG = logging.getLogger(__name__) - - -def execute(cmd, action, flags='', params='', fail_ok=False, - merge_stderr=False, cli_dir='/usr/bin', prefix=''): - """Executes specified command for the given action. - - :param cmd: command to be executed - :type cmd: string - :param action: string of the cli command to run - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: string of any optional positional args to use - :type params: string - :param fail_ok: boolean if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param merge_stderr: boolean if True the stderr buffer is merged into - stdout - :type merge_stderr: boolean - :param cli_dir: The path where the cmd can be executed - :type cli_dir: string - :param prefix: prefix to insert before command - :type prefix: string - """ - cmd = ' '.join([prefix, os.path.join(cli_dir, cmd), - flags, action, params]) - cmd = cmd.strip() - LOG.info("running: '%s'", cmd) - if six.PY2: - cmd = cmd.encode('utf-8') - cmd = shlex.split(cmd) - result = '' - result_err = '' - stdout = subprocess.PIPE - stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE - proc = subprocess.Popen(cmd, stdout=stdout, stderr=stderr) - result, result_err = proc.communicate() - if not fail_ok and proc.returncode != 0: - raise exceptions.CommandFailed(proc.returncode, - cmd, - result, - result_err) - if six.PY2: - return result - else: - return os.fsdecode(result) - - -class CLIClient(object): - """Class to use OpenStack official python client CLI's with auth - - :param username: The username to authenticate with - :type username: string - :param password: The password to authenticate with - :type password: string - :param tenant_name: The name of the tenant to use with the client calls - :type tenant_name: string - :param uri: The auth uri for the OpenStack Deployment - :type uri: string - :param cli_dir: The path where the python client binaries are installed. - defaults to /usr/bin - :type cli_dir: string - :param insecure: if True, --insecure is passed to python client binaries. - :type insecure: boolean - :param prefix: prefix to insert before commands - :type prefix: string - """ - - def __init__(self, username='', password='', tenant_name='', uri='', - cli_dir='', insecure=False, prefix='', *args, **kwargs): - """Initialize a new CLIClient object.""" - super(CLIClient, self).__init__() - self.cli_dir = cli_dir if cli_dir else '/usr/bin' - self.username = username - self.tenant_name = tenant_name - self.password = password - self.uri = uri - self.insecure = insecure - self.prefix = prefix - - def nova(self, action, flags='', params='', fail_ok=False, - endpoint_type='publicURL', merge_stderr=False): - """Executes nova command for the given action. - - :param action: the cli command to run using nova - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --os-endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'nova', action, flags, params, fail_ok, merge_stderr) - - def nova_manage(self, action, flags='', params='', fail_ok=False, - merge_stderr=False): - """Executes nova-manage command for the given action. - - :param action: the cli command to run using nova-manage - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - return execute( - 'nova-manage', action, flags, params, fail_ok, merge_stderr, - self.cli_dir) - - def keystone(self, action, flags='', params='', fail_ok=False, - merge_stderr=False): - """Executes keystone command for the given action. - - :param action: the cli command to run using keystone - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - return self.cmd_with_auth( - 'keystone', action, flags, params, fail_ok, merge_stderr) - - def glance(self, action, flags='', params='', fail_ok=False, - endpoint_type='publicURL', merge_stderr=False): - """Executes glance command for the given action. - - :param action: the cli command to run using glance - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --os-endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'glance', action, flags, params, fail_ok, merge_stderr) - - def ceilometer(self, action, flags='', params='', - fail_ok=False, endpoint_type='publicURL', - merge_stderr=False): - """Executes ceilometer command for the given action. - - :param action: the cli command to run using ceilometer - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --os-endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'ceilometer', action, flags, params, fail_ok, merge_stderr) - - def heat(self, action, flags='', params='', - fail_ok=False, endpoint_type='publicURL', merge_stderr=False): - """Executes heat command for the given action. - - :param action: the cli command to run using heat - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --os-endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'heat', action, flags, params, fail_ok, merge_stderr) - - def cinder(self, action, flags='', params='', fail_ok=False, - endpoint_type='publicURL', merge_stderr=False): - """Executes cinder command for the given action. - - :param action: the cli command to run using cinder - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'cinder', action, flags, params, fail_ok, merge_stderr) - - def swift(self, action, flags='', params='', fail_ok=False, - endpoint_type='publicURL', merge_stderr=False): - """Executes swift command for the given action. - - :param action: the cli command to run using swift - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --os-endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'swift', action, flags, params, fail_ok, merge_stderr) - - def neutron(self, action, flags='', params='', fail_ok=False, - endpoint_type='publicURL', merge_stderr=False): - """Executes neutron command for the given action. - - :param action: the cli command to run using neutron - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'neutron', action, flags, params, fail_ok, merge_stderr) - - def sahara(self, action, flags='', params='', - fail_ok=False, endpoint_type='publicURL', merge_stderr=True): - """Executes sahara command for the given action. - - :param action: the cli command to run using sahara - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'sahara', action, flags, params, fail_ok, merge_stderr) - - def openstack(self, action, flags='', params='', fail_ok=False, - merge_stderr=False): - """Executes openstack command for the given action. - - :param action: the cli command to run using openstack - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - return self.cmd_with_auth( - 'openstack', action, flags, params, fail_ok, merge_stderr) - - def cmd_with_auth(self, cmd, action, flags='', params='', - fail_ok=False, merge_stderr=False): - """Executes given command with auth attributes appended. - - :param cmd: command to be executed - :type cmd: string - :param action: command on cli to run - :type action: string - :param flags: optional cli flags to use - :type flags: string - :param params: optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the cli return - code is non-zero - :type fail_ok: boolean - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - creds = ('--os-username %s --os-tenant-name %s --os-password %s ' - '--os-auth-url %s' % - (self.username, - self.tenant_name, - self.password, - self.uri)) - if self.insecure: - flags = creds + ' --insecure ' + flags - else: - flags = creds + ' ' + flags - return execute(cmd, action, flags, params, fail_ok, merge_stderr, - self.cli_dir, prefix=self.prefix) - - -class ClientTestBase(base.BaseTestCase): - """Base test class for testing the OpenStack client CLI interfaces.""" - - def setUp(self): - super(ClientTestBase, self).setUp() - self.clients = self._get_clients() - self.parser = tempest.lib.cli.output_parser - - def _get_clients(self): - """Abstract method to initialize CLIClient object. - - This method must be overloaded in child test classes. It should be - used to initialize the CLIClient object with the appropriate - credentials during the setUp() phase of tests. - """ - raise NotImplementedError - - def assertTableStruct(self, items, field_names): - """Verify that all items has keys listed in field_names. - - :param items: items to assert are field names in the output table - :type items: list - :param field_names: field names from the output table of the cmd - :type field_names: list - """ - for item in items: - for field in field_names: - self.assertIn(field, item) - - def assertFirstLineStartsWith(self, lines, beginning): - """Verify that the first line starts with a string - - :param lines: strings for each line of output - :type lines: list - :param beginning: verify this is at the beginning of the first line - :type beginning: string - """ - self.assertTrue(lines[0].startswith(beginning), - msg=('Beginning of first line has invalid content: %s' - % lines[:3])) diff --git a/tempest/lib/cli/output_parser.py b/tempest/lib/cli/output_parser.py deleted file mode 100644 index 2edd5c16f..000000000 --- a/tempest/lib/cli/output_parser.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -"""Collection of utilities for parsing CLI clients output.""" - -import re - -from oslo_log import log as logging - -from tempest.lib import exceptions - - -LOG = logging.getLogger(__name__) - - -delimiter_line = re.compile('^\+\-[\+\-]+\-\+$') - - -def details_multiple(output_lines, with_label=False): - """Return list of dicts with item details from cli output tables. - - If with_label is True, key '__label' is added to each items dict. - For more about 'label' see OutputParser.tables(). - """ - items = [] - tables_ = tables(output_lines) - for table_ in tables_: - if ('Property' not in table_['headers'] - or 'Value' not in table_['headers']): - raise exceptions.InvalidStructure() - item = {} - for value in table_['values']: - item[value[0]] = value[1] - if with_label: - item['__label'] = table_['label'] - items.append(item) - return items - - -def details(output_lines, with_label=False): - """Return dict with details of first item (table) found in output.""" - items = details_multiple(output_lines, with_label) - return items[0] - - -def listing(output_lines): - """Return list of dicts with basic item info parsed from cli output.""" - - items = [] - table_ = table(output_lines) - for row in table_['values']: - item = {} - for col_idx, col_key in enumerate(table_['headers']): - item[col_key] = row[col_idx] - items.append(item) - return items - - -def tables(output_lines): - """Find all ascii-tables in output and parse them. - - Return list of tables parsed from cli output as dicts. - (see OutputParser.table()) - - And, if found, label key (separated line preceding the table) - is added to each tables dict. - """ - tables_ = [] - - table_ = [] - label = None - - start = False - header = False - - if not isinstance(output_lines, list): - output_lines = output_lines.split('\n') - - for line in output_lines: - if delimiter_line.match(line): - if not start: - start = True - elif not header: - # we are after head area - header = True - else: - # table ends here - start = header = None - table_.append(line) - - parsed = table(table_) - parsed['label'] = label - tables_.append(parsed) - - table_ = [] - label = None - continue - if start: - table_.append(line) - else: - if label is None: - label = line - else: - LOG.warning('Invalid line between tables: %s', line) - if table_: - LOG.warning('Missing end of table') - - return tables_ - - -def table(output_lines): - """Parse single table from cli output. - - Return dict with list of column names in 'headers' key and - rows in 'values' key. - """ - table_ = {'headers': [], 'values': []} - columns = None - - if not isinstance(output_lines, list): - output_lines = output_lines.split('\n') - - if not output_lines[-1]: - # skip last line if empty (just newline at the end) - output_lines = output_lines[:-1] - - for line in output_lines: - if delimiter_line.match(line): - columns = _table_columns(line) - continue - if '|' not in line: - LOG.warning('skipping invalid table line: %s', line) - continue - row = [] - for col in columns: - row.append(line[col[0]:col[1]].strip()) - if table_['headers']: - table_['values'].append(row) - else: - table_['headers'] = row - - return table_ - - -def _table_columns(first_table_row): - """Find column ranges in output line. - - Return list of tuples (start,end) for each column - detected by plus (+) characters in delimiter line. - """ - positions = [] - start = 1 # there is '+' at 0 - while start < len(first_table_row): - end = first_table_row.find('+', start) - if end == -1: - break - positions.append((start, end)) - start = end + 1 - return positions diff --git a/tempest/lib/cmd/__init__.py b/tempest/lib/cmd/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/cmd/check_uuid.py b/tempest/lib/cmd/check_uuid.py deleted file mode 100755 index 101d692c2..000000000 --- a/tempest/lib/cmd/check_uuid.py +++ /dev/null @@ -1,362 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2014 Mirantis, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import ast -import importlib -import inspect -import os -import sys -import unittest -import uuid - -from oslo_utils import uuidutils -import six.moves.urllib.parse as urlparse - -DECORATOR_MODULE = 'decorators' -DECORATOR_NAME = 'idempotent_id' -DECORATOR_IMPORT = 'tempest.%s' % DECORATOR_MODULE -IMPORT_LINE = 'from tempest.lib import %s' % DECORATOR_MODULE -DECORATOR_TEMPLATE = "@%s.%s('%%s')" % (DECORATOR_MODULE, - DECORATOR_NAME) -UNIT_TESTS_EXCLUDE = 'tempest.tests' - - -class SourcePatcher(object): - - """"Lazy patcher for python source files""" - - def __init__(self): - self.source_files = None - self.patches = None - self.clear() - - def clear(self): - """Clear inner state""" - self.source_files = {} - self.patches = {} - - @staticmethod - def _quote(s): - return urlparse.quote(s) - - @staticmethod - def _unquote(s): - return urlparse.unquote(s) - - def add_patch(self, filename, patch, line_no): - """Add lazy patch""" - if filename not in self.source_files: - with open(filename) as f: - self.source_files[filename] = self._quote(f.read()) - patch_id = uuidutils.generate_uuid() - if not patch.endswith('\n'): - patch += '\n' - self.patches[patch_id] = self._quote(patch) - lines = self.source_files[filename].split(self._quote('\n')) - lines[line_no - 1] = ''.join(('{%s:s}' % patch_id, lines[line_no - 1])) - self.source_files[filename] = self._quote('\n').join(lines) - - @staticmethod - def _save_changes(filename, source): - print('%s fixed' % filename) - with open(filename, 'w') as f: - f.write(source) - - def apply_patches(self): - """Apply all patches""" - for filename in self.source_files: - patched_source = self._unquote( - self.source_files[filename].format(**self.patches) - ) - self._save_changes(filename, patched_source) - self.clear() - - -class TestChecker(object): - - def __init__(self, package): - self.package = package - self.base_path = os.path.abspath(os.path.dirname(package.__file__)) - - def _path_to_package(self, path): - relative_path = path[len(self.base_path) + 1:] - if relative_path: - return '.'.join((self.package.__name__,) + - tuple(relative_path.split('/'))) - else: - return self.package.__name__ - - def _modules_search(self): - """Recursive search for python modules in base package""" - modules = [] - for root, dirs, files in os.walk(self.base_path): - if not os.path.exists(os.path.join(root, '__init__.py')): - continue - root_package = self._path_to_package(root) - for item in files: - if item.endswith('.py'): - module_name = '.'.join((root_package, - os.path.splitext(item)[0])) - if not module_name.startswith(UNIT_TESTS_EXCLUDE): - modules.append(module_name) - return modules - - @staticmethod - def _get_idempotent_id(test_node): - "Return key-value dict with metadata from @decorators.idempotent_id" - idempotent_id = None - for decorator in test_node.decorator_list: - if (hasattr(decorator, 'func') and - hasattr(decorator.func, 'attr') and - decorator.func.attr == DECORATOR_NAME and - hasattr(decorator.func, 'value') and - decorator.func.value.id == DECORATOR_MODULE): - for arg in decorator.args: - idempotent_id = ast.literal_eval(arg) - return idempotent_id - - @staticmethod - def _is_decorator(line): - return line.strip().startswith('@') - - @staticmethod - def _is_def(line): - return line.strip().startswith('def ') - - def _add_uuid_to_test(self, patcher, test_node, source_path): - with open(source_path) as src: - src_lines = src.read().split('\n') - lineno = test_node.lineno - insert_position = lineno - while True: - if (self._is_def(src_lines[lineno - 1]) or - (self._is_decorator(src_lines[lineno - 1]) and - (DECORATOR_TEMPLATE.split('(')[0] <= - src_lines[lineno - 1].strip().split('(')[0]))): - insert_position = lineno - break - lineno += 1 - patcher.add_patch( - source_path, - ' ' * test_node.col_offset + DECORATOR_TEMPLATE % uuid.uuid4(), - insert_position - ) - - @staticmethod - def _is_test_case(module, node): - if (node.__class__ is ast.ClassDef and - hasattr(module, node.name) and - inspect.isclass(getattr(module, node.name))): - return issubclass(getattr(module, node.name), unittest.TestCase) - - @staticmethod - def _is_test_method(node): - return (node.__class__ is ast.FunctionDef - and node.name.startswith('test_')) - - @staticmethod - def _next_node(body, node): - if body.index(node) < len(body): - return body[body.index(node) + 1] - - @staticmethod - def _import_name(node): - if isinstance(node, ast.Import): - return node.names[0].name - elif isinstance(node, ast.ImportFrom): - return '%s.%s' % (node.module, node.names[0].name) - - def _add_import_for_test_uuid(self, patcher, src_parsed, source_path): - with open(source_path) as f: - src_lines = f.read().split('\n') - line_no = 0 - tempest_imports = [node for node in src_parsed.body - if self._import_name(node) and - 'tempest.' in self._import_name(node)] - if not tempest_imports: - import_snippet = '\n'.join(('', IMPORT_LINE, '')) - else: - for node in tempest_imports: - if self._import_name(node) < DECORATOR_IMPORT: - continue - else: - line_no = node.lineno - import_snippet = IMPORT_LINE - break - else: - line_no = tempest_imports[-1].lineno - while True: - if (not src_lines[line_no - 1] or - getattr(self._next_node(src_parsed.body, - tempest_imports[-1]), - 'lineno') == line_no or - line_no == len(src_lines)): - break - line_no += 1 - import_snippet = '\n'.join((IMPORT_LINE, '')) - patcher.add_patch(source_path, import_snippet, line_no) - - def get_tests(self): - """Get test methods with sources from base package with metadata""" - tests = {} - for module_name in self._modules_search(): - tests[module_name] = {} - module = importlib.import_module(module_name) - source_path = '.'.join( - (os.path.splitext(module.__file__)[0], 'py') - ) - with open(source_path, 'r') as f: - source = f.read() - tests[module_name]['source_path'] = source_path - tests[module_name]['tests'] = {} - source_parsed = ast.parse(source) - tests[module_name]['ast'] = source_parsed - tests[module_name]['import_valid'] = ( - hasattr(module, DECORATOR_MODULE) and - inspect.ismodule(getattr(module, DECORATOR_MODULE)) - ) - test_cases = (node for node in source_parsed.body - if self._is_test_case(module, node)) - for node in test_cases: - for subnode in filter(self._is_test_method, node.body): - test_name = '%s.%s' % (node.name, subnode.name) - tests[module_name]['tests'][test_name] = subnode - return tests - - @staticmethod - def _filter_tests(function, tests): - """Filter tests with condition 'function(test_node) == True'""" - result = {} - for module_name in tests: - for test_name in tests[module_name]['tests']: - if function(module_name, test_name, tests): - if module_name not in result: - result[module_name] = { - 'ast': tests[module_name]['ast'], - 'source_path': tests[module_name]['source_path'], - 'import_valid': tests[module_name]['import_valid'], - 'tests': {} - } - result[module_name]['tests'][test_name] = \ - tests[module_name]['tests'][test_name] - return result - - def find_untagged(self, tests): - """Filter all tests without uuid in metadata""" - def check_uuid_in_meta(module_name, test_name, tests): - idempotent_id = self._get_idempotent_id( - tests[module_name]['tests'][test_name]) - return not idempotent_id - return self._filter_tests(check_uuid_in_meta, tests) - - def report_collisions(self, tests): - """Reports collisions if there are any - - Returns true if collisions exist. - """ - uuids = {} - - def report(module_name, test_name, tests): - test_uuid = self._get_idempotent_id( - tests[module_name]['tests'][test_name]) - if not test_uuid: - return - if test_uuid in uuids: - error_str = "%s:%s\n uuid %s collision: %s<->%s\n%s:%s" % ( - tests[module_name]['source_path'], - tests[module_name]['tests'][test_name].lineno, - test_uuid, - test_name, - uuids[test_uuid]['test_name'], - uuids[test_uuid]['source_path'], - uuids[test_uuid]['test_node'].lineno, - ) - print(error_str) - print("cannot automatically resolve the collision, please " - "manually remove the duplicate value on the new test.") - return True - else: - uuids[test_uuid] = { - 'module': module_name, - 'test_name': test_name, - 'test_node': tests[module_name]['tests'][test_name], - 'source_path': tests[module_name]['source_path'] - } - return bool(self._filter_tests(report, tests)) - - def report_untagged(self, tests): - """Reports untagged tests if there are any - - Returns true if untagged tests exist. - """ - def report(module_name, test_name, tests): - error_str = ("%s:%s\nmissing @decorators.idempotent_id" - "('...')\n%s\n") % ( - tests[module_name]['source_path'], - tests[module_name]['tests'][test_name].lineno, - test_name - ) - print(error_str) - return True - return bool(self._filter_tests(report, tests)) - - def fix_tests(self, tests): - """Add uuids to all specified in tests and fix it in source files""" - patcher = SourcePatcher() - for module_name in tests: - add_import_once = True - for test_name in tests[module_name]['tests']: - if not tests[module_name]['import_valid'] and add_import_once: - self._add_import_for_test_uuid( - patcher, - tests[module_name]['ast'], - tests[module_name]['source_path'] - ) - add_import_once = False - self._add_uuid_to_test( - patcher, tests[module_name]['tests'][test_name], - tests[module_name]['source_path']) - patcher.apply_patches() - - -def run(): - parser = argparse.ArgumentParser() - parser.add_argument('--package', action='store', dest='package', - default='tempest', type=str, - help='Package with tests') - parser.add_argument('--fix', action='store_true', dest='fix_tests', - help='Attempt to fix tests without UUIDs') - args = parser.parse_args() - sys.path.append(os.path.join(os.path.dirname(__file__), '..')) - pkg = importlib.import_module(args.package) - checker = TestChecker(pkg) - errors = False - tests = checker.get_tests() - untagged = checker.find_untagged(tests) - errors = checker.report_collisions(tests) or errors - if args.fix_tests and untagged: - checker.fix_tests(untagged) - else: - errors = checker.report_untagged(untagged) or errors - if errors: - sys.exit("@decorators.idempotent_id existence and uniqueness checks " - "failed\n" - "Run 'tox -v -e uuidgen' to automatically fix tests with\n" - "missing @decorators.idempotent_id decorators.") - -if __name__ == '__main__': - run() diff --git a/tempest/lib/cmd/skip_tracker.py b/tempest/lib/cmd/skip_tracker.py deleted file mode 100755 index 87806b7fc..000000000 --- a/tempest/lib/cmd/skip_tracker.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env python2 - -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Track test skips via launchpadlib API and raise alerts if a bug -is fixed but a skip is still in the Tempest test code -""" - -import argparse -import os -import re - -from oslo_log import log as logging - -try: - from launchpadlib import launchpad -except ImportError: - launchpad = None - -LPCACHEDIR = os.path.expanduser('~/.launchpadlib/cache') -LOG = logging.getLogger(__name__) - -BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..')) -TESTDIR = os.path.join(BASEDIR, 'tempest') - - -def parse_args(): - parser = argparse.ArgumentParser() - parser.add_argument('test_path', nargs='?', default=TESTDIR, - help='Path of test dir') - return parser.parse_args() - - -def info(msg, *args, **kwargs): - LOG.info(msg, *args, **kwargs) - - -def debug(msg, *args, **kwargs): - LOG.debug(msg, *args, **kwargs) - - -def find_skips(start): - """Find the entire list of skipped tests. - - Returns a list of tuples (method, bug) that represent - test methods that have been decorated to skip because of - a particular bug. - """ - results = {} - debug("Searching in %s", start) - for root, _dirs, files in os.walk(start): - for name in files: - if name.startswith('test_') and name.endswith('py'): - path = os.path.join(root, name) - debug("Searching in %s", path) - temp_result = find_skips_in_file(path) - for method_name, bug_no in temp_result: - if results.get(bug_no): - result_dict = results.get(bug_no) - if result_dict.get(name): - result_dict[name].append(method_name) - else: - result_dict[name] = [method_name] - results[bug_no] = result_dict - else: - results[bug_no] = {name: [method_name]} - return results - - -def find_skips_in_file(path): - """Return the skip tuples in a test file.""" - BUG_RE = re.compile(r'\s*@.*skip_because\(bug=[\'"](\d+)[\'"]') - DEF_RE = re.compile(r'\s*def (\w+)\(') - bug_found = False - results = [] - with open(path, 'rb') as content: - lines = content.readlines() - for x, line in enumerate(lines): - if not bug_found: - res = BUG_RE.match(line) - if res: - bug_no = int(res.group(1)) - debug("Found bug skip %s on line %d", bug_no, x + 1) - bug_found = True - else: - res = DEF_RE.match(line) - if res: - method = res.group(1) - debug("Found test method %s skips for bug %d", - method, bug_no) - results.append((method, bug_no)) - bug_found = False - return results - - -def get_results(result_dict): - results = [] - for bug_no in result_dict: - for method in result_dict[bug_no]: - results.append((method, bug_no)) - return results - - -def main(): - parser = parse_args() - results = find_skips(parser.test_path) - unique_bugs = sorted(set([bug for (method, bug) in get_results(results)])) - unskips = [] - duplicates = [] - info("Total bug skips found: %d", len(results)) - info("Total unique bugs causing skips: %d", len(unique_bugs)) - if launchpad is not None: - lp = launchpad.Launchpad.login_anonymously('grabbing bugs', - 'production', - LPCACHEDIR) - else: - print("To check the bug status launchpadlib should be installed") - exit(1) - - for bug_no in unique_bugs: - bug = lp.bugs[bug_no] - duplicate = bug.duplicate_of_link - if duplicate is not None: - dup_id = duplicate.split('/')[-1] - duplicates.append((bug_no, dup_id)) - for task in bug.bug_tasks: - info("Bug #%7s (%12s - %12s)", bug_no, - task.importance, task.status) - if task.status in ('Fix Released', 'Fix Committed'): - unskips.append(bug_no) - - for bug_id, dup_id in duplicates: - if bug_id not in unskips: - dup_bug = lp.bugs[dup_id] - for task in dup_bug.bug_tasks: - info("Bug #%7s is a duplicate of Bug#%7s (%12s - %12s)", - bug_id, dup_id, task.importance, task.status) - if task.status in ('Fix Released', 'Fix Committed'): - unskips.append(bug_id) - - unskips = sorted(set(unskips)) - if unskips: - print("The following bugs have been fixed and the corresponding skips") - print("should be removed from the test cases:") - print() - for bug in unskips: - message = " %7s in " % bug - locations = ["%s" % x for x in results[bug].keys()] - message += " and ".join(locations) - print(message) - - -if __name__ == '__main__': - main() diff --git a/tempest/lib/common/__init__.py b/tempest/lib/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/common/api_version_request.py b/tempest/lib/common/api_version_request.py deleted file mode 100644 index b2b68a6b2..000000000 --- a/tempest/lib/common/api_version_request.py +++ /dev/null @@ -1,159 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import re - -from tempest.lib import exceptions - - -# Define the minimum and maximum version of the API across all of the -# REST API. The format of the version is: -# X.Y where: -# -# - X will only be changed if a significant backwards incompatible API -# change is made which affects the API as whole. That is, something -# that is only very very rarely incremented. -# -# - Y when you make any change to the API. Note that this includes -# semantic changes which may not affect the input or output formats or -# even originate in the API code layer. We are not distinguishing -# between backwards compatible and backwards incompatible changes in -# the versioning system. It must be made clear in the documentation as -# to what is a backwards compatible change and what is a backwards -# incompatible one. - -class APIVersionRequest(object): - """This class represents an API Version Request. - - This class provides convenience methods for manipulation - and comparison of version numbers that we need to do to - implement microversions. - - :param version_string: String representation of APIVersionRequest. - Correct format is 'X.Y', where 'X' and 'Y' are int values. - None value should be used to create Null APIVersionRequest, - which is equal to 0.0 - """ - - # NOTE: This 'latest' version is a magic number, we assume any - # projects(Nova, etc.) never achieve this number. - latest_ver_major = 99999 - latest_ver_minor = 99999 - - def __init__(self, version_string=None): - """Create an API version request object.""" - # NOTE(gmann): 'version_string' as String "None" will be considered as - # invalid version string. - self.ver_major = 0 - self.ver_minor = 0 - - if version_string is not None: - match = re.match(r"^([1-9]\d*)\.([1-9]\d*|0)$", - version_string) - if match: - self.ver_major = int(match.group(1)) - self.ver_minor = int(match.group(2)) - elif version_string == 'latest': - self.ver_major = self.latest_ver_major - self.ver_minor = self.latest_ver_minor - else: - raise exceptions.InvalidAPIVersionString( - version=version_string) - - def __str__(self): - """Debug/Logging representation of object.""" - return ("API Version Request: %s" % self.get_string()) - - def is_null(self): - """Checks whether version is null. - - Return True if version object is null otherwise False. - - :returns: boolean - """ - return self.ver_major == 0 and self.ver_minor == 0 - - def _format_type_error(self, other): - return TypeError("'%(other)s' should be an instance of '%(cls)s'" % - {"other": other, "cls": self.__class__}) - - def __lt__(self, other): - if not isinstance(other, APIVersionRequest): - raise self._format_type_error(other) - - return ((self.ver_major, self.ver_minor) < - (other.ver_major, other.ver_minor)) - - def __eq__(self, other): - if not isinstance(other, APIVersionRequest): - raise self._format_type_error(other) - - return ((self.ver_major, self.ver_minor) == - (other.ver_major, other.ver_minor)) - - def __gt__(self, other): - if not isinstance(other, APIVersionRequest): - raise self._format_type_error(other) - - return ((self.ver_major, self.ver_minor) > - (other.ver_major, other.ver_minor)) - - def __le__(self, other): - return self < other or self == other - - def __ne__(self, other): - return not self.__eq__(other) - - def __ge__(self, other): - return self > other or self == other - - def matches(self, min_version, max_version): - """Matches the version object. - - Returns whether the version object represents a version - greater than or equal to the minimum version and less than - or equal to the maximum version. - - :param min_version: Minimum acceptable version. - :param max_version: Maximum acceptable version. - :returns: boolean - - If min_version is null then there is no minimum limit. - If max_version is null then there is no maximum limit. - If self is null then raise ValueError - """ - - if self.is_null(): - raise ValueError - if max_version.is_null() and min_version.is_null(): - return True - elif max_version.is_null(): - return min_version <= self - elif min_version.is_null(): - return self <= max_version - else: - return min_version <= self <= max_version - - def get_string(self): - """Version string representation. - - Converts object to string representation which if used to create - an APIVersionRequest object results in the same version request. - """ - if self.is_null(): - return None - if (self.ver_major == self.latest_ver_major and - self.ver_minor == self.latest_ver_minor): - return 'latest' - return "%s.%s" % (self.ver_major, self.ver_minor) diff --git a/tempest/lib/common/api_version_utils.py b/tempest/lib/common/api_version_utils.py deleted file mode 100644 index 1371b3c66..000000000 --- a/tempest/lib/common/api_version_utils.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.lib.common import api_version_request -from tempest.lib import exceptions - - -LATEST_MICROVERSION = 'latest' - - -class BaseMicroversionTest(object): - """Mixin class for API microversion test class.""" - - # NOTE: Basically, each microversion is small API change and we - # can use the same tests for most microversions in most cases. - # So it is nice to define the test class as possible to run - # for all microversions. We need to define microversion range - # (min_microversion, max_microversion) on each test class if necessary. - min_microversion = None - max_microversion = LATEST_MICROVERSION - - -def check_skip_with_microversion(test_min_version, test_max_version, - cfg_min_version, cfg_max_version): - """Checks API microversions range and returns whether test needs to be skip - - Compare the test and configured microversion range and returns - whether test microversion range is out of configured one. - This method can be used to skip the test based on configured and test - microversion range. - - :param test_min_version: Test Minimum Microversion - :param test_max_version: Test Maximum Microversion - :param cfg_min_version: Configured Minimum Microversion - :param cfg_max_version: Configured Maximum Microversion - :returns: boolean - """ - - min_version = api_version_request.APIVersionRequest(test_min_version) - max_version = api_version_request.APIVersionRequest(test_max_version) - config_min_version = api_version_request.APIVersionRequest(cfg_min_version) - config_max_version = api_version_request.APIVersionRequest(cfg_max_version) - if ((min_version > max_version) or - (config_min_version > config_max_version)): - msg = ("Test Class versions [%s - %s]. " - "Configuration versions [%s - %s]." - % (min_version.get_string(), - max_version.get_string(), - config_min_version.get_string(), - config_max_version.get_string())) - raise exceptions.InvalidAPIVersionRange(msg) - - # NOTE: Select tests which are in range of configuration like - # config min config max - # ----------------+--------------------------+---------------- - # ...don't-select| - # ...select... ...select... ...select... - # |don't-select... - # ......................select............................ - if (max_version < config_min_version or - config_max_version < min_version): - msg = ("The microversion range[%s - %s] of this test is out of the " - "configuration range[%s - %s]." - % (min_version.get_string(), - max_version.get_string(), - config_min_version.get_string(), - config_max_version.get_string())) - raise testtools.TestCase.skipException(msg) - - -def select_request_microversion(test_min_version, cfg_min_version): - """Select microversion from test and configuration min version. - - Compare requested microversion and return the maximum - microversion out of those. - - :param test_min_version: Test Minimum Microversion - :param cfg_min_version: Configured Minimum Microversion - :returns: Selected microversion string - """ - - test_version = api_version_request.APIVersionRequest(test_min_version) - cfg_version = api_version_request.APIVersionRequest(cfg_min_version) - max_version = cfg_version if cfg_version >= test_version else test_version - return max_version.get_string() - - -def assert_version_header_matches_request(api_microversion_header_name, - api_microversion, - response_header): - """Checks API microversion in response header - - Verify whether microversion is present in response header - and with specified 'api_microversion' value. - - :param api_microversion_header_name: Microversion header name - Example- "X-OpenStack-Nova-API-Version" - :param api_microversion: Microversion number like "2.10" - :param response_header: Response header where microversion is - expected to be present. - """ - api_microversion_header_name = api_microversion_header_name.lower() - if (api_microversion_header_name not in response_header or - api_microversion != response_header[api_microversion_header_name]): - msg = ("Microversion header '%s' with value '%s' does not match in " - "response - %s. " % (api_microversion_header_name, - api_microversion, - response_header)) - raise exceptions.InvalidHTTPResponseHeader(msg) diff --git a/tempest/lib/common/cred_client.py b/tempest/lib/common/cred_client.py deleted file mode 100644 index a81f53c9c..000000000 --- a/tempest/lib/common/cred_client.py +++ /dev/null @@ -1,212 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc - -from oslo_log import log as logging -import six - -from tempest.lib import auth -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.identity.v2 import identity_client as v2_identity - -LOG = logging.getLogger(__name__) - - -@six.add_metaclass(abc.ABCMeta) -class CredsClient(object): - """This class is a wrapper around the identity clients - - to provide a single interface for managing credentials in both v2 and v3 - cases. It's not bound to created credentials, only to a specific set of - admin credentials used for generating credentials. - """ - - def __init__(self, identity_client, projects_client, users_client, - roles_client): - # The client implies version and credentials - self.identity_client = identity_client - self.users_client = users_client - self.projects_client = projects_client - self.roles_client = roles_client - - def create_user(self, username, password, project, email): - params = {'name': username, - 'password': password, - self.project_id_param: project['id'], - 'email': email} - user = self.users_client.create_user(**params) - if 'user' in user: - user = user['user'] - return user - - def delete_user(self, user_id): - self.users_client.delete_user(user_id) - - @abc.abstractmethod - def create_project(self, name, description): - pass - - def _check_role_exists(self, role_name): - try: - roles = self._list_roles() - lc_role_name = role_name.lower() - role = next(r for r in roles if r['name'].lower() == lc_role_name) - except StopIteration: - return None - return role - - def create_user_role(self, role_name): - if not self._check_role_exists(role_name): - self.roles_client.create_role(name=role_name) - - def assign_user_role(self, user, project, role_name): - role = self._check_role_exists(role_name) - if not role: - msg = 'No "%s" role found' % role_name - raise lib_exc.NotFound(msg) - try: - self.roles_client.create_user_role_on_project(project['id'], - user['id'], - role['id']) - except lib_exc.Conflict: - LOG.debug("Role %s already assigned on project %s for user %s", - role['id'], project['id'], user['id']) - - @abc.abstractmethod - def get_credentials(self, user, project, password): - """Produces a Credentials object from the details provided - - :param user: a user dict - :param project: a project dict - :param password: the password as a string - :return: a Credentials object with all the available credential details - """ - pass - - def _list_roles(self): - roles = self.roles_client.list_roles()['roles'] - return roles - - -class V2CredsClient(CredsClient): - project_id_param = 'tenantId' - - def __init__(self, identity_client, projects_client, users_client, - roles_client): - super(V2CredsClient, self).__init__(identity_client, - projects_client, - users_client, - roles_client) - - def create_project(self, name, description): - tenant = self.projects_client.create_tenant( - name=name, description=description)['tenant'] - return tenant - - def delete_project(self, project_id): - self.projects_client.delete_tenant(project_id) - - def get_credentials(self, user, project, password): - # User and project already include both ID and name here, - # so there's no need to use the fill_in mode - return auth.get_credentials( - auth_url=None, - fill_in=False, - identity_version='v2', - username=user['name'], user_id=user['id'], - tenant_name=project['name'], tenant_id=project['id'], - password=password) - - -class V3CredsClient(CredsClient): - project_id_param = 'project_id' - - def __init__(self, identity_client, projects_client, users_client, - roles_client, domains_client, domain_name): - super(V3CredsClient, self).__init__(identity_client, projects_client, - users_client, roles_client) - self.domains_client = domains_client - - try: - # Domain names must be unique, in any case a list is returned, - # selecting the first (and only) element - self.creds_domain = self.domains_client.list_domains( - name=domain_name)['domains'][0] - except lib_exc.NotFound: - # TODO(andrea) we could probably create the domain on the fly - msg = "Requested domain %s could not be found" % domain_name - raise lib_exc.InvalidCredentials(msg) - - def create_project(self, name, description): - project = self.projects_client.create_project( - name=name, description=description, - domain_id=self.creds_domain['id'])['project'] - return project - - def delete_project(self, project_id): - self.projects_client.delete_project(project_id) - - def get_credentials(self, user, project, password): - # User, project and domain already include both ID and name here, - # so there's no need to use the fill_in mode. - # NOTE(andreaf) We need to set all fields in the returned credentials. - # Scope is then used to pick only those relevant for the type of - # token needed by each service client. - return auth.get_credentials( - auth_url=None, - fill_in=False, - identity_version='v3', - username=user['name'], user_id=user['id'], - project_name=project['name'], project_id=project['id'], - password=password, - project_domain_id=self.creds_domain['id'], - project_domain_name=self.creds_domain['name'], - domain_id=self.creds_domain['id'], - domain_name=self.creds_domain['name']) - - def assign_user_role_on_domain(self, user, role_name, domain=None): - """Assign the specified role on a domain - - :param user: a user dict - :param role_name: name of the role to be assigned - :param domain: (optional) The domain to assign the role on. If not - specified the default domain of cred_client - """ - # NOTE(andreaf) This method is very specific to the v3 case, and - # because of that it's not defined in the parent class. - if domain is None: - domain = self.creds_domain - role = self._check_role_exists(role_name) - if not role: - msg = 'No "%s" role found' % role_name - raise lib_exc.NotFound(msg) - try: - self.roles_client.create_user_role_on_domain( - domain['id'], user['id'], role['id']) - except lib_exc.Conflict: - LOG.debug("Role %s already assigned on domain %s for user %s", - role['id'], domain['id'], user['id']) - - -def get_creds_client(identity_client, - projects_client, - users_client, - roles_client, - domains_client=None, - project_domain_name=None): - if isinstance(identity_client, v2_identity.IdentityClient): - return V2CredsClient(identity_client, projects_client, users_client, - roles_client) - else: - return V3CredsClient(identity_client, projects_client, users_client, - roles_client, domains_client, project_domain_name) diff --git a/tempest/lib/common/cred_provider.py b/tempest/lib/common/cred_provider.py deleted file mode 100644 index 42ed41b39..000000000 --- a/tempest/lib/common/cred_provider.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (c) 2014 Deutsche Telekom AG -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import abc - -import six - -from tempest.lib import auth -from tempest.lib import exceptions - - -@six.add_metaclass(abc.ABCMeta) -class CredentialProvider(object): - def __init__(self, identity_version, name=None, - network_resources=None, credentials_domain=None, - admin_role=None, identity_uri=None): - """A CredentialProvider supplies credentials to test classes. - - :param identity_version: Identity version of the credentials provided - :param name: Name of the calling test. Included in provisioned - credentials when credentials are provisioned on the fly - :param network_resources: Network resources required for the - credentials - :param credentials_domain: Domain credentials belong to - :param admin_role: Name of the role of the admin account - :param identity_uri: Identity URI of the target cloud. This *must* be - specified for anything to work. - """ - self.identity_version = identity_version - self.identity_uri = identity_uri - self.name = name or "test_creds" - self.network_resources = network_resources - self.credentials_domain = credentials_domain or 'Default' - self.admin_role = admin_role - if not auth.is_identity_version_supported(self.identity_version): - raise exceptions.InvalidIdentityVersion( - identity_version=self.identity_version) - - @abc.abstractmethod - def get_primary_creds(self): - return - - @abc.abstractmethod - def get_admin_creds(self): - return - - @abc.abstractmethod - def get_alt_creds(self): - return - - @abc.abstractmethod - def clear_creds(self): - return - - @abc.abstractmethod - def is_multi_user(self): - return - - @abc.abstractmethod - def is_multi_tenant(self): - return - - @abc.abstractmethod - def get_creds_by_roles(self, roles, force_new=False): - return - - @abc.abstractmethod - def is_role_available(self, role): - return - - -class TestResources(object): - """Readonly Credentials, with network resources added.""" - - def __init__(self, credentials): - self._credentials = credentials - self.network = None - self.subnet = None - self.router = None - - def __getattr__(self, item): - return getattr(self._credentials, item) - - def __str__(self): - _format = "Credentials: %s, Network: %s, Subnet: %s, Router: %s" - return _format % (self._credentials, self.network, self.subnet, - self.router) - - def set_resources(self, **kwargs): - for key in kwargs: - if hasattr(self, key): - setattr(self, key, kwargs[key]) - - @property - def credentials(self): - return self._credentials diff --git a/tempest/lib/common/dynamic_creds.py b/tempest/lib/common/dynamic_creds.py deleted file mode 100644 index 90e67b4d4..000000000 --- a/tempest/lib/common/dynamic_creds.py +++ /dev/null @@ -1,477 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import ipaddress - -import netaddr -from oslo_log import log as logging -import six - -from tempest.lib.common import cred_client -from tempest.lib.common import cred_provider -from tempest.lib.common.utils import data_utils -from tempest.lib import exceptions as lib_exc -from tempest.lib.services import clients - -LOG = logging.getLogger(__name__) - - -class DynamicCredentialProvider(cred_provider.CredentialProvider): - - def __init__(self, identity_version, name=None, network_resources=None, - credentials_domain=None, admin_role=None, admin_creds=None, - identity_admin_domain_scope=False, - identity_admin_role='admin', extra_roles=None, - neutron_available=False, create_networks=True, - project_network_cidr=None, project_network_mask_bits=None, - public_network_id=None, resource_prefix=None, - identity_admin_endpoint_type='public', identity_uri=None): - """Creates credentials dynamically for tests - - A credential provider that, based on an initial set of - admin credentials, creates new credentials on the fly for - tests to use and then discard. - - :param str identity_version: identity API version to use `v2` or `v3` - :param str admin_role: name of the admin role added to admin users - :param str name: names of dynamic resources include this parameter - when specified - :param str credentials_domain: name of the domain where the users - are created. If not defined, the project - domain from admin_credentials is used - :param dict network_resources: network resources to be created for - the created credentials - :param Credentials admin_creds: initial admin credentials - :param bool identity_admin_domain_scope: Set to true if admin should be - scoped to the domain. By - default this is False and the - admin role is scoped to the - project. - :param str identity_admin_role: The role name to use for admin - :param list extra_roles: A list of strings for extra roles that should - be assigned to all created users - :param bool neutron_available: Whether we are running in an environemnt - with neutron - :param bool create_networks: Whether dynamic project networks should be - created or not - :param project_network_cidr: The CIDR to use for created project - networks - :param project_network_mask_bits: The network mask bits to use for - created project networks - :param public_network_id: The id for the public network to use - :param identity_admin_endpoint_type: The endpoint type for identity - admin clients. Defaults to public. - :param identity_uri: Identity URI of the target cloud - """ - super(DynamicCredentialProvider, self).__init__( - identity_version=identity_version, identity_uri=identity_uri, - admin_role=admin_role, name=name, - credentials_domain=credentials_domain, - network_resources=network_resources) - self.network_resources = network_resources - self._creds = {} - self.ports = [] - self.resource_prefix = resource_prefix or '' - self.neutron_available = neutron_available - self.create_networks = create_networks - self.project_network_cidr = project_network_cidr - self.project_network_mask_bits = project_network_mask_bits - self.public_network_id = public_network_id - self.default_admin_creds = admin_creds - self.identity_admin_domain_scope = identity_admin_domain_scope - self.identity_admin_role = identity_admin_role or 'admin' - self.identity_admin_endpoint_type = identity_admin_endpoint_type - self.extra_roles = extra_roles or [] - (self.identity_admin_client, - self.tenants_admin_client, - self.users_admin_client, - self.roles_admin_client, - self.domains_admin_client, - self.networks_admin_client, - self.routers_admin_client, - self.subnets_admin_client, - self.ports_admin_client, - self.security_groups_admin_client) = self._get_admin_clients( - identity_admin_endpoint_type) - # Domain where isolated credentials are provisioned (v3 only). - # Use that of the admin account is None is configured. - self.creds_domain_name = None - if self.identity_version == 'v3': - self.creds_domain_name = ( - self.default_admin_creds.project_domain_name or - self.credentials_domain) - self.creds_client = cred_client.get_creds_client( - self.identity_admin_client, - self.tenants_admin_client, - self.users_admin_client, - self.roles_admin_client, - self.domains_admin_client, - self.creds_domain_name) - - def _get_admin_clients(self, endpoint_type): - """Returns a tuple with instances of the following admin clients - - (in this order): - identity - network - """ - os = clients.ServiceClients(self.default_admin_creds, - self.identity_uri) - params = {'endpoint_type': endpoint_type} - if self.identity_version == 'v2': - return (os.identity_v2.IdentityClient(**params), - os.identity_v2.TenantsClient(**params), - os.identity_v2.UsersClient(**params), - os.identity_v2.RolesClient(**params), None, - os.network.NetworksClient(), - os.network.RoutersClient(), - os.network.SubnetsClient(), - os.network.PortsClient(), - os.network.SecurityGroupsClient()) - else: - # We use a dedicated client manager for identity client in case we - # need a different token scope for them. - scope = 'domain' if self.identity_admin_domain_scope else 'project' - identity_os = clients.ServiceClients(self.default_admin_creds, - self.identity_uri, - scope=scope) - return (identity_os.identity_v3.IdentityClient(**params), - identity_os.identity_v3.ProjectsClient(**params), - identity_os.identity_v3.UsersClient(**params), - identity_os.identity_v3.RolesClient(**params), - identity_os.identity_v3.DomainsClient(**params), - os.network.NetworksClient(), - os.network.RoutersClient(), - os.network.SubnetsClient(), - os.network.PortsClient(), - os.network.SecurityGroupsClient()) - - def _create_creds(self, admin=False, roles=None): - """Create credentials with random name. - - Creates project and user. When admin flag is True create user - with admin role. Assign user with additional roles (for example - _member_) and roles requested by caller. - - :param admin: Flag if to assign to the user admin role - :type admin: bool - :param roles: Roles to assign for the user - :type roles: list - :return: Readonly Credentials with network resources - """ - root = self.name - - project_name = data_utils.rand_name(root, prefix=self.resource_prefix) - project_desc = project_name + "-desc" - project = self.creds_client.create_project( - name=project_name, description=project_desc) - - # NOTE(andreaf) User and project can be distinguished from the context, - # having the same ID in both makes it easier to match them and debug. - username = project_name - user_password = data_utils.rand_password() - email = data_utils.rand_name( - root, prefix=self.resource_prefix) + "@example.com" - user = self.creds_client.create_user( - username, user_password, project, email) - role_assigned = False - if admin: - self.creds_client.assign_user_role(user, project, self.admin_role) - role_assigned = True - if (self.identity_version == 'v3' and - self.identity_admin_domain_scope): - self.creds_client.assign_user_role_on_domain( - user, self.identity_admin_role) - # Add roles specified in config file - for conf_role in self.extra_roles: - self.creds_client.assign_user_role(user, project, conf_role) - role_assigned = True - # Add roles requested by caller - if roles: - for role in roles: - self.creds_client.assign_user_role(user, project, role) - role_assigned = True - # NOTE(mtreinish) For a user to have access to a project with v3 auth - # it must beassigned a role on the project. So we need to ensure that - # our newly created user has a role on the newly created project. - if self.identity_version == 'v3' and not role_assigned: - try: - self.creds_client.create_user_role('Member') - except lib_exc.Conflict: - LOG.warning('Member role already exists, ignoring conflict.') - self.creds_client.assign_user_role(user, project, 'Member') - - creds = self.creds_client.get_credentials(user, project, user_password) - return cred_provider.TestResources(creds) - - def _create_network_resources(self, tenant_id): - """The function creates network resources in the given tenant. - - The function checks if network_resources class member is empty, - In case it is, it will create a network, a subnet and a router for - the tenant according to the given tenant id parameter. - Otherwise it will create a network resource according - to the values from network_resources dict. - - :param tenant_id: The tenant id to create resources for. - :type tenant_id: str - :raises: InvalidConfiguration, Exception - :returns: network resources(network,subnet,router) - :rtype: tuple - """ - network = None - subnet = None - router = None - # Make sure settings - if self.network_resources: - if self.network_resources['router']: - if (not self.network_resources['subnet'] or - not self.network_resources['network']): - raise lib_exc.InvalidConfiguration( - 'A router requires a subnet and network') - elif self.network_resources['subnet']: - if not self.network_resources['network']: - raise lib_exc.InvalidConfiguration( - 'A subnet requires a network') - elif self.network_resources['dhcp']: - raise lib_exc.InvalidConfiguration('DHCP requires a subnet') - - rand_name_root = data_utils.rand_name( - self.name, prefix=self.resource_prefix) - if not self.network_resources or self.network_resources['network']: - network_name = rand_name_root + "-network" - network = self._create_network(network_name, tenant_id) - try: - if not self.network_resources or self.network_resources['subnet']: - subnet_name = rand_name_root + "-subnet" - subnet = self._create_subnet(subnet_name, tenant_id, - network['id']) - if not self.network_resources or self.network_resources['router']: - router_name = rand_name_root + "-router" - router = self._create_router(router_name, tenant_id) - self._add_router_interface(router['id'], subnet['id']) - except Exception: - try: - if router: - self._clear_isolated_router(router['id'], router['name']) - if subnet: - self._clear_isolated_subnet(subnet['id'], subnet['name']) - if network: - self._clear_isolated_network(network['id'], - network['name']) - except Exception as cleanup_exception: - msg = "There was an exception trying to setup network " \ - "resources for tenant %s, and this error happened " \ - "trying to clean them up: %s" - LOG.warning(msg, tenant_id, cleanup_exception) - raise - return network, subnet, router - - def _create_network(self, name, tenant_id): - resp_body = self.networks_admin_client.create_network( - name=name, tenant_id=tenant_id) - return resp_body['network'] - - def _create_subnet(self, subnet_name, tenant_id, network_id): - base_cidr = netaddr.IPNetwork(self.project_network_cidr) - mask_bits = self.project_network_mask_bits - for subnet_cidr in base_cidr.subnet(mask_bits): - try: - if self.network_resources: - resp_body = self.subnets_admin_client.\ - create_subnet( - network_id=network_id, cidr=str(subnet_cidr), - name=subnet_name, - tenant_id=tenant_id, - enable_dhcp=self.network_resources['dhcp'], - ip_version=(ipaddress.ip_network( - six.text_type(subnet_cidr)).version)) - else: - resp_body = self.subnets_admin_client.\ - create_subnet(network_id=network_id, - cidr=str(subnet_cidr), - name=subnet_name, - tenant_id=tenant_id, - ip_version=(ipaddress.ip_network( - six.text_type(subnet_cidr)).version)) - break - except lib_exc.BadRequest as e: - if 'overlaps with another subnet' not in str(e): - raise - else: - message = 'Available CIDR for subnet creation could not be found' - raise Exception(message) - return resp_body['subnet'] - - def _create_router(self, router_name, tenant_id): - kwargs = {'name': router_name, - 'tenant_id': tenant_id} - if self.public_network_id: - kwargs['external_gateway_info'] = dict( - network_id=self.public_network_id) - resp_body = self.routers_admin_client.create_router(**kwargs) - return resp_body['router'] - - def _add_router_interface(self, router_id, subnet_id): - self.routers_admin_client.add_router_interface(router_id, - subnet_id=subnet_id) - - def get_credentials(self, credential_type): - if self._creds.get(str(credential_type)): - credentials = self._creds[str(credential_type)] - else: - if credential_type in ['primary', 'alt', 'admin']: - is_admin = (credential_type == 'admin') - credentials = self._create_creds(admin=is_admin) - else: - credentials = self._create_creds(roles=credential_type) - self._creds[str(credential_type)] = credentials - # Maintained until tests are ported - LOG.info("Acquired dynamic creds:\n credentials: %s", credentials) - if (self.neutron_available and - self.create_networks): - network, subnet, router = self._create_network_resources( - credentials.tenant_id) - credentials.set_resources(network=network, subnet=subnet, - router=router) - LOG.info("Created isolated network resources for : \n" - + " credentials: %s", credentials) - return credentials - - def get_primary_creds(self): - return self.get_credentials('primary') - - def get_admin_creds(self): - return self.get_credentials('admin') - - def get_alt_creds(self): - return self.get_credentials('alt') - - def get_creds_by_roles(self, roles, force_new=False): - roles = list(set(roles)) - # The roles list as a str will become the index as the dict key for - # the created credentials set in the dynamic_creds dict. - exist_creds = self._creds.get(str(roles)) - # If force_new flag is True 2 cred sets with the same roles are needed - # handle this by creating a separate index for old one to store it - # separately for cleanup - if exist_creds and force_new: - new_index = str(roles) + '-' + str(len(self._creds)) - self._creds[new_index] = exist_creds - del self._creds[str(roles)] - return self.get_credentials(roles) - - def _clear_isolated_router(self, router_id, router_name): - client = self.routers_admin_client - try: - client.delete_router(router_id) - except lib_exc.NotFound: - LOG.warning('router with name: %s not found for delete', - router_name) - - def _clear_isolated_subnet(self, subnet_id, subnet_name): - client = self.subnets_admin_client - try: - client.delete_subnet(subnet_id) - except lib_exc.NotFound: - LOG.warning('subnet with name: %s not found for delete', - subnet_name) - - def _clear_isolated_network(self, network_id, network_name): - net_client = self.networks_admin_client - try: - net_client.delete_network(network_id) - except lib_exc.NotFound: - LOG.warning('network with name: %s not found for delete', - network_name) - - def _cleanup_default_secgroup(self, tenant): - nsg_client = self.security_groups_admin_client - resp_body = nsg_client.list_security_groups(tenant_id=tenant, - name="default") - secgroups_to_delete = resp_body['security_groups'] - for secgroup in secgroups_to_delete: - try: - nsg_client.delete_security_group(secgroup['id']) - except lib_exc.NotFound: - LOG.warning('Security group %s, id %s not found for clean-up', - secgroup['name'], secgroup['id']) - - def _clear_isolated_net_resources(self): - client = self.routers_admin_client - for cred in self._creds: - creds = self._creds.get(cred) - if (not creds or not any([creds.router, creds.network, - creds.subnet])): - continue - LOG.debug("Clearing network: %(network)s, " - "subnet: %(subnet)s, router: %(router)s", - {'network': creds.network, 'subnet': creds.subnet, - 'router': creds.router}) - if (not self.network_resources or - (self.network_resources.get('router') and creds.subnet)): - try: - client.remove_router_interface( - creds.router['id'], - subnet_id=creds.subnet['id']) - except lib_exc.NotFound: - LOG.warning('router with name: %s not found for delete', - creds.router['name']) - self._clear_isolated_router(creds.router['id'], - creds.router['name']) - if (not self.network_resources or - self.network_resources.get('subnet')): - self._clear_isolated_subnet(creds.subnet['id'], - creds.subnet['name']) - if (not self.network_resources or - self.network_resources.get('network')): - self._clear_isolated_network(creds.network['id'], - creds.network['name']) - - def clear_creds(self): - if not self._creds: - return - self._clear_isolated_net_resources() - for creds in six.itervalues(self._creds): - try: - self.creds_client.delete_user(creds.user_id) - except lib_exc.NotFound: - LOG.warning("user with name: %s not found for delete", - creds.username) - # NOTE(zhufl): Only when neutron's security_group ext is - # enabled, _cleanup_default_secgroup will not raise error. But - # here cannot use test.is_extension_enabled for it will cause - # "circular dependency". So here just use try...except to - # ensure tenant deletion without big changes. - try: - if self.neutron_available: - self._cleanup_default_secgroup(creds.tenant_id) - except lib_exc.NotFound: - LOG.warning("failed to cleanup tenant %s's secgroup", - creds.tenant_name) - try: - self.creds_client.delete_project(creds.tenant_id) - except lib_exc.NotFound: - LOG.warning("tenant with name: %s not found for delete", - creds.tenant_name) - self._creds = {} - - def is_multi_user(self): - return True - - def is_multi_tenant(self): - return True - - def is_role_available(self, role): - return True diff --git a/tempest/lib/common/fixed_network.py b/tempest/lib/common/fixed_network.py deleted file mode 100644 index e2054a4d1..000000000 --- a/tempest/lib/common/fixed_network.py +++ /dev/null @@ -1,127 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from oslo_log import log as logging - -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions - -LOG = logging.getLogger(__name__) - - -def get_network_from_name(name, compute_networks_client): - """Get a full network dict from just a network name - - :param str name: the name of the network to use - :param NetworksClient compute_networks_client: The network client - object to use for making the network lists api request - :return: The full dictionary for the network in question - :rtype: dict - :raises InvalidTestResource: If the name provided is invalid, the networks - list returns a 404, there are no found networks, or the found network - is invalid - """ - caller = test_utils.find_test_caller() - - if not name: - raise exceptions.InvalidTestResource(type='network', name=name) - - networks = compute_networks_client.list_networks()['networks'] - networks = [n for n in networks if n['label'] == name] - - # Check that a network exists, else raise an InvalidConfigurationException - if len(networks) == 1: - network = sorted(networks)[0] - elif len(networks) > 1: - msg = ("Network with name: %s had multiple matching networks in the " - "list response: %s\n Unable to specify a single network" % ( - name, networks)) - if caller: - msg = '(%s) %s' % (caller, msg) - LOG.warning(msg) - raise exceptions.InvalidTestResource(type='network', name=name) - else: - msg = "Network with name: %s not found" % name - if caller: - msg = '(%s) %s' % (caller, msg) - LOG.warning(msg) - raise exceptions.InvalidTestResource(type='network', name=name) - # To be consistent between neutron and nova network always use name even - # if label is used in the api response. If neither is present than then - # the returned network is invalid. - name = network.get('name') or network.get('label') - if not name: - msg = "Network found from list doesn't contain a valid name or label" - if caller: - msg = '(%s) %s' % (caller, msg) - LOG.warning(msg) - raise exceptions.InvalidTestResource(type='network', name=name) - network['name'] = name - return network - - -def get_tenant_network(creds_provider, compute_networks_client, - shared_network_name): - """Get a network usable by the primary tenant - - :param creds_provider: instance of credential provider - :param compute_networks_client: compute network client. We want to have the - compute network client so we can have use a common approach for both - neutron and nova-network cases. If this is not an admin network - client, set_network_kwargs might fail in case fixed_network_name - is the network to be used, and it's not visible to the tenant - :param shared_network_name: name of the shared network to be used if no - tenant network is available in the creds provider - :returns: a dict with 'id' and 'name' of the network - """ - caller = test_utils.find_test_caller() - net_creds = creds_provider.get_primary_creds() - network = getattr(net_creds, 'network', None) - if not network or not network.get('name'): - if shared_network_name: - msg = ('No valid network provided or created, defaulting to ' - 'fixed_network_name') - if caller: - msg = '(%s) %s' % (caller, msg) - LOG.debug(msg) - try: - network = get_network_from_name(shared_network_name, - compute_networks_client) - except exceptions.InvalidTestResource: - network = {} - msg = ('Found network %s available for tenant' % network) - if caller: - msg = '(%s) %s' % (caller, msg) - LOG.info(msg) - return network - - -def set_networks_kwarg(network, kwargs=None): - """Set 'networks' kwargs for a server create if missing - - :param network: dict of network to be used with 'id' and 'name' - :param kwargs: server create kwargs to be enhanced - :return: new dict of kwargs updated to include networks - """ - params = copy.copy(kwargs) or {} - if kwargs and 'networks' in kwargs: - return params - - if network: - if 'id' in network.keys(): - params.update({"networks": [{'uuid': network['id']}]}) - else: - LOG.warning('The provided network dict: %s was invalid and did ' - 'not contain an id', network) - return params diff --git a/tempest/lib/common/http.py b/tempest/lib/common/http.py deleted file mode 100644 index 8a47d4436..000000000 --- a/tempest/lib/common/http.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import six -import urllib3 - - -class ClosingHttp(urllib3.poolmanager.PoolManager): - def __init__(self, disable_ssl_certificate_validation=False, - ca_certs=None, timeout=None): - kwargs = {} - - if disable_ssl_certificate_validation: - urllib3.disable_warnings() - kwargs['cert_reqs'] = 'CERT_NONE' - - if ca_certs: - kwargs['cert_reqs'] = 'CERT_REQUIRED' - kwargs['ca_certs'] = ca_certs - - if timeout: - kwargs['timeout'] = timeout - - super(ClosingHttp, self).__init__(**kwargs) - - def request(self, url, method, *args, **kwargs): - - class Response(dict): - def __init__(self, info): - for key, value in info.getheaders().items(): - # We assume HTTP header name to be string, not random - # bytes, thus ensure we have string keys. - self[six.u(key).lower()] = value - self.status = info.status - self['status'] = str(self.status) - self.reason = info.reason - self.version = info.version - self['content-location'] = url - - original_headers = kwargs.get('headers', {}) - new_headers = dict(original_headers, connection='close') - new_kwargs = dict(kwargs, headers=new_headers) - - # Follow up to 5 redirections. Don't raise an exception if - # it's exceeded but return the HTTP 3XX response instead. - retry = urllib3.util.Retry(raise_on_redirect=False, redirect=5) - r = super(ClosingHttp, self).request(method, url, retries=retry, - *args, **new_kwargs) - return Response(r), r.data diff --git a/tempest/lib/common/jsonschema_validator.py b/tempest/lib/common/jsonschema_validator.py deleted file mode 100644 index bbdf38255..000000000 --- a/tempest/lib/common/jsonschema_validator.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2016 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import jsonschema -from oslo_utils import timeutils - -# JSON Schema validator and format checker used for JSON Schema validation -JSONSCHEMA_VALIDATOR = jsonschema.Draft4Validator -FORMAT_CHECKER = jsonschema.draft4_format_checker - - -# NOTE(gmann): Add customized format checker for 'date-time' format because: -# 1. jsonschema needs strict_rfc3339 or isodate module to be installed -# for proper date-time checking as per rfc3339. -# 2. Nova or other OpenStack components handle the date time format as -# ISO 8601 which is defined in oslo_utils.timeutils -# so this checker will validate the date-time as defined in -# oslo_utils.timeutils -@FORMAT_CHECKER.checks('iso8601-date-time') -def _validate_datetime_format(instance): - try: - if isinstance(instance, jsonschema.compat.str_types): - timeutils.parse_isotime(instance) - except ValueError: - return False - else: - return True diff --git a/tempest/lib/common/preprov_creds.py b/tempest/lib/common/preprov_creds.py deleted file mode 100644 index cd3a10e4d..000000000 --- a/tempest/lib/common/preprov_creds.py +++ /dev/null @@ -1,374 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import hashlib -import os - -from oslo_concurrency import lockutils -from oslo_log import log as logging -import six -import yaml - -from tempest.lib import auth -from tempest.lib.common import cred_provider -from tempest.lib.common import fixed_network -from tempest.lib import exceptions as lib_exc -from tempest.lib.services import clients - -LOG = logging.getLogger(__name__) - - -def read_accounts_yaml(path): - try: - with open(path, 'r') as yaml_file: - accounts = yaml.safe_load(yaml_file) - except IOError: - raise lib_exc.InvalidConfiguration( - 'The path for the test accounts file: %s ' - 'could not be found' % path) - return accounts - - -class PreProvisionedCredentialProvider(cred_provider.CredentialProvider): - - # Exclude from the hash fields specific to v2 or v3 identity API - # i.e. only include user*, project*, tenant* and password - HASH_CRED_FIELDS = (set(auth.KeystoneV2Credentials.ATTRIBUTES) & - set(auth.KeystoneV3Credentials.ATTRIBUTES)) - - def __init__(self, identity_version, test_accounts_file, - accounts_lock_dir, name=None, credentials_domain=None, - admin_role=None, object_storage_operator_role=None, - object_storage_reseller_admin_role=None, identity_uri=None): - """Credentials provider using pre-provisioned accounts - - This credentials provider loads the details of pre-provisioned - accounts from a YAML file, in the format specified by - `etc/accounts.yaml.sample`. It locks accounts while in use, using the - external locking mechanism, allowing for multiple python processes - to share a single account file, and thus running tests in parallel. - - The accounts_lock_dir must be generated using `lockutils.get_lock_path` - from the oslo.concurrency library. For instance: - - accounts_lock_dir = os.path.join(lockutils.get_lock_path(CONF), - 'test_accounts') - - Role names for object storage are optional as long as the - `operator` and `reseller_admin` credential types are not used in the - accounts file. - - :param identity_version: identity version of the credentials - :param admin_role: name of the admin role - :param test_accounts_file: path to the accounts YAML file - :param accounts_lock_dir: the directory for external locking - :param name: name of the hash file (optional) - :param credentials_domain: name of the domain credentials belong to - (if no domain is configured) - :param object_storage_operator_role: name of the role - :param object_storage_reseller_admin_role: name of the role - :param identity_uri: Identity URI of the target cloud - """ - super(PreProvisionedCredentialProvider, self).__init__( - identity_version=identity_version, name=name, - admin_role=admin_role, credentials_domain=credentials_domain, - identity_uri=identity_uri) - self.test_accounts_file = test_accounts_file - if test_accounts_file: - accounts = read_accounts_yaml(self.test_accounts_file) - else: - raise lib_exc.InvalidCredentials("No accounts file specified") - self.hash_dict = self.get_hash_dict( - accounts, admin_role, object_storage_operator_role, - object_storage_reseller_admin_role) - self.accounts_dir = accounts_lock_dir - self._creds = {} - - @classmethod - def _append_role(cls, role, account_hash, hash_dict): - if role in hash_dict['roles']: - hash_dict['roles'][role].append(account_hash) - else: - hash_dict['roles'][role] = [account_hash] - return hash_dict - - @classmethod - def get_hash_dict(cls, accounts, admin_role, - object_storage_operator_role=None, - object_storage_reseller_admin_role=None): - hash_dict = {'roles': {}, 'creds': {}, 'networks': {}} - - # Loop over the accounts read from the yaml file - for account in accounts: - roles = [] - types = [] - resources = [] - if 'roles' in account: - roles = account.pop('roles') - if 'types' in account: - types = account.pop('types') - if 'resources' in account: - resources = account.pop('resources') - temp_hash = hashlib.md5() - account_for_hash = dict((k, v) for (k, v) in account.items() - if k in cls.HASH_CRED_FIELDS) - temp_hash.update(six.text_type(account_for_hash).encode('utf-8')) - temp_hash_key = temp_hash.hexdigest() - hash_dict['creds'][temp_hash_key] = account - for role in roles: - hash_dict = cls._append_role(role, temp_hash_key, - hash_dict) - # If types are set for the account append the matching role - # subdict with the hash - for type in types: - if type == 'admin': - hash_dict = cls._append_role(admin_role, temp_hash_key, - hash_dict) - elif type == 'operator': - if object_storage_operator_role: - hash_dict = cls._append_role( - object_storage_operator_role, temp_hash_key, - hash_dict) - else: - msg = ("Type 'operator' configured, but no " - "object_storage_operator_role specified") - raise lib_exc.InvalidCredentials(msg) - elif type == 'reseller_admin': - if object_storage_reseller_admin_role: - hash_dict = cls._append_role( - object_storage_reseller_admin_role, - temp_hash_key, - hash_dict) - else: - msg = ("Type 'reseller_admin' configured, but no " - "object_storage_reseller_admin_role specified") - raise lib_exc.InvalidCredentials(msg) - # Populate the network subdict - for resource in resources: - if resource == 'network': - hash_dict['networks'][temp_hash_key] = resources[resource] - else: - LOG.warning( - 'Unknown resource type %s, ignoring this field', - resource - ) - return hash_dict - - def is_multi_user(self): - return len(self.hash_dict['creds']) > 1 - - def is_multi_tenant(self): - return self.is_multi_user() - - def _create_hash_file(self, hash_string): - path = os.path.join(os.path.join(self.accounts_dir, hash_string)) - if not os.path.isfile(path): - with open(path, 'w') as fd: - fd.write(self.name) - return True - return False - - @lockutils.synchronized('test_accounts_io', external=True) - def _get_free_hash(self, hashes): - # Cast as a list because in some edge cases a set will be passed in - hashes = list(hashes) - if not os.path.isdir(self.accounts_dir): - os.mkdir(self.accounts_dir) - # Create File from first hash (since none are in use) - self._create_hash_file(hashes[0]) - return hashes[0] - names = [] - for _hash in hashes: - res = self._create_hash_file(_hash) - if res: - return _hash - else: - path = os.path.join(os.path.join(self.accounts_dir, - _hash)) - with open(path, 'r') as fd: - names.append(fd.read()) - msg = ('Insufficient number of users provided. %s have allocated all ' - 'the credentials for this allocation request' % ','.join(names)) - raise lib_exc.InvalidCredentials(msg) - - def _get_match_hash_list(self, roles=None): - hashes = [] - if roles: - # Loop over all the creds for each role in the subdict and generate - # a list of cred lists for each role - for role in roles: - temp_hashes = self.hash_dict['roles'].get(role, None) - if not temp_hashes: - raise lib_exc.InvalidCredentials( - "No credentials with role: %s specified in the " - "accounts ""file" % role) - hashes.append(temp_hashes) - # Take the list of lists and do a boolean and between each list to - # find the creds which fall under all the specified roles - temp_list = set(hashes[0]) - for hash_list in hashes[1:]: - temp_list = temp_list & set(hash_list) - hashes = temp_list - else: - hashes = self.hash_dict['creds'].keys() - # NOTE(mtreinish): admin is a special case because of the increased - # privilege set which could potentially cause issues on tests where - # that is not expected. So unless the admin role isn't specified do - # not allocate admin. - admin_hashes = self.hash_dict['roles'].get(self.admin_role, - None) - if ((not roles or self.admin_role not in roles) and - admin_hashes): - useable_hashes = [x for x in hashes if x not in admin_hashes] - else: - useable_hashes = hashes - return useable_hashes - - def _sanitize_creds(self, creds): - temp_creds = creds.copy() - temp_creds.pop('password') - return temp_creds - - def _get_creds(self, roles=None): - useable_hashes = self._get_match_hash_list(roles) - if not useable_hashes: - msg = 'No users configured for type/roles %s' % roles - raise lib_exc.InvalidCredentials(msg) - free_hash = self._get_free_hash(useable_hashes) - clean_creds = self._sanitize_creds( - self.hash_dict['creds'][free_hash]) - LOG.info('%s allocated creds:\n%s', self.name, clean_creds) - return self._wrap_creds_with_network(free_hash) - - @lockutils.synchronized('test_accounts_io', external=True) - def remove_hash(self, hash_string): - hash_path = os.path.join(self.accounts_dir, hash_string) - if not os.path.isfile(hash_path): - LOG.warning('Expected an account lock file %s to remove, but ' - 'one did not exist', hash_path) - else: - os.remove(hash_path) - if not os.listdir(self.accounts_dir): - os.rmdir(self.accounts_dir) - - def get_hash(self, creds): - for _hash in self.hash_dict['creds']: - # Comparing on the attributes that are expected in the YAML - init_attributes = creds.get_init_attributes() - # Only use the attributes initially used to calculate the hash - init_attributes = [x for x in init_attributes if - x in self.HASH_CRED_FIELDS] - hash_attributes = self.hash_dict['creds'][_hash].copy() - # NOTE(andreaf) Not all fields may be available on all credentials - # so defaulting to None for that case. - if all([getattr(creds, k, None) == hash_attributes.get(k, None) for - k in init_attributes]): - return _hash - raise AttributeError('Invalid credentials %s' % creds) - - def remove_credentials(self, creds): - _hash = self.get_hash(creds) - clean_creds = self._sanitize_creds(self.hash_dict['creds'][_hash]) - self.remove_hash(_hash) - LOG.info("%s returned allocated creds:\n%s", self.name, clean_creds) - - def get_primary_creds(self): - if self._creds.get('primary'): - return self._creds.get('primary') - net_creds = self._get_creds() - self._creds['primary'] = net_creds - return net_creds - - def get_alt_creds(self): - if self._creds.get('alt'): - return self._creds.get('alt') - net_creds = self._get_creds() - self._creds['alt'] = net_creds - return net_creds - - def get_creds_by_roles(self, roles, force_new=False): - roles = list(set(roles)) - exist_creds = self._creds.get(six.text_type(roles).encode( - 'utf-8'), None) - # The force kwarg is used to allocate an additional set of creds with - # the same role list. The index used for the previously allocation - # in the _creds dict will be moved. - if exist_creds and not force_new: - return exist_creds - elif exist_creds and force_new: - # NOTE(andreaf) In py3.x encode returns bytes, and b'' is bytes - # In py2.7 encode returns strings, and b'' is still string - new_index = six.text_type(roles).encode('utf-8') + b'-' + \ - six.text_type(len(self._creds)).encode('utf-8') - self._creds[new_index] = exist_creds - net_creds = self._get_creds(roles=roles) - self._creds[six.text_type(roles).encode('utf-8')] = net_creds - return net_creds - - def clear_creds(self): - for creds in self._creds.values(): - self.remove_credentials(creds) - - def get_admin_creds(self): - return self.get_creds_by_roles([self.admin_role]) - - def is_role_available(self, role): - if self.hash_dict['roles'].get(role): - return True - return False - - def admin_available(self): - return self.is_role_available(self.admin_role) - - def _wrap_creds_with_network(self, hash): - creds_dict = self.hash_dict['creds'][hash] - # Make sure a domain scope if defined for users in case of V3 - # Make sure a tenant is available in case of V2 - creds_dict = self._extend_credentials(creds_dict) - # This just builds a Credentials object, it does not validate - # nor fill with missing fields. - credential = auth.get_credentials( - auth_url=None, fill_in=False, - identity_version=self.identity_version, **creds_dict) - net_creds = cred_provider.TestResources(credential) - net_clients = clients.ServiceClients(credentials=credential, - identity_uri=self.identity_uri) - compute_network_client = net_clients.compute.NetworksClient() - net_name = self.hash_dict['networks'].get(hash, None) - try: - network = fixed_network.get_network_from_name( - net_name, compute_network_client) - except lib_exc.InvalidTestResource: - network = {} - net_creds.set_resources(network=network) - return net_creds - - def _extend_credentials(self, creds_dict): - # Add or remove credential domain fields to fit the identity version - domain_fields = set(x for x in auth.KeystoneV3Credentials.ATTRIBUTES - if 'domain' in x) - msg = 'Assuming they are valid in the default domain.' - if self.identity_version == 'v3': - if not domain_fields.intersection(set(creds_dict.keys())): - msg = 'Using credentials %s for v3 API calls. ' + msg - LOG.warning(msg, self._sanitize_creds(creds_dict)) - creds_dict['domain_name'] = self.credentials_domain - if self.identity_version == 'v2': - if domain_fields.intersection(set(creds_dict.keys())): - msg = 'Using credentials %s for v2 API calls. ' + msg - LOG.warning(msg, self._sanitize_creds(creds_dict)) - # Remove all valid domain attributes - for attr in domain_fields.intersection(set(creds_dict.keys())): - creds_dict.pop(attr) - return creds_dict diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py deleted file mode 100644 index f58d7372d..000000000 --- a/tempest/lib/common/rest_client.py +++ /dev/null @@ -1,976 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import collections -import email.utils -import re -import time - -import jsonschema -from oslo_log import log as logging -from oslo_serialization import jsonutils as json -import six -from six.moves import urllib - -from tempest.lib.common import http -from tempest.lib.common import jsonschema_validator -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions - -# redrive rate limited calls at most twice -MAX_RECURSION_DEPTH = 2 - -# All the successful HTTP status codes from RFC 7231 & 4918 -HTTP_SUCCESS = (200, 201, 202, 203, 204, 205, 206, 207) - -# All the redirection HTTP status codes from RFC 7231 & 4918 -HTTP_REDIRECTION = (300, 301, 302, 303, 304, 305, 306, 307) - -# JSON Schema validator and format checker used for JSON Schema validation -JSONSCHEMA_VALIDATOR = jsonschema_validator.JSONSCHEMA_VALIDATOR -FORMAT_CHECKER = jsonschema_validator.FORMAT_CHECKER - - -class RestClient(object): - """Unified OpenStack RestClient class - - This class is used for building openstack api clients on top of. It is - intended to provide a base layer for wrapping outgoing http requests in - keystone auth as well as providing response code checking and error - handling. - - :param auth_provider: an auth provider object used to wrap requests in auth - :param str service: The service name to use for the catalog lookup - :param str region: The region to use for the catalog lookup - :param str name: The endpoint name to use for the catalog lookup; this - returns only if the service exists - :param str endpoint_type: The endpoint type to use for the catalog lookup - :param int build_interval: Time in seconds between to status checks in - wait loops - :param int build_timeout: Timeout in seconds to wait for a wait operation. - :param bool disable_ssl_certificate_validation: Set to true to disable ssl - certificate validation - :param str ca_certs: File containing the CA Bundle to use in verifying a - TLS server cert - :param str trace_requests: Regex to use for specifying logging the entirety - of the request and response payload - :param str http_timeout: Timeout in seconds to wait for the http request to - return - """ - - # The version of the API this client implements - api_version = None - - LOG = logging.getLogger(__name__) - - def __init__(self, auth_provider, service, region, - endpoint_type='publicURL', - build_interval=1, build_timeout=60, - disable_ssl_certificate_validation=False, ca_certs=None, - trace_requests='', name=None, http_timeout=None): - self.auth_provider = auth_provider - self.service = service - self.region = region - self.name = name - self.endpoint_type = endpoint_type - self.build_interval = build_interval - self.build_timeout = build_timeout - self.trace_requests = trace_requests - - self._skip_path = False - self.general_header_lc = set(('cache-control', 'connection', - 'date', 'pragma', 'trailer', - 'transfer-encoding', 'via', - 'warning')) - self.response_header_lc = set(('accept-ranges', 'age', 'etag', - 'location', 'proxy-authenticate', - 'retry-after', 'server', - 'vary', 'www-authenticate')) - dscv = disable_ssl_certificate_validation - self.http_obj = http.ClosingHttp( - disable_ssl_certificate_validation=dscv, ca_certs=ca_certs, - timeout=http_timeout) - - def get_headers(self, accept_type=None, send_type=None): - """Return the default headers which will be used with outgoing requests - - :param str accept_type: The media type to use for the Accept header, if - one isn't provided the object var TYPE will be - used - :param str send_type: The media-type to use for the Content-Type - header, if one isn't provided the object var - TYPE will be used - :rtype: dict - :return: The dictionary of headers which can be used in the headers - dict for outgoing request - """ - if accept_type is None: - accept_type = 'json' - if send_type is None: - send_type = 'json' - return {'Content-Type': 'application/%s' % send_type, - 'Accept': 'application/%s' % accept_type} - - def __str__(self): - STRING_LIMIT = 80 - str_format = ("service:%s, base_url:%s, " - "filters: %s, build_interval:%s, build_timeout:%s" - "\ntoken:%s..., \nheaders:%s...") - return str_format % (self.service, self.base_url, - self.filters, self.build_interval, - self.build_timeout, - str(self.token)[0:STRING_LIMIT], - str(self.get_headers())[0:STRING_LIMIT]) - - @property - def user(self): - """The username used for requests - - :rtype: string - :return: The username being used for requests - """ - - return self.auth_provider.credentials.username - - @property - def user_id(self): - """The user_id used for requests - - :rtype: string - :return: The user id being used for requests - """ - return self.auth_provider.credentials.user_id - - @property - def tenant_name(self): - """The tenant/project being used for requests - - :rtype: string - :return: The tenant/project name being used for requests - """ - return self.auth_provider.credentials.tenant_name - - @property - def tenant_id(self): - """The tenant/project id being used for requests - - :rtype: string - :return: The tenant/project id being used for requests - """ - return self.auth_provider.credentials.tenant_id - - @property - def password(self): - """The password being used for requests - - :rtype: string - :return: The password being used for requests - """ - return self.auth_provider.credentials.password - - @property - def base_url(self): - return self.auth_provider.base_url(filters=self.filters) - - @property - def token(self): - return self.auth_provider.get_token() - - @property - def filters(self): - _filters = dict( - service=self.service, - endpoint_type=self.endpoint_type, - region=self.region, - name=self.name - ) - if self.api_version is not None: - _filters['api_version'] = self.api_version - if self._skip_path: - _filters['skip_path'] = self._skip_path - return _filters - - def skip_path(self): - """When set, ignore the path part of the base URL from the catalog""" - self._skip_path = True - - def reset_path(self): - """When reset, use the base URL from the catalog as-is""" - self._skip_path = False - - @classmethod - def expected_success(cls, expected_code, read_code): - """Check expected success response code against the http response - - :param int expected_code: The response code that is expected. - Optionally a list of integers can be used - to specify multiple valid success codes - :param int read_code: The response code which was returned in the - response - :raises AssertionError: if the expected_code isn't a valid http success - response code - :raises exceptions.InvalidHttpSuccessCode: if the read code isn't an - expected http success code - """ - if not isinstance(read_code, int): - raise TypeError("'read_code' must be an int instead of (%s)" - % type(read_code)) - - assert_msg = ("This function only allowed to use for HTTP status " - "codes which explicitly defined in the RFC 7231 & 4918. " - "{0} is not a defined Success Code!" - ).format(expected_code) - if isinstance(expected_code, list): - for code in expected_code: - assert code in HTTP_SUCCESS + HTTP_REDIRECTION, assert_msg - else: - assert expected_code in HTTP_SUCCESS + HTTP_REDIRECTION, assert_msg - - # NOTE(afazekas): the http status code above 400 is processed by - # the _error_checker method - if read_code < 400: - pattern = ("Unexpected http success status code {0}, " - "The expected status code is {1}") - if ((not isinstance(expected_code, list) and - (read_code != expected_code)) or - (isinstance(expected_code, list) and - (read_code not in expected_code))): - details = pattern.format(read_code, expected_code) - raise exceptions.InvalidHttpSuccessCode(details) - - def post(self, url, body, headers=None, extra_headers=False, - chunked=False): - """Send a HTTP POST request using keystone auth - - :param str url: the relative url to send the post request to - :param dict body: the request body - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :param bool chunked: sends the body with chunked encoding - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('POST', url, extra_headers, headers, body, chunked) - - def get(self, url, headers=None, extra_headers=False): - """Send a HTTP GET request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('GET', url, extra_headers, headers) - - def delete(self, url, headers=None, body=None, extra_headers=False): - """Send a HTTP DELETE request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict headers: The headers to use for the request - :param dict body: the request body - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('DELETE', url, extra_headers, headers, body) - - def patch(self, url, body, headers=None, extra_headers=False): - """Send a HTTP PATCH request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict body: the request body - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('PATCH', url, extra_headers, headers, body) - - def put(self, url, body, headers=None, extra_headers=False, chunked=False): - """Send a HTTP PUT request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict body: the request body - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :param bool chunked: sends the body with chunked encoding - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('PUT', url, extra_headers, headers, body, chunked) - - def head(self, url, headers=None, extra_headers=False): - """Send a HTTP HEAD request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('HEAD', url, extra_headers, headers) - - def copy(self, url, headers=None, extra_headers=False): - """Send a HTTP COPY request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('COPY', url, extra_headers, headers) - - def get_versions(self): - """Get the versions on a endpoint from the keystone catalog - - This method will make a GET request on the baseurl from the keystone - catalog to return a list of API versions. It is expected that a GET - on the endpoint in the catalog will return a list of supported API - versions. - - :return: tuple with response headers and list of version numbers - :rtype: tuple - """ - resp, body = self.get('') - body = self._parse_resp(body) - versions = map(lambda x: x['id'], body) - return resp, versions - - def _get_request_id(self, resp): - for i in ('x-openstack-request-id', 'x-compute-request-id'): - if i in resp: - return resp[i] - return "" - - def _safe_body(self, body, maxlen=4096): - # convert a structure into a string safely - try: - text = six.text_type(body) - except UnicodeDecodeError: - # if this isn't actually text, return marker that - return "" - if len(text) > maxlen: - return text[:maxlen] - else: - return text - - def _log_request_start(self, method, req_url): - caller_name = test_utils.find_test_caller() - if self.trace_requests and re.search(self.trace_requests, caller_name): - self.LOG.debug('Starting Request (%s): %s %s', caller_name, - method, req_url) - - def _log_request_full(self, resp, req_headers=None, req_body=None, - resp_body=None, extra=None): - if 'X-Auth-Token' in req_headers: - req_headers['X-Auth-Token'] = '' - # A shallow copy is sufficient - resp_log = resp.copy() - if 'x-subject-token' in resp_log: - resp_log['x-subject-token'] = '' - log_fmt = """Request - Headers: %s - Body: %s - Response - Headers: %s - Body: %s""" - - self.LOG.debug( - log_fmt, - str(req_headers), - self._safe_body(req_body), - str(resp_log), - self._safe_body(resp_body), - extra=extra) - - def _log_request(self, method, req_url, resp, - secs="", req_headers=None, - req_body=None, resp_body=None): - if req_headers is None: - req_headers = {} - # if we have the request id, put it in the right part of the log - extra = dict(request_id=self._get_request_id(resp)) - # NOTE(sdague): while we still have 6 callers to this function - # we're going to just provide work around on who is actually - # providing timings by gracefully adding no content if they don't. - # Once we're down to 1 caller, clean this up. - caller_name = test_utils.find_test_caller() - if secs: - secs = " %.3fs" % secs - self.LOG.info( - 'Request (%s): %s %s %s%s', - caller_name, - resp['status'], - method, - req_url, - secs, - extra=extra) - - # Also look everything at DEBUG if you want to filter this - # out, don't run at debug. - if self.LOG.isEnabledFor(logging.DEBUG): - self._log_request_full(resp, req_headers, req_body, - resp_body, extra) - - def _parse_resp(self, body): - try: - body = json.loads(body) - except ValueError: - return body - - # We assume, that if the first value of the deserialized body's - # item set is a dict or a list, that we just return the first value - # of deserialized body. - # Essentially "cutting out" the first placeholder element in a body - # that looks like this: - # - # { - # "users": [ - # ... - # ] - # } - try: - # Ensure there are not more than one top-level keys - # NOTE(freerunner): Ensure, that JSON is not nullable to - # to prevent StopIteration Exception - if not hasattr(body, "keys") or len(body.keys()) != 1: - return body - # Just return the "wrapped" element - first_key, first_item = six.next(six.iteritems(body)) - if isinstance(first_item, (dict, list)): - return first_item - except (ValueError, IndexError): - pass - return body - - def response_checker(self, method, resp, resp_body): - """A sanity check on the response from a HTTP request - - This method does a sanity check on whether the response from an HTTP - request conforms the HTTP RFC. - - :param str method: The HTTP verb of the request associated with the - response being passed in. - :param resp: The response headers - :param resp_body: The body of the response - :raises ResponseWithNonEmptyBody: If the response with the status code - is not supposed to have a body - :raises ResponseWithEntity: If the response code is 205 but has an - entity - """ - if (resp.status in set((204, 205, 304)) or resp.status < 200 or - method.upper() == 'HEAD') and resp_body: - raise exceptions.ResponseWithNonEmptyBody(status=resp.status) - # NOTE(afazekas): - # If the HTTP Status Code is 205 - # 'The response MUST NOT include an entity.' - # A HTTP entity has an entity-body and an 'entity-header'. - # In the HTTP response specification (Section 6) the 'entity-header' - # 'generic-header' and 'response-header' are in OR relation. - # All headers not in the above two group are considered as entity - # header in every interpretation. - - if (resp.status == 205 and - 0 != len(set(resp.keys()) - set(('status',)) - - self.response_header_lc - self.general_header_lc)): - raise exceptions.ResponseWithEntity() - # NOTE(afazekas) - # Now the swift sometimes (delete not empty container) - # returns with non json error response, we can create new rest class - # for swift. - # Usually RFC2616 says error responses SHOULD contain an explanation. - # The warning is normal for SHOULD/SHOULD NOT case - - # Likely it will cause an error - if method != 'HEAD' and not resp_body and resp.status >= 400: - self.LOG.warning("status >= 400 response with empty body") - - def _request(self, method, url, headers=None, body=None, chunked=False): - """A simple HTTP request interface.""" - # Authenticate the request with the auth provider - req_url, req_headers, req_body = self.auth_provider.auth_request( - method, url, headers, body, self.filters) - - # Do the actual request, and time it - start = time.time() - self._log_request_start(method, req_url) - resp, resp_body = self.raw_request( - req_url, method, headers=req_headers, body=req_body, - chunked=chunked - ) - end = time.time() - self._log_request(method, req_url, resp, secs=(end - start), - req_headers=req_headers, req_body=req_body, - resp_body=resp_body) - - # Verify HTTP response codes - self.response_checker(method, resp, resp_body) - - return resp, resp_body - - def raw_request(self, url, method, headers=None, body=None, chunked=False): - """Send a raw HTTP request without the keystone catalog or auth - - This method sends a HTTP request in the same manner as the request() - method, however it does so without using keystone auth or the catalog - to determine the base url. Additionally no response handling is done - the results from the request are just returned. - - :param str url: Full url to send the request - :param str method: The HTTP verb to use for the request - :param str headers: Headers to use for the request if none are specifed - the headers - :param str body: Body to send with the request - :param bool chunked: sends the body with chunked encoding - :rtype: tuple - :return: a tuple with the first entry containing the response headers - and the second the response body - """ - if headers is None: - headers = self.get_headers() - return self.http_obj.request(url, method, headers=headers, - body=body, chunked=chunked) - - def request(self, method, url, extra_headers=False, headers=None, - body=None, chunked=False): - """Send a HTTP request with keystone auth and using the catalog - - This method will send an HTTP request using keystone auth in the - headers and the catalog to determine the endpoint to use for the - baseurl to send the request to. Additionally - - When a response is received it will check it to see if an error - response was received. If it was an exception will be raised to enable - it to be handled quickly. - - This method will also handle rate-limiting, if a 413 response code is - received it will retry the request after waiting the 'retry-after' - duration from the header. - - :param str method: The HTTP verb to use for the request - :param str url: Relative url to send the request to - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :param dict headers: Headers to use for the request if none are - specifed the headers returned from the - get_headers() method are used. If the request - explicitly requires no headers use an empty dict. - :param str body: Body to send with the request - :param bool chunked: sends the body with chunked encoding - :rtype: tuple - :return: a tuple with the first entry containing the response headers - and the second the response body - :raises UnexpectedContentType: If the content-type of the response - isn't an expect type - :raises Unauthorized: If a 401 response code is received - :raises Forbidden: If a 403 response code is received - :raises NotFound: If a 404 response code is received - :raises BadRequest: If a 400 response code is received - :raises Gone: If a 410 response code is received - :raises Conflict: If a 409 response code is received - :raises PreconditionFailed: If a 412 response code is received - :raises OverLimit: If a 413 response code is received and over_limit is - not in the response body - :raises RateLimitExceeded: If a 413 response code is received and - over_limit is in the response body - :raises InvalidContentType: If a 415 response code is received - :raises UnprocessableEntity: If a 422 response code is received - :raises InvalidHTTPResponseBody: The response body wasn't valid JSON - and couldn't be parsed - :raises NotImplemented: If a 501 response code is received - :raises ServerFault: If a 500 response code is received - :raises UnexpectedResponseCode: If a response code above 400 is - received and it doesn't fall into any - of the handled checks - """ - # if extra_headers is True - # default headers would be added to headers - retry = 0 - - if headers is None: - # NOTE(vponomaryov): if some client do not need headers, - # it should explicitly pass empty dict - headers = self.get_headers() - elif extra_headers: - try: - headers.update(self.get_headers()) - except (ValueError, TypeError): - headers = self.get_headers() - - resp, resp_body = self._request(method, url, headers=headers, - body=body, chunked=chunked) - - while (resp.status == 413 and - 'retry-after' in resp and - not self.is_absolute_limit( - resp, self._parse_resp(resp_body)) and - retry < MAX_RECURSION_DEPTH): - retry += 1 - delay = self._get_retry_after_delay(resp) - self.LOG.debug( - "Sleeping %s seconds based on retry-after header", delay - ) - time.sleep(delay) - resp, resp_body = self._request(method, url, - headers=headers, body=body) - self._error_checker(resp, resp_body) - return resp, resp_body - - def _get_retry_after_delay(self, resp): - """Extract the delay from the retry-after header. - - This supports both integer and HTTP date formatted retry-after headers - per RFC 2616. - - :param resp: The response containing the retry-after headers - :rtype: int - :return: The delay in seconds, clamped to be at least 1 second - :raises ValueError: On failing to parse the delay - """ - delay = None - try: - delay = int(resp['retry-after']) - except (ValueError, KeyError): - pass - - try: - retry_timestamp = self._parse_http_date(resp['retry-after']) - date_timestamp = self._parse_http_date(resp['date']) - delay = int(retry_timestamp - date_timestamp) - except (ValueError, OverflowError, KeyError): - pass - - if delay is None: - raise ValueError( - "Failed to parse retry-after header %r as either int or " - "HTTP-date." % resp.get('retry-after') - ) - - # Retry-after headers do not have sub-second precision. Clients may - # receive a delay of 0. After sleeping 0 seconds, we would (likely) hit - # another 413. To avoid this, always sleep at least 1 second. - return max(1, delay) - - def _parse_http_date(self, val): - """Parse an HTTP date, like 'Fri, 31 Dec 1999 23:59:59 GMT'. - - Return an epoch timestamp (float), as returned by time.mktime(). - """ - parts = email.utils.parsedate(val) - if not parts: - raise ValueError("Failed to parse date %s" % val) - return time.mktime(parts) - - def _error_checker(self, resp, resp_body): - - # NOTE(mtreinish): Check for httplib response from glance_http. The - # object can't be used here because importing httplib breaks httplib2. - # If another object from a class not imported were passed here as - # resp this could possibly fail - if str(type(resp)) == "": - ctype = resp.getheader('content-type') - else: - try: - ctype = resp['content-type'] - # NOTE(mtreinish): Keystone delete user responses doesn't have a - # content-type header. (They don't have a body) So just pretend it - # is set. - except KeyError: - ctype = 'application/json' - - # It is not an error response - if resp.status < 400: - return - - # NOTE(zhipengh): There is a purposefully duplicate of content-type - # with the only difference is with or without spaces, as specified - # in RFC7231. - JSON_ENC = ['application/json', 'application/json; charset=utf-8', - 'application/json;charset=utf-8'] - - # NOTE(mtreinish): This is for compatibility with Glance and swift - # APIs. These are the return content types that Glance api v1 - # (and occasionally swift) are using. - # NOTE(zhipengh): There is a purposefully duplicate of content-type - # with the only difference is with or without spaces, as specified - # in RFC7231. - TXT_ENC = ['text/plain', 'text/html', 'text/html; charset=utf-8', - 'text/plain; charset=utf-8', 'text/html;charset=utf-8', - 'text/plain;charset=utf-8'] - - if ctype.lower() in JSON_ENC: - parse_resp = True - elif ctype.lower() in TXT_ENC: - parse_resp = False - else: - raise exceptions.UnexpectedContentType(str(resp.status), - resp=resp) - - if resp.status == 401: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.Unauthorized(resp_body, resp=resp) - - if resp.status == 403: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.Forbidden(resp_body, resp=resp) - - if resp.status == 404: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.NotFound(resp_body, resp=resp) - - if resp.status == 400: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.BadRequest(resp_body, resp=resp) - - if resp.status == 410: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.Gone(resp_body, resp=resp) - - if resp.status == 409: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.Conflict(resp_body, resp=resp) - - if resp.status == 412: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.PreconditionFailed(resp_body, resp=resp) - - if resp.status == 413: - if parse_resp: - resp_body = self._parse_resp(resp_body) - if self.is_absolute_limit(resp, resp_body): - raise exceptions.OverLimit(resp_body, resp=resp) - else: - raise exceptions.RateLimitExceeded(resp_body, resp=resp) - - if resp.status == 415: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.InvalidContentType(resp_body, resp=resp) - - if resp.status == 422: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.UnprocessableEntity(resp_body, resp=resp) - - if resp.status in (500, 501): - message = resp_body - if parse_resp: - try: - resp_body = self._parse_resp(resp_body) - except ValueError: - # If response body is a non-json string message. - # Use resp_body as is and raise InvalidResponseBody - # exception. - raise exceptions.InvalidHTTPResponseBody(message) - else: - if isinstance(resp_body, dict): - # I'm seeing both computeFault - # and cloudServersFault come back. - # Will file a bug to fix, but leave as is for now. - if 'cloudServersFault' in resp_body: - message = resp_body['cloudServersFault']['message'] - elif 'computeFault' in resp_body: - message = resp_body['computeFault']['message'] - elif 'error' in resp_body: - message = resp_body['error']['message'] - elif 'message' in resp_body: - message = resp_body['message'] - else: - message = resp_body - - if resp.status == 501: - raise exceptions.NotImplemented(resp_body, resp=resp, - message=message) - else: - raise exceptions.ServerFault(resp_body, resp=resp, - message=message) - - if resp.status >= 400: - raise exceptions.UnexpectedResponseCode(str(resp.status), - resp=resp) - - def is_absolute_limit(self, resp, resp_body): - if (not isinstance(resp_body, collections.Mapping) or - 'retry-after' not in resp): - return True - return 'exceed' in resp_body.get('message', 'blabla') - - def wait_for_resource_deletion(self, id): - """Waits for a resource to be deleted - - This method will loop over is_resource_deleted until either - is_resource_deleted returns True or the build timeout is reached. This - depends on is_resource_deleted being implemented - - :param str id: The id of the resource to check - :raises TimeoutException: If the build_timeout has elapsed and the - resource still hasn't been deleted - """ - start_time = int(time.time()) - while True: - if self.is_resource_deleted(id): - return - if int(time.time()) - start_time >= self.build_timeout: - message = ('Failed to delete %(resource_type)s %(id)s within ' - 'the required time (%(timeout)s s).' % - {'resource_type': self.resource_type, 'id': id, - 'timeout': self.build_timeout}) - caller = test_utils.find_test_caller() - if caller: - message = '(%s) %s' % (caller, message) - raise exceptions.TimeoutException(message) - time.sleep(self.build_interval) - - def is_resource_deleted(self, id): - """Subclasses override with specific deletion detection.""" - message = ('"%s" does not implement is_resource_deleted' - % self.__class__.__name__) - raise NotImplementedError(message) - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'resource' - - @classmethod - def validate_response(cls, schema, resp, body): - # Only check the response if the status code is a success code - # TODO(cyeoh): Eventually we should be able to verify that a failure - # code if it exists is something that we expect. This is explicitly - # declared in the V3 API and so we should be able to export this in - # the response schema. For now we'll ignore it. - if resp.status in HTTP_SUCCESS + HTTP_REDIRECTION: - cls.expected_success(schema['status_code'], resp.status) - - # Check the body of a response - body_schema = schema.get('response_body') - if body_schema: - try: - jsonschema.validate(body, body_schema, - cls=JSONSCHEMA_VALIDATOR, - format_checker=FORMAT_CHECKER) - except jsonschema.ValidationError as ex: - msg = ("HTTP response body is invalid (%s)" % ex) - raise exceptions.InvalidHTTPResponseBody(msg) - else: - if body: - msg = ("HTTP response body should not exist (%s)" % body) - raise exceptions.InvalidHTTPResponseBody(msg) - - # Check the header of a response - header_schema = schema.get('response_header') - if header_schema: - try: - jsonschema.validate(resp, header_schema, - cls=JSONSCHEMA_VALIDATOR, - format_checker=FORMAT_CHECKER) - except jsonschema.ValidationError as ex: - msg = ("HTTP response header is invalid (%s)" % ex) - raise exceptions.InvalidHTTPResponseHeader(msg) - - def _get_base_version_url(self): - # TODO(oomichi): This method can be used for auth's replace_version(). - # So it is nice to have common logic for the maintenance. - endpoint = self.base_url - url = urllib.parse.urlsplit(endpoint) - new_path = re.split(r'(^|/)+v\d+(\.\d+)?', url.path)[0] - url = list(url) - url[2] = new_path + '/' - return urllib.parse.urlunsplit(url) - - -class ResponseBody(dict): - """Class that wraps an http response and dict body into a single value. - - Callers that receive this object will normally use it as a dict but - can extract the response if needed. - """ - - def __init__(self, response, body=None): - body_data = body or {} - self.update(body_data) - self.response = response - - def __str__(self): - body = super(ResponseBody, self).__str__() - return "response: %s\nBody: %s" % (self.response, body) - - -class ResponseBodyData(object): - """Class that wraps an http response and string data into a single value. - - """ - - def __init__(self, response, data): - self.response = response - self.data = data - - def __str__(self): - return "response: %s\nBody: %s" % (self.response, self.data) - - -class ResponseBodyList(list): - """Class that wraps an http response and list body into a single value. - - Callers that receive this object will normally use it as a list but - can extract the response if needed. - """ - - def __init__(self, response, body=None): - body_data = body or [] - self.extend(body_data) - self.response = response - - def __str__(self): - body = super(ResponseBodyList, self).__str__() - return "response: %s\nBody: %s" % (self.response, body) diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py deleted file mode 100644 index d4ec6ad59..000000000 --- a/tempest/lib/common/ssh.py +++ /dev/null @@ -1,219 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -import select -import socket -import time -import warnings - -from oslo_log import log as logging -import six - -from tempest.lib import exceptions - - -with warnings.catch_warnings(): - warnings.simplefilter("ignore") - import paramiko - - -LOG = logging.getLogger(__name__) - - -class Client(object): - - def __init__(self, host, username, password=None, timeout=300, pkey=None, - channel_timeout=10, look_for_keys=False, key_filename=None, - port=22, proxy_client=None): - """SSH client. - - Many of parameters are just passed to the underlying implementation - as it is. See the paramiko documentation for more details. - http://docs.paramiko.org/en/2.1/api/client.html#paramiko.client.SSHClient.connect - - :param host: Host to login. - :param username: SSH username. - :param password: SSH password, or a password to unlock private key. - :param timeout: Timeout in seconds, including retries. - Default is 300 seconds. - :param pkey: Private key. - :param channel_timeout: Channel timeout in seconds, passed to the - paramiko. Default is 10 seconds. - :param look_for_keys: Whether or not to search for private keys - in ``~/.ssh``. Default is False. - :param key_filename: Filename for private key to use. - :param port: SSH port number. - :param proxy_client: Another SSH client to provide a transport - for ssh-over-ssh. The default is None, which means - not to use ssh-over-ssh. - :type proxy_client: ``tempest.lib.common.ssh.Client`` object - """ - self.host = host - self.username = username - self.port = port - self.password = password - if isinstance(pkey, six.string_types): - pkey = paramiko.RSAKey.from_private_key( - six.StringIO(str(pkey))) - self.pkey = pkey - self.look_for_keys = look_for_keys - self.key_filename = key_filename - self.timeout = int(timeout) - self.channel_timeout = float(channel_timeout) - self.buf_size = 1024 - self.proxy_client = proxy_client - self._proxy_conn = None - - def _get_ssh_connection(self, sleep=1.5, backoff=1): - """Returns an ssh connection to the specified host.""" - bsleep = sleep - ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy( - paramiko.AutoAddPolicy()) - _start_time = time.time() - if self.pkey is not None: - LOG.info("Creating ssh connection to '%s:%d' as '%s'" - " with public key authentication", - self.host, self.port, self.username) - else: - LOG.info("Creating ssh connection to '%s:%d' as '%s'" - " with password %s", - self.host, self.port, self.username, str(self.password)) - attempts = 0 - while True: - if self.proxy_client is not None: - proxy_chan = self._get_proxy_channel() - else: - proxy_chan = None - try: - ssh.connect(self.host, port=self.port, username=self.username, - password=self.password, - look_for_keys=self.look_for_keys, - key_filename=self.key_filename, - timeout=self.channel_timeout, pkey=self.pkey, - sock=proxy_chan) - LOG.info("ssh connection to %s@%s successfully created", - self.username, self.host) - return ssh - except (EOFError, - socket.error, socket.timeout, - paramiko.SSHException) as e: - ssh.close() - if self._is_timed_out(_start_time): - LOG.exception("Failed to establish authenticated ssh" - " connection to %s@%s after %d attempts", - self.username, self.host, attempts) - raise exceptions.SSHTimeout(host=self.host, - user=self.username, - password=self.password) - bsleep += backoff - attempts += 1 - LOG.warning("Failed to establish authenticated ssh" - " connection to %s@%s (%s). Number attempts: %s." - " Retry after %d seconds.", - self.username, self.host, e, attempts, bsleep) - time.sleep(bsleep) - - def _is_timed_out(self, start_time): - return (time.time() - self.timeout) > start_time - - @staticmethod - def _can_system_poll(): - return hasattr(select, 'poll') - - def exec_command(self, cmd, encoding="utf-8"): - """Execute the specified command on the server - - Note that this method is reading whole command outputs to memory, thus - shouldn't be used for large outputs. - - :param str cmd: Command to run at remote server. - :param str encoding: Encoding for result from paramiko. - Result will not be decoded if None. - :returns: data read from standard output of the command. - :raises: SSHExecCommandFailed if command returns nonzero - status. The exception contains command status stderr content. - :raises: TimeoutException if cmd doesn't end when timeout expires. - """ - ssh = self._get_ssh_connection() - transport = ssh.get_transport() - with transport.open_session() as channel: - channel.fileno() # Register event pipe - channel.exec_command(cmd) - channel.shutdown_write() - - # If the executing host is linux-based, poll the channel - if self._can_system_poll(): - out_data_chunks = [] - err_data_chunks = [] - poll = select.poll() - poll.register(channel, select.POLLIN) - start_time = time.time() - - while True: - ready = poll.poll(self.channel_timeout) - if not any(ready): - if not self._is_timed_out(start_time): - continue - raise exceptions.TimeoutException( - "Command: '{0}' executed on host '{1}'.".format( - cmd, self.host)) - if not ready[0]: # If there is nothing to read. - continue - out_chunk = err_chunk = None - if channel.recv_ready(): - out_chunk = channel.recv(self.buf_size) - out_data_chunks += out_chunk, - if channel.recv_stderr_ready(): - err_chunk = channel.recv_stderr(self.buf_size) - err_data_chunks += err_chunk, - if not err_chunk and not out_chunk: - break - out_data = b''.join(out_data_chunks) - err_data = b''.join(err_data_chunks) - # Just read from the channels - else: - out_file = channel.makefile('rb', self.buf_size) - err_file = channel.makefile_stderr('rb', self.buf_size) - out_data = out_file.read() - err_data = err_file.read() - if encoding: - out_data = out_data.decode(encoding) - err_data = err_data.decode(encoding) - - exit_status = channel.recv_exit_status() - - if 0 != exit_status: - raise exceptions.SSHExecCommandFailed( - command=cmd, exit_status=exit_status, - stderr=err_data, stdout=out_data) - return out_data - - def test_connection_auth(self): - """Raises an exception when we can not connect to server via ssh.""" - connection = self._get_ssh_connection() - connection.close() - - def _get_proxy_channel(self): - conn = self.proxy_client._get_ssh_connection() - # Keep a reference to avoid g/c - # https://github.com/paramiko/paramiko/issues/440 - self._proxy_conn = conn - transport = conn.get_transport() - chan = transport.open_session() - cmd = 'nc %s %s' % (self.host, self.port) - chan.exec_command(cmd) - return chan diff --git a/tempest/lib/common/utils/__init__.py b/tempest/lib/common/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py deleted file mode 100644 index a0941ef50..000000000 --- a/tempest/lib/common/utils/data_utils.py +++ /dev/null @@ -1,214 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import itertools -import random -import string -import uuid - -from debtcollector import removals -import netaddr -from oslo_utils import netutils -from oslo_utils import uuidutils -import six.moves - - -def rand_uuid(): - """Generate a random UUID string - - :return: a random UUID (e.g. '1dc12c7d-60eb-4b61-a7a2-17cf210155b6') - :rtype: string - """ - return uuidutils.generate_uuid() - - -def rand_uuid_hex(): - """Generate a random UUID hex string - - :return: a random UUID (e.g. '0b98cf96d90447bda4b46f31aeb1508c') - :rtype: string - """ - return uuid.uuid4().hex - - -def rand_name(name='', prefix='tempest'): - """Generate a random name that includes a random number - - :param str name: The name that you want to include - :param str prefix: The prefix that you want to include - :return: a random name. The format is - '--'. - (e.g. 'prefixfoo-namebar-154876201') - :rtype: string - """ - randbits = str(random.randint(1, 0x7fffffff)) - rand_name = randbits - if name: - rand_name = name + '-' + rand_name - if prefix: - rand_name = prefix + '-' + rand_name - return rand_name - - -def rand_password(length=15): - """Generate a random password - - :param int length: The length of password that you expect to set - (If it's smaller than 3, it's same as 3.) - :return: a random password. The format is - '-- - -' - (e.g. 'G2*ac8&lKFFgh%2') - :rtype: string - """ - upper = random.choice(string.ascii_uppercase) - ascii_char = string.ascii_letters - digits = string.digits - digit = random.choice(string.digits) - puncs = '~!@#%^&*_=+' - punc = random.choice(puncs) - seed = ascii_char + digits + puncs - pre = upper + digit + punc - password = pre + ''.join(random.choice(seed) for x in range(length - 3)) - return password - - -def rand_url(): - """Generate a random url that includes a random number - - :return: a random url. The format is 'https://url-.com'. - (e.g. 'https://url-154876201.com') - :rtype: string - """ - randbits = str(random.randint(1, 0x7fffffff)) - return 'https://url-' + randbits + '.com' - - -def rand_int_id(start=0, end=0x7fffffff): - """Generate a random integer value - - :param int start: The value that you expect to start here - :param int end: The value that you expect to end here - :return: a random integer value - :rtype: int - """ - return random.randint(start, end) - - -def rand_mac_address(): - """Generate an Ethernet MAC address - - :return: an random Ethernet MAC address - :rtype: string - """ - # NOTE(vish): We would prefer to use 0xfe here to ensure that linux - # bridge mac addresses don't change, but it appears to - # conflict with libvirt, so we use the next highest octet - # that has the unicast and locally administered bits set - # properly: 0xfa. - # Discussion: https://bugs.launchpad.net/nova/+bug/921838 - mac = [0xfa, 0x16, 0x3e, - random.randint(0x00, 0xff), - random.randint(0x00, 0xff), - random.randint(0x00, 0xff)] - return ':'.join(["%02x" % x for x in mac]) - - -def rand_infiniband_guid_address(): - """Generate an Infiniband GUID address - - :return: an random Infiniband GUID address - :rtype: string - """ - guid = [] - for i in range(8): - guid.append("%02x" % random.randint(0x00, 0xff)) - return ':'.join(guid) - - -def parse_image_id(image_ref): - """Return the image id from a given image ref - - This function just returns the last word of the given image ref string - splitting with '/'. - :param str image_ref: a string that includes the image id - :return: the image id string - :rtype: string - """ - return image_ref.rsplit('/')[-1] - - -def arbitrary_string(size=4, base_text=None): - """Return size characters from base_text - - This generates a string with an arbitrary number of characters, generated - by looping the base_text string. If the size is smaller than the size of - base_text, returning string is shrunk to the size. - :param int size: a returning characters size - :param str base_text: a string you want to repeat - :return: size string - :rtype: string - """ - if not base_text: - base_text = 'test' - return ''.join(itertools.islice(itertools.cycle(base_text), size)) - - -def random_bytes(size=1024): - """Return size randomly selected bytes as a string - - :param int size: a returning bytes size - :return: size randomly bytes - :rtype: string - """ - return b''.join([six.int2byte(random.randint(0, 255)) - for i in range(size)]) - - -@removals.remove( - message="use get_ipv6_addr_by_EUI64 from oslo_utils.netutils", - version="Newton", - removal_version="Ocata") -def get_ipv6_addr_by_EUI64(cidr, mac): - """Generate a IPv6 addr by EUI-64 with CIDR and MAC - - :param str cidr: a IPv6 CIDR - :param str mac: a MAC address - :return: an IPv6 Address - :rtype: netaddr.IPAddress - """ - # Check if the prefix is IPv4 address - is_ipv4 = netutils.is_valid_ipv4(cidr) - if is_ipv4: - msg = "Unable to generate IP address by EUI64 for IPv4 prefix" - raise TypeError(msg) - try: - eui64 = int(netaddr.EUI(mac).eui64()) - prefix = netaddr.IPNetwork(cidr) - return netaddr.IPAddress(prefix.first + eui64 ^ (1 << 57)) - except (ValueError, netaddr.AddrFormatError): - raise TypeError('Bad prefix or mac format for generating IPv6 ' - 'address by EUI-64: %(prefix)s, %(mac)s:' - % {'prefix': cidr, 'mac': mac}) - except TypeError: - raise TypeError('Bad prefix type for generate IPv6 address by ' - 'EUI-64: %s' % cidr) - - -# Courtesy of http://stackoverflow.com/a/312464 -def chunkify(sequence, chunksize): - """Yield successive chunks from `sequence`.""" - for i in range(0, len(sequence), chunksize): - yield sequence[i:i + chunksize] diff --git a/tempest/lib/common/utils/linux/__init__.py b/tempest/lib/common/utils/linux/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/common/utils/linux/remote_client.py b/tempest/lib/common/utils/linux/remote_client.py deleted file mode 100644 index aef2ff35b..000000000 --- a/tempest/lib/common/utils/linux/remote_client.py +++ /dev/null @@ -1,126 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import sys - -import netaddr -from oslo_log import log as logging -import six - -from tempest.lib.common import ssh -from tempest.lib.common.utils import test_utils -import tempest.lib.exceptions - -LOG = logging.getLogger(__name__) - - -def debug_ssh(function): - """Decorator to generate extra debug info in case off SSH failure""" - def wrapper(self, *args, **kwargs): - try: - return function(self, *args, **kwargs) - except Exception as e: - caller = test_utils.find_test_caller() or "not found" - if not isinstance(e, tempest.lib.exceptions.SSHTimeout): - message = ('Initializing SSH connection to %(ip)s failed. ' - 'Error: %(error)s' % {'ip': self.ip_address, - 'error': e}) - message = '(%s) %s' % (caller, message) - LOG.error(message) - raise - else: - try: - original_exception = sys.exc_info() - if self.server: - msg = 'Caller: %s. Timeout trying to ssh to server %s' - LOG.debug(msg, caller, self.server) - if self.console_output_enabled and self.servers_client: - try: - msg = 'Console log for server %s: %s' - console_log = ( - self.servers_client.get_console_output( - self.server['id'])['output']) - LOG.debug(msg, self.server['id'], console_log) - except Exception: - msg = 'Could not get console_log for server %s' - LOG.debug(msg, self.server['id']) - # re-raise the original ssh timeout exception - six.reraise(*original_exception) - finally: - # Delete the traceback to avoid circular references - _, _, trace = original_exception - del trace - return wrapper - - -class RemoteClient(object): - - def __init__(self, ip_address, username, password=None, pkey=None, - server=None, servers_client=None, ssh_timeout=300, - connect_timeout=60, console_output_enabled=True, - ssh_shell_prologue="set -eu -o pipefail; PATH=$$PATH:/sbin;", - ping_count=1, ping_size=56): - """Executes commands in a VM over ssh - - :param ip_address: IP address to ssh to - :param username: Ssh username - :param password: Ssh password - :param pkey: Ssh public key - :param server: Server dict, used for debugging purposes - :param servers_client: Servers client, used for debugging purposes - :param ssh_timeout: Timeout in seconds to wait for the ssh banner - :param connect_timeout: Timeout in seconds to wait for TCP connection - :param console_output_enabled: Support serial console output? - :param ssh_shell_prologue: Shell fragments to use before command - :param ping_count: Number of ping packets - :param ping_size: Packet size for ping packets - """ - self.server = server - self.servers_client = servers_client - self.ip_address = ip_address - self.console_output_enabled = console_output_enabled - self.ssh_shell_prologue = ssh_shell_prologue - self.ping_count = ping_count - self.ping_size = ping_size - - self.ssh_client = ssh.Client(ip_address, username, password, - ssh_timeout, pkey=pkey, - channel_timeout=connect_timeout) - - @debug_ssh - def exec_command(self, cmd): - # Shell options below add more clearness on failures, - # path is extended for some non-cirros guest oses (centos7) - cmd = self.ssh_shell_prologue + " " + cmd - LOG.debug("Remote command: %s", cmd) - return self.ssh_client.exec_command(cmd) - - @debug_ssh - def validate_authentication(self): - """Validate ssh connection and authentication - - This method raises an Exception when the validation fails. - """ - self.ssh_client.test_connection_auth() - - def ping_host(self, host, count=None, size=None, nic=None): - if count is None: - count = self.ping_count - if size is None: - size = self.ping_size - - addr = netaddr.IPAddress(host) - cmd = 'ping6' if addr.version == 6 else 'ping' - if nic: - cmd = 'sudo {cmd} -I {nic}'.format(cmd=cmd, nic=nic) - cmd += ' -c{0} -w{0} -s{1} {2}'.format(count, size, host) - return self.exec_command(cmd) diff --git a/tempest/lib/common/utils/misc.py b/tempest/lib/common/utils/misc.py deleted file mode 100644 index f13b4c882..000000000 --- a/tempest/lib/common/utils/misc.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -from oslo_log import log as logging - -from tempest.lib.common.utils import test_utils - -LOG = logging.getLogger(__name__) - - -def singleton(cls): - """Simple wrapper for classes that should only have a single instance.""" - instances = {} - - def getinstance(): - if cls not in instances: - instances[cls] = cls() - return instances[cls] - return getinstance - - -def find_test_caller(*args, **kwargs): - LOG.warning("tempest.lib.common.utils.misc.find_test_caller is deprecated " - "in favor of tempest.lib.common.utils.test_utils." - "find_test_caller") - test_utils.find_test_caller(*args, **kwargs) diff --git a/tempest/lib/common/utils/test_utils.py b/tempest/lib/common/utils/test_utils.py deleted file mode 100644 index bd0db7c81..000000000 --- a/tempest/lib/common/utils/test_utils.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import inspect -import re -import time - -from oslo_log import log as logging - -from tempest.lib import exceptions - -LOG = logging.getLogger(__name__) - - -def find_test_caller(): - """Find the caller class and test name. - - Because we know that the interesting things that call us are - test_* methods, and various kinds of setUp / tearDown, we - can look through the call stack to find appropriate methods, - and the class we were in when those were called. - """ - caller_name = None - names = [] - frame = inspect.currentframe() - is_cleanup = False - # Start climbing the ladder until we hit a good method - while True: - try: - frame = frame.f_back - name = frame.f_code.co_name - names.append(name) - if re.search("^(test_|setUp|tearDown)", name): - cname = "" - if 'self' in frame.f_locals: - cname = frame.f_locals['self'].__class__.__name__ - if 'cls' in frame.f_locals: - cname = frame.f_locals['cls'].__name__ - caller_name = cname + ":" + name - break - elif re.search("^_run_cleanup", name): - is_cleanup = True - elif name == 'main': - caller_name = 'main' - break - else: - cname = "" - if 'self' in frame.f_locals: - cname = frame.f_locals['self'].__class__.__name__ - if 'cls' in frame.f_locals: - cname = frame.f_locals['cls'].__name__ - - # the fact that we are running cleanups is indicated pretty - # deep in the stack, so if we see that we want to just - # start looking for a real class name, and declare victory - # once we do. - if is_cleanup and cname: - if not re.search("^RunTest", cname): - caller_name = cname + ":_run_cleanups" - break - except Exception: - break - # prevents frame leaks - del frame - if caller_name is None: - LOG.debug("Sane call name not found in %s", names) - return caller_name - - -def call_and_ignore_notfound_exc(func, *args, **kwargs): - """Call the given function and pass if a `NotFound` exception is raised.""" - try: - return func(*args, **kwargs) - except exceptions.NotFound: - pass - - -def call_until_true(func, duration, sleep_for): - """Call the given function until it returns True (and return True) - - or until the specified duration (in seconds) elapses (and return False). - - :param func: A zero argument callable that returns True on success. - :param duration: The number of seconds for which to attempt a - successful call of the function. - :param sleep_for: The number of seconds to sleep after an unsuccessful - invocation of the function. - """ - now = time.time() - timeout = now + duration - while now < timeout: - if func(): - return True - time.sleep(sleep_for) - now = time.time() - return False diff --git a/tempest/lib/decorators.py b/tempest/lib/decorators.py deleted file mode 100644 index f82f707af..000000000 --- a/tempest/lib/decorators.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import functools -import uuid - -import debtcollector.removals -from oslo_log import log as logging -import six -import testtools - -LOG = logging.getLogger(__name__) - - -def skip_because(*args, **kwargs): - """A decorator useful to skip tests hitting known bugs - - @param bug: bug number causing the test to skip - @param condition: optional condition to be True for the skip to have place - """ - def decorator(f): - @functools.wraps(f) - def wrapper(self, *func_args, **func_kwargs): - skip = False - if "condition" in kwargs: - if kwargs["condition"] is True: - skip = True - else: - skip = True - if "bug" in kwargs and skip is True: - if not kwargs['bug'].isdigit(): - raise ValueError('bug must be a valid bug number') - msg = "Skipped until Bug: %s is resolved." % kwargs["bug"] - raise testtools.TestCase.skipException(msg) - return f(self, *func_args, **func_kwargs) - return wrapper - return decorator - - -def related_bug(bug, status_code=None): - """A decorator useful to know solutions from launchpad bug reports - - @param bug: The launchpad bug number causing the test - @param status_code: The status code related to the bug report - """ - def decorator(f): - @functools.wraps(f) - def wrapper(self, *func_args, **func_kwargs): - try: - return f(self, *func_args, **func_kwargs) - except Exception as exc: - exc_status_code = getattr(exc, 'status_code', None) - if status_code is None or status_code == exc_status_code: - LOG.error('Hints: This test was made for the bug %s. ' - 'The failure could be related to ' - 'https://launchpad.net/bugs/%s', bug, bug) - raise exc - return wrapper - return decorator - - -def idempotent_id(id): - """Stub for metadata decorator""" - if not isinstance(id, six.string_types): - raise TypeError('Test idempotent_id must be string not %s' - '' % type(id).__name__) - uuid.UUID(id) - - def decorator(f): - f = testtools.testcase.attr('id-%s' % id)(f) - if f.__doc__: - f.__doc__ = 'Test idempotent id: %s\n%s' % (id, f.__doc__) - else: - f.__doc__ = 'Test idempotent id: %s' % id - return f - return decorator - - -@debtcollector.removals.remove(removal_version='Queen') -class skip_unless_attr(object): - """Decorator to skip tests if a specified attr does not exists or False""" - def __init__(self, attr, msg=None): - self.attr = attr - self.message = msg or ("Test case attribute %s not found " - "or False") % attr - - def __call__(self, func): - @functools.wraps(func) - def _skipper(*args, **kw): - """Wrapped skipper function.""" - testobj = args[0] - if not getattr(testobj, self.attr, False): - raise testtools.TestCase.skipException(self.message) - func(*args, **kw) - return _skipper - - -def attr(**kwargs): - """A decorator which applies the testtools attr decorator - - This decorator applies the testtools.testcase.attr if it is in the list of - attributes to testtools we want to apply. - """ - - def decorator(f): - if 'type' in kwargs and isinstance(kwargs['type'], str): - f = testtools.testcase.attr(kwargs['type'])(f) - elif 'type' in kwargs and isinstance(kwargs['type'], list): - for attr in kwargs['type']: - f = testtools.testcase.attr(attr)(f) - return f - - return decorator diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py deleted file mode 100644 index cdb8be9d0..000000000 --- a/tempest/lib/exceptions.py +++ /dev/null @@ -1,275 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - - -class TempestException(Exception): - """Base Tempest Exception - - To correctly use this class, inherit from it and define - a 'message' property. That message will get printf'd - with the keyword arguments provided to the constructor. - """ - message = "An unknown exception occurred" - - def __init__(self, *args, **kwargs): - super(TempestException, self).__init__() - try: - self._error_string = self.message % kwargs - except Exception: - # at least get the core message out if something happened - self._error_string = self.message - if args: - # If there is a non-kwarg parameter, assume it's the error - # message or reason description and tack it on to the end - # of the exception message - # Convert all arguments into their string representations... - args = ["%s" % arg for arg in args] - self._error_string = (self._error_string + - "\nDetails: %s" % '\n'.join(args)) - - def __str__(self): - return self._error_string - - -class RestClientException(TempestException, - testtools.TestCase.failureException): - def __init__(self, resp_body=None, *args, **kwargs): - if 'resp' in kwargs: - self.resp = kwargs.get('resp') - self.resp_body = resp_body - message = kwargs.get("message", resp_body) - super(RestClientException, self).__init__(message, *args, **kwargs) - - -class OtherRestClientException(RestClientException): - pass - - -class ServerRestClientException(RestClientException): - pass - - -class ClientRestClientException(RestClientException): - pass - - -class InvalidHttpSuccessCode(OtherRestClientException): - message = "The success code is different than the expected one" - - -class BadRequest(ClientRestClientException): - status_code = 400 - message = "Bad request" - - -class Unauthorized(ClientRestClientException): - status_code = 401 - message = 'Unauthorized' - - -class Forbidden(ClientRestClientException): - status_code = 403 - message = "Forbidden" - - -class NotFound(ClientRestClientException): - status_code = 404 - message = "Object not found" - - -class Conflict(ClientRestClientException): - status_code = 409 - message = "An object with that identifier already exists" - - -class Gone(ClientRestClientException): - status_code = 410 - message = "The requested resource is no longer available" - - -class PreconditionFailed(ClientRestClientException): - status_code = 412 - message = "Precondition Failed" - - -class RateLimitExceeded(ClientRestClientException): - status_code = 413 - message = "Rate limit exceeded" - - -class OverLimit(ClientRestClientException): - status_code = 413 - message = "Request entity is too large" - - -class InvalidContentType(ClientRestClientException): - status_code = 415 - message = "Invalid content type provided" - - -class UnprocessableEntity(ClientRestClientException): - status_code = 422 - message = "Unprocessable entity" - - -class ServerFault(ServerRestClientException): - status_code = 500 - message = "Got server fault" - - -class NotImplemented(ServerRestClientException): - status_code = 501 - message = "Got NotImplemented error" - - -class TimeoutException(OtherRestClientException): - message = "Request timed out" - - -class ResponseWithNonEmptyBody(OtherRestClientException): - message = ("RFC Violation! Response with %(status)d HTTP Status Code " - "MUST NOT have a body") - - -class ResponseWithEntity(OtherRestClientException): - message = ("RFC Violation! Response with 205 HTTP Status Code " - "MUST NOT have an entity") - - -class InvalidHTTPResponseBody(OtherRestClientException): - message = "HTTP response body is invalid json or xml" - - -class InvalidHTTPResponseHeader(OtherRestClientException): - message = "HTTP response header is invalid" - - -class UnexpectedContentType(OtherRestClientException): - message = "Unexpected content type provided" - - -class UnexpectedResponseCode(OtherRestClientException): - message = "Unexpected response code received" - - -class InvalidConfiguration(TempestException): - message = "Invalid Configuration" - - -class InvalidIdentityVersion(TempestException): - message = "Invalid version %(identity_version)s of the identity service" - - -class InvalidStructure(TempestException): - message = "Invalid structure of table with details" - - -class InvalidAPIVersionString(TempestException): - message = ("API Version String %(version)s is of invalid format. Must " - "be of format MajorNum.MinorNum or string 'latest'.") - - -class JSONSchemaNotFound(TempestException): - message = ("JSON Schema for %(version)s is not found in\n" - " %(schema_versions_info)s") - - -class InvalidAPIVersionRange(TempestException): - message = ("The API version range is invalid.") - - -class BadAltAuth(TempestException): - """Used when trying and failing to change to alt creds. - - If alt creds end up the same as primary creds, use this - exception. This is often going to be the case when you assume - project_id is in the url, but it's not. - - """ - message = "The alt auth looks the same as primary auth for %(part)s" - - -class CommandFailed(Exception): - def __init__(self, returncode, cmd, output, stderr): - super(CommandFailed, self).__init__() - self.returncode = returncode - self.cmd = cmd - self.stdout = output - self.stderr = stderr - - def __str__(self): - return ("Command '%s' returned non-zero exit status %d.\n" - "stdout:\n%s\n" - "stderr:\n%s" % (self.cmd, - self.returncode, - self.stdout, - self.stderr)) - - -class IdentityError(TempestException): - message = "Got identity error" - - -class EndpointNotFound(TempestException): - message = "Endpoint not found" - - -class InvalidCredentials(TempestException): - message = "Invalid Credentials" - - -class InvalidScope(TempestException): - message = "Invalid Scope %(scope)s for %(auth_provider)s" - - -class SSHTimeout(TempestException): - message = ("Connection to the %(host)s via SSH timed out.\n" - "User: %(user)s, Password: %(password)s") - - -class SSHExecCommandFailed(TempestException): - """Raised when remotely executed command returns nonzero status.""" - message = ("Command '%(command)s', exit status: %(exit_status)d, " - "stderr:\n%(stderr)s\n" - "stdout:\n%(stdout)s") - - -class UnknownServiceClient(TempestException): - message = "Service clients named %(services)s are not known" - - -class ServiceClientRegistrationException(TempestException): - message = ("Error registering module %(name)s in path %(module_path)s, " - "with service %(service_version)s and clients " - "%(client_names)s: %(detailed_error)s") - - -class PluginRegistrationException(TempestException): - message = "Error registering plugin %(name)s: %(detailed_error)s" - - -class VolumeBackupException(TempestException): - message = "Volume backup %(backup_id)s failed and is in ERROR status" - - -class DeleteErrorException(TempestException): - message = ("Resource %(resource_id)s failed to delete " - "and is in ERROR status") - - -class InvalidTestResource(TempestException): - message = "%(name)s is not a valid %(type)s, or the name is ambiguous" diff --git a/tempest/lib/services/__init__.py b/tempest/lib/services/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py deleted file mode 100644 index 5f230b7b4..000000000 --- a/tempest/lib/services/clients.py +++ /dev/null @@ -1,466 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import importlib -import inspect -import warnings - -from debtcollector import removals -from oslo_log import log as logging - -from tempest.lib import auth -from tempest.lib.common.utils import misc -from tempest.lib import exceptions -from tempest.lib.services import compute -from tempest.lib.services import identity -from tempest.lib.services import image -from tempest.lib.services import network -from tempest.lib.services import volume - -warnings.simplefilter("once") -LOG = logging.getLogger(__name__) - - -def tempest_modules(): - """Dict of service client modules available in Tempest. - - Provides a dict of stable service modules available in Tempest, with - ``service_version`` as key, and the module object as value. - """ - return { - 'compute': compute, - 'identity.v2': identity.v2, - 'identity.v3': identity.v3, - 'image.v1': image.v1, - 'image.v2': image.v2, - 'network': network, - 'volume.v1': volume.v1, - 'volume.v2': volume.v2, - 'volume.v3': volume.v3 - } - - -def _tempest_internal_modules(): - # Set of unstable service clients available in Tempest - # NOTE(andreaf) This list will exists only as long the remain clients - # are migrated to tempest.lib, and it will then be deleted without - # deprecation or advance notice - return set(['object-storage']) - - -def available_modules(): - """Set of service client modules available in Tempest and plugins - - Set of stable service clients from Tempest and service clients exposed - by plugins. This set of available modules can be used for automatic - configuration. - - :raise PluginRegistrationException: if a plugin exposes a service_version - already defined by Tempest or another plugin. - - Examples:: - - from tempest import config - params = {} - for service_version in available_modules(): - service = service_version.split('.')[0] - params[service] = config.service_client_config(service) - service_clients = ServiceClients(creds, identity_uri, - client_parameters=params) - """ - extra_service_versions = set([]) - _tempest_modules = set(tempest_modules()) - plugin_services = ClientsRegistry().get_service_clients() - for plugin_name in plugin_services: - plug_service_versions = set([x['service_version'] for x in - plugin_services[plugin_name]]) - # If a plugin exposes a duplicate service_version raise an exception - if plug_service_versions: - if not plug_service_versions.isdisjoint(extra_service_versions): - detailed_error = ( - 'Plugin %s is trying to register a service %s already ' - 'claimed by another one' % (plugin_name, - extra_service_versions & - plug_service_versions)) - raise exceptions.PluginRegistrationException( - name=plugin_name, detailed_error=detailed_error) - # NOTE(andreaf) Once all tempest clients are stable, the following - # if will have to be removed. - if not plug_service_versions.isdisjoint( - _tempest_internal_modules()): - detailed_error = ( - 'Plugin %s is trying to register a service %s already ' - 'claimed by a Tempest one' % (plugin_name, - _tempest_internal_modules() & - plug_service_versions)) - raise exceptions.PluginRegistrationException( - name=plugin_name, detailed_error=detailed_error) - extra_service_versions |= plug_service_versions - return _tempest_modules | extra_service_versions - - -@misc.singleton -class ClientsRegistry(object): - """Registry of all service clients available from plugins""" - - def __init__(self): - self._service_clients = {} - - def register_service_client(self, plugin_name, service_client_data): - if plugin_name in self._service_clients: - detailed_error = 'Clients for plugin %s already registered' - raise exceptions.PluginRegistrationException( - name=plugin_name, - detailed_error=detailed_error % plugin_name) - self._service_clients[plugin_name] = service_client_data - LOG.debug("Successfully registered plugin %s in the service client " - "registry with configuration: %s", plugin_name, - service_client_data) - - def get_service_clients(self): - return self._service_clients - - -class ClientsFactory(object): - """Builds service clients for a service client module - - This class implements the logic of feeding service client parameters - to service clients from a specific module. It allows setting the - parameters once and obtaining new instances of the clients without the - need of passing any parameter. - - ClientsFactory can be used directly, or consumed via the `ServiceClients` - class, which manages the authorization part. - """ - - def __init__(self, module_path, client_names, auth_provider, **kwargs): - """Initialises the client factory - - :param module_path: Path to module that includes all service clients. - All service client classes must be exposed by a single module. - If they are separated in different modules, defining __all__ - in the root module can help, similar to what is done by service - clients in tempest. - :param client_names: List or set of names of the service client - classes. - :param auth_provider: The auth provider used to initialise client. - :param kwargs: Parameters to be passed to all clients. Parameters - values can be overwritten when clients are initialised, but - parameters cannot be deleted. - :raise ImportError: if the specified module_path cannot be imported - - Example:: - - # Get credentials and an auth_provider - clients = ClientsFactory( - module_path='my_service.my_service_clients', - client_names=['ServiceClient1', 'ServiceClient2'], - auth_provider=auth_provider, - service='my_service', - region='region1') - my_api_client = clients.MyApiClient() - my_api_client_region2 = clients.MyApiClient(region='region2') - - """ - # Import the module. If it's not importable, the raised exception - # provides good enough information about what happened - _module = importlib.import_module(module_path) - # If any of the classes is not in the module we fail - for class_name in client_names: - # TODO(andreaf) This always passes all parameters to all clients. - # In future to allow clients to specify the list of parameters - # that they accept based out of a list of standard ones. - - # Obtain the class - klass = self._get_class(_module, class_name) - final_kwargs = copy.copy(kwargs) - - # Set the function as an attribute of the factory - setattr(self, class_name, self._get_partial_class( - klass, auth_provider, final_kwargs)) - - def _get_partial_class(self, klass, auth_provider, kwargs): - - # Define a function that returns a new class instance by - # combining default kwargs with extra ones - def partial_class(alias=None, **later_kwargs): - """Returns a callable the initialises a service client - - Builds a callable that accepts kwargs, which are passed through - to the __init__ of the service client, along with a set of defaults - set in factory at factory __init__ time. - Original args in the service client can only be passed as kwargs. - - It accepts one extra parameter 'alias' compared to the original - service client. When alias is provided, the returned callable will - also set an attribute called with a name defined in 'alias', which - contains the instance of the service client. - - :param alias: str Name of the attribute set on the factory once - the callable is invoked which contains the initialised - service client. If None, no attribute is set. - :param later_kwargs: kwargs passed through to the service client - __init__ on top of defaults set at factory level. - """ - kwargs.update(later_kwargs) - _client = klass(auth_provider=auth_provider, **kwargs) - if alias: - setattr(self, alias, _client) - return _client - - return partial_class - - @classmethod - def _get_class(cls, module, class_name): - klass = getattr(module, class_name, None) - if not klass: - msg = 'Invalid class name, %s is not found in %s' - raise AttributeError(msg % (class_name, module)) - if not inspect.isclass(klass): - msg = 'Expected a class, got %s of type %s instead' - raise TypeError(msg % (klass, type(klass))) - return klass - - -class ServiceClients(object): - """Service client provider class - - The ServiceClients object provides a useful means for tests to access - service clients configured for a specified set of credentials. - It hides some of the complexity from the authorization and configuration - layers. - - Examples:: - - # johndoe is a tempest.lib.auth.Credentials type instance - johndoe_clients = clients.ServiceClients(johndoe, identity_uri) - - # List servers in default region - johndoe_servers_client = johndoe_clients.compute.ServersClient() - johndoe_servers = johndoe_servers_client.list_servers() - - # List servers in Region B - johndoe_servers_client_B = johndoe_clients.compute.ServersClient( - region='B') - johndoe_servers = johndoe_servers_client_B.list_servers() - - """ - # NOTE(andreaf) This class does not depend on tempest configuration - # and its meant for direct consumption by external clients such as tempest - # plugins. Tempest provides a wrapper class, `clients.Manager`, that - # initialises this class using values from tempest CONF object. The wrapper - # class should only be used by tests hosted in Tempest. - - @removals.removed_kwarg('client_parameters') - def __init__(self, credentials, identity_uri, region=None, scope='project', - disable_ssl_certificate_validation=True, ca_certs=None, - trace_requests='', client_parameters=None): - """Service Clients provider - - Instantiate a `ServiceClients` object, from a set of credentials and an - identity URI. The identity version is inferred from the credentials - object. Optionally auth scope can be provided. - - A few parameters can be given a value which is applied as default - for all service clients: region, dscv, ca_certs, trace_requests. - - Parameters dscv, ca_certs and trace_requests all apply to the auth - provider as well as any service clients provided by this manager. - - Any other client parameter should be set via ClientsRegistry. - - Client parameter used to be set via client_parameters, but this is - deprecated, and it is actually already not honoured - anymore: https://launchpad.net/bugs/1680915. - - The list of available parameters is defined in the service clients - interfaces. For reference, most clients will accept 'region', - 'service', 'endpoint_type', 'build_timeout' and 'build_interval', which - are all inherited from RestClient. - - The `config` module in Tempest exposes an helper function - `service_client_config` that can be used to extract from configuration - a dictionary ready to be injected in kwargs. - - Exceptions are: - - Token clients for 'identity' must be given an 'auth_url' parameter - - Volume client for 'volume' accepts 'default_volume_size' - - Servers client from 'compute' accepts 'enable_instance_password' - - If Tempest configuration is used, parameters will be loaded in the - Registry automatically for all service client (Tempest stable ones - and plugins). - - Examples:: - - identity_params = config.service_client_config('identity') - params = { - 'identity': identity_params, - 'compute': {'region': 'region2'}} - manager = lib_manager.Manager( - my_creds, identity_uri, client_parameters=params) - - :param credentials: An instance of `auth.Credentials` - :param identity_uri: URI of the identity API. This should be a - mandatory parameter, and it will so soon. - :param region: Default value of region for service clients. - :param scope: default scope for tokens produced by the auth provider - :param disable_ssl_certificate_validation: Applies to auth and to all - service clients. - :param ca_certs: Applies to auth and to all service clients. - :param trace_requests: Applies to auth and to all service clients. - :param client_parameters: Dictionary with parameters for service - clients. Keys of the dictionary are the service client service - name, as declared in `service_clients.available_modules()` except - for the version. Values are dictionaries of parameters that are - going to be passed to all clients in the service client module. - """ - self._registered_services = set([]) - self.credentials = credentials - self.identity_uri = identity_uri - if not identity_uri: - raise exceptions.InvalidCredentials( - 'ServiceClients requires a non-empty identity_uri.') - self.region = region - # Check if passed or default credentials are valid - if not self.credentials.is_valid(): - raise exceptions.InvalidCredentials() - # Get the identity classes matching the provided credentials - # TODO(andreaf) Define a new interface in Credentials to get - # the API version from an instance - identity = [(k, auth.IDENTITY_VERSION[k][1]) for k in - auth.IDENTITY_VERSION.keys() if - isinstance(self.credentials, auth.IDENTITY_VERSION[k][0])] - # Zero matches or more than one are both not valid. - if len(identity) != 1: - raise exceptions.InvalidCredentials() - self.auth_version, auth_provider_class = identity[0] - self.dscv = disable_ssl_certificate_validation - self.ca_certs = ca_certs - self.trace_requests = trace_requests - # Creates an auth provider for the credentials - self.auth_provider = auth_provider_class( - self.credentials, self.identity_uri, scope=scope, - disable_ssl_certificate_validation=self.dscv, - ca_certs=self.ca_certs, trace_requests=self.trace_requests) - # Setup some defaults for client parameters of registered services - client_parameters = client_parameters or {} - self.parameters = {} - # Parameters are provided for unversioned services - all_modules = available_modules() | _tempest_internal_modules() - unversioned_services = set( - [x.split('.')[0] for x in all_modules]) - for service in unversioned_services: - self.parameters[service] = self._setup_parameters( - client_parameters.pop(service, {})) - # Check that no client parameters was supplied for unregistered clients - if client_parameters: - raise exceptions.UnknownServiceClient( - services=list(client_parameters.keys())) - - # Register service clients from the registry (__tempest__ and plugins) - clients_registry = ClientsRegistry() - plugin_service_clients = clients_registry.get_service_clients() - for plugin in plugin_service_clients: - service_clients = plugin_service_clients[plugin] - # Each plugin returns a list of service client parameters - for service_client in service_clients: - # NOTE(andreaf) If a plugin cannot register, stop the - # registration process, log some details to help - # troubleshooting, and re-raise - try: - self.register_service_client_module(**service_client) - except Exception: - LOG.exception( - 'Failed to register service client from plugin %s ' - 'with parameters %s', plugin, service_client) - raise - - def register_service_client_module(self, name, service_version, - module_path, client_names, **kwargs): - """Register a service client module - - Initiates a client factory for the specified module, using this - class auth_provider, and accessible via a `name` attribute in the - service client. - - :param name: Name used to access the client - :param service_version: Name of the service complete with version. - Used to track registered services. When a plugin implements it, - it can be used by other plugins to obtain their configuration. - :param module_path: Path to module that includes all service clients. - All service client classes must be exposed by a single module. - If they are separated in different modules, defining __all__ - in the root module can help, similar to what is done by service - clients in tempest. - :param client_names: List or set of names of service client classes. - :param kwargs: Extra optional parameters to be passed to all clients. - ServiceClient provides defaults for region, dscv, ca_certs and - trace_requests. - :raise ServiceClientRegistrationException: if the provided name is - already in use or if service_version is already registered. - :raise ImportError: if module_path cannot be imported. - """ - if hasattr(self, name): - using_name = getattr(self, name) - detailed_error = 'Module name already in use: %s' % using_name - raise exceptions.ServiceClientRegistrationException( - name=name, service_version=service_version, - module_path=module_path, client_names=client_names, - detailed_error=detailed_error) - if service_version in self.registered_services: - detailed_error = 'Service %s already registered.' % service_version - raise exceptions.ServiceClientRegistrationException( - name=name, service_version=service_version, - module_path=module_path, client_names=client_names, - detailed_error=detailed_error) - params = dict(region=self.region, - disable_ssl_certificate_validation=self.dscv, - ca_certs=self.ca_certs, - trace_requests=self.trace_requests) - params.update(kwargs) - # Instantiate the client factory - _factory = ClientsFactory(module_path=module_path, - client_names=client_names, - auth_provider=self.auth_provider, - **params) - # Adds the client factory to the service_client - setattr(self, name, _factory) - # Add the name of the new service in self.SERVICES for discovery - self._registered_services.add(service_version) - - @property - def registered_services(self): - # NOTE(andreaf) Once all tempest modules are stable this needs to - # be updated to remove _tempest_internal_modules - return self._registered_services | _tempest_internal_modules() - - def _setup_parameters(self, parameters): - """Setup default values for client parameters - - Region by default is the region passed as an __init__ parameter. - Checks that no parameter for an unknown service is provided. - """ - _parameters = {} - # Use region from __init__ - if self.region: - _parameters['region'] = self.region - # Update defaults with specified parameters - _parameters.update(parameters) - # If any parameter is left, parameters for an unknown service were - # provided as input. Fail rather than ignore silently. - return _parameters diff --git a/tempest/lib/services/compute/__init__.py b/tempest/lib/services/compute/__init__.py deleted file mode 100644 index 91e896af0..000000000 --- a/tempest/lib/services/compute/__init__.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.compute.agents_client import AgentsClient -from tempest.lib.services.compute.aggregates_client import AggregatesClient -from tempest.lib.services.compute.availability_zone_client import \ - AvailabilityZoneClient -from tempest.lib.services.compute.baremetal_nodes_client import \ - BaremetalNodesClient -from tempest.lib.services.compute.certificates_client import \ - CertificatesClient -from tempest.lib.services.compute.extensions_client import \ - ExtensionsClient -from tempest.lib.services.compute.fixed_ips_client import FixedIPsClient -from tempest.lib.services.compute.flavors_client import FlavorsClient -from tempest.lib.services.compute.floating_ip_pools_client import \ - FloatingIPPoolsClient -from tempest.lib.services.compute.floating_ips_bulk_client import \ - FloatingIPsBulkClient -from tempest.lib.services.compute.floating_ips_client import \ - FloatingIPsClient -from tempest.lib.services.compute.hosts_client import HostsClient -from tempest.lib.services.compute.hypervisor_client import \ - HypervisorClient -from tempest.lib.services.compute.images_client import ImagesClient -from tempest.lib.services.compute.instance_usage_audit_log_client import \ - InstanceUsagesAuditLogClient -from tempest.lib.services.compute.interfaces_client import InterfacesClient -from tempest.lib.services.compute.keypairs_client import KeyPairsClient -from tempest.lib.services.compute.limits_client import LimitsClient -from tempest.lib.services.compute.migrations_client import MigrationsClient -from tempest.lib.services.compute.networks_client import NetworksClient -from tempest.lib.services.compute.quota_classes_client import \ - QuotaClassesClient -from tempest.lib.services.compute.quotas_client import QuotasClient -from tempest.lib.services.compute.security_group_default_rules_client import \ - SecurityGroupDefaultRulesClient -from tempest.lib.services.compute.security_group_rules_client import \ - SecurityGroupRulesClient -from tempest.lib.services.compute.security_groups_client import \ - SecurityGroupsClient -from tempest.lib.services.compute.server_groups_client import \ - ServerGroupsClient -from tempest.lib.services.compute.servers_client import ServersClient -from tempest.lib.services.compute.services_client import ServicesClient -from tempest.lib.services.compute.snapshots_client import SnapshotsClient -from tempest.lib.services.compute.tenant_networks_client import \ - TenantNetworksClient -from tempest.lib.services.compute.tenant_usages_client import \ - TenantUsagesClient -from tempest.lib.services.compute.versions_client import VersionsClient -from tempest.lib.services.compute.volumes_client import \ - VolumesClient - -__all__ = ['AgentsClient', 'AggregatesClient', 'AvailabilityZoneClient', - 'BaremetalNodesClient', 'CertificatesClient', 'ExtensionsClient', - 'FixedIPsClient', 'FlavorsClient', 'FloatingIPPoolsClient', - 'FloatingIPsBulkClient', 'FloatingIPsClient', 'HostsClient', - 'HypervisorClient', 'ImagesClient', 'InstanceUsagesAuditLogClient', - 'InterfacesClient', 'KeyPairsClient', 'LimitsClient', - 'MigrationsClient', 'NetworksClient', 'QuotaClassesClient', - 'QuotasClient', 'SecurityGroupDefaultRulesClient', - 'SecurityGroupRulesClient', 'SecurityGroupsClient', - 'ServerGroupsClient', 'ServersClient', 'ServicesClient', - 'SnapshotsClient', 'TenantNetworksClient', 'TenantUsagesClient', - 'VersionsClient', 'VolumesClient'] diff --git a/tempest/lib/services/compute/agents_client.py b/tempest/lib/services/compute/agents_client.py deleted file mode 100644 index 408f75dc2..000000000 --- a/tempest/lib/services/compute/agents_client.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2014 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import agents as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class AgentsClient(base_compute_client.BaseComputeClient): - """Tests Agents API""" - - def list_agents(self, **params): - """List all agent builds. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-agent-builds - """ - url = 'os-agents' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_agents, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_agent(self, **kwargs): - """Create an agent build. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-agent-build - """ - post_body = json.dumps({'agent': kwargs}) - resp, body = self.post('os-agents', post_body) - body = json.loads(body) - self.validate_response(schema.create_agent, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_agent(self, agent_id): - """Delete an existing agent build. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-agent-build - """ - resp, body = self.delete("os-agents/%s" % agent_id) - self.validate_response(schema.delete_agent, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_agent(self, agent_id, **kwargs): - """Update an agent build. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-agent-build - """ - put_body = json.dumps({'para': kwargs}) - resp, body = self.put('os-agents/%s' % agent_id, put_body) - body = json.loads(body) - self.validate_response(schema.update_agent, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/aggregates_client.py b/tempest/lib/services/compute/aggregates_client.py deleted file mode 100644 index 713d7a30b..000000000 --- a/tempest/lib/services/compute/aggregates_client.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2013 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import aggregates as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class AggregatesClient(base_compute_client.BaseComputeClient): - - def list_aggregates(self): - """Get aggregate list.""" - resp, body = self.get("os-aggregates") - body = json.loads(body) - self.validate_response(schema.list_aggregates, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_aggregate(self, aggregate_id): - """Get details of the given aggregate.""" - resp, body = self.get("os-aggregates/%s" % aggregate_id) - body = json.loads(body) - self.validate_response(schema.get_aggregate, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_aggregate(self, **kwargs): - """Create a new aggregate. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-aggregate - """ - post_body = json.dumps({'aggregate': kwargs}) - resp, body = self.post('os-aggregates', post_body) - - body = json.loads(body) - self.validate_response(schema.create_aggregate, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_aggregate(self, aggregate_id, **kwargs): - """Update an aggregate. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-aggregate - """ - put_body = json.dumps({'aggregate': kwargs}) - resp, body = self.put('os-aggregates/%s' % aggregate_id, put_body) - - body = json.loads(body) - self.validate_response(schema.update_aggregate, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_aggregate(self, aggregate_id): - """Delete the given aggregate.""" - resp, body = self.delete("os-aggregates/%s" % aggregate_id) - self.validate_response(schema.delete_aggregate, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_aggregate(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'aggregate' - - def add_host(self, aggregate_id, **kwargs): - """Add a host to the given aggregate. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#add-host - """ - post_body = json.dumps({'add_host': kwargs}) - resp, body = self.post('os-aggregates/%s/action' % aggregate_id, - post_body) - body = json.loads(body) - self.validate_response(schema.aggregate_add_remove_host, resp, body) - return rest_client.ResponseBody(resp, body) - - def remove_host(self, aggregate_id, **kwargs): - """Remove a host from the given aggregate. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#remove-host - """ - post_body = json.dumps({'remove_host': kwargs}) - resp, body = self.post('os-aggregates/%s/action' % aggregate_id, - post_body) - body = json.loads(body) - self.validate_response(schema.aggregate_add_remove_host, resp, body) - return rest_client.ResponseBody(resp, body) - - def set_metadata(self, aggregate_id, **kwargs): - """Replace the aggregate's existing metadata with new metadata. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-or-update-aggregate-metadata - """ - post_body = json.dumps({'set_metadata': kwargs}) - resp, body = self.post('os-aggregates/%s/action' % aggregate_id, - post_body) - body = json.loads(body) - self.validate_response(schema.aggregate_set_metadata, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/availability_zone_client.py b/tempest/lib/services/compute/availability_zone_client.py deleted file mode 100644 index a91119161..000000000 --- a/tempest/lib/services/compute/availability_zone_client.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2013 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import availability_zone \ - as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class AvailabilityZoneClient(base_compute_client.BaseComputeClient): - - def list_availability_zones(self, detail=False): - url = 'os-availability-zone' - schema_list = schema.list_availability_zone_list - if detail: - url += '/detail' - schema_list = schema.list_availability_zone_list_detail - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema_list, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/baremetal_nodes_client.py b/tempest/lib/services/compute/baremetal_nodes_client.py deleted file mode 100644 index e44c19558..000000000 --- a/tempest/lib/services/compute/baremetal_nodes_client.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import baremetal_nodes \ - as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class BaremetalNodesClient(base_compute_client.BaseComputeClient): - """Tests Baremetal API""" - - def list_baremetal_nodes(self, **params): - """List all baremetal nodes. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-bare-metal-nodes - """ - url = 'os-baremetal-nodes' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_baremetal_nodes, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_baremetal_node(self, baremetal_node_id): - """Show the details of a single baremetal node. - - For more information, please refer to the official API reference: - https://developer.openstack.org/api-ref/compute/#show-bare-metal-node-details - """ - url = 'os-baremetal-nodes/%s' % baremetal_node_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_baremetal_node, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/base_compute_client.py b/tempest/lib/services/compute/base_compute_client.py deleted file mode 100644 index a706a79ac..000000000 --- a/tempest/lib/services/compute/base_compute_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.common import api_version_request -from tempest.lib.common import api_version_utils -from tempest.lib.common import rest_client -from tempest.lib import exceptions - -COMPUTE_MICROVERSION = None - - -class BaseComputeClient(rest_client.RestClient): - """Base compute service clients class to support microversion. - - This class adds microversion to API request header if that is set - and provides interface to select appropriate JSON schema file for - response validation. - - :param auth_provider: An auth provider object used to wrap requests in - auth - :param str service: The service name to use for the catalog lookup - :param str region: The region to use for the catalog lookup - :param kwargs: kwargs required by rest_client.RestClient - """ - - api_microversion_header_name = 'X-OpenStack-Nova-API-Version' - - def get_headers(self): - headers = super(BaseComputeClient, self).get_headers() - if COMPUTE_MICROVERSION: - headers[self.api_microversion_header_name] = COMPUTE_MICROVERSION - return headers - - def request(self, method, url, extra_headers=False, headers=None, - body=None, chunked=False): - resp, resp_body = super(BaseComputeClient, self).request( - method, url, extra_headers, headers, body, chunked) - if (COMPUTE_MICROVERSION and - COMPUTE_MICROVERSION != api_version_utils.LATEST_MICROVERSION): - api_version_utils.assert_version_header_matches_request( - self.api_microversion_header_name, - COMPUTE_MICROVERSION, - resp) - return resp, resp_body - - def get_schema(self, schema_versions_info): - """Get JSON schema - - This method provides the matching schema for requested - microversion. - - :param schema_versions_info: List of dict which provides schema - information with range of valid versions. - - Example:: - - schema_versions_info = [ - {'min': None, 'max': '2.1', 'schema': schemav21}, - {'min': '2.2', 'max': '2.9', 'schema': schemav22}, - {'min': '2.10', 'max': None, 'schema': schemav210}] - """ - schema = None - version = api_version_request.APIVersionRequest(COMPUTE_MICROVERSION) - for items in schema_versions_info: - min_version = api_version_request.APIVersionRequest(items['min']) - max_version = api_version_request.APIVersionRequest(items['max']) - # This is case where COMPUTE_MICROVERSION is None, which means - # request without microversion So select base v2.1 schema. - if version.is_null() and items['min'] is None: - schema = items['schema'] - break - # else select appropriate schema as per COMPUTE_MICROVERSION - elif version.matches(min_version, max_version): - schema = items['schema'] - break - if schema is None: - raise exceptions.JSONSchemaNotFound( - version=version.get_string(), - schema_versions_info=schema_versions_info) - return schema diff --git a/tempest/lib/services/compute/certificates_client.py b/tempest/lib/services/compute/certificates_client.py deleted file mode 100644 index 822756c78..000000000 --- a/tempest/lib/services/compute/certificates_client.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2013 IBM Corp -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import certificates as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class CertificatesClient(base_compute_client.BaseComputeClient): - - def show_certificate(self, certificate_id): - url = "os-certificates/%s" % certificate_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_certificate, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_certificate(self): - """Create a certificate.""" - url = "os-certificates" - resp, body = self.post(url, None) - body = json.loads(body) - self.validate_response(schema.create_certificate, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/extensions_client.py b/tempest/lib/services/compute/extensions_client.py deleted file mode 100644 index afaf28286..000000000 --- a/tempest/lib/services/compute/extensions_client.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import extensions as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class ExtensionsClient(base_compute_client.BaseComputeClient): - - def list_extensions(self): - url = 'extensions' - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_extensions, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_extension(self, extension_alias): - resp, body = self.get('extensions/%s' % extension_alias) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/fixed_ips_client.py b/tempest/lib/services/compute/fixed_ips_client.py deleted file mode 100644 index 968646c00..000000000 --- a/tempest/lib/services/compute/fixed_ips_client.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2013 IBM Corp -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import fixed_ips as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class FixedIPsClient(base_compute_client.BaseComputeClient): - - def show_fixed_ip(self, fixed_ip): - url = "os-fixed-ips/%s" % fixed_ip - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_fixed_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def reserve_fixed_ip(self, fixed_ip, **kwargs): - """Reserve/Unreserve a fixed IP. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#reserve-or-release-a-fixed-ip - """ - url = "os-fixed-ips/%s/action" % fixed_ip - resp, body = self.post(url, json.dumps(kwargs)) - self.validate_response(schema.reserve_unreserve_fixed_ip, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/flavors_client.py b/tempest/lib/services/compute/flavors_client.py deleted file mode 100644 index 0fb199151..000000000 --- a/tempest/lib/services/compute/flavors_client.py +++ /dev/null @@ -1,230 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import flavors as schema -from tempest.lib.api_schema.response.compute.v2_1 import flavors_access \ - as schema_access -from tempest.lib.api_schema.response.compute.v2_1 import flavors_extra_specs \ - as schema_extra_specs -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class FlavorsClient(base_compute_client.BaseComputeClient): - - def list_flavors(self, detail=False, **params): - """Lists flavors. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-flavors - https://developer.openstack.org/api-ref/compute/#list-flavors-with-details - """ - url = 'flavors' - _schema = schema.list_flavors - - if detail: - url += '/detail' - _schema = schema.list_flavors_details - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(_schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_flavor(self, flavor_id): - """Shows details for a flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-flavor-details - """ - resp, body = self.get("flavors/%s" % flavor_id) - body = json.loads(body) - self.validate_response(schema.create_get_flavor_details, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_flavor(self, **kwargs): - """Create a new flavor or instance type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-flavor - """ - if 'ephemeral' in kwargs: - kwargs['OS-FLV-EXT-DATA:ephemeral'] = kwargs.pop('ephemeral') - if 'is_public' in kwargs: - kwargs['os-flavor-access:is_public'] = kwargs.pop('is_public') - - post_body = json.dumps({'flavor': kwargs}) - resp, body = self.post('flavors', post_body) - - body = json.loads(body) - self.validate_response(schema.create_get_flavor_details, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_flavor(self, flavor_id): - """Delete the given flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-flavor - """ - resp, body = self.delete("flavors/{0}".format(flavor_id)) - self.validate_response(schema.delete_flavor, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - # Did not use show_flavor(id) for verification as it gives - # 200 ok even for deleted id. LP #981263 - # we can remove the loop here and use get by ID when bug gets sortedout - flavors = self.list_flavors(detail=True)['flavors'] - for flavor in flavors: - if flavor['id'] == id: - return False - return True - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'flavor' - - def set_flavor_extra_spec(self, flavor_id, **kwargs): - """Set extra Specs to the mentioned flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-extra-specs-for-a-flavor - """ - post_body = json.dumps({'extra_specs': kwargs}) - resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id, - post_body) - body = json.loads(body) - self.validate_response(schema_extra_specs.set_get_flavor_extra_specs, - resp, body) - return rest_client.ResponseBody(resp, body) - - def list_flavor_extra_specs(self, flavor_id): - """Get extra Specs details of the mentioned flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-extra-specs-for-a-flavor - """ - resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id) - body = json.loads(body) - self.validate_response(schema_extra_specs.set_get_flavor_extra_specs, - resp, body) - return rest_client.ResponseBody(resp, body) - - def show_flavor_extra_spec(self, flavor_id, key): - """Get extra Specs key-value of the mentioned flavor and key. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-an-extra-spec-for-a-flavor - """ - resp, body = self.get('flavors/%s/os-extra_specs/%s' % (flavor_id, - key)) - body = json.loads(body) - self.validate_response( - schema_extra_specs.set_get_flavor_extra_specs_key, - resp, body) - return rest_client.ResponseBody(resp, body) - - def update_flavor_extra_spec(self, flavor_id, key, **kwargs): - """Update specified extra Specs of the mentioned flavor and key. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-an-extra-spec-for-a-flavor - """ - resp, body = self.put('flavors/%s/os-extra_specs/%s' % - (flavor_id, key), json.dumps(kwargs)) - body = json.loads(body) - self.validate_response( - schema_extra_specs.set_get_flavor_extra_specs_key, - resp, body) - return rest_client.ResponseBody(resp, body) - - def unset_flavor_extra_spec(self, flavor_id, key): # noqa - # NOTE: This noqa is for passing T111 check and we cannot rename - # to keep backwards compatibility. - """Unset extra Specs from the mentioned flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-an-extra-spec-for-a-flavor - """ - resp, body = self.delete('flavors/%s/os-extra_specs/%s' % - (flavor_id, key)) - self.validate_response(schema.unset_flavor_extra_specs, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_flavor_access(self, flavor_id): - """Get flavor access information given the flavor id. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-flavor-access-information-for-given-flavor - """ - resp, body = self.get('flavors/%s/os-flavor-access' % flavor_id) - body = json.loads(body) - self.validate_response(schema_access.add_remove_list_flavor_access, - resp, body) - return rest_client.ResponseBody(resp, body) - - def add_flavor_access(self, flavor_id, tenant_id): - """Add flavor access for the specified tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#add-flavor-access-to-tenant-addtenantaccess-action - """ - post_body = { - 'addTenantAccess': { - 'tenant': tenant_id - } - } - post_body = json.dumps(post_body) - resp, body = self.post('flavors/%s/action' % flavor_id, post_body) - body = json.loads(body) - self.validate_response(schema_access.add_remove_list_flavor_access, - resp, body) - return rest_client.ResponseBody(resp, body) - - def remove_flavor_access(self, flavor_id, tenant_id): - """Remove flavor access from the specified tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#remove-flavor-access-from-tenant-removetenantaccess-action - """ - post_body = { - 'removeTenantAccess': { - 'tenant': tenant_id - } - } - post_body = json.dumps(post_body) - resp, body = self.post('flavors/%s/action' % flavor_id, post_body) - body = json.loads(body) - self.validate_response(schema_access.add_remove_list_flavor_access, - resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/floating_ip_pools_client.py b/tempest/lib/services/compute/floating_ip_pools_client.py deleted file mode 100644 index d3af050be..000000000 --- a/tempest/lib/services/compute/floating_ip_pools_client.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import floating_ips as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class FloatingIPPoolsClient(base_compute_client.BaseComputeClient): - - def list_floating_ip_pools(self, params=None): - """Gets all floating IP Pools list.""" - url = 'os-floating-ip-pools' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_floating_ip_pools, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/floating_ips_bulk_client.py b/tempest/lib/services/compute/floating_ips_bulk_client.py deleted file mode 100644 index 5f06009d6..000000000 --- a/tempest/lib/services/compute/floating_ips_bulk_client.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import floating_ips as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class FloatingIPsBulkClient(base_compute_client.BaseComputeClient): - - def create_floating_ips_bulk(self, ip_range, pool, interface): - """Allocate floating IPs in bulk.""" - post_body = { - 'ip_range': ip_range, - 'pool': pool, - 'interface': interface - } - post_body = json.dumps({'floating_ips_bulk_create': post_body}) - resp, body = self.post('os-floating-ips-bulk', post_body) - body = json.loads(body) - self.validate_response(schema.create_floating_ips_bulk, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_floating_ips_bulk(self): - """Gets all floating IPs in bulk.""" - resp, body = self.get('os-floating-ips-bulk') - body = json.loads(body) - self.validate_response(schema.list_floating_ips_bulk, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_floating_ips_bulk(self, ip_range): - """Deletes the provided floating IPs in bulk.""" - post_body = json.dumps({'ip_range': ip_range}) - resp, body = self.put('os-floating-ips-bulk/delete', post_body) - body = json.loads(body) - self.validate_response(schema.delete_floating_ips_bulk, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/floating_ips_client.py b/tempest/lib/services/compute/floating_ips_client.py deleted file mode 100644 index 5364d971f..000000000 --- a/tempest/lib/services/compute/floating_ips_client.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import floating_ips as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class FloatingIPsClient(base_compute_client.BaseComputeClient): - - def list_floating_ips(self, **params): - """Returns a list of all floating IPs filtered by any parameters. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-floating-ip-addresses - """ - url = 'os-floating-ips' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_floating_ips, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_floating_ip(self, floating_ip_id): - """Get the details of a floating IP. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-floating-ip-address-details - """ - url = "os-floating-ips/%s" % floating_ip_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.create_get_floating_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_floating_ip(self, **kwargs): - """Allocate a floating IP to the project. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-allocate-floating-ip-address - """ - url = 'os-floating-ips' - post_body = json.dumps(kwargs) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.validate_response(schema.create_get_floating_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_floating_ip(self, floating_ip_id): - """Deletes the provided floating IP from the project. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-deallocate-floating-ip-address - """ - url = "os-floating-ips/%s" % floating_ip_id - resp, body = self.delete(url) - self.validate_response(schema.add_remove_floating_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def associate_floating_ip_to_server(self, floating_ip, server_id): - """Associate the provided floating IP to a specific server.""" - url = "servers/%s/action" % server_id - post_body = { - 'addFloatingIp': { - 'address': floating_ip, - } - } - - post_body = json.dumps(post_body) - resp, body = self.post(url, post_body) - self.validate_response(schema.add_remove_floating_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def disassociate_floating_ip_from_server(self, floating_ip, server_id): - """Disassociate the provided floating IP from a specific server.""" - url = "servers/%s/action" % server_id - post_body = { - 'removeFloatingIp': { - 'address': floating_ip, - } - } - - post_body = json.dumps(post_body) - resp, body = self.post(url, post_body) - self.validate_response(schema.add_remove_floating_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_floating_ip(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'floating_ip' diff --git a/tempest/lib/services/compute/hosts_client.py b/tempest/lib/services/compute/hosts_client.py deleted file mode 100644 index 1fdd9075c..000000000 --- a/tempest/lib/services/compute/hosts_client.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import hosts as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class HostsClient(base_compute_client.BaseComputeClient): - - def list_hosts(self, **params): - """List all hosts. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-hosts - """ - - url = 'os-hosts' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_hosts, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_host(self, hostname): - """Show detail information for the host.""" - - resp, body = self.get("os-hosts/%s" % hostname) - body = json.loads(body) - self.validate_response(schema.get_host_detail, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_host(self, hostname, **kwargs): - """Update a host. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-host-status - """ - - request_body = { - 'status': None, - 'maintenance_mode': None, - } - request_body.update(**kwargs) - request_body = json.dumps(request_body) - - resp, body = self.put("os-hosts/%s" % hostname, request_body) - body = json.loads(body) - self.validate_response(schema.update_host, resp, body) - return rest_client.ResponseBody(resp, body) - - def startup_host(self, hostname): # noqa - # NOTE: This noqa is for passing T110 check and we cannot rename - # to keep backwards compatibility. Actually, the root problem - # of this is a wrong API design. GET operation should not change - # resource status, but current API does that. - """Startup a host.""" - - resp, body = self.get("os-hosts/%s/startup" % hostname) - body = json.loads(body) - self.validate_response(schema.startup_host, resp, body) - return rest_client.ResponseBody(resp, body) - - def shutdown_host(self, hostname): # noqa - # NOTE: This noqa is for passing T110 check and we cannot rename - # to keep backwards compatibility. Actually, the root problem - # of this is a wrong API design. GET operation should not change - # resource status, but current API does that. - """Shutdown a host.""" - - resp, body = self.get("os-hosts/%s/shutdown" % hostname) - body = json.loads(body) - self.validate_response(schema.shutdown_host, resp, body) - return rest_client.ResponseBody(resp, body) - - def reboot_host(self, hostname): # noqa - # NOTE: This noqa is for passing T110 check and we cannot rename - # to keep backwards compatibility. Actually, the root problem - # of this is a wrong API design. GET operation should not change - # resource status, but current API does that. - """Reboot a host.""" - - resp, body = self.get("os-hosts/%s/reboot" % hostname) - body = json.loads(body) - self.validate_response(schema.reboot_host, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/hypervisor_client.py b/tempest/lib/services/compute/hypervisor_client.py deleted file mode 100644 index 23c304e83..000000000 --- a/tempest/lib/services/compute/hypervisor_client.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2013 IBM Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import hypervisors as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class HypervisorClient(base_compute_client.BaseComputeClient): - - def list_hypervisors(self, detail=False): - """List hypervisors information.""" - url = 'os-hypervisors' - _schema = schema.list_search_hypervisors - if detail: - url += '/detail' - _schema = schema.list_hypervisors_detail - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(_schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_hypervisor(self, hypervisor_id): - """Display the details of the specified hypervisor.""" - resp, body = self.get('os-hypervisors/%s' % hypervisor_id) - body = json.loads(body) - self.validate_response(schema.get_hypervisor, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_servers_on_hypervisor(self, hypervisor_name): - """List instances belonging to the specified hypervisor.""" - resp, body = self.get('os-hypervisors/%s/servers' % hypervisor_name) - body = json.loads(body) - self.validate_response(schema.get_hypervisors_servers, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_hypervisor_statistics(self): - """Get hypervisor statistics over all compute nodes.""" - resp, body = self.get('os-hypervisors/statistics') - body = json.loads(body) - self.validate_response(schema.get_hypervisor_statistics, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_hypervisor_uptime(self, hypervisor_id): - """Display the uptime of the specified hypervisor.""" - resp, body = self.get('os-hypervisors/%s/uptime' % hypervisor_id) - body = json.loads(body) - self.validate_response(schema.get_hypervisor_uptime, resp, body) - return rest_client.ResponseBody(resp, body) - - def search_hypervisor(self, hypervisor_name): # noqa - # NOTE: This noqa is for passing T110 check and we cannot rename - # to keep backwards compatibility. - """Search specified hypervisor.""" - resp, body = self.get('os-hypervisors/%s/search' % hypervisor_name) - body = json.loads(body) - self.validate_response(schema.list_search_hypervisors, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/images_client.py b/tempest/lib/services/compute/images_client.py deleted file mode 100644 index 86bea9e7f..000000000 --- a/tempest/lib/services/compute/images_client.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import images as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class ImagesClient(base_compute_client.BaseComputeClient): - - def create_image(self, server_id, **kwargs): - """Create an image of the original server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-image-createimage-action - """ - - post_body = {'createImage': kwargs} - post_body = json.dumps(post_body) - resp, body = self.post('servers/%s/action' % server_id, - post_body) - self.validate_response(schema.create_image, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_images(self, detail=False, **params): - """Return a list of all images filtered by any parameter. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-images - https://developer.openstack.org/api-ref/compute/#list-images-with-details - """ - url = 'images' - _schema = schema.list_images - if detail: - url += '/detail' - _schema = schema.list_images_details - - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(_schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_image(self, image_id): - """Return the details of a single image.""" - resp, body = self.get("images/%s" % image_id) - body = json.loads(body) - self.validate_response(schema.get_image, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_image(self, image_id): - """Delete the provided image.""" - resp, body = self.delete("images/%s" % image_id) - self.validate_response(schema.delete, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_image_metadata(self, image_id): - """List all metadata items for an image.""" - resp, body = self.get("images/%s/metadata" % image_id) - body = json.loads(body) - self.validate_response(schema.image_metadata, resp, body) - return rest_client.ResponseBody(resp, body) - - def set_image_metadata(self, image_id, meta): - """Set the metadata for an image. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-image-metadata - """ - post_body = json.dumps({'metadata': meta}) - resp, body = self.put('images/%s/metadata' % image_id, post_body) - body = json.loads(body) - self.validate_response(schema.image_metadata, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_image_metadata(self, image_id, meta): - """Update the metadata for an image. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-image-metadata - """ - post_body = json.dumps({'metadata': meta}) - resp, body = self.post('images/%s/metadata' % image_id, post_body) - body = json.loads(body) - self.validate_response(schema.image_metadata, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_image_metadata_item(self, image_id, key): - """Return the value for a specific image metadata key.""" - resp, body = self.get("images/%s/metadata/%s" % (image_id, key)) - body = json.loads(body) - self.validate_response(schema.image_meta_item, resp, body) - return rest_client.ResponseBody(resp, body) - - def set_image_metadata_item(self, image_id, key, meta): - """Set the value for a specific image metadata key. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-or-update-image-metadata-item - """ - post_body = json.dumps({'meta': meta}) - resp, body = self.put('images/%s/metadata/%s' % (image_id, key), - post_body) - body = json.loads(body) - self.validate_response(schema.image_meta_item, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_image_metadata_item(self, image_id, key): - """Delete a single image metadata key/value pair.""" - resp, body = self.delete("images/%s/metadata/%s" % - (image_id, key)) - self.validate_response(schema.delete, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - # Added status check for user with admin role - try: - if self.show_image(id)['image']['status'] == 'DELETED': - return True - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'image' diff --git a/tempest/lib/services/compute/instance_usage_audit_log_client.py b/tempest/lib/services/compute/instance_usage_audit_log_client.py deleted file mode 100644 index 1b9430683..000000000 --- a/tempest/lib/services/compute/instance_usage_audit_log_client.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2013 IBM Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import \ - instance_usage_audit_logs as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class InstanceUsagesAuditLogClient(base_compute_client.BaseComputeClient): - - def list_instance_usage_audit_logs(self): - url = 'os-instance_usage_audit_log' - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_instance_usage_audit_log, - resp, body) - return rest_client.ResponseBody(resp, body) - - def show_instance_usage_audit_log(self, time_before): - url = 'os-instance_usage_audit_log/%s' % time_before - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_instance_usage_audit_log, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/interfaces_client.py b/tempest/lib/services/compute/interfaces_client.py deleted file mode 100644 index d7c3107d2..000000000 --- a/tempest/lib/services/compute/interfaces_client.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import interfaces as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class InterfacesClient(base_compute_client.BaseComputeClient): - - def list_interfaces(self, server_id): - resp, body = self.get('servers/%s/os-interface' % server_id) - body = json.loads(body) - self.validate_response(schema.list_interfaces, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_interface(self, server_id, **kwargs): - """Create an interface. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-interface - """ - post_body = {'interfaceAttachment': kwargs} - post_body = json.dumps(post_body) - resp, body = self.post('servers/%s/os-interface' % server_id, - body=post_body) - body = json.loads(body) - self.validate_response(schema.get_create_interfaces, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_interface(self, server_id, port_id): - resp, body = self.get('servers/%s/os-interface/%s' % (server_id, - port_id)) - body = json.loads(body) - self.validate_response(schema.get_create_interfaces, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_interface(self, server_id, port_id): - resp, body = self.delete('servers/%s/os-interface/%s' % (server_id, - port_id)) - self.validate_response(schema.delete_interface, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/keypairs_client.py b/tempest/lib/services/compute/keypairs_client.py deleted file mode 100644 index 5215fcadc..000000000 --- a/tempest/lib/services/compute/keypairs_client.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import keypairs as schemav21 -from tempest.lib.api_schema.response.compute.v2_2 import keypairs as schemav22 -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class KeyPairsClient(base_compute_client.BaseComputeClient): - - schema_versions_info = [{'min': None, 'max': '2.1', 'schema': schemav21}, - {'min': '2.2', 'max': None, 'schema': schemav22}] - - def list_keypairs(self, **params): - """Lists keypairs that are associated with the account. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-keypairs - """ - url = 'os-keypairs' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.list_keypairs, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_keypair(self, keypair_name, **params): - """Shows details for a keypair that is associated with the account. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-keypair-details - """ - url = "os-keypairs/%s" % keypair_name - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.get_keypair, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_keypair(self, **kwargs): - """Create a keypair. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-or-import-keypair - """ - post_body = json.dumps({'keypair': kwargs}) - resp, body = self.post("os-keypairs", body=post_body) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.create_keypair, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_keypair(self, keypair_name, **params): - """Deletes a keypair. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-keypair - """ - url = "os-keypairs/%s" % keypair_name - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.delete(url) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.delete_keypair, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/limits_client.py b/tempest/lib/services/compute/limits_client.py deleted file mode 100644 index efe98897e..000000000 --- a/tempest/lib/services/compute/limits_client.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import limits as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class LimitsClient(base_compute_client.BaseComputeClient): - - def show_limits(self): - resp, body = self.get("limits") - body = json.loads(body) - self.validate_response(schema.get_limit, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/migrations_client.py b/tempest/lib/services/compute/migrations_client.py deleted file mode 100644 index 68c8f3f4d..000000000 --- a/tempest/lib/services/compute/migrations_client.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2014 NEC Corporation. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import migrations as schema -from tempest.lib.api_schema.response.compute.v2_23 import migrations \ - as schemav223 -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class MigrationsClient(base_compute_client.BaseComputeClient): - schema_versions_info = [ - {'min': None, 'max': '2.22', 'schema': schema}, - {'min': '2.23', 'max': None, 'schema': schemav223}] - - def list_migrations(self, **params): - """List all migrations. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-migrations - """ - - url = 'os-migrations' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.list_migrations, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/networks_client.py b/tempest/lib/services/compute/networks_client.py deleted file mode 100644 index 6c8c943e4..000000000 --- a/tempest/lib/services/compute/networks_client.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class NetworksClient(base_compute_client.BaseComputeClient): - - def list_networks(self): - resp, body = self.get("os-networks") - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_network(self, network_id): - resp, body = self.get("os-networks/%s" % network_id) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/quota_classes_client.py b/tempest/lib/services/compute/quota_classes_client.py deleted file mode 100644 index 0fe9868f3..000000000 --- a/tempest/lib/services/compute/quota_classes_client.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2012 NTT Data -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1\ - import quota_classes as classes_schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class QuotaClassesClient(base_compute_client.BaseComputeClient): - - def show_quota_class_set(self, quota_class_id): - """List the quota class set for a quota class.""" - - url = 'os-quota-class-sets/%s' % quota_class_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(classes_schema.get_quota_class_set, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_quota_class_set(self, quota_class_id, **kwargs): - """Update the quota class's limits for one or more resources. - - # NOTE: Current api-site doesn't contain this API description. - # LP: https://bugs.launchpad.net/nova/+bug/1602400 - """ - post_body = json.dumps({'quota_class_set': kwargs}) - - resp, body = self.put('os-quota-class-sets/%s' % quota_class_id, - post_body) - - body = json.loads(body) - self.validate_response(classes_schema.update_quota_class_set, - resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/quotas_client.py b/tempest/lib/services/compute/quotas_client.py deleted file mode 100644 index daf4bc09c..000000000 --- a/tempest/lib/services/compute/quotas_client.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2012 NTT Data -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import quotas as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class QuotasClient(base_compute_client.BaseComputeClient): - - def show_quota_set(self, tenant_id, user_id=None, detail=False): - """List the quota set for a tenant. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref-compute-v2.1.html/#show-a-quota - http://developer.openstack.org/api-ref-compute-v2.1.html/#show-the-detail-of-quota - """ - - params = {} - url = 'os-quota-sets/%s' % tenant_id - if detail: - url += '/detail' - if user_id: - params.update({'user_id': user_id}) - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - if detail: - self.validate_response(schema.get_quota_set_details, resp, body) - else: - self.validate_response(schema.get_quota_set, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_default_quota_set(self, tenant_id): - """List the default quota set for a tenant.""" - - url = 'os-quota-sets/%s/defaults' % tenant_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_quota_set, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_quota_set(self, tenant_id, user_id=None, **kwargs): - """Updates the tenant's quota limits for one or more resources. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-quotas - """ - - post_body = json.dumps({'quota_set': kwargs}) - - if user_id: - resp, body = self.put('os-quota-sets/%s?user_id=%s' % - (tenant_id, user_id), post_body) - else: - resp, body = self.put('os-quota-sets/%s' % tenant_id, - post_body) - - body = json.loads(body) - self.validate_response(schema.update_quota_set, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_quota_set(self, tenant_id): - """Delete the tenant's quota set.""" - resp, body = self.delete('os-quota-sets/%s' % tenant_id) - self.validate_response(schema.delete_quota, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/security_group_default_rules_client.py b/tempest/lib/services/compute/security_group_default_rules_client.py deleted file mode 100644 index 70cab88e6..000000000 --- a/tempest/lib/services/compute/security_group_default_rules_client.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2014 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import \ - security_group_default_rule as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class SecurityGroupDefaultRulesClient(base_compute_client.BaseComputeClient): - - def create_security_default_group_rule(self, **kwargs): - """Create security group default rule. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-default-security-group-rule - """ - post_body = json.dumps({'security_group_default_rule': kwargs}) - url = 'os-security-group-default-rules' - resp, body = self.post(url, post_body) - body = json.loads(body) - self.validate_response(schema.create_get_security_group_default_rule, - resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_security_group_default_rule(self, - security_group_default_rule_id): - """Delete the provided Security Group default rule.""" - resp, body = self.delete('os-security-group-default-rules/%s' % ( - security_group_default_rule_id)) - self.validate_response(schema.delete_security_group_default_rule, - resp, body) - return rest_client.ResponseBody(resp, body) - - def list_security_group_default_rules(self): - """List all Security Group default rules.""" - resp, body = self.get('os-security-group-default-rules') - body = json.loads(body) - self.validate_response(schema.list_security_group_default_rules, - resp, body) - return rest_client.ResponseBody(resp, body) - - def show_security_group_default_rule(self, security_group_default_rule_id): - """Return the details of provided Security Group default rule.""" - resp, body = self.get('os-security-group-default-rules/%s' % - security_group_default_rule_id) - body = json.loads(body) - self.validate_response(schema.create_get_security_group_default_rule, - resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/security_group_rules_client.py b/tempest/lib/services/compute/security_group_rules_client.py deleted file mode 100644 index 710bfab4e..000000000 --- a/tempest/lib/services/compute/security_group_rules_client.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import \ - security_groups as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class SecurityGroupRulesClient(base_compute_client.BaseComputeClient): - - def create_security_group_rule(self, **kwargs): - """Create a new security group rule. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-security-group-rule - """ - post_body = json.dumps({'security_group_rule': kwargs}) - url = 'os-security-group-rules' - resp, body = self.post(url, post_body) - body = json.loads(body) - self.validate_response(schema.create_security_group_rule, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_security_group_rule(self, group_rule_id): - """Deletes the provided Security Group rule.""" - resp, body = self.delete('os-security-group-rules/%s' % - group_rule_id) - self.validate_response(schema.delete_security_group_rule, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/security_groups_client.py b/tempest/lib/services/compute/security_groups_client.py deleted file mode 100644 index b525f6861..000000000 --- a/tempest/lib/services/compute/security_groups_client.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import \ - security_groups as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class SecurityGroupsClient(base_compute_client.BaseComputeClient): - - def list_security_groups(self, **params): - """List all security groups for a user. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-security-groups - """ - - url = 'os-security-groups' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_security_groups, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_security_group(self, security_group_id): - """Get the details of a Security Group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-security-group-details - """ - url = "os-security-groups/%s" % security_group_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_security_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_security_group(self, **kwargs): - """Create a new security group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-security-group - """ - post_body = json.dumps({'security_group': kwargs}) - resp, body = self.post('os-security-groups', post_body) - body = json.loads(body) - self.validate_response(schema.get_security_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_security_group(self, security_group_id, **kwargs): - """Update a security group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-security-group - """ - post_body = json.dumps({'security_group': kwargs}) - resp, body = self.put('os-security-groups/%s' % security_group_id, - post_body) - body = json.loads(body) - self.validate_response(schema.update_security_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_security_group(self, security_group_id): - """Delete the provided Security Group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-security-group - """ - resp, body = self.delete( - 'os-security-groups/%s' % security_group_id) - self.validate_response(schema.delete_security_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_security_group(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'security_group' diff --git a/tempest/lib/services/compute/server_groups_client.py b/tempest/lib/services/compute/server_groups_client.py deleted file mode 100644 index 03cd645cd..000000000 --- a/tempest/lib/services/compute/server_groups_client.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import servers as schema -from tempest.lib.api_schema.response.compute.v2_13 import servers as schemav213 -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class ServerGroupsClient(base_compute_client.BaseComputeClient): - - schema_versions_info = [ - {'min': None, 'max': '2.12', 'schema': schema}, - {'min': '2.13', 'max': None, 'schema': schemav213}] - - def create_server_group(self, **kwargs): - """Create the server group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-server-group - """ - post_body = json.dumps({'server_group': kwargs}) - resp, body = self.post('os-server-groups', post_body) - - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.create_show_server_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_server_group(self, server_group_id): - """Delete the given server-group.""" - resp, body = self.delete("os-server-groups/%s" % server_group_id) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.delete_server_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_server_groups(self): - """List the server-groups.""" - resp, body = self.get("os-server-groups") - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.list_server_groups, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_server_group(self, server_group_id): - """Get the details of given server_group.""" - resp, body = self.get("os-server-groups/%s" % server_group_id) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.create_show_server_group, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py deleted file mode 100644 index 598d5a63e..000000000 --- a/tempest/lib/services/compute/servers_client.py +++ /dev/null @@ -1,864 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# Copyright 2017 AT&T Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import \ - security_groups as security_groups_schema -from tempest.lib.api_schema.response.compute.v2_1 import servers as schema -from tempest.lib.api_schema.response.compute.v2_16 import servers as schemav216 -from tempest.lib.api_schema.response.compute.v2_19 import servers as schemav219 -from tempest.lib.api_schema.response.compute.v2_26 import servers as schemav226 -from tempest.lib.api_schema.response.compute.v2_3 import servers as schemav23 -from tempest.lib.api_schema.response.compute.v2_47 import servers as schemav247 -from tempest.lib.api_schema.response.compute.v2_48 import servers as schemav248 -from tempest.lib.api_schema.response.compute.v2_6 import servers as schemav26 -from tempest.lib.api_schema.response.compute.v2_9 import servers as schemav29 -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class ServersClient(base_compute_client.BaseComputeClient): - """Service client for the resource /servers""" - - schema_versions_info = [ - {'min': None, 'max': '2.2', 'schema': schema}, - {'min': '2.3', 'max': '2.5', 'schema': schemav23}, - {'min': '2.6', 'max': '2.8', 'schema': schemav26}, - {'min': '2.9', 'max': '2.15', 'schema': schemav29}, - {'min': '2.16', 'max': '2.18', 'schema': schemav216}, - {'min': '2.19', 'max': '2.25', 'schema': schemav219}, - {'min': '2.26', 'max': '2.46', 'schema': schemav226}, - {'min': '2.47', 'max': '2.47', 'schema': schemav247}, - {'min': '2.48', 'max': None, 'schema': schemav248}] - - def __init__(self, auth_provider, service, region, - enable_instance_password=True, **kwargs): - super(ServersClient, self).__init__( - auth_provider, service, region, **kwargs) - self.enable_instance_password = enable_instance_password - - def create_server(self, **kwargs): - """Create server. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/compute/#create-server - - :param name: Server name - :param imageRef: Image reference (UUID) - :param flavorRef: Flavor reference (UUID or full URL) - - Most parameters except the following are passed to the API without - any changes. - :param disk_config: The name is changed to OS-DCF:diskConfig - :param scheduler_hints: The name is changed to os:scheduler_hints and - the parameter is set in the same level as the parameter 'server'. - """ - body = copy.deepcopy(kwargs) - if body.get('disk_config'): - body['OS-DCF:diskConfig'] = body.pop('disk_config') - - hints = None - if body.get('scheduler_hints'): - hints = {'os:scheduler_hints': body.pop('scheduler_hints')} - - post_body = {'server': body} - - if hints: - post_body.update(hints) - - post_body = json.dumps(post_body) - resp, body = self.post('servers', post_body) - - body = json.loads(body) - # NOTE(maurosr): this deals with the case of multiple server create - # with return reservation id set True - if 'reservation_id' in body: - return rest_client.ResponseBody(resp, body) - if self.enable_instance_password: - create_schema = schema.create_server_with_admin_pass - else: - create_schema = schema.create_server - self.validate_response(create_schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_server(self, server_id, **kwargs): - """Update server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-server - - Most parameters except the following are passed to the API without - any changes. - :param disk_config: The name is changed to OS-DCF:diskConfig - """ - if 'disk_config' in kwargs: - kwargs['OS-DCF:diskConfig'] = kwargs.pop('disk_config') - - post_body = json.dumps({'server': kwargs}) - resp, body = self.put("servers/%s" % server_id, post_body) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.update_server, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_server(self, server_id): - """Get server details. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref-compute-v2.1.html#showServer - """ - resp, body = self.get("servers/%s" % server_id) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.get_server, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_server(self, server_id): - """Delete server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-server - """ - resp, body = self.delete("servers/%s" % server_id) - self.validate_response(schema.delete_server, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_servers(self, detail=False, **params): - """List servers. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-servers - https://developer.openstack.org/api-ref/compute/#list-servers-detailed - """ - - url = 'servers' - schema = self.get_schema(self.schema_versions_info) - _schema = schema.list_servers - - if detail: - url += '/detail' - _schema = schema.list_servers_detail - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(_schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_addresses(self, server_id): - """Lists all addresses for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-ips - """ - resp, body = self.get("servers/%s/ips" % server_id) - body = json.loads(body) - self.validate_response(schema.list_addresses, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_addresses_by_network(self, server_id, network_id): - """Lists all addresses of a specific network type for a server.""" - resp, body = self.get("servers/%s/ips/%s" % - (server_id, network_id)) - body = json.loads(body) - self.validate_response(schema.list_addresses_by_network, resp, body) - return rest_client.ResponseBody(resp, body) - - def action(self, server_id, action_name, - schema=schema.server_actions_common_schema, - **kwargs): - post_body = json.dumps({action_name: kwargs}) - resp, body = self.post('servers/%s/action' % server_id, - post_body) - if body: - body = json.loads(body) - self.validate_response(schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_backup(self, server_id, **kwargs): - """Backup a server instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-server-back-up-createbackup-action - """ - return self.action(server_id, "createBackup", **kwargs) - - def change_password(self, server_id, **kwargs): - """Change the root password for the server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#change-administrative-password-changepassword-action - """ - return self.action(server_id, 'changePassword', **kwargs) - - def show_password(self, server_id): - resp, body = self.get("servers/%s/os-server-password" % - server_id) - body = json.loads(body) - self.validate_response(schema.show_password, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_password(self, server_id): - """Removes the encrypted server password from the metadata server - - Note that this does not actually change the instance server - password. - """ - resp, body = self.delete("servers/%s/os-server-password" % - server_id) - self.validate_response(schema.server_actions_delete_password, - resp, body) - return rest_client.ResponseBody(resp, body) - - def reboot_server(self, server_id, **kwargs): - """Reboot a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#reboot-server-reboot-action - """ - return self.action(server_id, 'reboot', **kwargs) - - def rebuild_server(self, server_id, image_ref, **kwargs): - """Rebuild a server with a new image. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#rebuild-server-rebuild-action - - Most parameters except the following are passed to the API without - any changes. - :param disk_config: The name is changed to OS-DCF:diskConfig - """ - kwargs['imageRef'] = image_ref - if 'disk_config' in kwargs: - kwargs['OS-DCF:diskConfig'] = kwargs.pop('disk_config') - schema = self.get_schema(self.schema_versions_info) - if self.enable_instance_password: - rebuild_schema = schema.rebuild_server_with_admin_pass - else: - rebuild_schema = schema.rebuild_server - return self.action(server_id, 'rebuild', - rebuild_schema, **kwargs) - - def resize_server(self, server_id, flavor_ref, **kwargs): - """Change the flavor of a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#resize-server-resize-action - - Most parameters except the following are passed to the API without - any changes. - :param disk_config: The name is changed to OS-DCF:diskConfig - """ - kwargs['flavorRef'] = flavor_ref - if 'disk_config' in kwargs: - kwargs['OS-DCF:diskConfig'] = kwargs.pop('disk_config') - return self.action(server_id, 'resize', **kwargs) - - def confirm_resize_server(self, server_id, **kwargs): - """Confirm the flavor change for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#confirm-resized-server-confirmresize-action - """ - return self.action(server_id, 'confirmResize', - schema.server_actions_confirm_resize, - **kwargs) - - def revert_resize_server(self, server_id, **kwargs): - """Revert a server back to its original flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#revert-resized-server-revertresize-action - """ - return self.action(server_id, 'revertResize', **kwargs) - - def list_server_metadata(self, server_id): - """Lists all metadata for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-all-metadata - """ - resp, body = self.get("servers/%s/metadata" % server_id) - body = json.loads(body) - self.validate_response(schema.list_server_metadata, resp, body) - return rest_client.ResponseBody(resp, body) - - def set_server_metadata(self, server_id, meta, no_metadata_field=False): - """Sets one or more metadata items for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-or-replace-metadata-items - """ - if no_metadata_field: - post_body = "" - else: - post_body = json.dumps({'metadata': meta}) - resp, body = self.put('servers/%s/metadata' % server_id, - post_body) - body = json.loads(body) - self.validate_response(schema.set_server_metadata, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_server_metadata(self, server_id, meta): - """Updates one or more metadata items for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-metadata-items - """ - post_body = json.dumps({'metadata': meta}) - resp, body = self.post('servers/%s/metadata' % server_id, - post_body) - body = json.loads(body) - self.validate_response(schema.update_server_metadata, - resp, body) - return rest_client.ResponseBody(resp, body) - - def show_server_metadata_item(self, server_id, key): - """Shows details for a metadata item, by key, for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-metadata-item-details - """ - resp, body = self.get("servers/%s/metadata/%s" % (server_id, key)) - body = json.loads(body) - self.validate_response(schema.set_show_server_metadata_item, - resp, body) - return rest_client.ResponseBody(resp, body) - - def set_server_metadata_item(self, server_id, key, meta): - """Sets a metadata item, by key, for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-or-update-metadata-item - """ - post_body = json.dumps({'meta': meta}) - resp, body = self.put('servers/%s/metadata/%s' % (server_id, key), - post_body) - body = json.loads(body) - self.validate_response(schema.set_show_server_metadata_item, - resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_server_metadata_item(self, server_id, key): - """Deletes a metadata item, by key, from a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-metadata-item - """ - resp, body = self.delete("servers/%s/metadata/%s" % - (server_id, key)) - self.validate_response(schema.delete_server_metadata_item, - resp, body) - return rest_client.ResponseBody(resp, body) - - def stop_server(self, server_id, **kwargs): - """Stops a running server and changes its status to SHUTOFF. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#stop-server-os-stop-action - """ - return self.action(server_id, 'os-stop', **kwargs) - - def start_server(self, server_id, **kwargs): - """Starts a stopped server and changes its status to ACTIVE. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#start-server-os-start-action - """ - return self.action(server_id, 'os-start', **kwargs) - - def attach_volume(self, server_id, **kwargs): - """Attaches a volume to a server instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#attach-a-volume-to-an-instance - """ - post_body = json.dumps({'volumeAttachment': kwargs}) - resp, body = self.post('servers/%s/os-volume_attachments' % server_id, - post_body) - body = json.loads(body) - self.validate_response(schema.attach_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_attached_volume(self, server_id, attachment_id, **kwargs): - """Swaps a volume attached to an instance for another volume""" - post_body = json.dumps({'volumeAttachment': kwargs}) - resp, body = self.put('servers/%s/os-volume_attachments/%s' % - (server_id, attachment_id), - post_body) - self.validate_response(schema.update_attached_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def detach_volume(self, server_id, volume_id): # noqa - """Detaches a volume from a server instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#detach-a-volume-from-an-instance - """ - resp, body = self.delete('servers/%s/os-volume_attachments/%s' % - (server_id, volume_id)) - self.validate_response(schema.detach_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_volume_attachment(self, server_id, volume_id): - """Return details about the given volume attachment. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-a-detail-of-a-volume-attachment - """ - resp, body = self.get('servers/%s/os-volume_attachments/%s' % ( - server_id, volume_id)) - body = json.loads(body) - self.validate_response(schema.show_volume_attachment, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_volume_attachments(self, server_id): - """Returns the list of volume attachments for a given instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-volume-attachments-for-an-instance - """ - resp, body = self.get('servers/%s/os-volume_attachments' % ( - server_id)) - body = json.loads(body) - self.validate_response(schema.list_volume_attachments, resp, body) - return rest_client.ResponseBody(resp, body) - - def add_security_group(self, server_id, **kwargs): - """Add a security group to the server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#add-security-group-to-a-server-addsecuritygroup-action - """ - return self.action(server_id, 'addSecurityGroup', **kwargs) - - def remove_security_group(self, server_id, **kwargs): - """Remove a security group from the server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#remove-security-group-from-a-server-removesecuritygroup-action - """ - return self.action(server_id, 'removeSecurityGroup', **kwargs) - - def live_migrate_server(self, server_id, **kwargs): - """This should be called with administrator privileges. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#live-migrate-server-os-migratelive-action - """ - return self.action(server_id, 'os-migrateLive', **kwargs) - - def migrate_server(self, server_id, **kwargs): - """Migrate a server to a new host. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#migrate-server-migrate-action - """ - return self.action(server_id, 'migrate', **kwargs) - - def lock_server(self, server_id, **kwargs): - """Lock the given server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#lock-server-lock-action - """ - return self.action(server_id, 'lock', **kwargs) - - def unlock_server(self, server_id, **kwargs): - """UNlock the given server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#unlock-server-unlock-action - """ - return self.action(server_id, 'unlock', **kwargs) - - def suspend_server(self, server_id, **kwargs): - """Suspend the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#suspend-server-suspend-action - """ - return self.action(server_id, 'suspend', **kwargs) - - def resume_server(self, server_id, **kwargs): - """Un-suspend the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#resume-suspended-server-resume-action - """ - return self.action(server_id, 'resume', **kwargs) - - def pause_server(self, server_id, **kwargs): - """Pause the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#pause-server-pause-action - """ - return self.action(server_id, 'pause', **kwargs) - - def unpause_server(self, server_id, **kwargs): - """Un-pause the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#unpause-server-unpause-action - """ - return self.action(server_id, 'unpause', **kwargs) - - def reset_state(self, server_id, **kwargs): - """Reset the state of a server to active/error. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#reset-server-state-os-resetstate-action - """ - return self.action(server_id, 'os-resetState', **kwargs) - - def shelve_server(self, server_id, **kwargs): - """Shelve the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#shelve-server-shelve-action - """ - return self.action(server_id, 'shelve', **kwargs) - - def unshelve_server(self, server_id, **kwargs): - """Un-shelve the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#unshelve-restore-shelved-server-unshelve-action - """ - return self.action(server_id, 'unshelve', **kwargs) - - def shelve_offload_server(self, server_id, **kwargs): - """Shelve-offload the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#shelf-offload-remove-server-shelveoffload-action - """ - return self.action(server_id, 'shelveOffload', **kwargs) - - def get_console_output(self, server_id, **kwargs): - """Get console output. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-console-output-os-getconsoleoutput-action - """ - return self.action(server_id, 'os-getConsoleOutput', - schema.get_console_output, **kwargs) - - def get_remote_console(self, server_id, console_type, protocol, **kwargs): - """Get a remote console. - - For a full list of available parameters, please refer to the official - API reference: - TODO (markus_z) The api-ref for that isn't yet available, update this - here when the docs in Nova are updated. The old API is at - http://developer.openstack.org/api-ref/compute/#get-serial-console-os-getserialconsole-action - """ - param = { - 'remote_console': { - 'type': console_type, - 'protocol': protocol, - } - } - post_body = json.dumps(param) - resp, body = self.post("servers/%s/remote-consoles" % server_id, - post_body) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.get_remote_consoles, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_virtual_interfaces(self, server_id): - """List the virtual interfaces used in an instance.""" - resp, body = self.get('/'.join(['servers', server_id, - 'os-virtual-interfaces'])) - body = json.loads(body) - self.validate_response(schema.list_virtual_interfaces, resp, body) - return rest_client.ResponseBody(resp, body) - - def rescue_server(self, server_id, **kwargs): - """Rescue the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#rescue-server-rescue-action - """ - if self.enable_instance_password: - rescue_schema = schema.rescue_server_with_admin_pass - else: - rescue_schema = schema.rescue_server - return self.action(server_id, 'rescue', rescue_schema, **kwargs) - - def unrescue_server(self, server_id): - """Unrescue the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#unrescue-server-unrescue-action - """ - return self.action(server_id, 'unrescue') - - def show_server_diagnostics(self, server_id): - """Get the usage data for a server.""" - resp, body = self.get("servers/%s/diagnostics" % server_id) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.show_server_diagnostics, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_instance_actions(self, server_id): - """List the provided server action.""" - resp, body = self.get("servers/%s/os-instance-actions" % - server_id) - body = json.loads(body) - self.validate_response(schema.list_instance_actions, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_instance_action(self, server_id, request_id): - """Returns the action details of the provided server.""" - resp, body = self.get("servers/%s/os-instance-actions/%s" % - (server_id, request_id)) - body = json.loads(body) - self.validate_response(schema.show_instance_action, resp, body) - return rest_client.ResponseBody(resp, body) - - def force_delete_server(self, server_id, **kwargs): - """Force delete a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#force-delete-server-forcedelete-action - """ - return self.action(server_id, 'forceDelete', **kwargs) - - def restore_soft_deleted_server(self, server_id, **kwargs): - """Restore a soft-deleted server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#restore-soft-deleted-instance-restore-action - """ - return self.action(server_id, 'restore', **kwargs) - - def reset_network(self, server_id, **kwargs): - """Reset the Network of a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#reset-networking-on-a-server-resetnetwork-action - """ - return self.action(server_id, 'resetNetwork', **kwargs) - - def inject_network_info(self, server_id, **kwargs): - """Inject the Network Info into server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#inject-network-information-injectnetworkinfo-action - """ - return self.action(server_id, 'injectNetworkInfo', **kwargs) - - def get_vnc_console(self, server_id, **kwargs): - """Get URL of VNC console. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#get-vnc-console-os-getvncconsole-action - """ - return self.action(server_id, "os-getVNCConsole", - schema.get_vnc_console, **kwargs) - - def add_fixed_ip(self, server_id, **kwargs): - """Add a fixed IP to server instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#add-associate-fixed-ip-addfixedip-action - """ - return self.action(server_id, 'addFixedIp', **kwargs) - - def remove_fixed_ip(self, server_id, **kwargs): - """Remove input fixed IP from input server instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#remove-disassociate-fixed-ip-removefixedip-action - """ - return self.action(server_id, 'removeFixedIp', **kwargs) - - def list_security_groups_by_server(self, server_id): - """Lists security groups for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-security-groups-by-server - """ - resp, body = self.get("servers/%s/os-security-groups" % server_id) - body = json.loads(body) - self.validate_response(security_groups_schema.list_security_groups, - resp, body) - return rest_client.ResponseBody(resp, body) - - def list_tags(self, server_id): - """Lists all tags for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-tags - """ - url = 'servers/%s/tags' % server_id - resp, body = self.get(url) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.list_tags, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_all_tags(self, server_id, tags): - """Replaces all tags on specified server with the new set of tags. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#replace-tags - - :param tags: List of tags to replace current server tags with. - """ - url = 'servers/%s/tags' % server_id - put_body = {'tags': tags} - resp, body = self.put(url, json.dumps(put_body)) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.update_all_tags, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_all_tags(self, server_id): - """Deletes all tags from the specified server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-all-tags - """ - url = 'servers/%s/tags' % server_id - resp, body = self.delete(url) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.delete_all_tags, resp, body) - return rest_client.ResponseBody(resp, body) - - def check_tag_existence(self, server_id, tag): - """Checks tag existence on the server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#check-tag-existence - - :param tag: Check for existence of tag on specified server. - """ - url = 'servers/%s/tags/%s' % (server_id, tag) - resp, body = self.get(url) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.check_tag_existence, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_tag(self, server_id, tag): - """Adds a single tag to the server if server has no specified tag. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#add-a-single-tag - - :param tag: Tag to be added to the specified server. - """ - url = 'servers/%s/tags/%s' % (server_id, tag) - resp, body = self.put(url, None) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.update_tag, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_tag(self, server_id, tag): - """Deletes a single tag from the specified server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-a-single-tag - - :param tag: Tag to be removed from the specified server. - """ - url = 'servers/%s/tags/%s' % (server_id, tag) - resp, body = self.delete(url) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.delete_tag, resp, body) - return rest_client.ResponseBody(resp, body) - - def evacuate_server(self, server_id, **kwargs): - """Evacuate the given server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#evacuate-server-evacuate-action - """ - if self.enable_instance_password: - evacuate_schema = schema.evacuate_server_with_admin_pass - else: - evacuate_schema = schema.evacuate_server - - return self.action(server_id, 'evacuate', - evacuate_schema, - **kwargs) diff --git a/tempest/lib/services/compute/services_client.py b/tempest/lib/services/compute/services_client.py deleted file mode 100644 index 857c435a6..000000000 --- a/tempest/lib/services/compute/services_client.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2013 NEC Corporation -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import services as schema -from tempest.lib.api_schema.response.compute.v2_11 import services \ - as schemav211 -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class ServicesClient(base_compute_client.BaseComputeClient): - - schema_versions_info = [ - {'min': None, 'max': '2.10', 'schema': schema}, - {'min': '2.11', 'max': None, 'schema': schemav211}] - - def list_services(self, **params): - """Lists all running Compute services for a tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-compute-services - """ - url = 'os-services' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - _schema = self.get_schema(self.schema_versions_info) - self.validate_response(_schema.list_services, resp, body) - return rest_client.ResponseBody(resp, body) - - def enable_service(self, **kwargs): - """Enable service on a host. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#enable-scheduling-for-a-compute-service - """ - post_body = json.dumps(kwargs) - resp, body = self.put('os-services/enable', post_body) - body = json.loads(body) - self.validate_response(schema.enable_disable_service, resp, body) - return rest_client.ResponseBody(resp, body) - - def disable_service(self, **kwargs): - """Disable service on a host. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#disable-scheduling-for-a-compute-service - """ - post_body = json.dumps(kwargs) - resp, body = self.put('os-services/disable', post_body) - body = json.loads(body) - self.validate_response(schema.enable_disable_service, resp, body) - return rest_client.ResponseBody(resp, body) - - def disable_log_reason(self, **kwargs): - """Disables scheduling for a Compute service and logs reason. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#log-disabled-compute-service-information - """ - post_body = json.dumps(kwargs) - resp, body = self.put('os-services/disable-log-reason', post_body) - body = json.loads(body) - self.validate_response(schema.disable_log_reason, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_forced_down(self, **kwargs): - """Set or unset ``forced_down`` flag for the service. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-forced-down - """ - post_body = json.dumps(kwargs) - resp, body = self.put('os-services/force-down', post_body) - body = json.loads(body) - # NOTE: Use schemav211.update_forced_down directly because there is no - # update_forced_down schema for <2.11. - self.validate_response(schemav211.update_forced_down, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/snapshots_client.py b/tempest/lib/services/compute/snapshots_client.py deleted file mode 100644 index df8d6fbd3..000000000 --- a/tempest/lib/services/compute/snapshots_client.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2015 Fujitsu(fnst) Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import snapshots as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class SnapshotsClient(base_compute_client.BaseComputeClient): - - def create_snapshot(self, volume_id, **kwargs): - """Create a snapshot. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-snapshot - """ - post_body = { - 'volume_id': volume_id - } - post_body.update(kwargs) - post_body = json.dumps({'snapshot': post_body}) - resp, body = self.post('os-snapshots', post_body) - body = json.loads(body) - self.validate_response(schema.create_get_snapshot, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_snapshot(self, snapshot_id): - url = "os-snapshots/%s" % snapshot_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.create_get_snapshot, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_snapshots(self, detail=False, params=None): - """List snapshots. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-snapshots - """ - url = 'os-snapshots' - - if detail: - url += '/detail' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_snapshots, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_snapshot(self, snapshot_id): - resp, body = self.delete("os-snapshots/%s" % snapshot_id) - self.validate_response(schema.delete_snapshot, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_snapshot(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'snapshot' diff --git a/tempest/lib/services/compute/tenant_networks_client.py b/tempest/lib/services/compute/tenant_networks_client.py deleted file mode 100644 index 04d8babae..000000000 --- a/tempest/lib/services/compute/tenant_networks_client.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import tenant_networks -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class TenantNetworksClient(base_compute_client.BaseComputeClient): - - def list_tenant_networks(self): - resp, body = self.get("os-tenant-networks") - body = json.loads(body) - self.validate_response(tenant_networks.list_tenant_networks, resp, - body) - return rest_client.ResponseBody(resp, body) - - def show_tenant_network(self, network_id): - resp, body = self.get("os-tenant-networks/%s" % network_id) - body = json.loads(body) - self.validate_response(tenant_networks.get_tenant_network, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/tenant_usages_client.py b/tempest/lib/services/compute/tenant_usages_client.py deleted file mode 100644 index ade60e541..000000000 --- a/tempest/lib/services/compute/tenant_usages_client.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import tenant_usages -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class TenantUsagesClient(base_compute_client.BaseComputeClient): - - def list_tenant_usages(self, **params): - """List Tenant Usage For All Tenants. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-tenant-usage-statistics-for-all-tenants - """ - url = 'os-simple-tenant-usage' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(tenant_usages.list_tenant_usage, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_tenant_usage(self, tenant_id, **params): - """Show Usage Details For Tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-usage-statistics-for-tenant - """ - url = 'os-simple-tenant-usage/%s' % tenant_id - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(tenant_usages.get_tenant_usage, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/versions_client.py b/tempest/lib/services/compute/versions_client.py deleted file mode 100644 index 8fbb136fc..000000000 --- a/tempest/lib/services/compute/versions_client.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import versions as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class VersionsClient(base_compute_client.BaseComputeClient): - - def list_versions(self): - version_url = self._get_base_version_url() - - start = time.time() - resp, body = self.raw_request(version_url, 'GET') - end = time.time() - self._log_request('GET', version_url, resp, secs=(end - start), - resp_body=body) - - self._error_checker(resp, body) - body = json.loads(body) - self.validate_response(schema.list_versions, resp, body) - return rest_client.ResponseBody(resp, body) - - def get_version_by_url(self, version_url): - """Get the version document by url. - - This gets the version document for a url, useful in testing - the contents of things like /v2/ or /v2.1/ in Nova. That - controller needs authenticated access, so we have to get - ourselves a token before making the request. - - """ - # we need a token for this request - resp, body = self.raw_request(version_url, 'GET', - {'X-Auth-Token': self.token}) - self._error_checker(resp, body) - body = json.loads(body) - self.validate_response(schema.get_one_version, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/volumes_client.py b/tempest/lib/services/compute/volumes_client.py deleted file mode 100644 index 95cdd5379..000000000 --- a/tempest/lib/services/compute/volumes_client.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import volumes as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class VolumesClient(base_compute_client.BaseComputeClient): - - def list_volumes(self, detail=False, **params): - """List all the volumes created. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-volumes - https://developer.openstack.org/api-ref/compute/#list-volumes-with-details - """ - url = 'os-volumes' - - if detail: - url += '/detail' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_volumes, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_volume(self, volume_id): - """Return the details of a single volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-volume-details - """ - url = "os-volumes/%s" % volume_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.create_get_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_volume(self, **kwargs): - """Create a new Volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-volume - """ - post_body = json.dumps({'volume': kwargs}) - resp, body = self.post('os-volumes', post_body) - body = json.loads(body) - self.validate_response(schema.create_get_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_volume(self, volume_id): - """Delete the Specified Volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-volume - """ - resp, body = self.delete("os-volumes/%s" % volume_id) - self.validate_response(schema.delete_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_volume(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'volume' diff --git a/tempest/lib/services/identity/__init__.py b/tempest/lib/services/identity/__init__.py deleted file mode 100644 index 941a10e7d..000000000 --- a/tempest/lib/services/identity/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.identity import v2 -from tempest.lib.services.identity import v3 - -__all__ = ['v2', 'v3'] diff --git a/tempest/lib/services/identity/v2/__init__.py b/tempest/lib/services/identity/v2/__init__.py deleted file mode 100644 index b7d3c7464..000000000 --- a/tempest/lib/services/identity/v2/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.identity.v2.endpoints_client import EndpointsClient -from tempest.lib.services.identity.v2.identity_client import IdentityClient -from tempest.lib.services.identity.v2.roles_client import RolesClient -from tempest.lib.services.identity.v2.services_client import ServicesClient -from tempest.lib.services.identity.v2.tenants_client import TenantsClient -from tempest.lib.services.identity.v2.token_client import TokenClient -from tempest.lib.services.identity.v2.users_client import UsersClient - -__all__ = ['EndpointsClient', 'IdentityClient', 'RolesClient', - 'ServicesClient', 'TenantsClient', 'TokenClient', 'UsersClient'] diff --git a/tempest/lib/services/identity/v2/endpoints_client.py b/tempest/lib/services/identity/v2/endpoints_client.py deleted file mode 100644 index db8d7cc60..000000000 --- a/tempest/lib/services/identity/v2/endpoints_client.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class EndpointsClient(rest_client.RestClient): - api_version = "v2.0" - - def create_endpoint(self, **kwargs): - """Create an endpoint for service. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/index.html#create-endpoint-template - """ - - post_body = json.dumps({'endpoint': kwargs}) - resp, body = self.post('/endpoints', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_endpoints(self): - """List Endpoints - Returns Endpoints.""" - resp, body = self.get('/endpoints') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_endpoint(self, endpoint_id): - """Delete an endpoint.""" - url = '/endpoints/%s' % endpoint_id - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v2/identity_client.py b/tempest/lib/services/identity/v2/identity_client.py deleted file mode 100644 index c610d65e1..000000000 --- a/tempest/lib/services/identity/v2/identity_client.py +++ /dev/null @@ -1,69 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class IdentityClient(rest_client.RestClient): - api_version = "v2.0" - - def show_api_description(self): - """Retrieves info about the v2.0 Identity API""" - url = '' - resp, body = self.get(url) - self.expected_success([200, 203], resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_token(self, token_id): - """Get token details.""" - resp, body = self.get("tokens/%s" % token_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_token(self, token_id): - """Delete a token.""" - resp, body = self.delete("tokens/%s" % token_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_extensions(self): - """List all the extensions.""" - resp, body = self.get('/extensions') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_endpoints_for_token(self, token_id): - """List endpoints for a token """ - resp, body = self.get("tokens/%s/endpoints" % token_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_token_existence(self, token_id, **params): - """Validates a token and confirms that it belongs to a tenant. - - For a full list of available parameters, please refer to the - official API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/#validate-token - """ - url = "tokens/%s" % token_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.head(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v2/roles_client.py b/tempest/lib/services/identity/v2/roles_client.py deleted file mode 100644 index 9e841dd3a..000000000 --- a/tempest/lib/services/identity/v2/roles_client.py +++ /dev/null @@ -1,109 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class RolesClient(rest_client.RestClient): - api_version = "v2.0" - - def create_role(self, **kwargs): - """Create a role. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#create-a-role - """ - post_body = json.dumps({'role': kwargs}) - resp, body = self.post('OS-KSADM/roles', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_role(self, role_id_or_name): - """Get a role by its id or name. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#show-a-role - OR - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#show-role-information-by-name - """ - resp, body = self.get('OS-KSADM/roles/%s' % role_id_or_name) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_roles(self, **params): - """Returns roles. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#list-all-roles - """ - url = 'OS-KSADM/roles' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_role(self, role_id): - """Delete a role. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#delete-a-role - """ - resp, body = self.delete('OS-KSADM/roles/%s' % role_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_user_role_on_project(self, tenant_id, user_id, role_id): - """Add roles to a user on a tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#grant-roles-to-user-on-tenant - """ - resp, body = self.put('/tenants/%s/users/%s/roles/OS-KSADM/%s' % - (tenant_id, user_id, role_id), "") - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_user_roles_on_project(self, tenant_id, user_id, **params): - """Returns a list of roles assigned to a user for a tenant.""" - # TODO(gmann): Need to write API-ref link, Bug# 1592711 - url = '/tenants/%s/users/%s/roles' % (tenant_id, user_id) - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_role_from_user_on_project(self, tenant_id, user_id, role_id): - """Removes a role assignment for a user on a tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#revoke-role-from-user-on-tenant - """ - resp, body = self.delete('/tenants/%s/users/%s/roles/OS-KSADM/%s' % - (tenant_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v2/services_client.py b/tempest/lib/services/identity/v2/services_client.py deleted file mode 100644 index 47398dbf7..000000000 --- a/tempest/lib/services/identity/v2/services_client.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ServicesClient(rest_client.RestClient): - api_version = "v2.0" - - def create_service(self, **kwargs): - """Create a service. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-ext/#create-service-admin-extension - """ - post_body = json.dumps({'OS-KSADM:service': kwargs}) - resp, body = self.post('/OS-KSADM/services', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_service(self, service_id): - """Get Service.""" - url = '/OS-KSADM/services/%s' % service_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_services(self, **params): - """List Service - Returns Services. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-ext/#list-services-admin-extension - """ - url = '/OS-KSADM/services' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_service(self, service_id): - """Delete Service.""" - url = '/OS-KSADM/services/%s' % service_id - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v2/tenants_client.py b/tempest/lib/services/identity/v2/tenants_client.py deleted file mode 100644 index 026db6420..000000000 --- a/tempest/lib/services/identity/v2/tenants_client.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class TenantsClient(rest_client.RestClient): - api_version = "v2.0" - - def create_tenant(self, **kwargs): - """Create a tenant - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#create-tenant - """ - post_body = json.dumps({'tenant': kwargs}) - resp, body = self.post('tenants', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_tenant(self, tenant_id): - """Delete a tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/index.html#delete-tenant - """ - resp, body = self.delete('tenants/%s' % str(tenant_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_tenant(self, tenant_id): - """Get tenant details. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/index.html#show-tenant-details-by-id - """ - resp, body = self.get('tenants/%s' % str(tenant_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_tenants(self, **params): - """Returns tenants. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#list-tenants-admin-endpoint - """ - url = 'tenants' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_tenant(self, tenant_id, **kwargs): - """Updates a tenant. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#update-tenant - """ - if 'id' not in kwargs: - kwargs['id'] = tenant_id - post_body = json.dumps({'tenant': kwargs}) - resp, body = self.post('tenants/%s' % tenant_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_tenant_users(self, tenant_id, **params): - """List users for a Tenant. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#list-users-on-a-tenant - """ - url = '/tenants/%s/users' % tenant_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v2/token_client.py b/tempest/lib/services/identity/v2/token_client.py deleted file mode 100644 index 458c862ad..000000000 --- a/tempest/lib/services/identity/v2/token_client.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions - - -class TokenClient(rest_client.RestClient): - - def __init__(self, auth_url, disable_ssl_certificate_validation=None, - ca_certs=None, trace_requests=None, **kwargs): - """Initialises the Token client - - :param auth_url: URL to which the token request is sent - :param disable_ssl_certificate_validation: pass-through to rest client - :param ca_certs: pass-through to rest client - :param trace_requests: pass-through to rest client - :param kwargs: any extra parameter to pass through the rest client. - region, service and auth_provider will be ignored, if passed, - as they are not meaningful for token client - """ - dscv = disable_ssl_certificate_validation - # NOTE(andreaf) region, service and auth_provider are passed - # positionally with None. Having them in kwargs would raise a - # "multiple values for keyword arguments" error - for unwanted_kwargs in ['region', 'service', 'auth_provider']: - kwargs.pop(unwanted_kwargs, None) - super(TokenClient, self).__init__( - None, None, None, disable_ssl_certificate_validation=dscv, - ca_certs=ca_certs, trace_requests=trace_requests, **kwargs) - - if auth_url is None: - raise exceptions.IdentityError("Couldn't determine auth_url") - - # Normalize URI to ensure /tokens is in it. - if 'tokens' not in auth_url: - auth_url = auth_url.rstrip('/') + '/tokens' - - self.auth_url = auth_url - - def auth(self, user, password, tenant=None): - creds = { - 'auth': { - 'passwordCredentials': { - 'username': user, - 'password': password, - }, - } - } - - if tenant: - creds['auth']['tenantName'] = tenant - - body = json.dumps(creds, sort_keys=True) - resp, body = self.post(self.auth_url, body=body) - self.expected_success(200, resp.status) - - return rest_client.ResponseBody(resp, body['access']) - - def auth_token(self, token_id, tenant=None): - creds = { - 'auth': { - 'token': { - 'id': token_id, - }, - } - } - - if tenant: - creds['auth']['tenantName'] = tenant - - body = json.dumps(creds) - resp, body = self.post(self.auth_url, body=body) - self.expected_success(200, resp.status) - - return rest_client.ResponseBody(resp, body['access']) - - def request(self, method, url, extra_headers=False, headers=None, - body=None, chunked=False): - """A simple HTTP request interface. - - Note: this overloads the `request` method from the parent class and - thus must implement the same method signature. - """ - if headers is None: - headers = self.get_headers(accept_type="json") - elif extra_headers: - try: - headers.update(self.get_headers(accept_type="json")) - except (ValueError, TypeError): - headers = self.get_headers(accept_type="json") - - resp, resp_body = self.raw_request(url, method, - headers=headers, body=body) - self._log_request(method, url, resp, req_headers=headers, - req_body='', resp_body=resp_body) - - if resp.status in [401, 403]: - resp_body = json.loads(resp_body) - raise exceptions.Unauthorized(resp_body['error']['message']) - elif resp.status not in [200, 201]: - raise exceptions.IdentityError( - 'Unexpected status code {0}'.format(resp.status)) - - return resp, json.loads(resp_body) - - def get_token(self, user, password, tenant, auth_data=False): - """Returns (token id, token data) for supplied credentials.""" - body = self.auth(user, password, tenant) - - if auth_data: - return body['token']['id'], body - else: - return body['token']['id'] - - -class TokenClientJSON(TokenClient): - LOG = logging.getLogger(__name__) - - def _warn(self): - self.LOG.warning("%s class was deprecated and renamed to %s", - self.__class__.__name__, 'TokenClient') - - def __init__(self, *args, **kwargs): - self._warn() - super(TokenClientJSON, self).__init__(*args, **kwargs) diff --git a/tempest/lib/services/identity/v2/users_client.py b/tempest/lib/services/identity/v2/users_client.py deleted file mode 100644 index 44bb5fd69..000000000 --- a/tempest/lib/services/identity/v2/users_client.py +++ /dev/null @@ -1,158 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class UsersClient(rest_client.RestClient): - api_version = "v2.0" - - def create_user(self, **kwargs): - """Create a user. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#create-user-admin-endpoint - """ - post_body = json.dumps({'user': kwargs}) - resp, body = self.post('users', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user(self, user_id, **kwargs): - """Updates a user. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#update-user-admin-endpoint - """ - put_body = json.dumps({'user': kwargs}) - resp, body = self.put('users/%s' % user_id, put_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_user(self, user_id): - """GET a user. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/index.html#show-user-details-admin-endpoint - """ - resp, body = self.get("users/%s" % user_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_user(self, user_id): - """Delete a user. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/index.html#delete-user-admin-endpoint - """ - resp, body = self.delete("users/%s" % user_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_users(self, **params): - """Get the list of users. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#list-users-admin-endpoint - """ - url = "users" - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user_enabled(self, user_id, **kwargs): - """Enables or disables a user. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#enable-disable-user - """ - # NOTE: The URL (users//enabled) is different from the api-site - # one (users//OS-KSADM/enabled) , but they are the same API - # because of the fact that in keystone/contrib/admin_crud/core.py - # both api use same action='set_user_enabled' - put_body = json.dumps({'user': kwargs}) - resp, body = self.put('users/%s/enabled' % user_id, put_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user_password(self, user_id, **kwargs): - """Update User Password.""" - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1524147 - put_body = json.dumps({'user': kwargs}) - resp, body = self.put('users/%s/OS-KSADM/password' % user_id, put_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user_own_password(self, user_id, **kwargs): - """User updates own password""" - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1524153 - # NOTE: This API is used for updating user password by itself. - # Ref: http://lists.openstack.org/pipermail/openstack-dev/2015-December - # /081803.html - patch_body = json.dumps({'user': kwargs}) - resp, body = self.patch('OS-KSCRUD/users/%s' % user_id, patch_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_user_ec2_credential(self, user_id, **kwargs): - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - post_body = json.dumps(kwargs) - resp, body = self.post('/users/%s/credentials/OS-EC2' % user_id, - post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_user_ec2_credential(self, user_id, access): - resp, body = self.delete('/users/%s/credentials/OS-EC2/%s' % - (user_id, access)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_user_ec2_credentials(self, user_id): - resp, body = self.get('/users/%s/credentials/OS-EC2' % user_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_user_ec2_credential(self, user_id, access): - resp, body = self.get('/users/%s/credentials/OS-EC2/%s' % - (user_id, access)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/__init__.py b/tempest/lib/services/identity/v3/__init__.py deleted file mode 100644 index a539d08c0..000000000 --- a/tempest/lib/services/identity/v3/__init__.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.identity.v3.catalog_client import \ - CatalogClient -from tempest.lib.services.identity.v3.credentials_client import \ - CredentialsClient -from tempest.lib.services.identity.v3.domain_configuration_client \ - import DomainConfigurationClient -from tempest.lib.services.identity.v3.domains_client import DomainsClient -from tempest.lib.services.identity.v3.endpoint_filter_client import \ - EndPointsFilterClient -from tempest.lib.services.identity.v3.endpoint_groups_client import \ - EndPointGroupsClient -from tempest.lib.services.identity.v3.endpoints_client import EndPointsClient -from tempest.lib.services.identity.v3.groups_client import GroupsClient -from tempest.lib.services.identity.v3.identity_client import IdentityClient -from tempest.lib.services.identity.v3.inherited_roles_client import \ - InheritedRolesClient -from tempest.lib.services.identity.v3.oauth_consumers_client import \ - OAUTHConsumerClient -from tempest.lib.services.identity.v3.oauth_token_client import \ - OAUTHTokenClient -from tempest.lib.services.identity.v3.policies_client import PoliciesClient -from tempest.lib.services.identity.v3.projects_client import ProjectsClient -from tempest.lib.services.identity.v3.regions_client import RegionsClient -from tempest.lib.services.identity.v3.role_assignments_client import \ - RoleAssignmentsClient -from tempest.lib.services.identity.v3.roles_client import RolesClient -from tempest.lib.services.identity.v3.services_client import ServicesClient -from tempest.lib.services.identity.v3.token_client import V3TokenClient -from tempest.lib.services.identity.v3.trusts_client import TrustsClient -from tempest.lib.services.identity.v3.users_client import UsersClient -from tempest.lib.services.identity.v3.versions_client import VersionsClient - -__all__ = ['CatalogClient', 'CredentialsClient', 'DomainsClient', - 'DomainConfigurationClient', 'EndPointGroupsClient', - 'EndPointsClient', 'EndPointsFilterClient', 'GroupsClient', - 'IdentityClient', 'InheritedRolesClient', 'OAUTHConsumerClient', - 'OAUTHTokenClient', 'PoliciesClient', 'ProjectsClient', - 'RegionsClient', 'RoleAssignmentsClient', 'RolesClient', - 'ServicesClient', 'V3TokenClient', 'TrustsClient', 'UsersClient', - 'VersionsClient'] diff --git a/tempest/lib/services/identity/v3/catalog_client.py b/tempest/lib/services/identity/v3/catalog_client.py deleted file mode 100644 index 0f9d48543..000000000 --- a/tempest/lib/services/identity/v3/catalog_client.py +++ /dev/null @@ -1,30 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#\ -get-service-catalog -""" - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class CatalogClient(rest_client.RestClient): - api_version = "v3" - - def show_catalog(self): - resp, body = self.get('auth/catalog') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/credentials_client.py b/tempest/lib/services/identity/v3/credentials_client.py deleted file mode 100644 index 6e5fd3150..000000000 --- a/tempest/lib/services/identity/v3/credentials_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -http://developer.openstack.org/api-ref/identity/v3/index.html#credentials -""" - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class CredentialsClient(rest_client.RestClient): - api_version = "v3" - - def create_credential(self, **kwargs): - """Creates a credential. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-credential - """ - post_body = json.dumps({'credential': kwargs}) - resp, body = self.post('credentials', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_credential(self, credential_id, **kwargs): - """Updates a credential. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-credential - """ - post_body = json.dumps({'credential': kwargs}) - resp, body = self.patch('credentials/%s' % credential_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_credential(self, credential_id): - """To GET Details of a credential. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-credential-details - """ - resp, body = self.get('credentials/%s' % credential_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_credentials(self, **params): - """Lists out all the available credentials. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-credentials - """ - url = 'credentials' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_credential(self, credential_id): - """Deletes a credential. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#delete-credential - """ - resp, body = self.delete('credentials/%s' % credential_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/domain_configuration_client.py b/tempest/lib/services/identity/v3/domain_configuration_client.py deleted file mode 100644 index d57f2d478..000000000 --- a/tempest/lib/services/identity/v3/domain_configuration_client.py +++ /dev/null @@ -1,188 +0,0 @@ -# Copyright 2017 AT&T Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class DomainConfigurationClient(rest_client.RestClient): - api_version = "v3" - - def show_default_config_settings(self): - """Show default configuration settings. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-default-configuration-settings - """ - url = 'domains/config/default' - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_default_group_config(self, group): - """Show default configuration for a group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-default-configuration-for-a-group - """ - url = 'domains/config/%s/default' % group - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_default_group_option(self, group, option): - """Show default option for a group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-default-option-for-a-group - """ - url = 'domains/config/%s/%s/default' % (group, option) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_domain_group_option_config(self, domain_id, group, option): - """Show domain group option configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-domain-group-option-configuration - """ - url = 'domains/%s/config/%s/%s' % (domain_id, group, option) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_domain_group_option_config(self, domain_id, group, option, - **kwargs): - """Update domain group option configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-domain-group-option-configuration - """ - url = 'domains/%s/config/%s/%s' % (domain_id, group, option) - resp, body = self.patch(url, json.dumps({'config': kwargs})) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_domain_group_option_config(self, domain_id, group, option): - """Delete domain group option configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#delete-domain-group-option-configuration - """ - url = 'domains/%s/config/%s/%s' % (domain_id, group, option) - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_domain_group_config(self, domain_id, group): - """Shows details for a domain group configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-domain-group-configuration - """ - url = 'domains/%s/config/%s' % (domain_id, group) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_domain_group_config(self, domain_id, group, **kwargs): - """Update domain group configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-domain-group-configuration - """ - url = 'domains/%s/config/%s' % (domain_id, group) - resp, body = self.patch(url, json.dumps({'config': kwargs})) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_domain_group_config(self, domain_id, group): - """Delete domain group configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#delete-domain-group-configuration - """ - url = 'domains/%s/config/%s' % (domain_id, group) - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_domain_config(self, domain_id, **kwargs): - """Create domain configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-domain-configuration - """ - url = 'domains/%s/config' % domain_id - resp, body = self.put(url, json.dumps({'config': kwargs})) - self.expected_success([200, 201], resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_domain_config(self, domain_id): - """Show domain configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-domain-configuration - """ - url = 'domains/%s/config' % domain_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_domain_config(self, domain_id, **kwargs): - """Update domain configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-domain-configuration - """ - url = 'domains/%s/config' % domain_id - resp, body = self.patch(url, json.dumps({'config': kwargs})) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_domain_config(self, domain_id): - """Delete domain configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#delete-domain-configuration - """ - url = 'domains/%s/config' % domain_id - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/domains_client.py b/tempest/lib/services/identity/v3/domains_client.py deleted file mode 100644 index 43cb62c73..000000000 --- a/tempest/lib/services/identity/v3/domains_client.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class DomainsClient(rest_client.RestClient): - api_version = "v3" - - def create_domain(self, **kwargs): - """Creates a domain. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-domain - """ - post_body = json.dumps({'domain': kwargs}) - resp, body = self.post('domains', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_domain(self, domain_id): - """Deletes a domain. - - For APi details, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#delete-domain - """ - resp, body = self.delete('domains/%s' % domain_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_domains(self, **params): - """List Domains. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#list-domains - """ - url = 'domains' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_domain(self, domain_id, **kwargs): - """Updates a domain. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-domain - """ - post_body = json.dumps({'domain': kwargs}) - resp, body = self.patch('domains/%s' % domain_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_domain(self, domain_id): - """Get Domain details. - - For API details, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-domain-details - """ - resp, body = self.get('domains/%s' % domain_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/endpoint_filter_client.py b/tempest/lib/services/identity/v3/endpoint_filter_client.py deleted file mode 100644 index a8cd7222e..000000000 --- a/tempest/lib/services/identity/v3/endpoint_filter_client.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2017 AT&T Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -https://developer.openstack.org/api-ref/identity/v3-ext/#os-ep-filter-api -""" - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class EndPointsFilterClient(rest_client.RestClient): - api_version = "v3" - ep_filter = "OS-EP-FILTER" - - def list_projects_for_endpoint(self, endpoint_id): - """List all projects that are associated with the endpoint.""" - resp, body = self.get(self.ep_filter + '/endpoints/%s/projects' % - endpoint_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def add_endpoint_to_project(self, project_id, endpoint_id): - """Add association between project and endpoint. """ - body = None - resp, body = self.put( - self.ep_filter + '/projects/%s/endpoints/%s' % - (project_id, endpoint_id), body) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_endpoint_in_project(self, project_id, endpoint_id): - """Check association of Project with Endpoint.""" - resp, body = self.head( - self.ep_filter + '/projects/%s/endpoints/%s' % - (project_id, endpoint_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_endpoints_in_project(self, project_id): - """List Endpoints associated with Project.""" - resp, body = self.get(self.ep_filter + '/projects/%s/endpoints' - % project_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_endpoint_from_project(self, project_id, endpoint_id): - """Delete association between project and endpoint.""" - resp, body = self.delete( - self.ep_filter + '/projects/%s/endpoints/%s' - % (project_id, endpoint_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/endpoint_groups_client.py b/tempest/lib/services/identity/v3/endpoint_groups_client.py deleted file mode 100644 index ce9938953..000000000 --- a/tempest/lib/services/identity/v3/endpoint_groups_client.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class EndPointGroupsClient(rest_client.RestClient): - api_version = "v3" - - def create_endpoint_group(self, **kwargs): - """Create endpoint group. - - For a full list of available parameters, please refer to the - official API reference: - https://developer.openstack.org/api-ref/identity/v3-ext/#create-endpoint-group - """ - post_body = json.dumps({'endpoint_group': kwargs}) - resp, body = self.post('OS-EP-FILTER/endpoint_groups', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_endpoint_group(self, endpoint_group_id, **kwargs): - """Update endpoint group. - - For a full list of available parameters, please refer to the - official API reference: - https://developer.openstack.org/api-ref/identity/v3-ext/#update-endpoint-group - """ - post_body = json.dumps({'endpoint_group': kwargs}) - resp, body = self.patch( - 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_endpoint_group(self, endpoint_group_id): - """Delete endpoint group.""" - resp_header, resp_body = self.delete( - 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id) - self.expected_success(204, resp_header.status) - return rest_client.ResponseBody(resp_header, resp_body) - - def show_endpoint_group(self, endpoint_group_id): - """Get endpoint group.""" - resp_header, resp_body = self.get( - 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id) - self.expected_success(200, resp_header.status) - resp_body = json.loads(resp_body) - return rest_client.ResponseBody(resp_header, resp_body) - - def check_endpoint_group(self, endpoint_group_id): - """Check endpoint group.""" - resp_header, resp_body = self.head( - 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id) - self.expected_success(200, resp_header.status) - return rest_client.ResponseBody(resp_header, resp_body) - - def list_endpoint_groups(self): - """Get endpoint groups.""" - resp_header, resp_body = self.get('OS-EP-FILTER/endpoint_groups') - self.expected_success(200, resp_header.status) - resp_body = json.loads(resp_body) - return rest_client.ResponseBody(resp_header, resp_body) diff --git a/tempest/lib/services/identity/v3/endpoints_client.py b/tempest/lib/services/identity/v3/endpoints_client.py deleted file mode 100644 index e24dca7b6..000000000 --- a/tempest/lib/services/identity/v3/endpoints_client.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#service-catalog-and-endpoints -""" - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class EndPointsClient(rest_client.RestClient): - api_version = "v3" - - def list_endpoints(self, **params): - """List endpoints. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-endpoints - """ - url = 'endpoints' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_endpoint(self, **kwargs): - """Create endpoint. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-endpoint - """ - post_body = json.dumps({'endpoint': kwargs}) - resp, body = self.post('endpoints', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_endpoint(self, endpoint_id, **kwargs): - """Updates an endpoint with given parameters. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-endpoint - """ - post_body = json.dumps({'endpoint': kwargs}) - resp, body = self.patch('endpoints/%s' % endpoint_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_endpoint(self, endpoint_id): - """Delete endpoint.""" - resp_header, resp_body = self.delete('endpoints/%s' % endpoint_id) - self.expected_success(204, resp_header.status) - return rest_client.ResponseBody(resp_header, resp_body) - - def show_endpoint(self, endpoint_id): - """Get endpoint.""" - resp_header, resp_body = self.get('endpoints/%s' % endpoint_id) - self.expected_success(200, resp_header.status) - resp_body = json.loads(resp_body) - return rest_client.ResponseBody(resp_header, resp_body) diff --git a/tempest/lib/services/identity/v3/groups_client.py b/tempest/lib/services/identity/v3/groups_client.py deleted file mode 100644 index bc6ead023..000000000 --- a/tempest/lib/services/identity/v3/groups_client.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#groups -""" - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class GroupsClient(rest_client.RestClient): - api_version = "v3" - - def create_group(self, **kwargs): - """Creates a group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-group - """ - post_body = json.dumps({'group': kwargs}) - resp, body = self.post('groups', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_group(self, group_id): - """Get group details.""" - resp, body = self.get('groups/%s' % group_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_groups(self, **params): - """Lists the groups. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-groups - """ - url = 'groups' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_group(self, group_id, **kwargs): - """Updates a group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-group - """ - post_body = json.dumps({'group': kwargs}) - resp, body = self.patch('groups/%s' % group_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_group(self, group_id): - """Delete a group.""" - resp, body = self.delete('groups/%s' % group_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def add_group_user(self, group_id, user_id): - """Add user into group.""" - resp, body = self.put('groups/%s/users/%s' % (group_id, user_id), - None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_group_users(self, group_id, **params): - """List users in group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-users-in-group - """ - url = 'groups/%s/users' % group_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_group_user(self, group_id, user_id): - """Delete user in group.""" - resp, body = self.delete('groups/%s/users/%s' % (group_id, user_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_group_user_existence(self, group_id, user_id): - """Check user in group.""" - resp, body = self.head('groups/%s/users/%s' % (group_id, user_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/identity/v3/identity_client.py b/tempest/lib/services/identity/v3/identity_client.py deleted file mode 100644 index 2512a3edc..000000000 --- a/tempest/lib/services/identity/v3/identity_client.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class IdentityClient(rest_client.RestClient): - api_version = "v3" - - def show_api_description(self): - """Retrieves info about the v3 Identity API""" - url = '' - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_token(self, resp_token): - """Get token details.""" - headers = {'X-Subject-Token': resp_token} - resp, body = self.get("auth/tokens", headers=headers) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_token(self, resp_token): - """Deletes token.""" - headers = {'X-Subject-Token': resp_token} - resp, body = self.delete("auth/tokens", headers=headers) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_token_existence(self, resp_token): - """Validates a token.""" - headers = {'X-Subject-Token': resp_token} - resp, body = self.head("auth/tokens", headers=headers) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_auth_projects(self): - """Get available project scopes.""" - resp, body = self.get("auth/projects") - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/inherited_roles_client.py b/tempest/lib/services/identity/v3/inherited_roles_client.py deleted file mode 100644 index 691c7fdc9..000000000 --- a/tempest/lib/services/identity/v3/inherited_roles_client.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class InheritedRolesClient(rest_client.RestClient): - api_version = "v3" - - def create_inherited_role_on_domains_user( - self, domain_id, user_id, role_id): - """Assigns a role to a user on projects owned by a domain.""" - resp, body = self.put( - "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects" - % (domain_id, user_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_inherited_role_from_user_on_domain( - self, domain_id, user_id, role_id): - """Revokes an inherited project role from a user on a domain.""" - resp, body = self.delete( - "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects" - % (domain_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_inherited_project_role_for_user_on_domain( - self, domain_id, user_id): - """Lists the inherited project roles on a domain for a user.""" - resp, body = self.get( - "OS-INHERIT/domains/%s/users/%s/roles/inherited_to_projects" - % (domain_id, user_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_user_inherited_project_role_on_domain( - self, domain_id, user_id, role_id): - """Checks whether a user has an inherited project role on a domain.""" - resp, body = self.head( - "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects" - % (domain_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_inherited_role_on_domains_group( - self, domain_id, group_id, role_id): - """Assigns a role to a group on projects owned by a domain.""" - resp, body = self.put( - "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects" - % (domain_id, group_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_inherited_role_from_group_on_domain( - self, domain_id, group_id, role_id): - """Revokes an inherited project role from a group on a domain.""" - resp, body = self.delete( - "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects" - % (domain_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_inherited_project_role_for_group_on_domain( - self, domain_id, group_id): - """Lists the inherited project roles on a domain for a group.""" - resp, body = self.get( - "OS-INHERIT/domains/%s/groups/%s/roles/inherited_to_projects" - % (domain_id, group_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_group_inherited_project_role_on_domain( - self, domain_id, group_id, role_id): - """Checks whether a group has an inherited project role on a domain.""" - resp, body = self.head( - "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects" - % (domain_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_inherited_role_on_projects_user( - self, project_id, user_id, role_id): - """Assigns a role to a user on projects in a subtree.""" - resp, body = self.put( - "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects" - % (project_id, user_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_inherited_role_from_user_on_project( - self, project_id, user_id, role_id): - """Revokes an inherited role from a user on a project.""" - resp, body = self.delete( - "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects" - % (project_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_user_has_flag_on_inherited_to_project( - self, project_id, user_id, role_id): - """Checks whether a user has a role assignment""" - """with the inherited_to_projects flag on a project.""" - resp, body = self.head( - "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects" - % (project_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_inherited_role_on_projects_group( - self, project_id, group_id, role_id): - """Assigns a role to a group on projects in a subtree.""" - resp, body = self.put( - "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects" - % (project_id, group_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_inherited_role_from_group_on_project( - self, project_id, group_id, role_id): - """Revokes an inherited role from a group on a project.""" - resp, body = self.delete( - "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects" - % (project_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_group_has_flag_on_inherited_to_project( - self, project_id, group_id, role_id): - """Checks whether a group has a role assignment""" - """with the inherited_to_projects flag on a project.""" - resp, body = self.head( - "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects" - % (project_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/identity/v3/oauth_consumers_client.py b/tempest/lib/services/identity/v3/oauth_consumers_client.py deleted file mode 100644 index 97fb14145..000000000 --- a/tempest/lib/services/identity/v3/oauth_consumers_client.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class OAUTHConsumerClient(rest_client.RestClient): - api_version = "v3" - - def create_consumer(self, description=None): - """Creates a consumer. - - :param str description: Optional field to add notes about the consumer - - For more information, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#create-consumer - """ - post_body = {"description": description} - post_body = json.dumps({'consumer': post_body}) - resp, body = self.post('OS-OAUTH1/consumers', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_consumer(self, consumer_id): - """Deletes a consumer. - - :param str consumer_id: The ID of the consumer that will be deleted - - For more information, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#delete-consumer - """ - resp, body = self.delete('OS-OAUTH1/consumers/%s' % consumer_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_consumer(self, consumer_id, description=None): - """Updates a consumer. - - :param str consumer_id: The ID of the consumer that will be updated - :param str description: Optional field to add notes about the consumer - - For more information, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v3-ext/#update-consumer - """ - post_body = {"description": description} - post_body = json.dumps({'consumer': post_body}) - resp, body = self.patch('OS-OAUTH1/consumers/%s' % consumer_id, - post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_consumer(self, consumer_id): - """Show consumer details. - - :param str consumer_id: The ID of the consumer that will be shown - - For more information, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#show-consumer-details - """ - resp, body = self.get('OS-OAUTH1/consumers/%s' % consumer_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_consumers(self): - """List all consumers. - - For more information, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#list-consumers - """ - resp, body = self.get('OS-OAUTH1/consumers') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/oauth_token_client.py b/tempest/lib/services/identity/v3/oauth_token_client.py deleted file mode 100644 index b1d298b8f..000000000 --- a/tempest/lib/services/identity/v3/oauth_token_client.py +++ /dev/null @@ -1,236 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import binascii -import hashlib -import hmac -import random -import time - -import six -from six.moves.urllib import parse as urlparse - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class OAUTHTokenClient(rest_client.RestClient): - api_version = "v3" - - def _escape(self, s): - """Escape a unicode string in an OAuth-compatible fashion.""" - safe = b'~' - s = s.encode('utf-8') if isinstance(s, six.text_type) else s - s = urlparse.quote(s, safe) - if isinstance(s, six.binary_type): - s = s.decode('utf-8') - return s - - def _generate_params_with_signature(self, client_key, uri, - client_secret=None, - resource_owner_key=None, - resource_owner_secret=None, - callback_uri=None, - verifier=None, - http_method='GET'): - """Generate OAUTH params along with signature.""" - timestamp = six.text_type(int(time.time())) - nonce = six.text_type(random.getrandbits(64)) + timestamp - oauth_params = [ - ('oauth_nonce', nonce), - ('oauth_timestamp', timestamp), - ('oauth_version', '1.0'), - ('oauth_signature_method', 'HMAC-SHA1'), - ('oauth_consumer_key', client_key), - ] - if resource_owner_key: - oauth_params.append(('oauth_token', resource_owner_key)) - if callback_uri: - oauth_params.append(('oauth_callback', callback_uri)) - if verifier: - oauth_params.append(('oauth_verifier', verifier)) - - # normalize_params - key_values = [(self._escape(k), self._escape(v)) - for k, v in oauth_params] - key_values.sort() - parameter_parts = ['{0}={1}'.format(k, v) for k, v in key_values] - normalized_params = '&'.join(parameter_parts) - - # normalize_uri - scheme, netloc, path, params, query, fragment = urlparse.urlparse(uri) - scheme = scheme.lower() - netloc = netloc.lower() - normalized_uri = urlparse.urlunparse((scheme, netloc, path, - params, '', '')) - - # construct base string - base_string = self._escape(http_method.upper()) - base_string += '&' - base_string += self._escape(normalized_uri) - base_string += '&' - base_string += self._escape(normalized_params) - - # sign using hmac-sha1 - key = self._escape(client_secret or '') - key += '&' - key += self._escape(resource_owner_secret or '') - key_utf8 = key.encode('utf-8') - text_utf8 = base_string.encode('utf-8') - signature = hmac.new(key_utf8, text_utf8, hashlib.sha1) - sig = binascii.b2a_base64(signature.digest())[:-1].decode('utf-8') - - oauth_params.append(('oauth_signature', sig)) - return oauth_params - - def _generate_oauth_header(self, oauth_params): - authorization_header = {} - authorization_header_parameters_parts = [] - for oauth_parameter_name, value in oauth_params: - escaped_name = self._escape(oauth_parameter_name) - escaped_value = self._escape(value) - part = '{0}="{1}"'.format(escaped_name, escaped_value) - authorization_header_parameters_parts.append(part) - - authorization_header_parameters = ', '.join( - authorization_header_parameters_parts) - oauth_string = 'OAuth %s' % authorization_header_parameters - authorization_header['Authorization'] = oauth_string - - return authorization_header - - def create_request_token(self, consumer_key, consumer_secret, project_id): - """Create request token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#create-request-token - """ - endpoint = 'OS-OAUTH1/request_token' - headers = {'Requested-Project-Id': project_id} - oauth_params = self._generate_params_with_signature( - consumer_key, - self.base_url + '/' + endpoint, - client_secret=consumer_secret, - callback_uri='oob', - http_method='POST') - oauth_header = self._generate_oauth_header(oauth_params) - headers.update(oauth_header) - resp, body = self.post(endpoint, - body=None, - headers=headers) - self.expected_success(201, resp.status) - if not isinstance(body, str): - body = body.decode('utf-8') - body = dict(item.split("=") for item in body.split("&")) - return rest_client.ResponseBody(resp, body) - - def authorize_request_token(self, request_token_id, role_ids): - """Authorize request token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#authorize-request-token - """ - roles = [{'id': role_id} for role_id in role_ids] - body = {'roles': roles} - post_body = json.dumps(body) - resp, body = self.put("OS-OAUTH1/authorize/%s" % request_token_id, - post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_access_token(self, consumer_key, consumer_secret, request_key, - request_secret, oauth_verifier): - """Create access token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#create-access-token - """ - endpoint = 'OS-OAUTH1/access_token' - oauth_params = self._generate_params_with_signature( - consumer_key, - self.base_url + '/' + endpoint, - client_secret=consumer_secret, - resource_owner_key=request_key, - resource_owner_secret=request_secret, - verifier=oauth_verifier, - http_method='POST') - headers = self._generate_oauth_header(oauth_params) - resp, body = self.post(endpoint, body=None, headers=headers) - self.expected_success(201, resp.status) - if not isinstance(body, str): - body = body.decode('utf-8') - body = dict(item.split("=") for item in body.split("&")) - return rest_client.ResponseBody(resp, body) - - def get_access_token(self, user_id, access_token_id): - """Get access token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#get-access-token - """ - resp, body = self.get("users/%s/OS-OAUTH1/access_tokens/%s" - % (user_id, access_token_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def revoke_access_token(self, user_id, access_token_id): - """Revoke access token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#revoke-access-token - """ - resp, body = self.delete("users/%s/OS-OAUTH1/access_tokens/%s" - % (user_id, access_token_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_access_tokens(self, user_id): - """List access tokens. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#list-access-tokens - """ - resp, body = self.get("users/%s/OS-OAUTH1/access_tokens" - % (user_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_access_token_roles(self, user_id, access_token_id): - """List roles for an access token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#list-roles-for-an-access-token - """ - resp, body = self.get("users/%s/OS-OAUTH1/access_tokens/%s/roles" - % (user_id, access_token_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def get_access_token_role(self, user_id, access_token_id, role_id): - """Show role details for an access token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#show-role-details-for-an-access-token - """ - resp, body = self.get("users/%s/OS-OAUTH1/access_tokens/%s/roles/%s" - % (user_id, access_token_id, role_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/policies_client.py b/tempest/lib/services/identity/v3/policies_client.py deleted file mode 100644 index d4560e2fd..000000000 --- a/tempest/lib/services/identity/v3/policies_client.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#policies -""" - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class PoliciesClient(rest_client.RestClient): - api_version = "v3" - - def create_policy(self, **kwargs): - """Creates a Policy. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-policy - """ - post_body = json.dumps({'policy': kwargs}) - resp, body = self.post('policies', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_policies(self): - """Lists the policies.""" - resp, body = self.get('policies') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_policy(self, policy_id): - """Lists out the given policy.""" - url = 'policies/%s' % policy_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_policy(self, policy_id, **kwargs): - """Updates a policy. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-policy - """ - post_body = json.dumps({'policy': kwargs}) - url = 'policies/%s' % policy_id - resp, body = self.patch(url, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_policy(self, policy_id): - """Deletes the policy.""" - url = "policies/%s" % policy_id - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/projects_client.py b/tempest/lib/services/identity/v3/projects_client.py deleted file mode 100644 index 20787da21..000000000 --- a/tempest/lib/services/identity/v3/projects_client.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ProjectsClient(rest_client.RestClient): - api_version = "v3" - - def create_project(self, name, **kwargs): - """Create a Project. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-project - - """ - # Include the project name to the kwargs parameters - kwargs['name'] = name - post_body = json.dumps({'project': kwargs}) - resp, body = self.post('projects', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_projects(self, params=None): - url = "projects" - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_project(self, project_id, **kwargs): - """Update a Project. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-project - - """ - post_body = json.dumps({'project': kwargs}) - resp, body = self.patch('projects/%s' % project_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_project(self, project_id): - """GET a Project.""" - resp, body = self.get("projects/%s" % project_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_project(self, project_id): - """Delete a project.""" - resp, body = self.delete('projects/%s' % project_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/regions_client.py b/tempest/lib/services/identity/v3/regions_client.py deleted file mode 100644 index d7507cf70..000000000 --- a/tempest/lib/services/identity/v3/regions_client.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#regions -""" - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class RegionsClient(rest_client.RestClient): - api_version = "v3" - - def create_region(self, region_id=None, **kwargs): - """Create region. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-region - """ - if region_id is not None: - method = self.put - url = 'regions/%s' % region_id - else: - method = self.post - url = 'regions' - req_body = json.dumps({'region': kwargs}) - resp, body = method(url, req_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_region(self, region_id, **kwargs): - """Updates a region. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-region - """ - post_body = json.dumps({'region': kwargs}) - resp, body = self.patch('regions/%s' % region_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_region(self, region_id): - """Get region.""" - url = 'regions/%s' % region_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_regions(self, params=None): - """List regions.""" - url = 'regions' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_region(self, region_id): - """Delete region.""" - resp, body = self.delete('regions/%s' % region_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/role_assignments_client.py b/tempest/lib/services/identity/v3/role_assignments_client.py deleted file mode 100644 index a426e695d..000000000 --- a/tempest/lib/services/identity/v3/role_assignments_client.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class RoleAssignmentsClient(rest_client.RestClient): - api_version = "v3" - - def list_role_assignments(self, effective=False, **kwargs): - """List role assignments. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-role-assignments - - :param effective: If True, returns the effective assignments, including - any assignments gained by virtue of group membership - or inherited roles. - """ - url = 'role_assignments' - if kwargs: - # NOTE(rodrigods): "effective" is a key-only query parameter and - # is treated below. - if 'effective' in kwargs: - del kwargs['effective'] - url += '?%s' % urllib.urlencode(kwargs) - if effective: - url += '&effective' - - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/roles_client.py b/tempest/lib/services/identity/v3/roles_client.py deleted file mode 100644 index 43e3c0187..000000000 --- a/tempest/lib/services/identity/v3/roles_client.py +++ /dev/null @@ -1,241 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class RolesClient(rest_client.RestClient): - api_version = "v3" - - def create_role(self, **kwargs): - """Create a Role. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-role - """ - post_body = json.dumps({'role': kwargs}) - resp, body = self.post('roles', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_role(self, role_id): - """GET a Role.""" - resp, body = self.get('roles/%s' % role_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_roles(self, **params): - """Get the list of Roles.""" - - url = 'roles' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_role(self, role_id, **kwargs): - """Update a Role. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-role - """ - post_body = json.dumps({'role': kwargs}) - resp, body = self.patch('roles/%s' % role_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_role(self, role_id): - """Delete a role.""" - resp, body = self.delete('roles/%s' % role_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_user_role_on_project(self, project_id, user_id, role_id): - """Add roles to a user on a project.""" - resp, body = self.put('projects/%s/users/%s/roles/%s' % - (project_id, user_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_user_role_on_domain(self, domain_id, user_id, role_id): - """Add roles to a user on a domain.""" - resp, body = self.put('domains/%s/users/%s/roles/%s' % - (domain_id, user_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_user_roles_on_project(self, project_id, user_id): - """list roles of a user on a project.""" - resp, body = self.get('projects/%s/users/%s/roles' % - (project_id, user_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_user_roles_on_domain(self, domain_id, user_id): - """list roles of a user on a domain.""" - resp, body = self.get('domains/%s/users/%s/roles' % - (domain_id, user_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_role_from_user_on_project(self, project_id, user_id, role_id): - """Delete role of a user on a project.""" - resp, body = self.delete('projects/%s/users/%s/roles/%s' % - (project_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_role_from_user_on_domain(self, domain_id, user_id, role_id): - """Delete role of a user on a domain.""" - resp, body = self.delete('domains/%s/users/%s/roles/%s' % - (domain_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_user_role_existence_on_project(self, project_id, - user_id, role_id): - """Check role of a user on a project.""" - resp, body = self.head('projects/%s/users/%s/roles/%s' % - (project_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def check_user_role_existence_on_domain(self, domain_id, - user_id, role_id): - """Check role of a user on a domain.""" - resp, body = self.head('domains/%s/users/%s/roles/%s' % - (domain_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_group_role_on_project(self, project_id, group_id, role_id): - """Add roles to a group on a project.""" - resp, body = self.put('projects/%s/groups/%s/roles/%s' % - (project_id, group_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_group_role_on_domain(self, domain_id, group_id, role_id): - """Add roles to a group on a domain.""" - resp, body = self.put('domains/%s/groups/%s/roles/%s' % - (domain_id, group_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_group_roles_on_project(self, project_id, group_id): - """list roles of a group on a project.""" - resp, body = self.get('projects/%s/groups/%s/roles' % - (project_id, group_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_group_roles_on_domain(self, domain_id, group_id): - """list roles of a group on a domain.""" - resp, body = self.get('domains/%s/groups/%s/roles' % - (domain_id, group_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_role_from_group_on_project(self, project_id, group_id, role_id): - """Delete role of a group on a project.""" - resp, body = self.delete('projects/%s/groups/%s/roles/%s' % - (project_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_role_from_group_on_domain(self, domain_id, group_id, role_id): - """Delete role of a group on a domain.""" - resp, body = self.delete('domains/%s/groups/%s/roles/%s' % - (domain_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_role_from_group_on_project_existence(self, project_id, - group_id, role_id): - """Check role of a group on a project.""" - resp, body = self.head('projects/%s/groups/%s/roles/%s' % - (project_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def check_role_from_group_on_domain_existence(self, domain_id, - group_id, role_id): - """Check role of a group on a domain.""" - resp, body = self.head('domains/%s/groups/%s/roles/%s' % - (domain_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_role_inference_rule(self, prior_role, implies_role): - """Create a role inference rule.""" - resp, body = self.put('roles/%s/implies/%s' % - (prior_role, implies_role), None) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_role_inference_rule(self, prior_role, implies_role): - """Get a role inference rule.""" - resp, body = self.get('roles/%s/implies/%s' % - (prior_role, implies_role)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_role_inferences_rules(self, prior_role): - """List the inferences rules from a role.""" - resp, body = self.get('roles/%s/implies' % prior_role) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_all_role_inference_rules(self): - """Lists all role inference rules. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#list-all-role-inference-rules - """ - resp, body = self.get('role_inferences') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_role_inference_rule(self, prior_role, implies_role): - """Check a role inference rule.""" - resp, body = self.head('roles/%s/implies/%s' % - (prior_role, implies_role)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def delete_role_inference_rule(self, prior_role, implies_role): - """Delete a role inference rule.""" - resp, body = self.delete('roles/%s/implies/%s' % - (prior_role, implies_role)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/identity/v3/services_client.py b/tempest/lib/services/identity/v3/services_client.py deleted file mode 100644 index 7bbe850b5..000000000 --- a/tempest/lib/services/identity/v3/services_client.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#service-catalog-and-endpoints -""" - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ServicesClient(rest_client.RestClient): - api_version = "v3" - - def update_service(self, service_id, **kwargs): - """Updates a service. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-service - """ - patch_body = json.dumps({'service': kwargs}) - resp, body = self.patch('services/%s' % service_id, patch_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_service(self, service_id): - """Get Service.""" - url = 'services/%s' % service_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_service(self, **kwargs): - """Creates a service. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-service - """ - body = json.dumps({'service': kwargs}) - resp, body = self.post("services", body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_service(self, service_id): - url = "services/" + service_id - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_services(self, **params): - """List services. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-services - """ - url = 'services' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/token_client.py b/tempest/lib/services/identity/v3/token_client.py deleted file mode 100644 index 33f6f16fb..000000000 --- a/tempest/lib/services/identity/v3/token_client.py +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions - - -class V3TokenClient(rest_client.RestClient): - - def __init__(self, auth_url, disable_ssl_certificate_validation=None, - ca_certs=None, trace_requests=None, **kwargs): - """Initialises the Token client - - :param auth_url: URL to which the token request is sent - :param disable_ssl_certificate_validation: pass-through to rest client - :param ca_certs: pass-through to rest client - :param trace_requests: pass-through to rest client - :param kwargs: any extra parameter to pass through the rest client. - Three kwargs are forbidden: region, service and auth_provider - as they are not meaningful for token client - """ - dscv = disable_ssl_certificate_validation - for unwanted_kwargs in ['region', 'service', 'auth_provider']: - kwargs.pop(unwanted_kwargs, None) - super(V3TokenClient, self).__init__( - None, None, None, disable_ssl_certificate_validation=dscv, - ca_certs=ca_certs, trace_requests=trace_requests, **kwargs) - - if auth_url is None: - raise exceptions.IdentityError("Couldn't determine auth_url") - - if 'auth/tokens' not in auth_url: - auth_url = auth_url.rstrip('/') + '/auth/tokens' - - self.auth_url = auth_url - - def auth(self, user_id=None, username=None, password=None, project_id=None, - project_name=None, user_domain_id=None, user_domain_name=None, - project_domain_id=None, project_domain_name=None, domain_id=None, - domain_name=None, token=None): - """Obtains a token from the authentication service - - :param user_id: user id - :param username: user name - :param user_domain_id: the user domain id - :param user_domain_name: the user domain name - :param project_domain_id: the project domain id - :param project_domain_name: the project domain name - :param domain_id: a domain id to scope to - :param domain_name: a domain name to scope to - :param project_id: a project id to scope to - :param project_name: a project name to scope to - :param token: a token to re-scope. - - Accepts different combinations of credentials. - Sample sample valid combinations: - - token - - token, project_name, project_domain_id - - user_id, password - - username, password, user_domain_id - - username, password, project_name, user_domain_id, project_domain_id - Validation is left to the server side. - """ - creds = { - 'auth': { - 'identity': { - 'methods': [], - } - } - } - id_obj = creds['auth']['identity'] - if token: - id_obj['methods'].append('token') - id_obj['token'] = { - 'id': token - } - - if (user_id or username) and password: - id_obj['methods'].append('password') - id_obj['password'] = { - 'user': { - 'password': password, - } - } - if user_id: - id_obj['password']['user']['id'] = user_id - else: - id_obj['password']['user']['name'] = username - - _domain = None - if user_domain_id is not None: - _domain = dict(id=user_domain_id) - elif user_domain_name is not None: - _domain = dict(name=user_domain_name) - if _domain: - id_obj['password']['user']['domain'] = _domain - - if (project_id or project_name): - _project = dict() - - if project_id: - _project['id'] = project_id - elif project_name: - _project['name'] = project_name - - if project_domain_id is not None: - _project['domain'] = {'id': project_domain_id} - elif project_domain_name is not None: - _project['domain'] = {'name': project_domain_name} - - creds['auth']['scope'] = dict(project=_project) - elif domain_id: - creds['auth']['scope'] = dict(domain={'id': domain_id}) - elif domain_name: - creds['auth']['scope'] = dict(domain={'name': domain_name}) - - body = json.dumps(creds, sort_keys=True) - resp, body = self.post(self.auth_url, body=body) - self.expected_success(201, resp.status) - return rest_client.ResponseBody(resp, body) - - def request(self, method, url, extra_headers=False, headers=None, - body=None, chunked=False): - """A simple HTTP request interface. - - Note: this overloads the `request` method from the parent class and - thus must implement the same method signature. - """ - if headers is None: - # Always accept 'json', for xml token client too. - # Because XML response is not easily - # converted to the corresponding JSON one - headers = self.get_headers(accept_type="json") - elif extra_headers: - try: - headers.update(self.get_headers(accept_type="json")) - except (ValueError, TypeError): - headers = self.get_headers(accept_type="json") - - resp, resp_body = self.raw_request(url, method, - headers=headers, body=body) - self._log_request(method, url, resp, req_headers=headers, - req_body='', resp_body=resp_body) - - if resp.status in [401, 403]: - resp_body = json.loads(resp_body) - raise exceptions.Unauthorized(resp_body['error']['message']) - elif resp.status not in [200, 201, 204]: - raise exceptions.IdentityError( - 'Unexpected status code {0}'.format(resp.status)) - - return resp, json.loads(resp_body) - - def get_token(self, **kwargs): - """Returns (token id, token data) for supplied credentials""" - - auth_data = kwargs.pop('auth_data', False) - - if not (kwargs.get('user_domain_id') or - kwargs.get('user_domain_name')): - kwargs['user_domain_name'] = 'Default' - - if not (kwargs.get('project_domain_id') or - kwargs.get('project_domain_name')): - kwargs['project_domain_name'] = 'Default' - - body = self.auth(**kwargs) - - token = body.response.get('x-subject-token') - if auth_data: - return token, body['token'] - else: - return token - - -class V3TokenClientJSON(V3TokenClient): - LOG = logging.getLogger(__name__) - - def _warn(self): - self.LOG.warning("%s class was deprecated and renamed to %s", - self.__class__.__name__, 'V3TokenClient') - - def __init__(self, *args, **kwargs): - self._warn() - super(V3TokenClientJSON, self).__init__(*args, **kwargs) diff --git a/tempest/lib/services/identity/v3/trusts_client.py b/tempest/lib/services/identity/v3/trusts_client.py deleted file mode 100644 index d113905d7..000000000 --- a/tempest/lib/services/identity/v3/trusts_client.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class TrustsClient(rest_client.RestClient): - api_version = "v3" - - def create_trust(self, **kwargs): - """Creates a trust. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/index.html#create-trust - """ - post_body = json.dumps({'trust': kwargs}) - resp, body = self.post('OS-TRUST/trusts', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_trust(self, trust_id): - """Deletes a trust.""" - resp, body = self.delete("OS-TRUST/trusts/%s" % trust_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_trusts(self, **params): - """Returns trusts - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/index.html#list-trusts - """ - url = "OS-TRUST/trusts/" - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_trust(self, trust_id): - """GET trust.""" - resp, body = self.get("OS-TRUST/trusts/%s" % trust_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_trust_roles(self, trust_id): - """GET roles delegated by a trust.""" - resp, body = self.get("OS-TRUST/trusts/%s/roles" % trust_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_trust_role(self, trust_id, role_id): - """GET role delegated by a trust.""" - resp, body = self.get("OS-TRUST/trusts/%s/roles/%s" - % (trust_id, role_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_trust_role(self, trust_id, role_id): - """HEAD Check if role is delegated by a trust.""" - resp, body = self.head("OS-TRUST/trusts/%s/roles/%s" - % (trust_id, role_id)) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/users_client.py b/tempest/lib/services/identity/v3/users_client.py deleted file mode 100644 index e99a971aa..000000000 --- a/tempest/lib/services/identity/v3/users_client.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class UsersClient(rest_client.RestClient): - api_version = "v3" - - def create_user(self, **kwargs): - """Creates a user. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#create-user - """ - post_body = json.dumps({'user': kwargs}) - resp, body = self.post('users', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user(self, user_id, **kwargs): - """Updates a user. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#update-user - """ - if 'id' not in kwargs: - kwargs['id'] = user_id - post_body = json.dumps({'user': kwargs}) - resp, body = self.patch('users/%s' % user_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user_password(self, user_id, **kwargs): - """Update a user password - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#change-password-for-user - """ - update_user = json.dumps({'user': kwargs}) - resp, _ = self.post('users/%s/password' % user_id, update_user) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def list_user_projects(self, user_id, **params): - """Lists the projects on which a user has roles assigned. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-projects-for-user - """ - url = 'users/%s/projects' % user_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_users(self, **params): - """Get the list of users. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-users - """ - url = 'users' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_user(self, user_id): - """GET a user.""" - resp, body = self.get("users/%s" % user_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_user(self, user_id): - """Deletes a User.""" - resp, body = self.delete("users/%s" % user_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_user_groups(self, user_id, **params): - """Lists groups which a user belongs to. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-groups-to-which-a-user-belongs - """ - url = 'users/%s/groups' % user_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/versions_client.py b/tempest/lib/services/identity/v3/versions_client.py deleted file mode 100644 index 441ee0dd8..000000000 --- a/tempest/lib/services/identity/v3/versions_client.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2017 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class VersionsClient(rest_client.RestClient): - api_version = "v3" - - def list_versions(self): - """List API versions""" - version_url = self._get_base_version_url() - - start = time.time() - resp, body = self.raw_request(version_url, 'GET') - end = time.time() - self._log_request('GET', version_url, resp, secs=(end - start), - resp_body=body) - self._error_checker(resp, body) - - self.expected_success(300, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/image/__init__.py b/tempest/lib/services/image/__init__.py deleted file mode 100644 index 4b01663ea..000000000 --- a/tempest/lib/services/image/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.image import v1 -from tempest.lib.services.image import v2 - -__all__ = ['v1', 'v2'] diff --git a/tempest/lib/services/image/v1/__init__.py b/tempest/lib/services/image/v1/__init__.py deleted file mode 100644 index 9bd8262a8..000000000 --- a/tempest/lib/services/image/v1/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.image.v1.image_members_client import \ - ImageMembersClient -from tempest.lib.services.image.v1.images_client import ImagesClient - -__all__ = ['ImageMembersClient', 'ImagesClient'] diff --git a/tempest/lib/services/image/v1/image_members_client.py b/tempest/lib/services/image/v1/image_members_client.py deleted file mode 100644 index 231808722..000000000 --- a/tempest/lib/services/image/v1/image_members_client.py +++ /dev/null @@ -1,66 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class ImageMembersClient(rest_client.RestClient): - api_version = "v1" - - def list_image_members(self, image_id): - """List all members of an image.""" - url = 'images/%s/members' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_shared_images(self, tenant_id): - """List image memberships for the given tenant. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v1/#list-shared-images - """ - - url = 'shared-images/%s' % tenant_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_image_member(self, image_id, member_id, **kwargs): - """Add a member to an image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v1/#add-member-to-image - """ - url = 'images/%s/members/%s' % (image_id, member_id) - body = json.dumps({'member': kwargs}) - resp, __ = self.put(url, body) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def delete_image_member(self, image_id, member_id): - """Removes a membership from the image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v1/#remove-member - """ - url = 'images/%s/members/%s' % (image_id, member_id) - resp, __ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v1/images_client.py b/tempest/lib/services/image/v1/images_client.py deleted file mode 100644 index 42f8cf212..000000000 --- a/tempest/lib/services/image/v1/images_client.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import functools - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - -CHUNKSIZE = 1024 * 64 # 64kB - - -class ImagesClient(rest_client.RestClient): - api_version = "v1" - - def _create_with_data(self, headers, data): - # We are going to do chunked transfert, so split the input data - # info fixed-sized chunks. - headers['Content-Type'] = 'application/octet-stream' - data = iter(functools.partial(data.read, CHUNKSIZE), b'') - resp, body = self.request('POST', 'images', - headers=headers, body=data, chunked=True) - self._error_checker(resp, body) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def _update_with_data(self, image_id, headers, data): - # We are going to do chunked transfert, so split the input data - # info fixed-sized chunks. - headers['Content-Type'] = 'application/octet-stream' - data = iter(functools.partial(data.read, CHUNKSIZE), b'') - url = 'images/%s' % image_id - resp, body = self.request('PUT', url, headers=headers, - body=data, chunked=True) - self._error_checker(resp, body) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - @property - def http(self): - if self._http is None: - self._http = self._get_http() - return self._http - - def create_image(self, data=None, headers=None): - """Create an image. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/image/v1/index.html#create-image - """ - if headers is None: - headers = {} - - if data is not None: - return self._create_with_data(headers, data) - - resp, body = self.post('images', None, headers) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_image(self, image_id, data=None, headers=None): - """Update an image. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/image/v1/index.html#update-image - """ - if headers is None: - headers = {} - - if data is not None: - return self._update_with_data(image_id, headers, data) - - url = 'images/%s' % image_id - resp, body = self.put(url, None, headers) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_image(self, image_id): - url = 'images/%s' % image_id - resp, body = self.delete(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_images(self, detail=False, **kwargs): - """Return a list of all images filtered by input parameters. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v1/#list-images - - Most parameters except the following are passed to the API without - any changes. - :param changes_since: The name is changed to changes-since - """ - url = 'images' - - if detail: - url += '/detail' - - if 'changes_since' in kwargs: - kwargs['changes-since'] = kwargs.pop('changes_since') - - if kwargs: - url += '?%s' % urllib.urlencode(kwargs) - - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_image(self, image_id): - """Check image metadata.""" - url = 'images/%s' % image_id - resp, body = self.head(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_image(self, image_id): - """Get image details plus the image itself.""" - url = 'images/%s' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBodyData(resp, body) - - def is_resource_deleted(self, id): - try: - resp = self.check_image(id) - if resp.response["x-image-meta-status"] == 'deleted': - return True - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'image_meta' diff --git a/tempest/lib/services/image/v2/__init__.py b/tempest/lib/services/image/v2/__init__.py deleted file mode 100644 index 99a5321b9..000000000 --- a/tempest/lib/services/image/v2/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.image.v2.image_members_client import \ - ImageMembersClient -from tempest.lib.services.image.v2.images_client import ImagesClient -from tempest.lib.services.image.v2.namespace_objects_client import \ - NamespaceObjectsClient -from tempest.lib.services.image.v2.namespace_properties_client import \ - NamespacePropertiesClient -from tempest.lib.services.image.v2.namespace_tags_client import \ - NamespaceTagsClient -from tempest.lib.services.image.v2.namespaces_client import NamespacesClient -from tempest.lib.services.image.v2.resource_types_client import \ - ResourceTypesClient -from tempest.lib.services.image.v2.schemas_client import SchemasClient -from tempest.lib.services.image.v2.versions_client import VersionsClient - -__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespaceObjectsClient', - 'NamespacePropertiesClient', 'NamespaceTagsClient', - 'NamespacesClient', 'ResourceTypesClient', 'SchemasClient', - 'VersionsClient'] diff --git a/tempest/lib/services/image/v2/image_members_client.py b/tempest/lib/services/image/v2/image_members_client.py deleted file mode 100644 index e5118a813..000000000 --- a/tempest/lib/services/image/v2/image_members_client.py +++ /dev/null @@ -1,84 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class ImageMembersClient(rest_client.RestClient): - api_version = "v2" - - def list_image_members(self, image_id): - """List image members. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#list-image-members - """ - url = 'images/%s/members' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_image_member(self, image_id, **kwargs): - """Create an image member. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#create-image-member - """ - url = 'images/%s/members' % image_id - data = json.dumps(kwargs) - resp, body = self.post(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_image_member(self, image_id, member_id, **kwargs): - """Update an image member. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#update-image-member - """ - url = 'images/%s/members/%s' % (image_id, member_id) - data = json.dumps(kwargs) - resp, body = self.put(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_image_member(self, image_id, member_id): - """Show an image member. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#show-image-member-details - """ - url = 'images/%s/members/%s' % (image_id, member_id) - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, json.loads(body)) - - def delete_image_member(self, image_id, member_id): - """Delete an image member. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#delete-image-member - """ - url = 'images/%s/members/%s' % (image_id, member_id) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/images_client.py b/tempest/lib/services/image/v2/images_client.py deleted file mode 100644 index bcdae4454..000000000 --- a/tempest/lib/services/image/v2/images_client.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import functools - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - -CHUNKSIZE = 1024 * 64 # 64kB - - -class ImagesClient(rest_client.RestClient): - api_version = "v2" - - def update_image(self, image_id, patch): - """Update an image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/index.html#update-an-image - """ - data = json.dumps(patch) - headers = {"Content-Type": "application/openstack-images-v2.0" - "-json-patch"} - resp, body = self.patch('images/%s' % image_id, data, headers) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_image(self, **kwargs): - """Create an image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/index.html#create-an-image - """ - data = json.dumps(kwargs) - resp, body = self.post('images', data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def deactivate_image(self, image_id): - """Deactivate image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#deactivate-image - """ - url = 'images/%s/actions/deactivate' % image_id - resp, body = self.post(url, None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def reactivate_image(self, image_id): - """Reactivate image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#reactivate-image - """ - url = 'images/%s/actions/reactivate' % image_id - resp, body = self.post(url, None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_image(self, image_id): - """Delete image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#delete-an-image - """ - url = 'images/%s' % image_id - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def list_images(self, params=None): - """List images. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#show-images - """ - url = 'images' - - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_image(self, image_id): - """Show image details. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#show-image-details - """ - url = 'images/%s' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_image(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'image' - - def store_image_file(self, image_id, data): - """Upload binary image data. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#upload-binary-image-data - """ - url = 'images/%s/file' % image_id - - # We are going to do chunked transfert, so split the input data - # info fixed-sized chunks. - headers = {'Content-Type': 'application/octet-stream'} - data = iter(functools.partial(data.read, CHUNKSIZE), b'') - - resp, body = self.request('PUT', url, headers=headers, - body=data, chunked=True) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_image_file(self, image_id): - """Download binary image data. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#download-binary-image-data - """ - url = 'images/%s/file' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBodyData(resp, body) - - def add_image_tag(self, image_id, tag): - """Add an image tag. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#add-image-tag - """ - url = 'images/%s/tags/%s' % (image_id, tag) - resp, body = self.put(url, body=None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_image_tag(self, image_id, tag): - """Delete an image tag. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#delete-image-tag - """ - url = 'images/%s/tags/%s' % (image_id, tag) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/namespace_objects_client.py b/tempest/lib/services/image/v2/namespace_objects_client.py deleted file mode 100644 index ac2e63e98..000000000 --- a/tempest/lib/services/image/v2/namespace_objects_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2016 EasyStack. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class NamespaceObjectsClient(rest_client.RestClient): - api_version = "v2" - - def list_namespace_objects(self, namespace, **kwargs): - """Lists all namespace objects. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-objects - """ - url = 'metadefs/namespaces/%s/objects' % namespace - if kwargs: - url += '?%s' % urllib.urlencode(kwargs) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_namespace_object(self, namespace, **kwargs): - """Create a namespace object - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-object - """ - url = 'metadefs/namespaces/%s/objects' % namespace - data = json.dumps(kwargs) - resp, body = self.post(url, data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_namespace_object(self, namespace, object_name, **kwargs): - """Update a namespace object - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-object - """ - url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name) - data = json.dumps(kwargs) - resp, body = self.put(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_namespace_object(self, namespace, object_name): - """Show a namespace object - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#show-object - """ - url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_namespace_object(self, namespace, object_name): - """Delete a namespace object - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-object - """ - url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/namespace_properties_client.py b/tempest/lib/services/image/v2/namespace_properties_client.py deleted file mode 100644 index 1236b2b9c..000000000 --- a/tempest/lib/services/image/v2/namespace_properties_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2016 EasyStack. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class NamespacePropertiesClient(rest_client.RestClient): - api_version = "v2" - - def list_namespace_properties(self, namespace): - """Lists property definitions in a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-properties - """ - url = 'metadefs/namespaces/%s/properties' % namespace - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_namespace_property(self, namespace, **kwargs): - """Creates a property definition in a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-property - """ - url = 'metadefs/namespaces/%s/properties' % namespace - data = json.dumps(kwargs) - resp, body = self.post(url, data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_namespace_properties(self, namespace, property_name): - """Shows the definition for a property. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#show-property-definition - """ - url = 'metadefs/namespaces/%s/properties/%s' % (namespace, - property_name) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_namespace_properties(self, namespace, property_name, **kwargs): - """Updates a property definition. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-property-definition - """ - url = 'metadefs/namespaces/%s/properties/%s' % (namespace, - property_name) - data = json.dumps(kwargs) - resp, body = self.put(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_namespace_property(self, namespace, property_name): - """Removes a property definition from a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#remove-property-definition - """ - url = 'metadefs/namespaces/%s/properties/%s' % (namespace, - property_name) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/namespace_tags_client.py b/tempest/lib/services/image/v2/namespace_tags_client.py deleted file mode 100644 index 61cc33ddc..000000000 --- a/tempest/lib/services/image/v2/namespace_tags_client.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright 2016 EasyStack. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class NamespaceTagsClient(rest_client.RestClient): - api_version = "v2" - - def create_namespace_tag(self, namespace, tag_name): - """Adds a tag to the list of namespace tag definitions. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-tag-definition - """ - url = 'metadefs/namespaces/%s/tags/%s' % (namespace, - tag_name) - resp, body = self.post(url, None) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_namespace_tag(self, namespace, tag_name): - """Gets a definition for a tag. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/image/v2/metadefs-index.html#get-tag-definition - """ - url = 'metadefs/namespaces/%s/tags/%s' % (namespace, - tag_name) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_namespace_tag(self, namespace, tag_name, **kwargs): - """Renames a tag definition. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-tag-definition - """ - url = 'metadefs/namespaces/%s/tags/%s' % (namespace, - tag_name) - data = json.dumps(kwargs) - resp, body = self.put(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_namespace_tag(self, namespace, tag_name): - """Deletes a tag definition within a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-tag-definition - """ - url = 'metadefs/namespaces/%s/tags/%s' % (namespace, tag_name) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_namespace_tags(self, namespace, **kwargs): - """Creates one or more tag definitions in a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-tags - """ - url = 'metadefs/namespaces/%s/tags' % namespace - data = json.dumps(kwargs) - resp, body = self.post(url, data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_namespace_tags(self, namespace, **params): - """Lists the tag definitions within a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-tags - """ - url = 'metadefs/namespaces/%s/tags' % namespace - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_namespace_tags(self, namespace): - """Deletes all tag definitions within a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-all-tag-definitions - """ - url = 'metadefs/namespaces/%s/tags' % namespace - resp, _ = self.delete(url) - - # NOTE(rosmaita): Bug 1656183 fixed the success response code for - # this call to make it consistent with the other metadefs delete - # calls. Accept both codes in case tempest is being run against - # an old Glance. - self.expected_success([200, 204], resp.status) - - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/namespaces_client.py b/tempest/lib/services/image/v2/namespaces_client.py deleted file mode 100644 index b00de89f4..000000000 --- a/tempest/lib/services/image/v2/namespaces_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class NamespacesClient(rest_client.RestClient): - api_version = "v2" - - def create_namespace(self, **kwargs): - """Create a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-namespace - """ - data = json.dumps(kwargs) - resp, body = self.post('metadefs/namespaces', data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_namespaces(self): - """List namespaces - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-namespaces - """ - url = 'metadefs/namespaces' - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_namespace(self, namespace): - """Show namespace details. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#get-namespace-details - """ - url = 'metadefs/namespaces/%s' % namespace - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_namespace(self, namespace, **kwargs): - """Update a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-namespace - """ - # NOTE: On Glance API, we need to pass namespace on both URI - # and a request body. - params = {'namespace': namespace} - params.update(kwargs) - data = json.dumps(params) - url = 'metadefs/namespaces/%s' % namespace - resp, body = self.put(url, body=data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_namespace(self, namespace): - """Delete a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-namespace - """ - url = 'metadefs/namespaces/%s' % namespace - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/resource_types_client.py b/tempest/lib/services/image/v2/resource_types_client.py deleted file mode 100644 index 13259d1c7..000000000 --- a/tempest/lib/services/image/v2/resource_types_client.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class ResourceTypesClient(rest_client.RestClient): - api_version = "v2" - - def list_resource_types(self): - """Lists all resource types. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-resource-types - """ - url = 'metadefs/resource_types' - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_resource_type_association(self, namespace_id, **kwargs): - """Creates a resource type association in given namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-resource-type-association - """ - url = 'metadefs/namespaces/%s/resource_types' % namespace_id - data = json.dumps(kwargs) - resp, body = self.post(url, data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_resource_type_association(self, namespace_id): - """Lists resource type associations in given namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-resource-type-associations - """ - url = 'metadefs/namespaces/%s/resource_types' % namespace_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_resource_type_association(self, namespace_id, resource_name): - """Removes resource type association in given namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#remove-resource-type-association - """ - url = 'metadefs/namespaces/%s/resource_types/%s' % (namespace_id, - resource_name) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/schemas_client.py b/tempest/lib/services/image/v2/schemas_client.py deleted file mode 100644 index 0c9db401c..000000000 --- a/tempest/lib/services/image/v2/schemas_client.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class SchemasClient(rest_client.RestClient): - api_version = "v2" - - def show_schema(self, schema): - url = 'schemas/%s' % schema - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/image/v2/versions_client.py b/tempest/lib/services/image/v2/versions_client.py deleted file mode 100644 index 1adc46694..000000000 --- a/tempest/lib/services/image/v2/versions_client.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2017 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class VersionsClient(rest_client.RestClient): - api_version = "v2" - - def list_versions(self): - """List API versions""" - version_url = self._get_base_version_url() - - start = time.time() - resp, body = self.raw_request(version_url, 'GET') - end = time.time() - self._log_request('GET', version_url, resp, secs=(end - start), - resp_body=body) - self._error_checker(resp, body) - - self.expected_success(300, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/network/__init__.py b/tempest/lib/services/network/__init__.py deleted file mode 100644 index 419e59393..000000000 --- a/tempest/lib/services/network/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.network.agents_client import AgentsClient -from tempest.lib.services.network.extensions_client import ExtensionsClient -from tempest.lib.services.network.floating_ips_client import FloatingIPsClient -from tempest.lib.services.network.metering_label_rules_client import \ - MeteringLabelRulesClient -from tempest.lib.services.network.metering_labels_client import \ - MeteringLabelsClient -from tempest.lib.services.network.networks_client import NetworksClient -from tempest.lib.services.network.ports_client import PortsClient -from tempest.lib.services.network.quotas_client import QuotasClient -from tempest.lib.services.network.routers_client import RoutersClient -from tempest.lib.services.network.security_group_rules_client import \ - SecurityGroupRulesClient -from tempest.lib.services.network.security_groups_client import \ - SecurityGroupsClient -from tempest.lib.services.network.service_providers_client import \ - ServiceProvidersClient -from tempest.lib.services.network.subnetpools_client import SubnetpoolsClient -from tempest.lib.services.network.subnets_client import SubnetsClient -from tempest.lib.services.network.tags_client import TagsClient -from tempest.lib.services.network.versions_client import NetworkVersionsClient - -__all__ = ['AgentsClient', 'ExtensionsClient', 'FloatingIPsClient', - 'MeteringLabelRulesClient', 'MeteringLabelsClient', - 'NetworksClient', 'NetworkVersionsClient', 'PortsClient', - 'QuotasClient', 'RoutersClient', 'SecurityGroupRulesClient', - 'SecurityGroupsClient', 'ServiceProvidersClient', - 'SubnetpoolsClient', 'SubnetsClient', 'TagsClient'] diff --git a/tempest/lib/services/network/agents_client.py b/tempest/lib/services/network/agents_client.py deleted file mode 100644 index 9bdf090b0..000000000 --- a/tempest/lib/services/network/agents_client.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class AgentsClient(base.BaseNetworkClient): - - def update_agent(self, agent_id, **kwargs): - """Update agent.""" - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1526673 - uri = '/agents/%s' % agent_id - return self.update_resource(uri, kwargs) - - def show_agent(self, agent_id, **fields): - uri = '/agents/%s' % agent_id - return self.show_resource(uri, **fields) - - def list_agents(self, **filters): - uri = '/agents' - return self.list_resources(uri, **filters) - - def list_routers_on_l3_agent(self, agent_id): - uri = '/agents/%s/l3-routers' % agent_id - return self.list_resources(uri) - - def create_router_on_l3_agent(self, agent_id, **kwargs): - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1526670 - uri = '/agents/%s/l3-routers' % agent_id - return self.create_resource(uri, kwargs, expect_empty_body=True) - - def delete_router_from_l3_agent(self, agent_id, router_id): - uri = '/agents/%s/l3-routers/%s' % (agent_id, router_id) - return self.delete_resource(uri) - - def list_networks_hosted_by_one_dhcp_agent(self, agent_id): - uri = '/agents/%s/dhcp-networks' % agent_id - return self.list_resources(uri) - - def delete_network_from_dhcp_agent(self, agent_id, network_id): - uri = '/agents/%s/dhcp-networks/%s' % (agent_id, - network_id) - return self.delete_resource(uri) - - def add_dhcp_agent_to_network(self, agent_id, **kwargs): - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1526212 - uri = '/agents/%s/dhcp-networks' % agent_id - return self.create_resource(uri, kwargs, expect_empty_body=True) diff --git a/tempest/lib/services/network/base.py b/tempest/lib/services/network/base.py deleted file mode 100644 index fe8b244ea..000000000 --- a/tempest/lib/services/network/base.py +++ /dev/null @@ -1,85 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class BaseNetworkClient(rest_client.RestClient): - - """Base class for Tempest REST clients for Neutron. - - Child classes use v2 of the Neutron API, since the V1 API has been - removed from the code base. - """ - - version = '2.0' - uri_prefix = "v2.0" - - def list_resources(self, uri, **filters): - req_uri = self.uri_prefix + uri - if filters: - req_uri += '?' + urllib.urlencode(filters, doseq=1) - resp, body = self.get(req_uri) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_resource(self, uri): - req_uri = self.uri_prefix + uri - resp, body = self.delete(req_uri) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_resource(self, uri, **fields): - # fields is a dict which key is 'fields' and value is a - # list of field's name. An example: - # {'fields': ['id', 'name']} - req_uri = self.uri_prefix + uri - if fields: - req_uri += '?' + urllib.urlencode(fields, doseq=1) - resp, body = self.get(req_uri) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_resource(self, uri, post_data, expect_empty_body=False, - expect_response_code=201): - req_uri = self.uri_prefix + uri - req_post_data = json.dumps(post_data) - resp, body = self.post(req_uri, req_post_data) - # NOTE: RFC allows both a valid non-empty body and an empty body for - # response of POST API. If a body is expected not empty, we decode the - # body. Otherwise we returns the body as it is. - if not expect_empty_body: - body = json.loads(body) - else: - body = None - self.expected_success(expect_response_code, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_resource(self, uri, post_data, expect_empty_body=False, - expect_response_code=200): - req_uri = self.uri_prefix + uri - req_post_data = json.dumps(post_data) - resp, body = self.put(req_uri, req_post_data) - # NOTE: RFC allows both a valid non-empty body and an empty body for - # response of PUT API. If a body is expected not empty, we decode the - # body. Otherwise we returns the body as it is. - if not expect_empty_body: - body = json.loads(body) - else: - body = None - self.expected_success(expect_response_code, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/network/extensions_client.py b/tempest/lib/services/network/extensions_client.py deleted file mode 100644 index 3910c849c..000000000 --- a/tempest/lib/services/network/extensions_client.py +++ /dev/null @@ -1,24 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class ExtensionsClient(base.BaseNetworkClient): - - def show_extension(self, ext_alias, **fields): - uri = '/extensions/%s' % ext_alias - return self.show_resource(uri, **fields) - - def list_extensions(self, **filters): - uri = '/extensions' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/floating_ips_client.py b/tempest/lib/services/network/floating_ips_client.py deleted file mode 100644 index 2bb18e03f..000000000 --- a/tempest/lib/services/network/floating_ips_client.py +++ /dev/null @@ -1,65 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class FloatingIPsClient(base.BaseNetworkClient): - - def create_floatingip(self, **kwargs): - """Creates a floating IP. - - If you specify port information, associates the floating IP with an - internal port. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-floating-ip - """ - uri = '/floatingips' - post_data = {'floatingip': kwargs} - return self.create_resource(uri, post_data) - - def update_floatingip(self, floatingip_id, **kwargs): - """Updates a floating IP and its association with an internal port. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-floating-ip - """ - uri = '/floatingips/%s' % floatingip_id - post_data = {'floatingip': kwargs} - return self.update_resource(uri, post_data) - - def show_floatingip(self, floatingip_id, **fields): - """Shows details for a floating IP. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-floating-ip-details - """ - uri = '/floatingips/%s' % floatingip_id - return self.show_resource(uri, **fields) - - def delete_floatingip(self, floatingip_id): - uri = '/floatingips/%s' % floatingip_id - return self.delete_resource(uri) - - def list_floatingips(self, **filters): - """Lists floating IPs. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-floating-ips - """ - uri = '/floatingips' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/metering_label_rules_client.py b/tempest/lib/services/network/metering_label_rules_client.py deleted file mode 100644 index 36cf8e30a..000000000 --- a/tempest/lib/services/network/metering_label_rules_client.py +++ /dev/null @@ -1,33 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class MeteringLabelRulesClient(base.BaseNetworkClient): - - def create_metering_label_rule(self, **kwargs): - uri = '/metering/metering-label-rules' - post_data = {'metering_label_rule': kwargs} - return self.create_resource(uri, post_data) - - def show_metering_label_rule(self, metering_label_rule_id, **fields): - uri = '/metering/metering-label-rules/%s' % metering_label_rule_id - return self.show_resource(uri, **fields) - - def delete_metering_label_rule(self, metering_label_rule_id): - uri = '/metering/metering-label-rules/%s' % metering_label_rule_id - return self.delete_resource(uri) - - def list_metering_label_rules(self, **filters): - uri = '/metering/metering-label-rules' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/metering_labels_client.py b/tempest/lib/services/network/metering_labels_client.py deleted file mode 100644 index 411da1f47..000000000 --- a/tempest/lib/services/network/metering_labels_client.py +++ /dev/null @@ -1,57 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class MeteringLabelsClient(base.BaseNetworkClient): - - def create_metering_label(self, **kwargs): - """Creates an L3 metering label. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-metering-label - """ - uri = '/metering/metering-labels' - post_data = {'metering_label': kwargs} - return self.create_resource(uri, post_data) - - def show_metering_label(self, metering_label_id, **fields): - """Shows details for a metering label. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-metering-label-details - """ - uri = '/metering/metering-labels/%s' % metering_label_id - return self.show_resource(uri, **fields) - - def delete_metering_label(self, metering_label_id): - """Deletes an L3 metering label. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#delete-metering-label - """ - uri = '/metering/metering-labels/%s' % metering_label_id - return self.delete_resource(uri) - - def list_metering_labels(self, **filters): - """Lists all L3 metering labels that belong to the tenant. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-metering-labels - """ - uri = '/metering/metering-labels' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/networks_client.py b/tempest/lib/services/network/networks_client.py deleted file mode 100644 index 77d482331..000000000 --- a/tempest/lib/services/network/networks_client.py +++ /dev/null @@ -1,76 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class NetworksClient(base.BaseNetworkClient): - - def create_network(self, **kwargs): - """Creates a network. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-network - """ - uri = '/networks' - post_data = {'network': kwargs} - return self.create_resource(uri, post_data) - - def update_network(self, network_id, **kwargs): - """Updates a network. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-network - """ - uri = '/networks/%s' % network_id - post_data = {'network': kwargs} - return self.update_resource(uri, post_data) - - def show_network(self, network_id, **fields): - """Shows details for a network. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-network-details - """ - uri = '/networks/%s' % network_id - return self.show_resource(uri, **fields) - - def delete_network(self, network_id): - uri = '/networks/%s' % network_id - return self.delete_resource(uri) - - def list_networks(self, **filters): - """Lists networks to which the tenant has access. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-networks - """ - uri = '/networks' - return self.list_resources(uri, **filters) - - def create_bulk_networks(self, **kwargs): - """Create multiple networks in a single request. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#bulk-create-networks - """ - uri = '/networks' - return self.create_resource(uri, kwargs) - - def list_dhcp_agents_on_hosting_network(self, network_id): - uri = '/networks/%s/dhcp-agents' % network_id - return self.list_resources(uri) diff --git a/tempest/lib/services/network/ports_client.py b/tempest/lib/services/network/ports_client.py deleted file mode 100644 index daa15d759..000000000 --- a/tempest/lib/services/network/ports_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.network import base - - -class PortsClient(base.BaseNetworkClient): - - def create_port(self, **kwargs): - """Creates a port on a network. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-port - """ - uri = '/ports' - post_data = {'port': kwargs} - return self.create_resource(uri, post_data) - - def update_port(self, port_id, **kwargs): - """Updates a port. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-port - """ - uri = '/ports/%s' % port_id - post_data = {'port': kwargs} - return self.update_resource(uri, post_data) - - def show_port(self, port_id, **fields): - """Shows details for a port. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-port-details - """ - uri = '/ports/%s' % port_id - return self.show_resource(uri, **fields) - - def delete_port(self, port_id): - """Deletes a port. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#delete-port - """ - uri = '/ports/%s' % port_id - return self.delete_resource(uri) - - def list_ports(self, **filters): - """Lists ports to which the tenant has access. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-ports - """ - uri = '/ports' - return self.list_resources(uri, **filters) - - def create_bulk_ports(self, **kwargs): - """Create multiple ports in a single request. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#bulk-create-ports - """ - uri = '/ports' - return self.create_resource(uri, kwargs) - - def is_resource_deleted(self, id): - try: - self.show_port(id) - except lib_exc.NotFound: - return True - return False diff --git a/tempest/lib/services/network/quotas_client.py b/tempest/lib/services/network/quotas_client.py deleted file mode 100644 index 752b253f4..000000000 --- a/tempest/lib/services/network/quotas_client.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class QuotasClient(base.BaseNetworkClient): - - def update_quotas(self, tenant_id, **kwargs): - put_body = {'quota': kwargs} - uri = '/quotas/%s' % tenant_id - return self.update_resource(uri, put_body) - - def reset_quotas(self, tenant_id): # noqa - # NOTE: This noqa is for passing T111 check and we cannot rename - # to keep backwards compatibility. - uri = '/quotas/%s' % tenant_id - return self.delete_resource(uri) - - def show_quotas(self, tenant_id, **fields): - uri = '/quotas/%s' % tenant_id - return self.show_resource(uri, **fields) - - def list_quotas(self, **filters): - uri = '/quotas' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/routers_client.py b/tempest/lib/services/network/routers_client.py deleted file mode 100644 index 19b7627df..000000000 --- a/tempest/lib/services/network/routers_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class RoutersClient(base.BaseNetworkClient): - - def create_router(self, **kwargs): - """Create a router. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-router - """ - post_body = {'router': kwargs} - uri = '/routers' - return self.create_resource(uri, post_body) - - def update_router(self, router_id, **kwargs): - """Updates a logical router. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-router - """ - uri = '/routers/%s' % router_id - update_body = {'router': kwargs} - return self.update_resource(uri, update_body) - - def show_router(self, router_id, **fields): - """Shows details for a router. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-router-details - """ - uri = '/routers/%s' % router_id - return self.show_resource(uri, **fields) - - def delete_router(self, router_id): - uri = '/routers/%s' % router_id - return self.delete_resource(uri) - - def list_routers(self, **filters): - """Lists logical routers. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-routers - """ - uri = '/routers' - return self.list_resources(uri, **filters) - - def add_router_interface(self, router_id, **kwargs): - """Add router interface. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#add-interface-to-router - """ - uri = '/routers/%s/add_router_interface' % router_id - return self.update_resource(uri, kwargs) - - def remove_router_interface(self, router_id, **kwargs): - """Remove router interface. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#remove-interface-from-router - """ - uri = '/routers/%s/remove_router_interface' % router_id - return self.update_resource(uri, kwargs) - - def list_l3_agents_hosting_router(self, router_id): - uri = '/routers/%s/l3-agents' % router_id - return self.list_resources(uri) diff --git a/tempest/lib/services/network/security_group_rules_client.py b/tempest/lib/services/network/security_group_rules_client.py deleted file mode 100644 index d2bc4a9c5..000000000 --- a/tempest/lib/services/network/security_group_rules_client.py +++ /dev/null @@ -1,51 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class SecurityGroupRulesClient(base.BaseNetworkClient): - - def create_security_group_rule(self, **kwargs): - """Creates an OpenStack Networking security group rule. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-security-group-rule - """ - uri = '/security-group-rules' - post_data = {'security_group_rule': kwargs} - return self.create_resource(uri, post_data) - - def show_security_group_rule(self, security_group_rule_id, **fields): - """Shows detailed information for a security group rule. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-security-group-rule - """ - uri = '/security-group-rules/%s' % security_group_rule_id - return self.show_resource(uri, **fields) - - def delete_security_group_rule(self, security_group_rule_id): - uri = '/security-group-rules/%s' % security_group_rule_id - return self.delete_resource(uri) - - def list_security_group_rules(self, **filters): - """Lists a summary of all OpenStack Networking security group rules. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-security-group-rules - """ - uri = '/security-group-rules' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/security_groups_client.py b/tempest/lib/services/network/security_groups_client.py deleted file mode 100644 index 1f30216f7..000000000 --- a/tempest/lib/services/network/security_groups_client.py +++ /dev/null @@ -1,68 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class SecurityGroupsClient(base.BaseNetworkClient): - - def create_security_group(self, **kwargs): - """Creates an OpenStack Networking security group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-security-group - """ - uri = '/security-groups' - post_data = {'security_group': kwargs} - return self.create_resource(uri, post_data) - - def update_security_group(self, security_group_id, **kwargs): - """Updates a security group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-security-group - """ - uri = '/security-groups/%s' % security_group_id - post_data = {'security_group': kwargs} - return self.update_resource(uri, post_data) - - def show_security_group(self, security_group_id, **fields): - """Shows details for a security group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-security-group - """ - uri = '/security-groups/%s' % security_group_id - return self.show_resource(uri, **fields) - - def delete_security_group(self, security_group_id): - """Deletes an OpenStack Networking security group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#delete-security-group - """ - uri = '/security-groups/%s' % security_group_id - return self.delete_resource(uri) - - def list_security_groups(self, **filters): - """Lists OpenStack Networking security groups. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-security-groups - """ - uri = '/security-groups' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/service_providers_client.py b/tempest/lib/services/network/service_providers_client.py deleted file mode 100644 index 0ee9bc32a..000000000 --- a/tempest/lib/services/network/service_providers_client.py +++ /dev/null @@ -1,21 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class ServiceProvidersClient(base.BaseNetworkClient): - - def list_service_providers(self, **filters): - """Lists service providers.""" - uri = '/service-providers' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/subnetpools_client.py b/tempest/lib/services/network/subnetpools_client.py deleted file mode 100644 index 7e77e3026..000000000 --- a/tempest/lib/services/network/subnetpools_client.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class SubnetpoolsClient(base.BaseNetworkClient): - - def list_subnetpools(self, **filters): - """Lists subnet pools to which the tenant has access. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-subnet-pools - """ - uri = '/subnetpools' - return self.list_resources(uri, **filters) - - def create_subnetpool(self, **kwargs): - """Creates a subnet pool. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-subnet-pool - """ - uri = '/subnetpools' - post_data = {'subnetpool': kwargs} - return self.create_resource(uri, post_data) - - def show_subnetpool(self, subnetpool_id, **fields): - """Shows information for a subnet pool. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-subnet-pool - """ - uri = '/subnetpools/%s' % subnetpool_id - return self.show_resource(uri, **fields) - - def update_subnetpool(self, subnetpool_id, **kwargs): - """Updates a subnet pool. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-subnet-pool - """ - uri = '/subnetpools/%s' % subnetpool_id - post_data = {'subnetpool': kwargs} - return self.update_resource(uri, post_data) - - def delete_subnetpool(self, subnetpool_id): - uri = '/subnetpools/%s' % subnetpool_id - return self.delete_resource(uri) diff --git a/tempest/lib/services/network/subnets_client.py b/tempest/lib/services/network/subnets_client.py deleted file mode 100644 index b843f840a..000000000 --- a/tempest/lib/services/network/subnets_client.py +++ /dev/null @@ -1,72 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import base - - -class SubnetsClient(base.BaseNetworkClient): - - def create_subnet(self, **kwargs): - """Creates a subnet on a network. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-subnet - """ - uri = '/subnets' - post_data = {'subnet': kwargs} - return self.create_resource(uri, post_data) - - def update_subnet(self, subnet_id, **kwargs): - """Updates a subnet. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-subnet - """ - uri = '/subnets/%s' % subnet_id - post_data = {'subnet': kwargs} - return self.update_resource(uri, post_data) - - def show_subnet(self, subnet_id, **fields): - """Shows details for a subnet. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-subnet-details - """ - uri = '/subnets/%s' % subnet_id - return self.show_resource(uri, **fields) - - def delete_subnet(self, subnet_id): - uri = '/subnets/%s' % subnet_id - return self.delete_resource(uri) - - def list_subnets(self, **filters): - """Lists subnets to which the tenant has access. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-subnets - """ - uri = '/subnets' - return self.list_resources(uri, **filters) - - def create_bulk_subnets(self, **kwargs): - """Create multiple subnets in a single request. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#bulk-create-subnet - """ - uri = '/subnets' - return self.create_resource(uri, kwargs) diff --git a/tempest/lib/services/network/tags_client.py b/tempest/lib/services/network/tags_client.py deleted file mode 100644 index 5d49a79c2..000000000 --- a/tempest/lib/services/network/tags_client.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib.services.network import base - - -class TagsClient(base.BaseNetworkClient): - - def create_tag(self, resource_type, resource_id, tag): - """Adds a tag on the resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#add-a-tag - """ - uri = '/%s/%s/tags/%s' % (resource_type, resource_id, tag) - return self.update_resource( - uri, json.dumps({}), expect_response_code=201, - expect_empty_body=True) - - def check_tag_existence(self, resource_type, resource_id, tag): - """Confirm that a given tag is set on the resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#confirm-a-tag - """ - # TODO(felipemonteiro): Use the "check_resource" method in - # ``BaseNetworkClient`` once it has been implemented. - uri = '%s/%s/%s/tags/%s' % ( - self.uri_prefix, resource_type, resource_id, tag) - resp, _ = self.get(uri) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def update_all_tags(self, resource_type, resource_id, tags): - """Replace all tags on the resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#replace-all-tags - """ - uri = '/%s/%s/tags' % (resource_type, resource_id) - put_body = {"tags": tags} - return self.update_resource(uri, put_body) - - def delete_tag(self, resource_type, resource_id, tag): - """Removes a tag on the resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#remove-a-tag - """ - uri = '/%s/%s/tags/%s' % (resource_type, resource_id, tag) - return self.delete_resource(uri) - - def delete_all_tags(self, resource_type, resource_id): - """Removes all tags on the resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#remove-all-tags - """ - uri = '/%s/%s/tags' % (resource_type, resource_id) - return self.delete_resource(uri) - - def list_tags(self, resource_type, resource_id): - """Retrieves the tags for a resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#obtain-tag-list - """ - uri = '/%s/%s/tags' % (resource_type, resource_id) - return self.list_resources(uri) diff --git a/tempest/lib/services/network/versions_client.py b/tempest/lib/services/network/versions_client.py deleted file mode 100644 index a9c3bbfb8..000000000 --- a/tempest/lib/services/network/versions_client.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2016 VMware, Inc. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from oslo_serialization import jsonutils as json -from six.moves import urllib - -from tempest.lib.services.network import base - - -class NetworkVersionsClient(base.BaseNetworkClient): - - def list_versions(self): - """Do a GET / to fetch available API version information.""" - - endpoint = self.base_url - url = urllib.parse.urlparse(endpoint) - version_url = '%s://%s/' % (url.scheme, url.netloc) - - # Note: we do a raw_request here because we want to use - # an unversioned URL, not "v2/$project_id/". - # Since raw_request doesn't log anything, we do that too. - start = time.time() - self._log_request_start('GET', version_url) - response, body = self.raw_request(version_url, 'GET') - self._error_checker(response, body) - end = time.time() - self._log_request('GET', version_url, response, - secs=(end - start), resp_body=body) - - self.response_checker('GET', response, body) - self.expected_success(200, response.status) - body = json.loads(body) - return body diff --git a/tempest/lib/services/volume/__init__.py b/tempest/lib/services/volume/__init__.py deleted file mode 100644 index 6855d8ee8..000000000 --- a/tempest/lib/services/volume/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.volume import v1 -from tempest.lib.services.volume import v2 -from tempest.lib.services.volume import v3 - -__all__ = ['v1', 'v2', 'v3'] diff --git a/tempest/lib/services/volume/base_client.py b/tempest/lib/services/volume/base_client.py deleted file mode 100644 index c7fb21a97..000000000 --- a/tempest/lib/services/volume/base_client.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2016 Andrew Kerr -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.common import api_version_utils -from tempest.lib.common import rest_client - -VOLUME_MICROVERSION = None - - -class BaseClient(rest_client.RestClient): - """Base volume service clients class to support microversion.""" - api_microversion_header_name = 'Openstack-Api-Version' - - def get_headers(self, accept_type=None, send_type=None): - headers = super(BaseClient, self).get_headers( - accept_type=accept_type, send_type=send_type) - if VOLUME_MICROVERSION: - headers[self.api_microversion_header_name] = ('volume %s' % - VOLUME_MICROVERSION) - return headers - - def request(self, method, url, extra_headers=False, headers=None, - body=None, chunked=False): - - resp, resp_body = super(BaseClient, self).request( - method, url, extra_headers, headers, body, chunked) - if (VOLUME_MICROVERSION and - VOLUME_MICROVERSION != api_version_utils.LATEST_MICROVERSION): - api_version_utils.assert_version_header_matches_request( - self.api_microversion_header_name, - 'volume %s' % VOLUME_MICROVERSION, - resp) - return resp, resp_body diff --git a/tempest/lib/services/volume/v1/__init__.py b/tempest/lib/services/volume/v1/__init__.py deleted file mode 100644 index 7b5991f73..000000000 --- a/tempest/lib/services/volume/v1/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.volume.v1.availability_zone_client \ - import AvailabilityZoneClient -from tempest.lib.services.volume.v1.backups_client import BackupsClient -from tempest.lib.services.volume.v1.encryption_types_client import \ - EncryptionTypesClient -from tempest.lib.services.volume.v1.extensions_client import ExtensionsClient -from tempest.lib.services.volume.v1.hosts_client import HostsClient -from tempest.lib.services.volume.v1.limits_client import LimitsClient -from tempest.lib.services.volume.v1.qos_client import QosSpecsClient -from tempest.lib.services.volume.v1.quotas_client import QuotasClient -from tempest.lib.services.volume.v1.services_client import ServicesClient -from tempest.lib.services.volume.v1.snapshots_client import SnapshotsClient -from tempest.lib.services.volume.v1.types_client import TypesClient -from tempest.lib.services.volume.v1.volumes_client import VolumesClient - -__all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient', - 'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient', - 'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient', - 'LimitsClient'] diff --git a/tempest/lib/services/volume/v1/availability_zone_client.py b/tempest/lib/services/volume/v1/availability_zone_client.py deleted file mode 100644 index be4f53928..000000000 --- a/tempest/lib/services/volume/v1/availability_zone_client.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2014 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class AvailabilityZoneClient(rest_client.RestClient): - """Volume V1 availability zone client.""" - - def list_availability_zones(self): - resp, body = self.get('os-availability-zone') - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/backups_client.py b/tempest/lib/services/volume/v1/backups_client.py deleted file mode 100644 index 867791374..000000000 --- a/tempest/lib/services/volume/v1/backups_client.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class BackupsClient(rest_client.RestClient): - """Volume V1 Backups client""" - api_version = "v1" - - def create_backup(self, **kwargs): - """Creates a backup of volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-backup - """ - post_body = json.dumps({'backup': kwargs}) - resp, body = self.post('backups', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def restore_backup(self, backup_id, **kwargs): - """Restore volume from backup. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#restore-backup - """ - post_body = json.dumps({'restore': kwargs}) - resp, body = self.post('backups/%s/restore' % (backup_id), post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_backup(self, backup_id): - """Delete a backup of volume.""" - resp, body = self.delete('backups/%s' % backup_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_backup(self, backup_id): - """Returns the details of a single backup.""" - url = "backups/%s" % backup_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_backups(self, detail=False): - """Information for all the tenant's backups.""" - url = "backups" - if detail: - url += "/detail" - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def export_backup(self, backup_id): - """Export backup metadata record.""" - url = "backups/%s/export_record" % backup_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def import_backup(self, **kwargs): - """Import backup metadata record.""" - post_body = json.dumps({'backup-record': kwargs}) - resp, body = self.post("backups/import_record", post_body) - body = json.loads(body) - self.expected_success(201, resp.status) - return rest_client.ResponseBody(resp, body) - - def reset_backup_status(self, backup_id, status): - """Reset the specified backup's status.""" - post_body = json.dumps({'os-reset_status': {"status": status}}) - resp, body = self.post('backups/%s/action' % backup_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_backup(id) - except lib_exc.NotFound: - return True - return False diff --git a/tempest/lib/services/volume/v1/encryption_types_client.py b/tempest/lib/services/volume/v1/encryption_types_client.py deleted file mode 100755 index 067b4e823..000000000 --- a/tempest/lib/services/volume/v1/encryption_types_client.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class EncryptionTypesClient(rest_client.RestClient): - - def is_resource_deleted(self, id): - try: - body = self.show_encryption_type(id) - if not body: - return True - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'encryption-type' - - def show_encryption_type(self, volume_type_id): - """Get the volume encryption type for the specified volume type. - - volume_type_id: Id of volume_type. - """ - url = "/types/%s/encryption" % volume_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_encryption_type(self, volume_type_id, **kwargs): - """Create encryption type. - - TODO: Current api-site doesn't contain this API description. - After fixing the api-site, we need to fix here also for putting - the link to api-site. - """ - url = "/types/%s/encryption" % volume_type_id - post_body = json.dumps({'encryption': kwargs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_encryption_type(self, volume_type_id): - """Delete the encryption type for the specified volume-type.""" - resp, body = self.delete( - "/types/%s/encryption/provider" % volume_type_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/extensions_client.py b/tempest/lib/services/volume/v1/extensions_client.py deleted file mode 100644 index 7b849a83d..000000000 --- a/tempest/lib/services/volume/v1/extensions_client.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class ExtensionsClient(rest_client.RestClient): - """Volume V1 extensions client.""" - - def list_extensions(self): - url = 'extensions' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/hosts_client.py b/tempest/lib/services/volume/v1/hosts_client.py deleted file mode 100644 index 56ba12c5b..000000000 --- a/tempest/lib/services/volume/v1/hosts_client.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class HostsClient(rest_client.RestClient): - """Client class to send CRUD Volume Host API V1 requests""" - - def list_hosts(self, **params): - """Lists all hosts.""" - - url = 'os-hosts' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/limits_client.py b/tempest/lib/services/volume/v1/limits_client.py deleted file mode 100644 index e14b2dc92..000000000 --- a/tempest/lib/services/volume/v1/limits_client.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class LimitsClient(rest_client.RestClient): - """Volume V1 limits client.""" - - api_version = "v1" - - def show_limits(self): - """Returns the details of a volume absolute limits.""" - url = "limits" - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/qos_client.py b/tempest/lib/services/volume/v1/qos_client.py deleted file mode 100644 index e247b7b7c..000000000 --- a/tempest/lib/services/volume/v1/qos_client.py +++ /dev/null @@ -1,131 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class QosSpecsClient(rest_client.RestClient): - """Volume V1 QoS client. - - Client class to send CRUD QoS API requests - """ - - api_version = "v1" - - def is_resource_deleted(self, qos_id): - try: - self.show_qos(qos_id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'qos' - - def create_qos(self, **kwargs): - """Create a QoS Specification. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-qos-specification - """ - post_body = json.dumps({'qos_specs': kwargs}) - resp, body = self.post('qos-specs', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_qos(self, qos_id, force=False): - """Delete the specified QoS specification.""" - resp, body = self.delete( - "qos-specs/%s?force=%s" % (qos_id, force)) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_qos(self): - """List all the QoS specifications created.""" - url = 'qos-specs' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_qos(self, qos_id): - """Get the specified QoS specification.""" - url = "qos-specs/%s" % qos_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def set_qos_key(self, qos_id, **kwargs): - """Set the specified keys/values of QoS specification. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#set-keys-in-qos-specification - """ - put_body = json.dumps({"qos_specs": kwargs}) - resp, body = self.put('qos-specs/%s' % qos_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def unset_qos_key(self, qos_id, keys): - """Unset the specified keys of QoS specification. - - :param keys: keys to delete from the QoS specification. - - TODO(jordanP): Add a link once LP #1524877 is fixed. - """ - put_body = json.dumps({'keys': keys}) - resp, body = self.put('qos-specs/%s/delete_keys' % qos_id, put_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def associate_qos(self, qos_id, vol_type_id): - """Associate the specified QoS with specified volume-type.""" - url = "qos-specs/%s/associate" % qos_id - url += "?vol_type_id=%s" % vol_type_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_association_qos(self, qos_id): - """Get the association of the specified QoS specification.""" - url = "qos-specs/%s/associations" % qos_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def disassociate_qos(self, qos_id, vol_type_id): - """Disassociate the specified QoS with specified volume-type.""" - url = "qos-specs/%s/disassociate" % qos_id - url += "?vol_type_id=%s" % vol_type_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def disassociate_all_qos(self, qos_id): - """Disassociate the specified QoS with all associations.""" - url = "qos-specs/%s/disassociate_all" % qos_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/quotas_client.py b/tempest/lib/services/volume/v1/quotas_client.py deleted file mode 100644 index 678fd8234..000000000 --- a/tempest/lib/services/volume/v1/quotas_client.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (C) 2014 eNovance SAS -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class QuotasClient(rest_client.RestClient): - """Client class to send CRUD Volume Quotas API V1 requests""" - - def show_default_quota_set(self, tenant_id): - """List the default volume quota set for a tenant.""" - - url = 'os-quota-sets/%s/defaults' % tenant_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_quota_set(self, tenant_id, params=None): - """List the quota set for a tenant.""" - - url = 'os-quota-sets/%s' % tenant_id - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_quota_set(self, tenant_id, **kwargs): - """Updates quota set - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref-blockstorage-v1.html#updateQuota - """ - put_body = jsonutils.dumps({'quota_set': kwargs}) - resp, body = self.put('os-quota-sets/%s' % tenant_id, put_body) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_quota_set(self, tenant_id): - """Delete the tenant's quota set.""" - resp, body = self.delete('os-quota-sets/%s' % tenant_id) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/services_client.py b/tempest/lib/services/volume/v1/services_client.py deleted file mode 100644 index d438a34ec..000000000 --- a/tempest/lib/services/volume/v1/services_client.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2014 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ServicesClient(rest_client.RestClient): - """Volume V1 volume services client""" - - def list_services(self, **params): - url = 'os-services' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/snapshots_client.py b/tempest/lib/services/volume/v1/snapshots_client.py deleted file mode 100644 index 3433e6811..000000000 --- a/tempest/lib/services/volume/v1/snapshots_client.py +++ /dev/null @@ -1,186 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class SnapshotsClient(rest_client.RestClient): - """Client class to send CRUD Volume V1 API requests.""" - - create_resp = 200 - - def list_snapshots(self, detail=False, **params): - """List all the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#list-snapshots-with-details-v1 - """ - url = 'snapshots' - if detail: - url += '/detail' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_snapshot(self, snapshot_id): - """Returns the details of a single snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#show-snapshot-details-v1 - """ - url = "snapshots/%s" % snapshot_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_snapshot(self, **kwargs): - """Creates a new snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#create-snapshot-v1 - """ - post_body = json.dumps({'snapshot': kwargs}) - resp, body = self.post('snapshots', post_body) - body = json.loads(body) - self.expected_success(self.create_resp, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_snapshot(self, snapshot_id): - """Delete Snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#delete-snapshot-v1 - """ - resp, body = self.delete("snapshots/%s" % snapshot_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_snapshot(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume-snapshot' - - def reset_snapshot_status(self, snapshot_id, status): - """Reset the specified snapshot's status.""" - post_body = json.dumps({'os-reset_status': {"status": status}}) - resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_status(self, snapshot_id, **kwargs): - """Update the specified snapshot's status.""" - # TODO(gmann): api-site doesn't contain doc ref - # for this API. After fixing the api-site, we need to - # add the link here. - # Bug https://bugs.launchpad.net/openstack-api-site/+bug/1532645 - - post_body = json.dumps({'os-update_snapshot_status': kwargs}) - url = 'snapshots/%s/action' % snapshot_id - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_snapshot_metadata(self, snapshot_id, metadata): - """Create metadata for the snapshot.""" - put_body = json.dumps({'metadata': metadata}) - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.post(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot(self, snapshot_id, **kwargs): - """Updates a snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#update-snapshot-v1 - """ - put_body = json.dumps({'snapshot': kwargs}) - resp, body = self.put('snapshots/%s' % snapshot_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_snapshot_metadata(self, snapshot_id): - """Get metadata of the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#show-snapshot-metadata-v1 - """ - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_metadata(self, snapshot_id, **kwargs): - """Update metadata for the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#update-snapshot-metadata-v1 - """ - put_body = json.dumps(kwargs) - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_metadata_item(self, snapshot_id, id, **kwargs): - """Update metadata item for the snapshot.""" - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1529064 - put_body = json.dumps(kwargs) - url = "snapshots/%s/metadata/%s" % (snapshot_id, id) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_snapshot_metadata_item(self, snapshot_id, id): - """Delete metadata item for the snapshot.""" - url = "snapshots/%s/metadata/%s" % (snapshot_id, id) - resp, body = self.delete(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def force_delete_snapshot(self, snapshot_id): - """Force Delete Snapshot.""" - post_body = json.dumps({'os-force_delete': {}}) - resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/types_client.py b/tempest/lib/services/volume/v1/types_client.py deleted file mode 100644 index 4ae99357d..000000000 --- a/tempest/lib/services/volume/v1/types_client.py +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class TypesClient(rest_client.RestClient): - """Client class to send CRUD Volume Types API requests""" - - def is_resource_deleted(self, id): - try: - self.show_volume_type(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume-type' - - def list_volume_types(self, **params): - """List all the volume_types created. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#list-volume-types-v1 - """ - url = 'types' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_type(self, volume_type_id): - """Returns the details of a single volume_type. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#show-volume-type-v1 - """ - url = "types/%s" % volume_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_type(self, **kwargs): - """Create volume type. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#create-volume-type-v1 - """ - post_body = json.dumps({'volume_type': kwargs}) - resp, body = self.post('types', post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_type(self, volume_type_id): - """Deletes the Specified Volume_type. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#delete-volume-type-v1 - """ - resp, body = self.delete("types/%s" % volume_type_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_volume_types_extra_specs(self, volume_type_id, **params): - """List all the volume_types extra specs created. - - TODO: Current api-site doesn't contain this API description. - After fixing the api-site, we need to fix here also for putting - the link to api-site. - """ - url = 'types/%s/extra_specs' % volume_type_id - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_type_extra_specs(self, volume_type_id, extra_specs_name): - """Returns the details of a single volume_type extra spec.""" - url = "types/%s/extra_specs/%s" % (volume_type_id, extra_specs_name) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_type_extra_specs(self, volume_type_id, extra_specs): - """Creates a new Volume_type extra spec. - - volume_type_id: Id of volume_type. - extra_specs: A dictionary of values to be used as extra_specs. - """ - url = "types/%s/extra_specs" % volume_type_id - post_body = json.dumps({'extra_specs': extra_specs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_type_extra_specs(self, volume_type_id, extra_spec_name): - """Deletes the Specified Volume_type extra spec.""" - resp, body = self.delete("types/%s/extra_specs/%s" % ( - volume_type_id, extra_spec_name)) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_type(self, volume_type_id, **kwargs): - """Updates volume type name, description, and/or is_public. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#update-volume-type-v1 - """ - put_body = json.dumps({'volume_type': kwargs}) - resp, body = self.put('types/%s' % volume_type_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_type_extra_specs(self, volume_type_id, extra_spec_name, - extra_specs): - """Update a volume_type extra spec. - - volume_type_id: Id of volume_type. - extra_spec_name: Name of the extra spec to be updated. - extra_spec: A dictionary of with key as extra_spec_name and the - updated value. - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#update-extra-specs-for-a-volume-type-v1 - """ - url = "types/%s/extra_specs/%s" % (volume_type_id, extra_spec_name) - put_body = json.dumps(extra_specs) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/volumes_client.py b/tempest/lib/services/volume/v1/volumes_client.py deleted file mode 100644 index 7a256979f..000000000 --- a/tempest/lib/services/volume/v1/volumes_client.py +++ /dev/null @@ -1,301 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -import six -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class VolumesClient(rest_client.RestClient): - """Client class to send CRUD Volume V1 API requests""" - - def _prepare_params(self, params): - """Prepares params for use in get or _ext_get methods. - - If params is a string it will be left as it is, but if it's not it will - be urlencoded. - """ - if isinstance(params, six.string_types): - return params - return urllib.urlencode(params) - - def list_volumes(self, detail=False, params=None): - """List all the volumes created. - - Params can be a string (must be urlencoded) or a dictionary. - """ - url = 'volumes' - if detail: - url += '/detail' - if params: - url += '?%s' % self._prepare_params(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume(self, volume_id): - """Returns the details of a single volume.""" - url = "volumes/%s" % volume_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume(self, **kwargs): - """Creates a new Volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#create-volume - """ - post_body = json.dumps({'volume': kwargs}) - resp, body = self.post('volumes', post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume(self, volume_id, **kwargs): - """Updates the Specified Volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#update-volume - """ - put_body = json.dumps({'volume': kwargs}) - resp, body = self.put('volumes/%s' % volume_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume(self, volume_id): - """Deletes the Specified Volume.""" - resp, body = self.delete("volumes/%s" % volume_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def upload_volume(self, volume_id, **kwargs): - """Uploads a volume in Glance.""" - post_body = json.dumps({'os-volume_upload_image': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def attach_volume(self, volume_id, **kwargs): - """Attaches a volume to a given instance on a given mountpoint. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#attach-volume - """ - post_body = json.dumps({'os-attach': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def set_bootable_volume(self, volume_id, **kwargs): - """set a bootable flag for a volume - true or false.""" - post_body = json.dumps({'os-set_bootable': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def detach_volume(self, volume_id): - """Detaches a volume from an instance.""" - post_body = json.dumps({'os-detach': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def reserve_volume(self, volume_id): - """Reserves a volume.""" - post_body = json.dumps({'os-reserve': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def unreserve_volume(self, volume_id): - """Restore a reserved volume .""" - post_body = json.dumps({'os-unreserve': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_volume(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume' - - def extend_volume(self, volume_id, **kwargs): - """Extend a volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#extend-volume - """ - post_body = json.dumps({'os-extend': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def reset_volume_status(self, volume_id, **kwargs): - """Reset the Specified Volume's Status. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#reset-volume-status - """ - post_body = json.dumps({'os-reset_status': kwargs}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_transfer(self, **kwargs): - """Create a volume transfer. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#create-volume-transfer - """ - post_body = json.dumps({'transfer': kwargs}) - resp, body = self.post('os-volume-transfer', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_transfer(self, transfer_id): - """Returns the details of a volume transfer.""" - url = "os-volume-transfer/%s" % transfer_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_volume_transfers(self, **params): - """List all the volume transfers created. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#list-volume-transfers - """ - url = 'os-volume-transfer' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_transfer(self, transfer_id): - """Delete a volume transfer.""" - resp, body = self.delete("os-volume-transfer/%s" % transfer_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def accept_volume_transfer(self, transfer_id, **kwargs): - """Accept a volume transfer. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#accept-volume-transfer - """ - url = 'os-volume-transfer/%s/accept' % transfer_id - post_body = json.dumps({'accept': kwargs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_readonly(self, volume_id, **kwargs): - """Update the Specified Volume readonly.""" - post_body = json.dumps({'os-update_readonly_flag': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def force_delete_volume(self, volume_id): - """Force Delete Volume.""" - post_body = json.dumps({'os-force_delete': {}}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_metadata(self, volume_id, metadata): - """Create metadata for the volume.""" - put_body = json.dumps({'metadata': metadata}) - url = "volumes/%s/metadata" % volume_id - resp, body = self.post(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_metadata(self, volume_id): - """Get metadata of the volume.""" - url = "volumes/%s/metadata" % volume_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_metadata(self, volume_id, metadata): - """Update metadata for the volume.""" - put_body = json.dumps({'metadata': metadata}) - url = "volumes/%s/metadata" % volume_id - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_metadata_item(self, volume_id, id, meta_item): - """Update metadata item for the volume.""" - put_body = json.dumps({'meta': meta_item}) - url = "volumes/%s/metadata/%s" % (volume_id, id) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_metadata_item(self, volume_id, id): - """Delete metadata item for the volume.""" - url = "volumes/%s/metadata/%s" % (volume_id, id) - resp, body = self.delete(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def retype_volume(self, volume_id, **kwargs): - """Updates volume with new volume type.""" - post_body = json.dumps({'os-retype': kwargs}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) diff --git a/tempest/lib/services/volume/v2/__init__.py b/tempest/lib/services/volume/v2/__init__.py deleted file mode 100644 index 68982d99e..000000000 --- a/tempest/lib/services/volume/v2/__init__.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.volume.v2.availability_zone_client \ - import AvailabilityZoneClient -from tempest.lib.services.volume.v2.backups_client import BackupsClient -from tempest.lib.services.volume.v2.capabilities_client import \ - CapabilitiesClient -from tempest.lib.services.volume.v2.encryption_types_client import \ - EncryptionTypesClient -from tempest.lib.services.volume.v2.extensions_client import ExtensionsClient -from tempest.lib.services.volume.v2.hosts_client import HostsClient -from tempest.lib.services.volume.v2.limits_client import LimitsClient -from tempest.lib.services.volume.v2.qos_client import QosSpecsClient -from tempest.lib.services.volume.v2.quota_classes_client import \ - QuotaClassesClient -from tempest.lib.services.volume.v2.quotas_client import QuotasClient -from tempest.lib.services.volume.v2.scheduler_stats_client import \ - SchedulerStatsClient -from tempest.lib.services.volume.v2.services_client import ServicesClient -from tempest.lib.services.volume.v2.snapshot_manage_client import \ - SnapshotManageClient -from tempest.lib.services.volume.v2.snapshots_client import SnapshotsClient -from tempest.lib.services.volume.v2.transfers_client import TransfersClient -from tempest.lib.services.volume.v2.types_client import TypesClient -from tempest.lib.services.volume.v2.volume_manage_client import \ - VolumeManageClient -from tempest.lib.services.volume.v2.volumes_client import VolumesClient - -__all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient', - 'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient', - 'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient', - 'LimitsClient', 'CapabilitiesClient', 'SchedulerStatsClient', - 'SnapshotManageClient', 'VolumeManageClient', 'TransfersClient', - 'QuotaClassesClient'] diff --git a/tempest/lib/services/volume/v2/availability_zone_client.py b/tempest/lib/services/volume/v2/availability_zone_client.py deleted file mode 100644 index bb4a357f4..000000000 --- a/tempest/lib/services/volume/v2/availability_zone_client.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2014 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class AvailabilityZoneClient(rest_client.RestClient): - api_version = "v2" - - def list_availability_zones(self): - resp, body = self.get('os-availability-zone') - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/backups_client.py b/tempest/lib/services/volume/v2/backups_client.py deleted file mode 100644 index 830fb82fe..000000000 --- a/tempest/lib/services/volume/v2/backups_client.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.volume import base_client - - -class BackupsClient(base_client.BaseClient): - """Volume V2 Backups client""" - api_version = "v2" - - def create_backup(self, **kwargs): - """Creates a backup of volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/index.html#create-backup - """ - post_body = json.dumps({'backup': kwargs}) - resp, body = self.post('backups', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def restore_backup(self, backup_id, **kwargs): - """Restore volume from backup. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/index.html#restore-backup - """ - post_body = json.dumps({'restore': kwargs}) - resp, body = self.post('backups/%s/restore' % (backup_id), post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_backup(self, backup_id): - """Delete a backup of volume.""" - resp, body = self.delete('backups/%s' % backup_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_backup(self, backup_id): - """Returns the details of a single backup.""" - url = "backups/%s" % backup_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_backups(self, detail=False, **params): - """List all the tenant's backups. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#list-backups - http://developer.openstack.org/api-ref/block-storage/v2/#list-backups-with-details - """ - url = "backups" - if detail: - url += "/detail" - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def export_backup(self, backup_id): - """Export backup metadata record.""" - url = "backups/%s/export_record" % backup_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def import_backup(self, **kwargs): - """Import backup metadata record.""" - post_body = json.dumps({'backup-record': kwargs}) - resp, body = self.post("backups/import_record", post_body) - body = json.loads(body) - self.expected_success(201, resp.status) - return rest_client.ResponseBody(resp, body) - - def reset_backup_status(self, backup_id, status): - """Reset the specified backup's status.""" - post_body = json.dumps({'os-reset_status': {"status": status}}) - resp, body = self.post('backups/%s/action' % backup_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_backup(id) - except lib_exc.NotFound: - return True - return False diff --git a/tempest/lib/services/volume/v2/capabilities_client.py b/tempest/lib/services/volume/v2/capabilities_client.py deleted file mode 100644 index 240be135d..000000000 --- a/tempest/lib/services/volume/v2/capabilities_client.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class CapabilitiesClient(rest_client.RestClient): - api_version = "v2" - - def show_backend_capabilities(self, host): - """Shows capabilities for a storage back end. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/index.html#show-back-end-capabilities - """ - url = 'capabilities/%s' % host - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/encryption_types_client.py b/tempest/lib/services/volume/v2/encryption_types_client.py deleted file mode 100755 index 20f3356b4..000000000 --- a/tempest/lib/services/volume/v2/encryption_types_client.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class EncryptionTypesClient(rest_client.RestClient): - api_version = "v2" - - def is_resource_deleted(self, id): - try: - body = self.show_encryption_type(id) - if not body: - return True - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'encryption-type' - - def show_encryption_type(self, volume_type_id): - """Get the volume encryption type for the specified volume type. - - volume_type_id: Id of volume_type. - """ - url = "/types/%s/encryption" % volume_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_encryption_type(self, volume_type_id, **kwargs): - """Create encryption type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#create-an-encryption-type-for-v2 - """ - url = "/types/%s/encryption" % volume_type_id - post_body = json.dumps({'encryption': kwargs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_encryption_type(self, volume_type_id): - """Delete the encryption type for the specified volume-type.""" - resp, body = self.delete( - "/types/%s/encryption/provider" % volume_type_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_encryption_type(self, volume_type_id, **kwargs): - """Update an encryption type for an existing volume type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#update-an-encryption-type-for-v2 - """ - url = "/types/%s/encryption/provider" % volume_type_id - put_body = json.dumps({'encryption': kwargs}) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/extensions_client.py b/tempest/lib/services/volume/v2/extensions_client.py deleted file mode 100644 index 09279d578..000000000 --- a/tempest/lib/services/volume/v2/extensions_client.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2014 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class ExtensionsClient(rest_client.RestClient): - """Volume V2 extensions client.""" - api_version = "v2" - - def list_extensions(self): - url = 'extensions' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/hosts_client.py b/tempest/lib/services/volume/v2/hosts_client.py deleted file mode 100644 index f44bda391..000000000 --- a/tempest/lib/services/volume/v2/hosts_client.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class HostsClient(rest_client.RestClient): - """Client class to send CRUD Volume V2 API requests""" - api_version = "v2" - - def list_hosts(self, **params): - """Lists all hosts. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#list-all-hosts - """ - url = 'os-hosts' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_host(self, host_name): - """Show host details.""" - url = 'os-hosts/%s' % host_name - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/limits_client.py b/tempest/lib/services/volume/v2/limits_client.py deleted file mode 100644 index ce9fba9b9..000000000 --- a/tempest/lib/services/volume/v2/limits_client.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class LimitsClient(rest_client.RestClient): - """Volume V2 limits client.""" - - api_version = "v2" - - def show_limits(self): - """Returns the details of a volume absolute limits.""" - url = "limits" - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/qos_client.py b/tempest/lib/services/volume/v2/qos_client.py deleted file mode 100644 index 47d3914cb..000000000 --- a/tempest/lib/services/volume/v2/qos_client.py +++ /dev/null @@ -1,133 +0,0 @@ -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class QosSpecsClient(rest_client.RestClient): - """Volume V2 QoS client. - - Client class to send CRUD QoS API requests - """ - - api_version = "v2" - - def is_resource_deleted(self, qos_id): - try: - self.show_qos(qos_id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'qos' - - def create_qos(self, **kwargs): - """Create a QoS Specification. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-qos-specification - """ - post_body = json.dumps({'qos_specs': kwargs}) - resp, body = self.post('qos-specs', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_qos(self, qos_id, force=False): - """Delete the specified QoS specification.""" - resp, body = self.delete( - "qos-specs/%s?force=%s" % (qos_id, force)) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_qos(self): - """List all the QoS specifications created.""" - url = 'qos-specs' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_qos(self, qos_id): - """Get the specified QoS specification.""" - url = "qos-specs/%s" % qos_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def set_qos_key(self, qos_id, **kwargs): - """Set the specified keys/values of QoS specification. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#set-keys-in-qos-specification - """ - put_body = json.dumps({"qos_specs": kwargs}) - resp, body = self.put('qos-specs/%s' % qos_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def unset_qos_key(self, qos_id, keys): - """Unset the specified keys of QoS specification. - - :param keys: keys to delete from the QoS specification. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#unset-keys-in-qos-specification - """ - put_body = json.dumps({'keys': keys}) - resp, body = self.put('qos-specs/%s/delete_keys' % qos_id, put_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def associate_qos(self, qos_id, vol_type_id): - """Associate the specified QoS with specified volume-type.""" - url = "qos-specs/%s/associate" % qos_id - url += "?vol_type_id=%s" % vol_type_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_association_qos(self, qos_id): - """Get the association of the specified QoS specification.""" - url = "qos-specs/%s/associations" % qos_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def disassociate_qos(self, qos_id, vol_type_id): - """Disassociate the specified QoS with specified volume-type.""" - url = "qos-specs/%s/disassociate" % qos_id - url += "?vol_type_id=%s" % vol_type_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def disassociate_all_qos(self, qos_id): - """Disassociate the specified QoS with all associations.""" - url = "qos-specs/%s/disassociate_all" % qos_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/quota_classes_client.py b/tempest/lib/services/volume/v2/quota_classes_client.py deleted file mode 100644 index d40d2d9c7..000000000 --- a/tempest/lib/services/volume/v2/quota_classes_client.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class QuotaClassesClient(rest_client.RestClient): - """Volume quota class V2 client.""" - - api_version = "v2" - - def show_quota_class_set(self, quota_class_id): - """List quotas for a quota class. - - TODO: Current api-site doesn't contain this API description. - LP: https://bugs.launchpad.net/nova/+bug/1602400 - """ - url = 'os-quota-class-sets/%s' % quota_class_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_quota_class_set(self, quota_class_id, **kwargs): - """Update quotas for a quota class. - - TODO: Current api-site doesn't contain this API description. - LP: https://bugs.launchpad.net/nova/+bug/1602400 - """ - url = 'os-quota-class-sets/%s' % quota_class_id - put_body = json.dumps({'quota_class_set': kwargs}) - resp, body = self.put(url, put_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/quotas_client.py b/tempest/lib/services/volume/v2/quotas_client.py deleted file mode 100644 index e4b289509..000000000 --- a/tempest/lib/services/volume/v2/quotas_client.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class QuotasClient(rest_client.RestClient): - """Client class to send CRUD Volume Quotas API V2 requests""" - api_version = "v2" - - def show_default_quota_set(self, tenant_id): - """List the default volume quota set for a tenant.""" - - url = 'os-quota-sets/%s/defaults' % tenant_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_quota_set(self, tenant_id, params=None): - """List the quota set for a tenant.""" - - url = 'os-quota-sets/%s' % tenant_id - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_quota_set(self, tenant_id, **kwargs): - """Updates quota set - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/index.html#update-quotas - """ - put_body = jsonutils.dumps({'quota_set': kwargs}) - resp, body = self.put('os-quota-sets/%s' % tenant_id, put_body) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_quota_set(self, tenant_id): - """Delete the tenant's quota set.""" - resp, body = self.delete('os-quota-sets/%s' % tenant_id) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/scheduler_stats_client.py b/tempest/lib/services/volume/v2/scheduler_stats_client.py deleted file mode 100644 index 0d04f85d2..000000000 --- a/tempest/lib/services/volume/v2/scheduler_stats_client.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class SchedulerStatsClient(rest_client.RestClient): - api_version = "v2" - - def list_pools(self, detail=False): - """List all the volumes pools (hosts). - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/index.html#list-back-end-storage-pools - """ - url = 'scheduler-stats/get_pools' - if detail: - url += '?detail=True' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/services_client.py b/tempest/lib/services/volume/v2/services_client.py deleted file mode 100644 index bc554696d..000000000 --- a/tempest/lib/services/volume/v2/services_client.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ServicesClient(rest_client.RestClient): - """Client class to send CRUD Volume V2 API requests""" - api_version = "v2" - - def list_services(self, **params): - url = 'os-services' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/snapshot_manage_client.py b/tempest/lib/services/volume/v2/snapshot_manage_client.py deleted file mode 100644 index aecd30b1d..000000000 --- a/tempest/lib/services/volume/v2/snapshot_manage_client.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class SnapshotManageClient(rest_client.RestClient): - """Snapshot manage V2 client.""" - - api_version = "v2" - - def manage_snapshot(self, **kwargs): - """Manage a snapshot.""" - post_body = json.dumps({'snapshot': kwargs}) - url = 'os-snapshot-manage' - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/snapshots_client.py b/tempest/lib/services/volume/v2/snapshots_client.py deleted file mode 100644 index 4bc2842a6..000000000 --- a/tempest/lib/services/volume/v2/snapshots_client.py +++ /dev/null @@ -1,208 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class SnapshotsClient(rest_client.RestClient): - """Client class to send CRUD Volume V2 API requests.""" - api_version = "v2" - create_resp = 202 - - def list_snapshots(self, detail=False, **params): - """List all the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#list-snapshots-with-details - http://developer.openstack.org/api-ref/block-storage/v2/#list-snapshots - """ - url = 'snapshots' - if detail: - url += '/detail' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_snapshot(self, snapshot_id): - """Returns the details of a single snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-details - """ - url = "snapshots/%s" % snapshot_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_snapshot(self, **kwargs): - """Creates a new snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-snapshot - """ - post_body = json.dumps({'snapshot': kwargs}) - resp, body = self.post('snapshots', post_body) - body = json.loads(body) - self.expected_success(self.create_resp, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot(self, snapshot_id, **kwargs): - """Updates a snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot - """ - put_body = json.dumps({'snapshot': kwargs}) - resp, body = self.put('snapshots/%s' % snapshot_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_snapshot(self, snapshot_id): - """Delete Snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#delete-snapshot - """ - resp, body = self.delete("snapshots/%s" % snapshot_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_snapshot(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume-snapshot' - - def reset_snapshot_status(self, snapshot_id, status): - """Reset the specified snapshot's status.""" - post_body = json.dumps({'os-reset_status': {"status": status}}) - resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_status(self, snapshot_id, **kwargs): - """Update the specified snapshot's status.""" - # TODO(gmann): api-site doesn't contain doc ref - # for this API. After fixing the api-site, we need to - # add the link here. - # Bug https://bugs.launchpad.net/openstack-api-site/+bug/1532645 - - post_body = json.dumps({'os-update_snapshot_status': kwargs}) - url = 'snapshots/%s/action' % snapshot_id - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_snapshot_metadata(self, snapshot_id, metadata): - """Create metadata for the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-snapshot-metadata - """ - put_body = json.dumps({'metadata': metadata}) - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.post(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_snapshot_metadata(self, snapshot_id): - """Get metadata of the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-metadata - """ - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_metadata(self, snapshot_id, **kwargs): - """Update metadata for the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot-metadata - """ - put_body = json.dumps(kwargs) - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_snapshot_metadata_item(self, snapshot_id, id): - """Show metadata item for the snapshot.""" - url = "snapshots/%s/metadata/%s" % (snapshot_id, id) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_metadata_item(self, snapshot_id, id, **kwargs): - """Update metadata item for the snapshot.""" - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1529064 - put_body = json.dumps(kwargs) - url = "snapshots/%s/metadata/%s" % (snapshot_id, id) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_snapshot_metadata_item(self, snapshot_id, id): - """Delete metadata item for the snapshot.""" - url = "snapshots/%s/metadata/%s" % (snapshot_id, id) - resp, body = self.delete(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def force_delete_snapshot(self, snapshot_id): - """Force Delete Snapshot.""" - post_body = json.dumps({'os-force_delete': {}}) - resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def unmanage_snapshot(self, snapshot_id): - """Unmanage a snapshot.""" - post_body = json.dumps({'os-unmanage': {}}) - url = 'snapshots/%s/action' % (snapshot_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/transfers_client.py b/tempest/lib/services/volume/v2/transfers_client.py deleted file mode 100644 index 2dfbe7bb1..000000000 --- a/tempest/lib/services/volume/v2/transfers_client.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class TransfersClient(rest_client.RestClient): - """Client class to send CRUD Volume Transfer V2 API requests""" - api_version = "v2" - - def create_volume_transfer(self, **kwargs): - """Create a volume transfer. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#create-volume-transfer - """ - post_body = json.dumps({'transfer': kwargs}) - resp, body = self.post('os-volume-transfer', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_transfer(self, transfer_id): - """Returns the details of a volume transfer.""" - url = "os-volume-transfer/%s" % transfer_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_volume_transfers(self, detail=False, **params): - """List all the volume transfers created. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#list-volume-transfers - https://developer.openstack.org/api-ref/block-storage/v2/#list-volume-transfers-with-details - """ - url = 'os-volume-transfer' - if detail: - url += '/detail' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_transfer(self, transfer_id): - """Delete a volume transfer.""" - resp, body = self.delete("os-volume-transfer/%s" % transfer_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def accept_volume_transfer(self, transfer_id, **kwargs): - """Accept a volume transfer. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#accept-volume-transfer - """ - url = 'os-volume-transfer/%s/accept' % transfer_id - post_body = json.dumps({'accept': kwargs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/types_client.py b/tempest/lib/services/volume/v2/types_client.py deleted file mode 100644 index af4fd8cd6..000000000 --- a/tempest/lib/services/volume/v2/types_client.py +++ /dev/null @@ -1,205 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class TypesClient(rest_client.RestClient): - """Client class to send CRUD Volume V2 API requests""" - api_version = "v2" - - def is_resource_deleted(self, id): - try: - self.show_volume_type(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume-type' - - def list_volume_types(self, **params): - """List all the volume_types created. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#list-all-volume-types-for-v2 - """ - url = 'types' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_type(self, volume_type_id): - """Returns the details of a single volume_type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#show-volume-type-details-for-v2 - """ - url = "types/%s" % volume_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_type(self, **kwargs): - """Create volume type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#create-volume-type-for-v2 - """ - post_body = json.dumps({'volume_type': kwargs}) - resp, body = self.post('types', post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_type(self, volume_type_id): - """Deletes the Specified Volume_type. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#delete-volume-type - """ - resp, body = self.delete("types/%s" % volume_type_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_volume_types_extra_specs(self, volume_type_id, **params): - """List all the volume_types extra specs created. - - TODO: Current api-site doesn't contain this API description. - After fixing the api-site, we need to fix here also for putting - the link to api-site. - """ - url = 'types/%s/extra_specs' % volume_type_id - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_type_extra_specs(self, volume_type_id, extra_specs_name): - """Returns the details of a single volume_type extra spec.""" - url = "types/%s/extra_specs/%s" % (volume_type_id, extra_specs_name) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_type_extra_specs(self, volume_type_id, extra_specs): - """Creates a new Volume_type extra spec. - - volume_type_id: Id of volume_type. - extra_specs: A dictionary of values to be used as extra_specs. - """ - url = "types/%s/extra_specs" % volume_type_id - post_body = json.dumps({'extra_specs': extra_specs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_type_extra_specs(self, volume_type_id, extra_spec_name): - """Deletes the Specified Volume_type extra spec.""" - resp, body = self.delete("types/%s/extra_specs/%s" % ( - volume_type_id, extra_spec_name)) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_type(self, volume_type_id, **kwargs): - """Updates volume type name, description, and/or is_public. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-type - """ - put_body = json.dumps({'volume_type': kwargs}) - resp, body = self.put('types/%s' % volume_type_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_type_extra_specs(self, volume_type_id, extra_spec_name, - extra_specs): - """Update a volume_type extra spec. - - volume_type_id: Id of volume_type. - extra_spec_name: Name of the extra spec to be updated. - extra_spec: A dictionary of with key as extra_spec_name and the - updated value. - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-extra-specs-for-a-volume-type - """ - url = "types/%s/extra_specs/%s" % (volume_type_id, extra_spec_name) - put_body = json.dumps(extra_specs) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def add_type_access(self, volume_type_id, **kwargs): - """Adds volume type access for the given project. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#add-private-volume-type-access - """ - post_body = json.dumps({'addProjectAccess': kwargs}) - url = 'types/%s/action' % volume_type_id - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def remove_type_access(self, volume_type_id, **kwargs): - """Removes volume type access for the given project. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#remove-private-volume-type-access - """ - post_body = json.dumps({'removeProjectAccess': kwargs}) - url = 'types/%s/action' % volume_type_id - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_type_access(self, volume_type_id): - """Print access information about the given volume type. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#list-private-volume-type-access-details - """ - url = 'types/%s/os-volume-type-access' % volume_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/volume_manage_client.py b/tempest/lib/services/volume/v2/volume_manage_client.py deleted file mode 100644 index 12f4240a5..000000000 --- a/tempest/lib/services/volume/v2/volume_manage_client.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class VolumeManageClient(rest_client.RestClient): - """Volume manage V2 client.""" - - api_version = "v2" - - def manage_volume(self, **kwargs): - """Manage existing volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#manage-existing-volume - """ - post_body = json.dumps({'volume': kwargs}) - resp, body = self.post('os-volume-manage', post_body) - self.expected_success(202, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py deleted file mode 100644 index 62b9992dd..000000000 --- a/tempest/lib/services/volume/v2/volumes_client.py +++ /dev/null @@ -1,396 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from debtcollector import moves -from debtcollector import removals -from oslo_serialization import jsonutils as json -import six -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.volume import base_client -from tempest.lib.services.volume.v2 import transfers_client - - -class VolumesClient(base_client.BaseClient): - """Client class to send CRUD Volume V2 API requests""" - api_version = "v2" - - create_volume_transfer = moves.moved_function( - transfers_client.TransfersClient.create_volume_transfer, - 'VolumesClient.create_volume_transfer', __name__, - message='Use create_volume_transfer from new location.', - version='Pike', removal_version='Queens') - - show_volume_transfer = moves.moved_function( - transfers_client.TransfersClient.show_volume_transfer, - 'VolumesClient.show_volume_transfer', __name__, - message='Use show_volume_transfer from new location.', - version='Pike', removal_version='Queens') - - list_volume_transfers = moves.moved_function( - transfers_client.TransfersClient.list_volume_transfers, - 'VolumesClient.list_volume_transfers', __name__, - message='Use list_volume_transfer from new location.', - version='Pike', removal_version='Queens') - - delete_volume_transfer = moves.moved_function( - transfers_client.TransfersClient.delete_volume_transfer, - 'VolumesClient.delete_volume_transfer', __name__, - message='Use delete_volume_transfer from new location.', - version='Pike', removal_version='Queens') - - accept_volume_transfer = moves.moved_function( - transfers_client.TransfersClient.accept_volume_transfer, - 'VolumesClient.accept_volume_transfer', __name__, - message='Use accept_volume_transfer from new location.', - version='Pike', removal_version='Queens') - - def _prepare_params(self, params): - """Prepares params for use in get or _ext_get methods. - - If params is a string it will be left as it is, but if it's not it will - be urlencoded. - """ - if isinstance(params, six.string_types): - return params - return urllib.urlencode(params) - - def list_volumes(self, detail=False, params=None): - """List all the volumes created. - - Params can be a string (must be urlencoded) or a dictionary. - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#list-volumes-with-details - http://developer.openstack.org/api-ref/block-storage/v2/#list-volumes - """ - url = 'volumes' - if detail: - url += '/detail' - if params: - url += '?%s' % self._prepare_params(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume(self, volume_id): - """Returns the details of a single volume.""" - url = "volumes/%s" % volume_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume(self, **kwargs): - """Creates a new Volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-volume - """ - post_body = json.dumps({'volume': kwargs}) - resp, body = self.post('volumes', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume(self, volume_id, **kwargs): - """Updates the Specified Volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-volume - """ - put_body = json.dumps({'volume': kwargs}) - resp, body = self.put('volumes/%s' % volume_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume(self, volume_id, **params): - """Deletes the Specified Volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#delete-volume - """ - url = 'volumes/%s' % volume_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.delete(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def upload_volume(self, volume_id, **kwargs): - """Uploads a volume in Glance.""" - post_body = json.dumps({'os-volume_upload_image': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def attach_volume(self, volume_id, **kwargs): - """Attaches a volume to a given instance on a given mountpoint. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#attach-volume-to-server - """ - post_body = json.dumps({'os-attach': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def set_bootable_volume(self, volume_id, **kwargs): - """Set a bootable flag for a volume - true or false. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-bootable-status - """ - post_body = json.dumps({'os-set_bootable': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def detach_volume(self, volume_id): - """Detaches a volume from an instance.""" - post_body = json.dumps({'os-detach': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def reserve_volume(self, volume_id): - """Reserves a volume.""" - post_body = json.dumps({'os-reserve': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def unreserve_volume(self, volume_id): - """Restore a reserved volume .""" - post_body = json.dumps({'os-unreserve': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_volume(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume' - - def extend_volume(self, volume_id, **kwargs): - """Extend a volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#extend-volume-size - """ - post_body = json.dumps({'os-extend': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def reset_volume_status(self, volume_id, **kwargs): - """Reset the Specified Volume's Status. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#reset-volume-statuses - """ - post_body = json.dumps({'os-reset_status': kwargs}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_readonly(self, volume_id, **kwargs): - """Update the Specified Volume readonly.""" - post_body = json.dumps({'os-update_readonly_flag': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def force_delete_volume(self, volume_id): - """Force Delete Volume.""" - post_body = json.dumps({'os-force_delete': {}}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_metadata(self, volume_id, metadata): - """Create metadata for the volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-metadata - """ - put_body = json.dumps({'metadata': metadata}) - url = "volumes/%s/metadata" % volume_id - resp, body = self.post(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_metadata(self, volume_id): - """Get metadata of the volume.""" - url = "volumes/%s/metadata" % volume_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_metadata(self, volume_id, metadata): - """Update metadata for the volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-metadata - """ - put_body = json.dumps({'metadata': metadata}) - url = "volumes/%s/metadata" % volume_id - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_metadata_item(self, volume_id, id): - """Show metadata item for the volume.""" - url = "volumes/%s/metadata/%s" % (volume_id, id) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_metadata_item(self, volume_id, id, meta_item): - """Update metadata item for the volume.""" - put_body = json.dumps({'meta': meta_item}) - url = "volumes/%s/metadata/%s" % (volume_id, id) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_metadata_item(self, volume_id, id): - """Delete metadata item for the volume.""" - url = "volumes/%s/metadata/%s" % (volume_id, id) - resp, body = self.delete(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def retype_volume(self, volume_id, **kwargs): - """Updates volume with new volume type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#retype-volume - """ - post_body = json.dumps({'os-retype': kwargs}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def force_detach_volume(self, volume_id, **kwargs): - """Force detach a volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#force-detach-volume - """ - post_body = json.dumps({'os-force_detach': kwargs}) - url = 'volumes/%s/action' % volume_id - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_image_metadata(self, volume_id, **kwargs): - """Update image metadata for the volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#set-image-metadata-for-volume - """ - post_body = json.dumps({'os-set_image_metadata': {'metadata': kwargs}}) - url = "volumes/%s/action" % (volume_id) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_image_metadata(self, volume_id, key_name): - """Delete image metadata item for the volume.""" - post_body = json.dumps({'os-unset_image_metadata': {'key': key_name}}) - url = "volumes/%s/action" % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - @removals.remove(message="use list_pools from tempest.lib.services." - "volume.v2.scheduler_stats_client") - def show_pools(self, detail=False): - # List all the volumes pools (hosts) - url = 'scheduler-stats/get_pools' - if detail: - url += '?detail=True' - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - @removals.remove(message="use show_backend_capabilities from tempest.lib." - "services.volume.v2.capabilities_client") - def show_backend_capabilities(self, host): - """Shows capabilities for a storage back end. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#show-back-end-capabilities - """ - url = 'capabilities/%s' % host - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def unmanage_volume(self, volume_id): - """Unmanage volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#unmanage-volume - """ - post_body = json.dumps({'os-unmanage': {}}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v3/__init__.py b/tempest/lib/services/volume/v3/__init__.py deleted file mode 100644 index ff58fc2e4..000000000 --- a/tempest/lib/services/volume/v3/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.lib.services.volume.v3.backups_client import BackupsClient -from tempest.lib.services.volume.v3.base_client import BaseClient -from tempest.lib.services.volume.v3.group_types_client import GroupTypesClient -from tempest.lib.services.volume.v3.groups_client import GroupsClient -from tempest.lib.services.volume.v3.messages_client import MessagesClient -from tempest.lib.services.volume.v3.versions_client import VersionsClient -from tempest.lib.services.volume.v3.volumes_client import VolumesClient - -__all__ = ['BackupsClient', 'BaseClient', 'GroupsClient', 'GroupTypesClient', - 'MessagesClient', 'VersionsClient', 'VolumesClient'] diff --git a/tempest/lib/services/volume/v3/backups_client.py b/tempest/lib/services/volume/v3/backups_client.py deleted file mode 100644 index e742e3901..000000000 --- a/tempest/lib/services/volume/v3/backups_client.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib.services.volume.v2 import backups_client - - -class BackupsClient(backups_client.BackupsClient): - """Volume V3 Backups client""" - api_version = "v3" - - def update_backup(self, backup_id, **kwargs): - """Updates the specified volume backup. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#update-a-backup - """ - put_body = json.dumps({'backup': kwargs}) - resp, body = self.put('backups/%s' % backup_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v3/base_client.py b/tempest/lib/services/volume/v3/base_client.py deleted file mode 100644 index e78380bb7..000000000 --- a/tempest/lib/services/volume/v3/base_client.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2016 Andrew Kerr -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from debtcollector import moves - -from tempest.lib.services.volume import base_client - - -BaseClient = moves.moved_class(base_client.BaseClient, 'BaseClient', __name__, - version="Pike", removal_version='?') -BaseClient.api_version = 'v3' diff --git a/tempest/lib/services/volume/v3/group_types_client.py b/tempest/lib/services/volume/v3/group_types_client.py deleted file mode 100644 index 97bac4847..000000000 --- a/tempest/lib/services/volume/v3/group_types_client.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib.services.volume import base_client - - -class GroupTypesClient(base_client.BaseClient): - """Client class to send CRUD Volume V3 Group Types API requests""" - api_version = 'v3' - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'group-type' - - def create_group_type(self, **kwargs): - """Create group_type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#create-group-type - """ - post_body = json.dumps({'group_type': kwargs}) - resp, body = self.post('group_types', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_group_type(self, group_type_id): - """Deletes the specified group_type.""" - resp, body = self.delete("group_types/%s" % group_type_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_group_types(self, **params): - """List all the group_types created. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#list-group-types - """ - url = 'group_types' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_group_type(self, group_type_id): - """Returns the details of a single group_type. - - For more information, please refer to the official API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#show-group-type-details - """ - url = "group_types/%s" % group_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v3/groups_client.py b/tempest/lib/services/volume/v3/groups_client.py deleted file mode 100644 index 9b53bb7da..000000000 --- a/tempest/lib/services/volume/v3/groups_client.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.volume import base_client - - -class GroupsClient(base_client.BaseClient): - """Client class to send CRUD Volume Group API requests""" - api_version = 'v3' - - def create_group(self, **kwargs): - """Creates a group. - - group_type and volume_types are required parameters in kwargs. - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#create-group - """ - post_body = json.dumps({'group': kwargs}) - resp, body = self.post('groups', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_group(self, group_id, delete_volumes=True): - """Deletes a group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#delete-group - """ - post_body = {'delete-volumes': delete_volumes} - post_body = json.dumps({'delete': post_body}) - resp, body = self.post('groups/%s/action' % group_id, - post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_group(self, group_id): - """Returns the details of a single group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#show-group-details - """ - url = "groups/%s" % str(group_id) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_groups(self, detail=False, **params): - """Lists information for all the tenant's groups. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#list-groups - https://developer.openstack.org/api-ref/block-storage/v3/#list-groups-with-details - """ - url = "groups" - if detail: - url += "/detail" - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_group(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'group' diff --git a/tempest/lib/services/volume/v3/messages_client.py b/tempest/lib/services/volume/v3/messages_client.py deleted file mode 100644 index 012727137..000000000 --- a/tempest/lib/services/volume/v3/messages_client.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2016 Andrew Kerr -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.volume import base_client - - -class MessagesClient(base_client.BaseClient): - """Client class to send user messages API requests.""" - api_version = 'v3' - - def show_message(self, message_id): - """Show details for a single message.""" - url = 'messages/%s' % str(message_id) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_messages(self): - """List all messages.""" - url = 'messages' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_message(self, message_id): - """Delete a single message.""" - url = 'messages/%s' % str(message_id) - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_message(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'message' diff --git a/tempest/lib/services/volume/v3/versions_client.py b/tempest/lib/services/volume/v3/versions_client.py deleted file mode 100644 index 5702f9521..000000000 --- a/tempest/lib/services/volume/v3/versions_client.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2017 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.volume import versions as schema -from tempest.lib.common import rest_client -from tempest.lib.services.volume import base_client - - -class VersionsClient(base_client.BaseClient): - api_version = 'v3' - - def list_versions(self): - """List API versions - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#list-all-api-versions - """ - version_url = self._get_base_version_url() - - start = time.time() - resp, body = self.raw_request(version_url, 'GET') - end = time.time() - # NOTE: We need a raw_request() here instead of request() call because - # "list API versions" API doesn't require an authentication and we can - # skip it with raw_request() call. - self._log_request('GET', version_url, resp, secs=(end - start), - resp_body=body) - self._error_checker(resp, body) - - body = json.loads(body) - self.validate_response(schema.list_versions, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v3/volumes_client.py b/tempest/lib/services/volume/v3/volumes_client.py deleted file mode 100644 index 5f4b278e8..000000000 --- a/tempest/lib/services/volume/v3/volumes_client.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib.services.volume.v2 import volumes_client - - -class VolumesClient(volumes_client.VolumesClient): - """Client class to send CRUD Volume V3 API requests""" - api_version = "v3" - - def show_volume_summary(self, **params): - """Get volumes summary. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#get-volumes-summary - """ - url = 'volumes/summary' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/manager.py b/tempest/manager.py deleted file mode 100644 index e3174d448..000000000 --- a/tempest/manager.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging - -from tempest import clients as tempest_clients -from tempest import config -from tempest.lib.services import clients - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class Manager(clients.ServiceClients): - """Service client manager class for backward compatibility - - The former manager.Manager is not a stable interface in Tempest, - nonetheless it is consumed by a number of plugins already. This class - exists to provide some grace time for the move to tempest.lib. - """ - - def __init__(self, credentials, scope='project'): - msg = ("tempest.manager.Manager is not a stable interface and as such " - "it should not imported directly. It will be removed as " - "soon as the client manager becomes available in tempest.lib.") - LOG.warning(msg) - dscv = CONF.identity.disable_ssl_certificate_validation - _, uri = tempest_clients.get_auth_provider_class(credentials) - super(Manager, self).__init__( - credentials=credentials, scope=scope, - identity_uri=uri, - disable_ssl_certificate_validation=dscv, - ca_certs=CONF.identity.ca_certificates_file, - trace_requests=CONF.debug.trace_requests) - - -def get_auth_provider(credentials, pre_auth=False, scope='project'): - """Shim to get_auth_provider in clients.py - - get_auth_provider used to be hosted in this module, but it has been - moved to clients.py now as a more permanent location. - This module will be removed eventually, and this shim is only - maintained for the benefit of plugins already consuming this interface. - """ - msg = ("tempest.manager.get_auth_provider is not a stable interface and " - "as such it should not imported directly. It will be removed as " - "the client manager becomes available in tempest.lib.") - LOG.warning(msg) - return tempest_clients.get_auth_provider(credentials=credentials, - pre_auth=pre_auth, scope=scope) diff --git a/tempest/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml b/tempest/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml deleted file mode 100644 index 4abfe9ed8..000000000 --- a/tempest/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - Add a missing return statement to the retype_volume API in the v2 volumes_client library. - This changes the response body from None to an empty dictionary. - diff --git a/tempest/scenario/README.rst b/tempest/scenario/README.rst deleted file mode 100644 index c1dcccc0b..000000000 --- a/tempest/scenario/README.rst +++ /dev/null @@ -1,49 +0,0 @@ -.. _scenario_field_guide: - -Tempest Field Guide to Scenario tests -===================================== - - -What are these tests? ---------------------- - -Scenario tests are "through path" tests of OpenStack -function. Complicated setups where one part might depend on completion -of a previous part. They ideally involve the integration between -multiple OpenStack services to exercise the touch points between them. - -Any scenario test should have a real-life use case. An example would be: - - - "As operator I want to start with a blank environment": - 1. upload a glance image - 2. deploy a vm from it - 3. ssh to the guest - 4. create a snapshot of the vm - - -Why are these tests in Tempest? -------------------------------- -This is one of Tempest's core purposes, testing the integration between -projects. - - -Scope of these tests --------------------- -Scenario tests should always use the Tempest implementation of the -OpenStack API, as we want to ensure that bugs aren't hidden by the -official clients. - -Tests should be tagged with which services they exercise, as -determined by which client libraries are used directly by the test. - - -Example of a good test ----------------------- -While we are looking for interaction of 2 or more services, be -specific in your interactions. A giant "this is my data center" smoke -test is hard to debug when it goes wrong. - -A flow of interactions between Glance and Nova, like in the -introduction, is a good example. Especially if it involves a repeated -interaction when a resource is setup, modified, detached, and then -reused later again. diff --git a/tempest/scenario/__init__.py b/tempest/scenario/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py deleted file mode 100644 index 9b8c7a01f..000000000 --- a/tempest/scenario/manager.py +++ /dev/null @@ -1,1375 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import subprocess - -import netaddr -from oslo_log import log -from oslo_serialization import jsonutils as json -from oslo_utils import netutils - -from tempest.common import compute -from tempest.common import image as common_image -from tempest.common.utils.linux import remote_client -from tempest.common.utils import net_utils -from tempest.common import waiters -from tempest import config -from tempest import exceptions -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -import tempest.test - -CONF = config.CONF - -LOG = log.getLogger(__name__) - - -class ScenarioTest(tempest.test.BaseTestCase): - """Base class for scenario tests. Uses tempest own clients. """ - - credentials = ['primary'] - - @classmethod - def setup_clients(cls): - super(ScenarioTest, cls).setup_clients() - # Clients (in alphabetical order) - cls.flavors_client = cls.os_primary.flavors_client - cls.compute_floating_ips_client = ( - cls.os_primary.compute_floating_ips_client) - if CONF.service_available.glance: - # Check if glance v1 is available to determine which client to use. - if CONF.image_feature_enabled.api_v1: - cls.image_client = cls.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - cls.image_client = cls.os_primary.image_client_v2 - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - # Compute image client - cls.compute_images_client = cls.os_primary.compute_images_client - cls.keypairs_client = cls.os_primary.keypairs_client - # Nova security groups client - cls.compute_security_groups_client = ( - cls.os_primary.compute_security_groups_client) - cls.compute_security_group_rules_client = ( - cls.os_primary.compute_security_group_rules_client) - cls.servers_client = cls.os_primary.servers_client - cls.interface_client = cls.os_primary.interfaces_client - # Neutron network client - cls.networks_client = cls.os_primary.networks_client - cls.ports_client = cls.os_primary.ports_client - cls.routers_client = cls.os_primary.routers_client - cls.subnets_client = cls.os_primary.subnets_client - cls.floating_ips_client = cls.os_primary.floating_ips_client - cls.security_groups_client = cls.os_primary.security_groups_client - cls.security_group_rules_client = ( - cls.os_primary.security_group_rules_client) - cls.volumes_client = cls.os_primary.volumes_v2_client - cls.snapshots_client = cls.os_primary.snapshots_v2_client - - # ## Test functions library - # - # The create_[resource] functions only return body and discard the - # resp part which is not used in scenario tests - - def _create_port(self, network_id, client=None, namestart='port-quotatest', - **kwargs): - if not client: - client = self.ports_client - name = data_utils.rand_name(namestart) - result = client.create_port( - name=name, - network_id=network_id, - **kwargs) - self.assertIsNotNone(result, 'Unable to allocate port') - port = result['port'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_port, port['id']) - return port - - def create_keypair(self, client=None): - if not client: - client = self.keypairs_client - name = data_utils.rand_name(self.__class__.__name__) - # We don't need to create a keypair by pubkey in scenario - body = client.create_keypair(name=name) - self.addCleanup(client.delete_keypair, name) - return body['keypair'] - - def create_server(self, name=None, image_id=None, flavor=None, - validatable=False, wait_until='ACTIVE', - clients=None, **kwargs): - """Wrapper utility that returns a test server. - - This wrapper utility calls the common create test server and - returns a test server. The purpose of this wrapper is to minimize - the impact on the code of the tests already using this - function. - """ - - # NOTE(jlanoux): As a first step, ssh checks in the scenario - # tests need to be run regardless of the run_validation and - # validatable parameters and thus until the ssh validation job - # becomes voting in CI. The test resources management and IP - # association are taken care of in the scenario tests. - # Therefore, the validatable parameter is set to false in all - # those tests. In this way create_server just return a standard - # server and the scenario tests always perform ssh checks. - - # Needed for the cross_tenant_traffic test: - if clients is None: - clients = self.os_primary - - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + "-server") - - vnic_type = CONF.network.port_vnic_type - - # If vnic_type is configured create port for - # every network - if vnic_type: - ports = [] - - create_port_body = {'binding:vnic_type': vnic_type, - 'namestart': 'port-smoke'} - if kwargs: - # Convert security group names to security group ids - # to pass to create_port - if 'security_groups' in kwargs: - security_groups = \ - clients.security_groups_client.list_security_groups( - ).get('security_groups') - sec_dict = dict([(s['name'], s['id']) - for s in security_groups]) - - sec_groups_names = [s['name'] for s in kwargs.pop( - 'security_groups')] - security_groups_ids = [sec_dict[s] - for s in sec_groups_names] - - if security_groups_ids: - create_port_body[ - 'security_groups'] = security_groups_ids - networks = kwargs.pop('networks', []) - else: - networks = [] - - # If there are no networks passed to us we look up - # for the project's private networks and create a port. - # The same behaviour as we would expect when passing - # the call to the clients with no networks - if not networks: - networks = clients.networks_client.list_networks( - **{'router:external': False, 'fields': 'id'})['networks'] - - # It's net['uuid'] if networks come from kwargs - # and net['id'] if they come from - # clients.networks_client.list_networks - for net in networks: - net_id = net.get('uuid', net.get('id')) - if 'port' not in net: - port = self._create_port(network_id=net_id, - client=clients.ports_client, - **create_port_body) - ports.append({'port': port['id']}) - else: - ports.append({'port': net['port']}) - if ports: - kwargs['networks'] = ports - self.ports = ports - - tenant_network = self.get_tenant_network() - - body, _ = compute.create_test_server( - clients, - tenant_network=tenant_network, - wait_until=wait_until, - name=name, flavor=flavor, - image_id=image_id, **kwargs) - - self.addCleanup(waiters.wait_for_server_termination, - clients.servers_client, body['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - clients.servers_client.delete_server, body['id']) - server = clients.servers_client.show_server(body['id'])['server'] - return server - - def create_volume(self, size=None, name=None, snapshot_id=None, - imageRef=None, volume_type=None): - if size is None: - size = CONF.volume.volume_size - if imageRef: - image = self.compute_images_client.show_image(imageRef)['image'] - min_disk = image.get('minDisk') - size = max(size, min_disk) - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + "-volume") - kwargs = {'display_name': name, - 'snapshot_id': snapshot_id, - 'imageRef': imageRef, - 'volume_type': volume_type, - 'size': size} - volume = self.volumes_client.create_volume(**kwargs)['volume'] - - self.addCleanup(self.volumes_client.wait_for_resource_deletion, - volume['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.volumes_client.delete_volume, volume['id']) - self.assertEqual(name, volume['name']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - # The volume retrieved on creation has a non-up-to-date status. - # Retrieval after it becomes active ensures correct details. - volume = self.volumes_client.show_volume(volume['id'])['volume'] - return volume - - def create_volume_snapshot(self, volume_id, name=None, description=None, - metadata=None, force=False): - name = name or data_utils.rand_name( - self.__class__.__name__ + '-snapshot') - snapshot = self.snapshots_client.create_snapshot( - volume_id=volume_id, - force=force, - display_name=name, - description=description, - metadata=metadata)['snapshot'] - self.addCleanup(self.snapshots_client.wait_for_resource_deletion, - snapshot['id']) - self.addCleanup(self.snapshots_client.delete_snapshot, snapshot['id']) - waiters.wait_for_volume_resource_status(self.snapshots_client, - snapshot['id'], 'available') - return snapshot - - def create_volume_type(self, client=None, name=None, backend_name=None): - if not client: - client = self.os_admin.volume_types_v2_client - if not name: - class_name = self.__class__.__name__ - name = data_utils.rand_name(class_name + '-volume-type') - randomized_name = data_utils.rand_name('scenario-type-' + name) - - LOG.debug("Creating a volume type: %s on backend %s", - randomized_name, backend_name) - extra_specs = {} - if backend_name: - extra_specs = {"volume_backend_name": backend_name} - - body = client.create_volume_type(name=randomized_name, - extra_specs=extra_specs) - volume_type = body['volume_type'] - self.assertIn('id', volume_type) - self.addCleanup(client.delete_volume_type, volume_type['id']) - return volume_type - - def _create_loginable_secgroup_rule(self, secgroup_id=None): - _client = self.compute_security_groups_client - _client_rules = self.compute_security_group_rules_client - if secgroup_id is None: - sgs = _client.list_security_groups()['security_groups'] - for sg in sgs: - if sg['name'] == 'default': - secgroup_id = sg['id'] - - # These rules are intended to permit inbound ssh and icmp - # traffic from all sources, so no group_id is provided. - # Setting a group_id would only permit traffic from ports - # belonging to the same security group. - rulesets = [ - { - # ssh - 'ip_protocol': 'tcp', - 'from_port': 22, - 'to_port': 22, - 'cidr': '0.0.0.0/0', - }, - { - # ping - 'ip_protocol': 'icmp', - 'from_port': -1, - 'to_port': -1, - 'cidr': '0.0.0.0/0', - } - ] - rules = list() - for ruleset in rulesets: - sg_rule = _client_rules.create_security_group_rule( - parent_group_id=secgroup_id, **ruleset)['security_group_rule'] - rules.append(sg_rule) - return rules - - def _create_security_group(self): - # Create security group - sg_name = data_utils.rand_name(self.__class__.__name__) - sg_desc = sg_name + " description" - secgroup = self.compute_security_groups_client.create_security_group( - name=sg_name, description=sg_desc)['security_group'] - self.assertEqual(secgroup['name'], sg_name) - self.assertEqual(secgroup['description'], sg_desc) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.compute_security_groups_client.delete_security_group, - secgroup['id']) - - # Add rules to the security group - self._create_loginable_secgroup_rule(secgroup['id']) - - return secgroup - - def get_remote_client(self, ip_address, username=None, private_key=None, - server=None): - """Get a SSH client to a remote server - - @param ip_address the server floating or fixed IP address to use - for ssh validation - @param username name of the Linux account on the remote server - @param private_key the SSH private key to use - @param server: server dict, used for debugging purposes - @return a RemoteClient object - """ - - if username is None: - username = CONF.validation.image_ssh_user - # Set this with 'keypair' or others to log in with keypair or - # username/password. - if CONF.validation.auth_method == 'keypair': - password = None - if private_key is None: - private_key = self.keypair['private_key'] - else: - password = CONF.validation.image_ssh_password - private_key = None - linux_client = remote_client.RemoteClient( - ip_address, username, pkey=private_key, password=password, - server=server, servers_client=self.servers_client) - linux_client.validate_authentication() - return linux_client - - def _image_create(self, name, fmt, path, - disk_format=None, properties=None): - if properties is None: - properties = {} - name = data_utils.rand_name('%s-' % name) - params = { - 'name': name, - 'container_format': fmt, - 'disk_format': disk_format or fmt, - } - if CONF.image_feature_enabled.api_v1: - params['is_public'] = 'False' - params['properties'] = properties - params = {'headers': common_image.image_meta_to_headers(**params)} - else: - params['visibility'] = 'private' - # Additional properties are flattened out in the v2 API. - params.update(properties) - body = self.image_client.create_image(**params) - image = body['image'] if 'image' in body else body - self.addCleanup(self.image_client.delete_image, image['id']) - self.assertEqual("queued", image['status']) - with open(path, 'rb') as image_file: - if CONF.image_feature_enabled.api_v1: - self.image_client.update_image(image['id'], data=image_file) - else: - self.image_client.store_image_file(image['id'], image_file) - return image['id'] - - def glance_image_create(self): - img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file - aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file - ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file - ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file - img_container_format = CONF.scenario.img_container_format - img_disk_format = CONF.scenario.img_disk_format - img_properties = CONF.scenario.img_properties - LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, " - "properties: %s, ami: %s, ari: %s, aki: %s", - img_path, img_container_format, img_disk_format, - img_properties, ami_img_path, ari_img_path, aki_img_path) - try: - image = self._image_create('scenario-img', - img_container_format, - img_path, - disk_format=img_disk_format, - properties=img_properties) - except IOError: - LOG.debug("A qcow2 image was not found. Try to get a uec image.") - kernel = self._image_create('scenario-aki', 'aki', aki_img_path) - ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path) - properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk} - image = self._image_create('scenario-ami', 'ami', - path=ami_img_path, - properties=properties) - LOG.debug("image:%s", image) - - return image - - def _log_console_output(self, servers=None, client=None): - if not CONF.compute_feature_enabled.console_output: - LOG.debug('Console output not supported, cannot log') - return - client = client or self.servers_client - if not servers: - servers = client.list_servers() - servers = servers['servers'] - for server in servers: - try: - console_output = client.get_console_output( - server['id'])['output'] - LOG.debug('Console output for %s\nbody=\n%s', - server['id'], console_output) - except lib_exc.NotFound: - LOG.debug("Server %s disappeared(deleted) while looking " - "for the console log", server['id']) - - def _log_net_info(self, exc): - # network debug is called as part of ssh init - if not isinstance(exc, lib_exc.SSHTimeout): - LOG.debug('Network information on a devstack host') - - def create_server_snapshot(self, server, name=None): - # Glance client - _image_client = self.image_client - # Compute client - _images_client = self.compute_images_client - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + 'snapshot') - LOG.debug("Creating a snapshot image for server: %s", server['name']) - image = _images_client.create_image(server['id'], name=name) - image_id = image.response['location'].split('images/')[1] - waiters.wait_for_image_status(_image_client, image_id, 'active') - - self.addCleanup(_image_client.wait_for_resource_deletion, - image_id) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - _image_client.delete_image, image_id) - - if CONF.image_feature_enabled.api_v1: - # In glance v1 the additional properties are stored in the headers. - resp = _image_client.check_image(image_id) - snapshot_image = common_image.get_image_meta_from_headers(resp) - image_props = snapshot_image.get('properties', {}) - else: - # In glance v2 the additional properties are flattened. - snapshot_image = _image_client.show_image(image_id) - image_props = snapshot_image - - bdm = image_props.get('block_device_mapping') - if bdm: - bdm = json.loads(bdm) - if bdm and 'snapshot_id' in bdm[0]: - snapshot_id = bdm[0]['snapshot_id'] - self.addCleanup( - self.snapshots_client.wait_for_resource_deletion, - snapshot_id) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.snapshots_client.delete_snapshot, - snapshot_id) - waiters.wait_for_volume_resource_status(self.snapshots_client, - snapshot_id, - 'available') - image_name = snapshot_image['name'] - self.assertEqual(name, image_name) - LOG.debug("Created snapshot image %s for server %s", - image_name, server['name']) - return snapshot_image - - def nova_volume_attach(self, server, volume_to_attach): - volume = self.servers_client.attach_volume( - server['id'], volumeId=volume_to_attach['id'], device='/dev/%s' - % CONF.compute.volume_device_name)['volumeAttachment'] - self.assertEqual(volume_to_attach['id'], volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'in-use') - - # Return the updated volume after the attachment - return self.volumes_client.show_volume(volume['id'])['volume'] - - def nova_volume_detach(self, server, volume): - self.servers_client.detach_volume(server['id'], volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - volume = self.volumes_client.show_volume(volume['id'])['volume'] - self.assertEqual('available', volume['status']) - - def rebuild_server(self, server_id, image=None, - preserve_ephemeral=False, wait=True, - rebuild_kwargs=None): - if image is None: - image = CONF.compute.image_ref - - rebuild_kwargs = rebuild_kwargs or {} - - LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)", - server_id, image, preserve_ephemeral) - self.servers_client.rebuild_server( - server_id=server_id, image_ref=image, - preserve_ephemeral=preserve_ephemeral, - **rebuild_kwargs) - if wait: - waiters.wait_for_server_status(self.servers_client, - server_id, 'ACTIVE') - - def ping_ip_address(self, ip_address, should_succeed=True, - ping_timeout=None, mtu=None): - timeout = ping_timeout or CONF.validation.ping_timeout - cmd = ['ping', '-c1', '-w1'] - - if mtu: - cmd += [ - # don't fragment - '-M', 'do', - # ping receives just the size of ICMP payload - '-s', str(net_utils.get_ping_payload_size(mtu, 4)) - ] - cmd.append(ip_address) - - def ping(): - proc = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - proc.communicate() - - return (proc.returncode == 0) == should_succeed - - caller = test_utils.find_test_caller() - LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the' - ' expected result is %(should_succeed)s', { - 'caller': caller, 'ip': ip_address, 'timeout': timeout, - 'should_succeed': - 'reachable' if should_succeed else 'unreachable' - }) - result = test_utils.call_until_true(ping, timeout, 1) - LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the ' - 'ping result is %(result)s', { - 'caller': caller, 'ip': ip_address, 'timeout': timeout, - 'result': 'expected' if result else 'unexpected' - }) - return result - - def check_vm_connectivity(self, ip_address, - username=None, - private_key=None, - should_connect=True, - mtu=None): - """Check server connectivity - - :param ip_address: server to test against - :param username: server's ssh username - :param private_key: server's ssh private key to be used - :param should_connect: True/False indicates positive/negative test - positive - attempt ping and ssh - negative - attempt ping and fail if succeed - :param mtu: network MTU to use for connectivity validation - - :raises: AssertError if the result of the connectivity check does - not match the value of the should_connect param - """ - if should_connect: - msg = "Timed out waiting for %s to become reachable" % ip_address - else: - msg = "ip address %s is reachable" % ip_address - self.assertTrue(self.ping_ip_address(ip_address, - should_succeed=should_connect, - mtu=mtu), - msg=msg) - if should_connect: - # no need to check ssh for negative connectivity - self.get_remote_client(ip_address, username, private_key) - - def check_public_network_connectivity(self, ip_address, username, - private_key, should_connect=True, - msg=None, servers=None, mtu=None): - # The target login is assumed to have been configured for - # key-based authentication by cloud-init. - LOG.debug('checking network connections to IP %s with user: %s', - ip_address, username) - try: - self.check_vm_connectivity(ip_address, - username, - private_key, - should_connect=should_connect, - mtu=mtu) - except Exception: - ex_msg = 'Public network connectivity check failed' - if msg: - ex_msg += ": " + msg - LOG.exception(ex_msg) - self._log_console_output(servers) - raise - - def create_floating_ip(self, thing, pool_name=None): - """Create a floating IP and associates to a server on Nova""" - - if not pool_name: - pool_name = CONF.network.floating_network_name - floating_ip = (self.compute_floating_ips_client. - create_floating_ip(pool=pool_name)['floating_ip']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.compute_floating_ips_client.delete_floating_ip, - floating_ip['id']) - self.compute_floating_ips_client.associate_floating_ip_to_server( - floating_ip['ip'], thing['id']) - return floating_ip - - def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt', - private_key=None): - ssh_client = self.get_remote_client(ip_address, - private_key=private_key) - if dev_name is not None: - ssh_client.make_fs(dev_name) - ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name, - mount_path)) - cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path - ssh_client.exec_command(cmd_timestamp) - timestamp = ssh_client.exec_command('sudo cat %s/timestamp' - % mount_path) - if dev_name is not None: - ssh_client.exec_command('sudo umount %s' % mount_path) - return timestamp - - def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt', - private_key=None): - ssh_client = self.get_remote_client(ip_address, - private_key=private_key) - if dev_name is not None: - ssh_client.mount(dev_name, mount_path) - timestamp = ssh_client.exec_command('sudo cat %s/timestamp' - % mount_path) - if dev_name is not None: - ssh_client.exec_command('sudo umount %s' % mount_path) - return timestamp - - def get_server_ip(self, server): - """Get the server fixed or floating IP. - - Based on the configuration we're in, return a correct ip - address for validating that a guest is up. - """ - if CONF.validation.connect_method == 'floating': - # The tests calling this method don't have a floating IP - # and can't make use of the validation resources. So the - # method is creating the floating IP there. - return self.create_floating_ip(server)['ip'] - elif CONF.validation.connect_method == 'fixed': - # Determine the network name to look for based on config or creds - # provider network resources. - if CONF.validation.network_for_ssh: - addresses = server['addresses'][ - CONF.validation.network_for_ssh] - else: - creds_provider = self._get_credentials_provider() - net_creds = creds_provider.get_primary_creds() - network = getattr(net_creds, 'network', None) - addresses = (server['addresses'][network['name']] - if network else []) - for address in addresses: - if (address['version'] == CONF.validation.ip_version_for_ssh - and address['OS-EXT-IPS:type'] == 'fixed'): - return address['addr'] - raise exceptions.ServerUnreachable(server_id=server['id']) - else: - raise lib_exc.InvalidConfiguration() - - -class NetworkScenarioTest(ScenarioTest): - """Base class for network scenario tests. - - This class provide helpers for network scenario tests, using the neutron - API. Helpers from ancestor which use the nova network API are overridden - with the neutron API. - - This Class also enforces using Neutron instead of novanetwork. - Subclassed tests will be skipped if Neutron is not enabled - - """ - - credentials = ['primary', 'admin'] - - @classmethod - def skip_checks(cls): - super(NetworkScenarioTest, cls).skip_checks() - if not CONF.service_available.neutron: - raise cls.skipException('Neutron not available') - - def _create_network(self, networks_client=None, - tenant_id=None, - namestart='network-smoke-', - port_security_enabled=True): - if not networks_client: - networks_client = self.networks_client - if not tenant_id: - tenant_id = networks_client.tenant_id - name = data_utils.rand_name(namestart) - network_kwargs = dict(name=name, tenant_id=tenant_id) - # Neutron disables port security by default so we have to check the - # config before trying to create the network with port_security_enabled - if CONF.network_feature_enabled.port_security: - network_kwargs['port_security_enabled'] = port_security_enabled - result = networks_client.create_network(**network_kwargs) - network = result['network'] - - self.assertEqual(network['name'], name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - networks_client.delete_network, - network['id']) - return network - - def _create_subnet(self, network, subnets_client=None, - routers_client=None, namestart='subnet-smoke', - **kwargs): - """Create a subnet for the given network - - within the cidr block configured for tenant networks. - """ - if not subnets_client: - subnets_client = self.subnets_client - if not routers_client: - routers_client = self.routers_client - - def cidr_in_use(cidr, tenant_id): - """Check cidr existence - - :returns: True if subnet with cidr already exist in tenant - False else - """ - cidr_in_use = self.os_admin.subnets_client.list_subnets( - tenant_id=tenant_id, cidr=cidr)['subnets'] - return len(cidr_in_use) != 0 - - ip_version = kwargs.pop('ip_version', 4) - - if ip_version == 6: - tenant_cidr = netaddr.IPNetwork( - CONF.network.project_network_v6_cidr) - num_bits = CONF.network.project_network_v6_mask_bits - else: - tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - num_bits = CONF.network.project_network_mask_bits - - result = None - str_cidr = None - # Repeatedly attempt subnet creation with sequential cidr - # blocks until an unallocated block is found. - for subnet_cidr in tenant_cidr.subnet(num_bits): - str_cidr = str(subnet_cidr) - if cidr_in_use(str_cidr, tenant_id=network['tenant_id']): - continue - - subnet = dict( - name=data_utils.rand_name(namestart), - network_id=network['id'], - tenant_id=network['tenant_id'], - cidr=str_cidr, - ip_version=ip_version, - **kwargs - ) - try: - result = subnets_client.create_subnet(**subnet) - break - except lib_exc.Conflict as e: - is_overlapping_cidr = 'overlaps with another subnet' in str(e) - if not is_overlapping_cidr: - raise - self.assertIsNotNone(result, 'Unable to allocate tenant network') - - subnet = result['subnet'] - self.assertEqual(subnet['cidr'], str_cidr) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - subnets_client.delete_subnet, subnet['id']) - - return subnet - - def _get_server_port_id_and_ip4(self, server, ip_addr=None): - ports = self.os_admin.ports_client.list_ports( - device_id=server['id'], fixed_ip=ip_addr)['ports'] - # A port can have more than one IP address in some cases. - # If the network is dual-stack (IPv4 + IPv6), this port is associated - # with 2 subnets - p_status = ['ACTIVE'] - # NOTE(vsaienko) With Ironic, instances live on separate hardware - # servers. Neutron does not bind ports for Ironic instances, as a - # result the port remains in the DOWN state. - # TODO(vsaienko) remove once bug: #1599836 is resolved. - if getattr(CONF.service_available, 'ironic', False): - p_status.append('DOWN') - port_map = [(p["id"], fxip["ip_address"]) - for p in ports - for fxip in p["fixed_ips"] - if netutils.is_valid_ipv4(fxip["ip_address"]) - and p['status'] in p_status] - inactive = [p for p in ports if p['status'] != 'ACTIVE'] - if inactive: - LOG.warning("Instance has ports that are not ACTIVE: %s", inactive) - - self.assertNotEmpty(port_map, - "No IPv4 addresses found in: %s" % ports) - self.assertEqual(len(port_map), 1, - "Found multiple IPv4 addresses: %s. " - "Unable to determine which port to target." - % port_map) - return port_map[0] - - def _get_network_by_name(self, network_name): - net = self.os_admin.networks_client.list_networks( - name=network_name)['networks'] - self.assertNotEmpty(net, - "Unable to get network by name: %s" % network_name) - return net[0] - - def create_floating_ip(self, thing, external_network_id=None, - port_id=None, client=None): - """Create a floating IP and associates to a resource/port on Neutron""" - if not external_network_id: - external_network_id = CONF.network.public_network_id - if not client: - client = self.floating_ips_client - if not port_id: - port_id, ip4 = self._get_server_port_id_and_ip4(thing) - else: - ip4 = None - result = client.create_floatingip( - floating_network_id=external_network_id, - port_id=port_id, - tenant_id=thing['tenant_id'], - fixed_ip_address=ip4 - ) - floating_ip = result['floatingip'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_floatingip, - floating_ip['id']) - return floating_ip - - def _associate_floating_ip(self, floating_ip, server): - port_id, _ = self._get_server_port_id_and_ip4(server) - kwargs = dict(port_id=port_id) - floating_ip = self.floating_ips_client.update_floatingip( - floating_ip['id'], **kwargs)['floatingip'] - self.assertEqual(port_id, floating_ip['port_id']) - return floating_ip - - def _disassociate_floating_ip(self, floating_ip): - """:param floating_ip: floating_ips_client.create_floatingip""" - kwargs = dict(port_id=None) - floating_ip = self.floating_ips_client.update_floatingip( - floating_ip['id'], **kwargs)['floatingip'] - self.assertIsNone(floating_ip['port_id']) - return floating_ip - - def check_floating_ip_status(self, floating_ip, status): - """Verifies floatingip reaches the given status - - :param dict floating_ip: floating IP dict to check status - :param status: target status - :raises: AssertionError if status doesn't match - """ - floatingip_id = floating_ip['id'] - - def refresh(): - result = (self.floating_ips_client. - show_floatingip(floatingip_id)['floatingip']) - return status == result['status'] - - if not test_utils.call_until_true(refresh, - CONF.network.build_timeout, - CONF.network.build_interval): - floating_ip = self.floating_ips_client.show_floatingip( - floatingip_id)['floatingip'] - self.assertEqual(status, floating_ip['status'], - message="FloatingIP: {fp} is at status: {cst}. " - "failed to reach status: {st}" - .format(fp=floating_ip, cst=floating_ip['status'], - st=status)) - LOG.info("FloatingIP: {fp} is at status: {st}" - .format(fp=floating_ip, st=status)) - - def _check_tenant_network_connectivity(self, server, - username, - private_key, - should_connect=True, - servers_for_debug=None): - if not CONF.network.project_networks_reachable: - msg = 'Tenant networks not configured to be reachable.' - LOG.info(msg) - return - # The target login is assumed to have been configured for - # key-based authentication by cloud-init. - try: - for ip_addresses in server['addresses'].values(): - for ip_address in ip_addresses: - self.check_vm_connectivity(ip_address['addr'], - username, - private_key, - should_connect=should_connect) - except Exception as e: - LOG.exception('Tenant network connectivity check failed') - self._log_console_output(servers_for_debug) - self._log_net_info(e) - raise - - def _check_remote_connectivity(self, source, dest, should_succeed=True, - nic=None): - """assert ping server via source ssh connection - - Note: This is an internal method. Use check_remote_connectivity - instead. - - :param source: RemoteClient: an ssh connection from which to ping - :param dest: and IP to ping against - :param should_succeed: boolean should ping succeed or not - :param nic: specific network interface to ping from - """ - def ping_remote(): - try: - source.ping_host(dest, nic=nic) - except lib_exc.SSHExecCommandFailed: - LOG.warning('Failed to ping IP: %s via a ssh connection ' - 'from: %s.', dest, source.ssh_client.host) - return not should_succeed - return should_succeed - - return test_utils.call_until_true(ping_remote, - CONF.validation.ping_timeout, - 1) - - def check_remote_connectivity(self, source, dest, should_succeed=True, - nic=None): - """assert ping server via source ssh connection - - :param source: RemoteClient: an ssh connection from which to ping - :param dest: and IP to ping against - :param should_succeed: boolean should ping succeed or not - :param nic: specific network interface to ping from - """ - result = self._check_remote_connectivity(source, dest, should_succeed, - nic) - source_host = source.ssh_client.host - if should_succeed: - msg = "Timed out waiting for %s to become reachable from %s" \ - % (dest, source_host) - else: - msg = "%s is reachable from %s" % (dest, source_host) - self.assertTrue(result, msg) - - def _create_security_group(self, security_group_rules_client=None, - tenant_id=None, - namestart='secgroup-smoke', - security_groups_client=None): - if security_group_rules_client is None: - security_group_rules_client = self.security_group_rules_client - if security_groups_client is None: - security_groups_client = self.security_groups_client - if tenant_id is None: - tenant_id = security_groups_client.tenant_id - secgroup = self._create_empty_security_group( - namestart=namestart, client=security_groups_client, - tenant_id=tenant_id) - - # Add rules to the security group - rules = self._create_loginable_secgroup_rule( - security_group_rules_client=security_group_rules_client, - secgroup=secgroup, - security_groups_client=security_groups_client) - for rule in rules: - self.assertEqual(tenant_id, rule['tenant_id']) - self.assertEqual(secgroup['id'], rule['security_group_id']) - return secgroup - - def _create_empty_security_group(self, client=None, tenant_id=None, - namestart='secgroup-smoke'): - """Create a security group without rules. - - Default rules will be created: - - IPv4 egress to any - - IPv6 egress to any - - :param tenant_id: secgroup will be created in this tenant - :returns: the created security group - """ - if client is None: - client = self.security_groups_client - if not tenant_id: - tenant_id = client.tenant_id - sg_name = data_utils.rand_name(namestart) - sg_desc = sg_name + " description" - sg_dict = dict(name=sg_name, - description=sg_desc) - sg_dict['tenant_id'] = tenant_id - result = client.create_security_group(**sg_dict) - - secgroup = result['security_group'] - self.assertEqual(secgroup['name'], sg_name) - self.assertEqual(tenant_id, secgroup['tenant_id']) - self.assertEqual(secgroup['description'], sg_desc) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_security_group, secgroup['id']) - return secgroup - - def _default_security_group(self, client=None, tenant_id=None): - """Get default secgroup for given tenant_id. - - :returns: default secgroup for given tenant - """ - if client is None: - client = self.security_groups_client - if not tenant_id: - tenant_id = client.tenant_id - sgs = [ - sg for sg in list(client.list_security_groups().values())[0] - if sg['tenant_id'] == tenant_id and sg['name'] == 'default' - ] - msg = "No default security group for tenant %s." % (tenant_id) - self.assertNotEmpty(sgs, msg) - return sgs[0] - - def _create_security_group_rule(self, secgroup=None, - sec_group_rules_client=None, - tenant_id=None, - security_groups_client=None, **kwargs): - """Create a rule from a dictionary of rule parameters. - - Create a rule in a secgroup. if secgroup not defined will search for - default secgroup in tenant_id. - - :param secgroup: the security group. - :param tenant_id: if secgroup not passed -- the tenant in which to - search for default secgroup - :param kwargs: a dictionary containing rule parameters: - for example, to allow incoming ssh: - rule = { - direction: 'ingress' - protocol:'tcp', - port_range_min: 22, - port_range_max: 22 - } - """ - if sec_group_rules_client is None: - sec_group_rules_client = self.security_group_rules_client - if security_groups_client is None: - security_groups_client = self.security_groups_client - if not tenant_id: - tenant_id = security_groups_client.tenant_id - if secgroup is None: - secgroup = self._default_security_group( - client=security_groups_client, tenant_id=tenant_id) - - ruleset = dict(security_group_id=secgroup['id'], - tenant_id=secgroup['tenant_id']) - ruleset.update(kwargs) - - sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset) - sg_rule = sg_rule['security_group_rule'] - - self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id']) - self.assertEqual(secgroup['id'], sg_rule['security_group_id']) - - return sg_rule - - def _create_loginable_secgroup_rule(self, security_group_rules_client=None, - secgroup=None, - security_groups_client=None): - """Create loginable security group rule - - This function will create: - 1. egress and ingress tcp port 22 allow rule in order to allow ssh - access for ipv4. - 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6. - 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4. - """ - - if security_group_rules_client is None: - security_group_rules_client = self.security_group_rules_client - if security_groups_client is None: - security_groups_client = self.security_groups_client - rules = [] - rulesets = [ - dict( - # ssh - protocol='tcp', - port_range_min=22, - port_range_max=22, - ), - dict( - # ping - protocol='icmp', - ), - dict( - # ipv6-icmp for ping6 - protocol='icmp', - ethertype='IPv6', - ) - ] - sec_group_rules_client = security_group_rules_client - for ruleset in rulesets: - for r_direction in ['ingress', 'egress']: - ruleset['direction'] = r_direction - try: - sg_rule = self._create_security_group_rule( - sec_group_rules_client=sec_group_rules_client, - secgroup=secgroup, - security_groups_client=security_groups_client, - **ruleset) - except lib_exc.Conflict as ex: - # if rule already exist - skip rule and continue - msg = 'Security group rule already exists' - if msg not in ex._error_string: - raise ex - else: - self.assertEqual(r_direction, sg_rule['direction']) - rules.append(sg_rule) - - return rules - - def _get_router(self, client=None, tenant_id=None): - """Retrieve a router for the given tenant id. - - If a public router has been configured, it will be returned. - - If a public router has not been configured, but a public - network has, a tenant router will be created and returned that - routes traffic to the public network. - """ - if not client: - client = self.routers_client - if not tenant_id: - tenant_id = client.tenant_id - router_id = CONF.network.public_router_id - network_id = CONF.network.public_network_id - if router_id: - body = client.show_router(router_id) - return body['router'] - elif network_id: - router = self._create_router(client, tenant_id) - kwargs = {'external_gateway_info': dict(network_id=network_id)} - router = client.update_router(router['id'], **kwargs)['router'] - return router - else: - raise Exception("Neither of 'public_router_id' or " - "'public_network_id' has been defined.") - - def _create_router(self, client=None, tenant_id=None, - namestart='router-smoke'): - if not client: - client = self.routers_client - if not tenant_id: - tenant_id = client.tenant_id - name = data_utils.rand_name(namestart) - result = client.create_router(name=name, - admin_state_up=True, - tenant_id=tenant_id) - router = result['router'] - self.assertEqual(router['name'], name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_router, - router['id']) - return router - - def _update_router_admin_state(self, router, admin_state_up): - kwargs = dict(admin_state_up=admin_state_up) - router = self.routers_client.update_router( - router['id'], **kwargs)['router'] - self.assertEqual(admin_state_up, router['admin_state_up']) - - def create_networks(self, networks_client=None, - routers_client=None, subnets_client=None, - tenant_id=None, dns_nameservers=None, - port_security_enabled=True): - """Create a network with a subnet connected to a router. - - The baremetal driver is a special case since all nodes are - on the same shared network. - - :param tenant_id: id of tenant to create resources in. - :param dns_nameservers: list of dns servers to send to subnet. - :returns: network, subnet, router - """ - if CONF.network.shared_physical_network: - # NOTE(Shrews): This exception is for environments where tenant - # credential isolation is available, but network separation is - # not (the current baremetal case). Likely can be removed when - # test account mgmt is reworked: - # https://blueprints.launchpad.net/tempest/+spec/test-accounts - if not CONF.compute.fixed_network_name: - m = 'fixed_network_name must be specified in config' - raise lib_exc.InvalidConfiguration(m) - network = self._get_network_by_name( - CONF.compute.fixed_network_name) - router = None - subnet = None - else: - network = self._create_network( - networks_client=networks_client, - tenant_id=tenant_id, - port_security_enabled=port_security_enabled) - router = self._get_router(client=routers_client, - tenant_id=tenant_id) - subnet_kwargs = dict(network=network, - subnets_client=subnets_client, - routers_client=routers_client) - # use explicit check because empty list is a valid option - if dns_nameservers is not None: - subnet_kwargs['dns_nameservers'] = dns_nameservers - subnet = self._create_subnet(**subnet_kwargs) - if not routers_client: - routers_client = self.routers_client - router_id = router['id'] - routers_client.add_router_interface(router_id, - subnet_id=subnet['id']) - - # save a cleanup job to remove this association between - # router and subnet - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - routers_client.remove_router_interface, router_id, - subnet_id=subnet['id']) - return network, subnet, router - - -class EncryptionScenarioTest(ScenarioTest): - """Base class for encryption scenario tests""" - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(EncryptionScenarioTest, cls).setup_clients() - cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client - cls.admin_encryption_types_client =\ - cls.os_admin.encryption_types_v2_client - - def create_encryption_type(self, client=None, type_id=None, provider=None, - key_size=None, cipher=None, - control_location=None): - if not client: - client = self.admin_encryption_types_client - if not type_id: - volume_type = self.create_volume_type() - type_id = volume_type['id'] - LOG.debug("Creating an encryption type for volume type: %s", type_id) - client.create_encryption_type( - type_id, provider=provider, key_size=key_size, cipher=cipher, - control_location=control_location)['encryption'] - - def create_encrypted_volume(self, encryption_provider, volume_type, - key_size=256, cipher='aes-xts-plain64', - control_location='front-end'): - volume_type = self.create_volume_type(name=volume_type) - self.create_encryption_type(type_id=volume_type['id'], - provider=encryption_provider, - key_size=key_size, - cipher=cipher, - control_location=control_location) - return self.create_volume(volume_type=volume_type['name']) - - -class ObjectStorageScenarioTest(ScenarioTest): - """Provide harness to do Object Storage scenario tests. - - Subclasses implement the tests that use the methods provided by this - class. - """ - - @classmethod - def skip_checks(cls): - super(ObjectStorageScenarioTest, cls).skip_checks() - if not CONF.service_available.swift: - skip_msg = ("%s skipped as swift is not available" % - cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(ObjectStorageScenarioTest, cls).setup_credentials() - operator_role = CONF.object_storage.operator_role - cls.os_operator = cls.get_client_manager(roles=[operator_role]) - - @classmethod - def setup_clients(cls): - super(ObjectStorageScenarioTest, cls).setup_clients() - # Clients for Swift - cls.account_client = cls.os_operator.account_client - cls.container_client = cls.os_operator.container_client - cls.object_client = cls.os_operator.object_client - - def get_swift_stat(self): - """get swift status for our user account.""" - self.account_client.list_account_containers() - LOG.debug('Swift status information obtained successfully') - - def create_container(self, container_name=None): - name = container_name or data_utils.rand_name( - 'swift-scenario-container') - self.container_client.create_container(name) - # look for the container to assure it is created - self.list_and_check_container_objects(name) - LOG.debug('Container %s created', name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.container_client.delete_container, - name) - return name - - def delete_container(self, container_name): - self.container_client.delete_container(container_name) - LOG.debug('Container %s deleted', container_name) - - def upload_object_to_container(self, container_name, obj_name=None): - obj_name = obj_name or data_utils.rand_name('swift-scenario-object') - obj_data = data_utils.random_bytes() - self.object_client.create_object(container_name, obj_name, obj_data) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.object_client.delete_object, - container_name, - obj_name) - return obj_name, obj_data - - def delete_object(self, container_name, filename): - self.object_client.delete_object(container_name, filename) - self.list_and_check_container_objects(container_name, - not_present_obj=[filename]) - - def list_and_check_container_objects(self, container_name, - present_obj=None, - not_present_obj=None): - # List objects for a given container and assert which are present and - # which are not. - if present_obj is None: - present_obj = [] - if not_present_obj is None: - not_present_obj = [] - _, object_list = self.container_client.list_container_contents( - container_name) - if present_obj: - for obj in present_obj: - self.assertIn(obj, object_list) - if not_present_obj: - for obj in not_present_obj: - self.assertNotIn(obj, object_list) - - def change_container_acl(self, container_name, acl): - metadata_param = {'metadata_prefix': 'x-container-', - 'metadata': {'read': acl}} - self.container_client.update_container_metadata(container_name, - **metadata_param) - resp, _ = self.container_client.list_container_metadata(container_name) - self.assertEqual(resp['x-container-read'], acl) - - def download_and_verify(self, container_name, obj_name, expected_data): - _, obj = self.object_client.get_object(container_name, obj_name) - self.assertEqual(obj, expected_data) diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py deleted file mode 100644 index 25227be74..000000000 --- a/tempest/scenario/test_aggregates_basic_ops.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.common import tempest_fixtures as fixtures -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - - -class TestAggregatesBasicOps(manager.ScenarioTest): - """Creates an aggregate within an availability zone - - Adds a host to the aggregate - Checks aggregate details - Updates aggregate's name - Removes host from aggregate - Deletes aggregate - """ - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(TestAggregatesBasicOps, cls).setup_clients() - # Use admin client by default - cls.aggregates_client = cls.os_admin.aggregates_client - cls.hosts_client = cls.os_admin.hosts_client - - def _create_aggregate(self, **kwargs): - aggregate = (self.aggregates_client.create_aggregate(**kwargs) - ['aggregate']) - self.addCleanup(self.aggregates_client.delete_aggregate, - aggregate['id']) - aggregate_name = kwargs['name'] - availability_zone = kwargs['availability_zone'] - self.assertEqual(aggregate['name'], aggregate_name) - self.assertEqual(aggregate['availability_zone'], availability_zone) - return aggregate - - def _get_host_name(self): - hosts = self.hosts_client.list_hosts()['hosts'] - self.assertNotEmpty(hosts) - computes = [x for x in hosts if x['service'] == 'compute'] - return computes[0]['host_name'] - - def _add_host(self, aggregate_id, host): - aggregate = (self.aggregates_client.add_host(aggregate_id, host=host) - ['aggregate']) - self.addCleanup(self._remove_host, aggregate['id'], host) - self.assertIn(host, aggregate['hosts']) - - def _remove_host(self, aggregate_id, host): - aggregate = self.aggregates_client.remove_host(aggregate_id, host=host) - self.assertNotIn(host, aggregate['aggregate']['hosts']) - - def _check_aggregate_details(self, aggregate, aggregate_name, azone, - hosts, metadata): - aggregate = (self.aggregates_client.show_aggregate(aggregate['id']) - ['aggregate']) - self.assertEqual(aggregate_name, aggregate['name']) - self.assertEqual(azone, aggregate['availability_zone']) - self.assertEqual(hosts, aggregate['hosts']) - for meta_key in metadata: - self.assertIn(meta_key, aggregate['metadata']) - self.assertEqual(metadata[meta_key], - aggregate['metadata'][meta_key]) - - def _set_aggregate_metadata(self, aggregate, meta): - aggregate = self.aggregates_client.set_metadata(aggregate['id'], - metadata=meta) - - for key in meta.keys(): - self.assertEqual(meta[key], - aggregate['aggregate']['metadata'][key]) - - def _update_aggregate(self, aggregate, aggregate_name, - availability_zone): - aggregate = self.aggregates_client.update_aggregate( - aggregate['id'], name=aggregate_name, - availability_zone=availability_zone)['aggregate'] - self.assertEqual(aggregate['name'], aggregate_name) - self.assertEqual(aggregate['availability_zone'], availability_zone) - return aggregate - - @decorators.idempotent_id('cb2b4c4f-0c7c-4164-bdde-6285b302a081') - @decorators.attr(type='slow') - @test.services('compute') - def test_aggregate_basic_ops(self): - self.useFixture(fixtures.LockFixture('availability_zone')) - az = 'foo_zone' - aggregate_name = data_utils.rand_name('aggregate-scenario') - aggregate = self._create_aggregate(name=aggregate_name, - availability_zone=az) - - metadata = {'meta_key': 'meta_value'} - self._set_aggregate_metadata(aggregate, metadata) - - host = self._get_host_name() - self._add_host(aggregate['id'], host) - self._check_aggregate_details(aggregate, aggregate_name, az, [host], - metadata) - - aggregate_name = data_utils.rand_name('renamed-aggregate-scenario') - # Updating the name alone. The az must be specified again otherwise - # the tempest client would send None in the put body - aggregate = self._update_aggregate(aggregate, aggregate_name, az) - - new_metadata = {'foo': 'bar'} - self._set_aggregate_metadata(aggregate, new_metadata) - - self._check_aggregate_details(aggregate, aggregate['name'], az, - [host], new_metadata) diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py deleted file mode 100644 index cbdf30766..000000000 --- a/tempest/scenario/test_encrypted_cinder_volumes.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright (c) 2014 The Johns Hopkins University/Applied Physics Laboratory -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestEncryptedCinderVolumes(manager.EncryptionScenarioTest): - - """The test suite for encrypted cinder volumes - - This test is for verifying the functionality of encrypted cinder volumes. - - For both LUKS and cryptsetup encryption types, this test performs - the following: - * Creates an image in Glance - * Boots an instance from the image - * Creates an encryption type (as admin) - * Creates a volume of that encryption type (as a regular user) - * Attaches and detaches the encrypted volume to the instance - """ - - @classmethod - def skip_checks(cls): - super(TestEncryptedCinderVolumes, cls).skip_checks() - if not CONF.compute_feature_enabled.attach_encrypted_volume: - raise cls.skipException('Encrypted volume attach is not supported') - - def launch_instance(self): - image = self.glance_image_create() - keypair = self.create_keypair() - - return self.create_server(image_id=image, key_name=keypair['name']) - - def attach_detach_volume(self, server, volume): - attached_volume = self.nova_volume_attach(server, volume) - self.nova_volume_detach(server, attached_volume) - - @decorators.idempotent_id('79165fb4-5534-4b9d-8429-97ccffb8f86e') - @decorators.attr(type='slow') - @test.services('compute', 'volume', 'image') - def test_encrypted_cinder_volumes_luks(self): - server = self.launch_instance() - volume = self.create_encrypted_volume('nova.volume.encryptors.' - 'luks.LuksEncryptor', - volume_type='luks') - self.attach_detach_volume(server, volume) - - @decorators.idempotent_id('cbc752ed-b716-4717-910f-956cce965722') - @decorators.attr(type='slow') - @test.services('compute', 'volume', 'image') - def test_encrypted_cinder_volumes_cryptsetup(self): - server = self.launch_instance() - volume = self.create_encrypted_volume('nova.volume.encryptors.' - 'cryptsetup.CryptsetupEncryptor', - volume_type='cryptsetup') - self.attach_detach_volume(server, volume) diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py deleted file mode 100644 index 26a834b94..000000000 --- a/tempest/scenario/test_minimum_basic.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.common import custom_matchers -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestMinimumBasicScenario(manager.ScenarioTest): - - """This is a basic minimum scenario test. - - This test below: - * across the multiple components - * as a regular user - * with and without optional parameters - * check command outputs - - Steps: - 1. Create image - 2. Create keypair - 3. Boot instance with keypair and get list of instances - 4. Create volume and show list of volumes - 5. Attach volume to instance and getlist of volumes - 6. Add IP to instance - 7. Create and add security group to instance - 8. Check SSH connection to instance - 9. Reboot instance - 10. Check SSH connection to instance after reboot - - """ - def nova_show(self, server): - got_server = (self.servers_client.show_server(server['id']) - ['server']) - excluded_keys = ['OS-EXT-AZ:availability_zone'] - # Exclude these keys because of LP:#1486475 - excluded_keys.extend(['OS-EXT-STS:power_state', 'updated']) - self.assertThat( - server, custom_matchers.MatchesDictExceptForKeys( - got_server, excluded_keys=excluded_keys)) - - def cinder_show(self, volume): - got_volume = self.volumes_client.show_volume(volume['id'])['volume'] - self.assertEqual(volume, got_volume) - - def nova_reboot(self, server): - self.servers_client.reboot_server(server['id'], type='SOFT') - waiters.wait_for_server_status(self.servers_client, - server['id'], 'ACTIVE') - - def check_disks(self): - # NOTE(andreaf) The device name may be different on different guest OS - disks = self.linux_client.get_disks() - self.assertEqual(1, disks.count(CONF.compute.volume_device_name)) - - def create_and_add_security_group_to_server(self, server): - secgroup = self._create_security_group() - self.servers_client.add_security_group(server['id'], - name=secgroup['name']) - self.addCleanup(self.servers_client.remove_security_group, - server['id'], name=secgroup['name']) - - def wait_for_secgroup_add(): - body = (self.servers_client.show_server(server['id']) - ['server']) - return {'name': secgroup['name']} in body['security_groups'] - - if not test_utils.call_until_true(wait_for_secgroup_add, - CONF.compute.build_timeout, - CONF.compute.build_interval): - msg = ('Timed out waiting for adding security group %s to server ' - '%s' % (secgroup['id'], server['id'])) - raise exceptions.TimeoutException(msg) - - def _get_floating_ip_in_server_addresses(self, floating_ip, server): - for addresses in server['addresses'].values(): - for address in addresses: - if (address['OS-EXT-IPS:type'] == 'floating' and - address['addr'] == floating_ip['ip']): - return address - - @decorators.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @testtools.skipUnless(CONF.network_feature_enabled.floating_ips, - 'Floating ips are not available') - @test.services('compute', 'volume', 'image', 'network') - def test_minimum_basic_scenario(self): - image = self.glance_image_create() - keypair = self.create_keypair() - - server = self.create_server(image_id=image, key_name=keypair['name']) - servers = self.servers_client.list_servers()['servers'] - self.assertIn(server['id'], [x['id'] for x in servers]) - - self.nova_show(server) - - volume = self.create_volume() - volumes = self.volumes_client.list_volumes()['volumes'] - self.assertIn(volume['id'], [x['id'] for x in volumes]) - - self.cinder_show(volume) - - volume = self.nova_volume_attach(server, volume) - self.addCleanup(self.nova_volume_detach, server, volume) - self.cinder_show(volume) - - floating_ip = self.create_floating_ip(server) - # fetch the server again to make sure the addresses were refreshed - # after associating the floating IP - server = self.servers_client.show_server(server['id'])['server'] - address = self._get_floating_ip_in_server_addresses( - floating_ip, server) - self.assertIsNotNone( - address, - "Failed to find floating IP '%s' in server addresses: %s" % - (floating_ip['ip'], server['addresses'])) - - self.create_and_add_security_group_to_server(server) - - # check that we can SSH to the server before reboot - self.linux_client = self.get_remote_client( - floating_ip['ip'], private_key=keypair['private_key'], - server=server) - - self.nova_reboot(server) - - # check that we can SSH to the server after reboot - # (both connections are part of the scenario) - self.linux_client = self.get_remote_client( - floating_ip['ip'], private_key=keypair['private_key'], - server=server) - - self.check_disks() - - # delete the floating IP, this should refresh the server addresses - self.compute_floating_ips_client.delete_floating_ip(floating_ip['id']) - - def is_floating_ip_detached_from_server(): - server_info = self.servers_client.show_server( - server['id'])['server'] - address = self._get_floating_ip_in_server_addresses( - floating_ip, server_info) - return (not address) - - if not test_utils.call_until_true( - is_floating_ip_detached_from_server, - CONF.compute.build_timeout, - CONF.compute.build_interval): - msg = ("Floating IP '%s' should not be in server addresses: %s" % - (floating_ip['ip'], server['addresses'])) - raise exceptions.TimeoutException(msg) diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py deleted file mode 100644 index c8add8b61..000000000 --- a/tempest/scenario/test_network_advanced_server_ops.py +++ /dev/null @@ -1,251 +0,0 @@ -# Copyright 2014 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestNetworkAdvancedServerOps(manager.NetworkScenarioTest): - """Check VM connectivity after some advanced instance operations executed: - - * Stop/Start an instance - * Reboot an instance - * Rebuild an instance - * Pause/Unpause an instance - * Suspend/Resume an instance - * Resize an instance - """ - - @classmethod - def setup_clients(cls): - super(TestNetworkAdvancedServerOps, cls).setup_clients() - cls.admin_servers_client = cls.os_admin.servers_client - - @classmethod - def skip_checks(cls): - super(TestNetworkAdvancedServerOps, cls).skip_checks() - if not (CONF.network.project_networks_reachable - or CONF.network.public_network_id): - msg = ('Either project_networks_reachable must be "true", or ' - 'public_network_id must be defined.') - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_credentials(cls): - # Create no network resources for these tests. - cls.set_network_resources() - super(TestNetworkAdvancedServerOps, cls).setup_credentials() - - def _setup_server(self, keypair): - security_groups = [] - if test.is_extension_enabled('security-group', 'network'): - security_group = self._create_security_group() - security_groups = [{'name': security_group['name']}] - network, _, _ = self.create_networks() - server = self.create_server( - networks=[{'uuid': network['id']}], - key_name=keypair['name'], - security_groups=security_groups) - return server - - def _setup_network(self, server, keypair): - public_network_id = CONF.network.public_network_id - floating_ip = self.create_floating_ip(server, public_network_id) - # Verify that we can indeed connect to the server before we mess with - # it's state - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - return floating_ip - - def _check_network_connectivity(self, server, keypair, floating_ip, - should_connect=True): - username = CONF.validation.image_ssh_user - private_key = keypair['private_key'] - self._check_tenant_network_connectivity( - server, username, private_key, - should_connect=should_connect, - servers_for_debug=[server]) - floating_ip_addr = floating_ip['floating_ip_address'] - # Check FloatingIP status before checking the connectivity - self.check_floating_ip_status(floating_ip, 'ACTIVE') - self.check_public_network_connectivity(floating_ip_addr, username, - private_key, should_connect, - servers=[server]) - - def _wait_server_status_and_check_network_connectivity(self, server, - keypair, - floating_ip): - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - self._check_network_connectivity(server, keypair, floating_ip) - - def _get_host_for_server(self, server_id): - body = self.admin_servers_client.show_server(server_id)['server'] - return body['OS-EXT-SRV-ATTR:host'] - - @decorators.idempotent_id('61f1aa9a-1573-410e-9054-afa557cab021') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_stop_start(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - self.servers_client.stop_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'SHUTOFF') - self._check_network_connectivity(server, keypair, floating_ip, - should_connect=False) - self.servers_client.start_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('7b6860c2-afa3-4846-9522-adeb38dfbe08') - @test.services('compute', 'network') - def test_server_connectivity_reboot(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - self.servers_client.reboot_server(server['id'], type='SOFT') - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('88a529c2-1daa-4c85-9aec-d541ba3eb699') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_rebuild(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - image_ref_alt = CONF.compute.image_ref_alt - self.servers_client.rebuild_server(server['id'], - image_ref=image_ref_alt) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('2b2642db-6568-4b35-b812-eceed3fa20ce') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_pause_unpause(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - self.servers_client.pause_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'PAUSED') - self._check_network_connectivity(server, keypair, floating_ip, - should_connect=False) - self.servers_client.unpause_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('5cdf9499-541d-4923-804e-b9a60620a7f0') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_suspend_resume(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - self.servers_client.suspend_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'SUSPENDED') - self._check_network_connectivity(server, keypair, floating_ip, - should_connect=False) - self.servers_client.resume_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('719eb59d-2f42-4b66-b8b1-bb1254473967') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize is not available.') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_resize(self): - resize_flavor = CONF.compute.flavor_ref_alt - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - self.servers_client.resize_server(server['id'], - flavor_ref=resize_flavor) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'VERIFY_RESIZE') - self.servers_client.confirm_resize_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('a4858f6c-401e-4155-9a49-d5cd053d1a2f') - @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, - 'Cold migration is not available.') - @testtools.skipUnless(CONF.compute.min_compute_nodes > 1, - 'Less than 2 compute nodes, skipping multinode ' - 'tests.') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_cold_migration(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - src_host = self._get_host_for_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - self.admin_servers_client.migrate_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'VERIFY_RESIZE') - self.servers_client.confirm_resize_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - dst_host = self._get_host_for_server(server['id']) - - self.assertNotEqual(src_host, dst_host) - - @decorators.idempotent_id('25b188d7-0183-4b1e-a11d-15840c8e2fd6') - @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, - 'Cold migration is not available.') - @testtools.skipUnless(CONF.compute.min_compute_nodes > 1, - 'Less than 2 compute nodes, skipping multinode ' - 'tests.') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_cold_migration_revert(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - src_host = self._get_host_for_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - self.admin_servers_client.migrate_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'VERIFY_RESIZE') - self.servers_client.revert_resize_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - dst_host = self._get_host_for_server(server['id']) - - self.assertEqual(src_host, dst_host) diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py deleted file mode 100644 index 48ddac684..000000000 --- a/tempest/scenario/test_network_basic_ops.py +++ /dev/null @@ -1,857 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import collections -import re - -from oslo_log import log as logging -import testtools - -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF -LOG = logging.getLogger(__name__) - -Floating_IP_tuple = collections.namedtuple('Floating_IP_tuple', - ['floating_ip', 'server']) - - -class TestNetworkBasicOps(manager.NetworkScenarioTest): - - """The test suite of network basic operations - - This smoke test suite assumes that Nova has been configured to - boot VM's with Neutron-managed networking, and attempts to - verify network connectivity as follows: - - There are presumed to be two types of networks: tenant and - public. A tenant network may or may not be reachable from the - Tempest host. A public network is assumed to be reachable from - the Tempest host, and it should be possible to associate a public - ('floating') IP address with a tenant ('fixed') IP address to - facilitate external connectivity to a potentially unroutable - tenant IP address. - - This test suite can be configured to test network connectivity to - a VM via a tenant network, a public network, or both. If both - networking types are to be evaluated, tests that need to be - executed remotely on the VM (via ssh) will only be run against - one of the networks (to minimize test execution time). - - Determine which types of networks to test as follows: - - * Configure tenant network checks (via the - 'project_networks_reachable' key) if the Tempest host should - have direct connectivity to tenant networks. This is likely to - be the case if Tempest is running on the same host as a - single-node devstack installation with IP namespaces disabled. - - * Configure checks for a public network if a public network has - been configured prior to the test suite being run and if the - Tempest host should have connectivity to that public network. - Checking connectivity for a public network requires that a - value be provided for 'public_network_id'. A value can - optionally be provided for 'public_router_id' if tenants will - use a shared router to access a public network (as is likely to - be the case when IP namespaces are not enabled). If a value is - not provided for 'public_router_id', a router will be created - for each tenant and use the network identified by - 'public_network_id' as its gateway. - - """ - - @classmethod - def skip_checks(cls): - super(TestNetworkBasicOps, cls).skip_checks() - if not (CONF.network.project_networks_reachable - or CONF.network.public_network_id): - msg = ('Either project_networks_reachable must be "true", or ' - 'public_network_id must be defined.') - raise cls.skipException(msg) - for ext in ['router', 'security-group']: - if not test.is_extension_enabled(ext, 'network'): - msg = "%s extension not enabled." % ext - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_credentials(cls): - # Create no network resources for these tests. - cls.set_network_resources() - super(TestNetworkBasicOps, cls).setup_credentials() - - def setUp(self): - super(TestNetworkBasicOps, self).setUp() - self.keypairs = {} - self.servers = [] - - def _setup_network_and_servers(self, **kwargs): - boot_with_port = kwargs.pop('boot_with_port', False) - self.network, self.subnet, self.router = self.create_networks(**kwargs) - self.check_networks() - - self.ports = [] - port_id = None - if boot_with_port: - # create a port on the network and boot with that - port_id = self._create_port(self.network['id'])['id'] - self.ports.append({'port': port_id}) - - server = self._create_server(self.network, port_id) - self._check_tenant_network_connectivity() - - floating_ip = self.create_floating_ip(server) - self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server) - - def check_networks(self): - """Checks that we see the newly created network/subnet/router - - via checking the result of list_[networks,routers,subnets] - """ - - seen_nets = self.os_admin.networks_client.list_networks() - seen_names = [n['name'] for n in seen_nets['networks']] - seen_ids = [n['id'] for n in seen_nets['networks']] - self.assertIn(self.network['name'], seen_names) - self.assertIn(self.network['id'], seen_ids) - - if self.subnet: - seen_subnets = self.os_admin.subnets_client.list_subnets() - seen_net_ids = [n['network_id'] for n in seen_subnets['subnets']] - seen_subnet_ids = [n['id'] for n in seen_subnets['subnets']] - self.assertIn(self.network['id'], seen_net_ids) - self.assertIn(self.subnet['id'], seen_subnet_ids) - - if self.router: - seen_routers = self.os_admin.routers_client.list_routers() - seen_router_ids = [n['id'] for n in seen_routers['routers']] - seen_router_names = [n['name'] for n in seen_routers['routers']] - self.assertIn(self.router['name'], - seen_router_names) - self.assertIn(self.router['id'], - seen_router_ids) - - def _create_server(self, network, port_id=None): - keypair = self.create_keypair() - self.keypairs[keypair['name']] = keypair - security_groups = [ - {'name': self._create_security_group()['name']} - ] - network = {'uuid': network['id']} - if port_id is not None: - network['port'] = port_id - - server = self.create_server( - networks=[network], - key_name=keypair['name'], - security_groups=security_groups) - self.servers.append(server) - return server - - def _get_server_key(self, server): - return self.keypairs[server['key_name']]['private_key'] - - def _check_tenant_network_connectivity(self): - ssh_login = CONF.validation.image_ssh_user - for server in self.servers: - # call the common method in the parent class - super(TestNetworkBasicOps, self).\ - _check_tenant_network_connectivity( - server, ssh_login, self._get_server_key(server), - servers_for_debug=self.servers) - - def check_public_network_connectivity( - self, should_connect=True, msg=None, - should_check_floating_ip_status=True, mtu=None): - """Verifies connectivty to a VM via public network and floating IP - - and verifies floating IP has resource status is correct. - - :param should_connect: bool. determines if connectivity check is - negative or positive. - :param msg: Failure message to add to Error message. Should describe - the place in the test scenario where the method was called, - to indicate the context of the failure - :param should_check_floating_ip_status: bool. should status of - floating_ip be checked or not - :param mtu: int. MTU network to use for connectivity validation - """ - ssh_login = CONF.validation.image_ssh_user - floating_ip, server = self.floating_ip_tuple - ip_address = floating_ip['floating_ip_address'] - private_key = None - floatingip_status = 'DOWN' - if should_connect: - private_key = self._get_server_key(server) - floatingip_status = 'ACTIVE' - # Check FloatingIP Status before initiating a connection - if should_check_floating_ip_status: - self.check_floating_ip_status(floating_ip, floatingip_status) - # call the common method in the parent class - super(TestNetworkBasicOps, self).check_public_network_connectivity( - ip_address, ssh_login, private_key, should_connect, msg, - self.servers, mtu=mtu) - - def _disassociate_floating_ips(self): - floating_ip, _ = self.floating_ip_tuple - self._disassociate_floating_ip(floating_ip) - self.floating_ip_tuple = Floating_IP_tuple( - floating_ip, None) - - def _reassociate_floating_ips(self): - floating_ip, server = self.floating_ip_tuple - # create a new server for the floating ip - server = self._create_server(self.network) - self._associate_floating_ip(floating_ip, server) - self.floating_ip_tuple = Floating_IP_tuple( - floating_ip, server) - - def _create_new_network(self, create_gateway=False): - self.new_net = self._create_network() - if create_gateway: - self.new_subnet = self._create_subnet( - network=self.new_net) - else: - self.new_subnet = self._create_subnet( - network=self.new_net, - gateway_ip=None) - - def _hotplug_server(self): - old_floating_ip, server = self.floating_ip_tuple - ip_address = old_floating_ip['floating_ip_address'] - private_key = self._get_server_key(server) - ssh_client = self.get_remote_client( - ip_address, private_key=private_key, server=server) - old_nic_list = self._get_server_nics(ssh_client) - # get a port from a list of one item - port_list = self.os_admin.ports_client.list_ports( - device_id=server['id'])['ports'] - self.assertEqual(1, len(port_list)) - old_port = port_list[0] - interface = self.interface_client.create_interface( - server_id=server['id'], - net_id=self.new_net['id'])['interfaceAttachment'] - self.addCleanup(self.ports_client.wait_for_resource_deletion, - interface['port_id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.interface_client.delete_interface, - server['id'], interface['port_id']) - - def check_ports(): - self.new_port_list = [ - port for port in - self.os_admin.ports_client.list_ports( - device_id=server['id'])['ports'] - if port['id'] != old_port['id'] - ] - return len(self.new_port_list) == 1 - - if not test_utils.call_until_true( - check_ports, CONF.network.build_timeout, - CONF.network.build_interval): - raise exceptions.TimeoutException( - "No new port attached to the server in time (%s sec)! " - "Old port: %s. Number of new ports: %d" % ( - CONF.network.build_timeout, old_port, - len(self.new_port_list))) - new_port = self.new_port_list[0] - - def check_new_nic(): - new_nic_list = self._get_server_nics(ssh_client) - self.diff_list = [n for n in new_nic_list if n not in old_nic_list] - return len(self.diff_list) == 1 - - if not test_utils.call_until_true( - check_new_nic, CONF.network.build_timeout, - CONF.network.build_interval): - raise exceptions.TimeoutException("Interface not visible on the " - "guest after %s sec" - % CONF.network.build_timeout) - - _, new_nic = self.diff_list[0] - ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % ( - new_port['fixed_ips'][0]['ip_address'], - CONF.network.project_network_mask_bits, - new_nic)) - ssh_client.exec_command("sudo ip link set %s up" % new_nic) - - def _get_server_nics(self, ssh_client): - reg = re.compile(r'(?P\d+): (?P\w+)[@]?.*:') - ipatxt = ssh_client.exec_command("ip address") - return reg.findall(ipatxt) - - def _check_network_internal_connectivity(self, network, - should_connect=True): - """via ssh check VM internal connectivity: - - - ping internal gateway and DHCP port, implying in-tenant connectivity - pinging both, because L3 and DHCP agents might be on different nodes - """ - floating_ip, server = self.floating_ip_tuple - # get internal ports' ips: - # get all network ports in the new network - internal_ips = ( - p['fixed_ips'][0]['ip_address'] for p in - self.os_admin.ports_client.list_ports( - tenant_id=server['tenant_id'], - network_id=network['id'])['ports'] - if p['device_owner'].startswith('network') - ) - - self._check_server_connectivity(floating_ip, - internal_ips, - should_connect) - - def _check_network_external_connectivity(self): - """ping default gateway to imply external connectivity""" - if not CONF.network.public_network_id: - msg = 'public network not defined.' - LOG.info(msg) - return - - # We ping the external IP from the instance using its floating IP - # which is always IPv4, so we must only test connectivity to - # external IPv4 IPs if the external network is dualstack. - v4_subnets = [ - s for s in self.os_admin.subnets_client.list_subnets( - network_id=CONF.network.public_network_id)['subnets'] - if s['ip_version'] == 4 - ] - self.assertEqual(1, len(v4_subnets), - "Found %d IPv4 subnets" % len(v4_subnets)) - - external_ips = [v4_subnets[0]['gateway_ip']] - self._check_server_connectivity(self.floating_ip_tuple.floating_ip, - external_ips) - - def _check_server_connectivity(self, floating_ip, address_list, - should_connect=True): - ip_address = floating_ip['floating_ip_address'] - private_key = self._get_server_key(self.floating_ip_tuple.server) - ssh_source = self.get_remote_client( - ip_address, private_key=private_key, - server=self.floating_ip_tuple.server) - - for remote_ip in address_list: - self.check_remote_connectivity(ssh_source, remote_ip, - should_connect) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f323b3ba-82f8-4db7-8ea6-6a895869ec49') - @test.services('compute', 'network') - def test_network_basic_ops(self): - """Basic network operation test - - For a freshly-booted VM with an IP address ("port") on a given - network: - - - the Tempest host can ping the IP address. This implies, but - does not guarantee (see the ssh check that follows), that the - VM has been assigned the correct IP address and has - connectivity to the Tempest host. - - - the Tempest host can perform key-based authentication to an - ssh server hosted at the IP address. This check guarantees - that the IP address is associated with the target VM. - - - the Tempest host can ssh into the VM via the IP address and - successfully execute the following: - - - ping an external IP address, implying external connectivity. - - - ping an external hostname, implying that dns is correctly - configured. - - - ping an internal IP address, implying connectivity to another - VM on the same network. - - - detach the floating-ip from the VM and verify that it becomes - unreachable - - - associate detached floating ip to a new VM and verify connectivity. - VMs are created with unique keypair so connectivity also asserts that - floating IP is associated with the new VM instead of the old one - - Verifies that floating IP status is updated correctly after each change - - - """ - self._setup_network_and_servers() - self.check_public_network_connectivity(should_connect=True) - self._check_network_internal_connectivity(network=self.network) - self._check_network_external_connectivity() - self._disassociate_floating_ips() - self.check_public_network_connectivity(should_connect=False, - msg="after disassociate " - "floating ip") - self._reassociate_floating_ips() - self.check_public_network_connectivity(should_connect=True, - msg="after re-associate " - "floating ip") - - @decorators.idempotent_id('b158ea55-472e-4086-8fa9-c64ac0c6c1d0') - @testtools.skipUnless(test.is_extension_enabled('net-mtu', 'network'), - 'No way to calculate MTU for networks') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_mtu_sized_frames(self): - """Validate that network MTU sized frames fit through.""" - self._setup_network_and_servers() - self.check_public_network_connectivity( - should_connect=True, mtu=self.network['mtu']) - - @decorators.idempotent_id('1546850e-fbaa-42f5-8b5f-03d8a6a95f15') - @testtools.skipIf(CONF.network.shared_physical_network, - 'Connectivity can only be tested when in a ' - 'multitenant network environment') - @decorators.skip_because(bug="1610994") - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_connectivity_between_vms_on_different_networks(self): - """Test connectivity between VMs on different networks - - For a freshly-booted VM with an IP address ("port") on a given - network: - - - the Tempest host can ping the IP address. - - - the Tempest host can ssh into the VM via the IP address and - successfully execute the following: - - - ping an external IP address, implying external connectivity. - - - ping an external hostname, implying that dns is correctly - configured. - - - ping an internal IP address, implying connectivity to another - VM on the same network. - - - Create another network on the same tenant with subnet, create - an VM on the new network. - - - Ping the new VM from previous VM failed since the new network - was not attached to router yet. - - - Attach the new network to the router, Ping the new VM from - previous VM succeed. - - """ - self._setup_network_and_servers() - self.check_public_network_connectivity(should_connect=True) - self._check_network_internal_connectivity(network=self.network) - self._check_network_external_connectivity() - self._create_new_network(create_gateway=True) - self._create_server(self.new_net) - self._check_network_internal_connectivity(network=self.new_net, - should_connect=False) - router_id = self.router['id'] - self.routers_client.add_router_interface( - router_id, subnet_id=self.new_subnet['id']) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.routers_client.remove_router_interface, - router_id, subnet_id=self.new_subnet['id']) - self._check_network_internal_connectivity(network=self.new_net, - should_connect=True) - - @decorators.idempotent_id('c5adff73-e961-41f1-b4a9-343614f18cfa') - @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach, - 'NIC hotplug not available') - @testtools.skipIf(CONF.network.port_vnic_type in ['direct', 'macvtap'], - 'NIC hotplug not supported for ' - 'vnic_type direct or macvtap') - @test.services('compute', 'network') - def test_hotplug_nic(self): - """Test hotplug network interface - - 1. Create a network and a VM. - 2. Check connectivity to the VM via a public network. - 3. Create a new network, with no gateway. - 4. Bring up a new interface - 5. check the VM reach the new network - - """ - self._setup_network_and_servers() - self.check_public_network_connectivity(should_connect=True) - self._create_new_network() - self._hotplug_server() - self._check_network_internal_connectivity(network=self.new_net) - - @decorators.idempotent_id('04b9fe4e-85e8-4aea-b937-ea93885ac59f') - @testtools.skipIf(CONF.network.shared_physical_network, - 'Router state can be altered only with multitenant ' - 'networks capabilities') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_update_router_admin_state(self): - """Test to update admin state up of router - - 1. Check public connectivity before updating - admin_state_up attribute of router to False - 2. Check public connectivity after updating - admin_state_up attribute of router to False - 3. Check public connectivity after updating - admin_state_up attribute of router to True - """ - self._setup_network_and_servers() - self.check_public_network_connectivity( - should_connect=True, msg="before updating " - "admin_state_up of router to False") - self._update_router_admin_state(self.router, False) - # TODO(alokmaurya): Remove should_check_floating_ip_status=False check - # once bug 1396310 is fixed - - self.check_public_network_connectivity( - should_connect=False, msg="after updating " - "admin_state_up of router to False", - should_check_floating_ip_status=False) - self._update_router_admin_state(self.router, True) - self.check_public_network_connectivity( - should_connect=True, msg="after updating " - "admin_state_up of router to True") - - @decorators.idempotent_id('d8bb918e-e2df-48b2-97cd-b73c95450980') - @testtools.skipIf(CONF.network.shared_physical_network, - 'network isolation not available') - @testtools.skipUnless(CONF.scenario.dhcp_client, - "DHCP client is not available.") - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_subnet_details(self): - """Tests that subnet's extra configuration details are affecting VMs. - - This test relies on non-shared, isolated tenant networks. - - NOTE: Neutron subnets push data to servers via dhcp-agent, so any - update in subnet requires server to actively renew its DHCP lease. - - 1. Configure subnet with dns nameserver - 2. retrieve the VM's configured dns and verify it matches the one - configured for the subnet. - 3. update subnet's dns - 4. retrieve the VM's configured dns and verify it matches the new one - configured for the subnet. - - TODO(yfried): add host_routes - - any resolution check would be testing either: - * l3 forwarding (tested in test_network_basic_ops) - * Name resolution of an external DNS nameserver - out of scope for - Tempest - """ - # this test check only updates (no actual resolution) so using - # arbitrary ip addresses as nameservers, instead of parsing CONF - initial_dns_server = '1.2.3.4' - alt_dns_server = '9.8.7.6' - - # renewal should be immediate. - # Timeouts are suggested by salvatore-orlando in - # https://bugs.launchpad.net/neutron/+bug/1412325/comments/3 - renew_delay = CONF.network.build_interval - renew_timeout = CONF.network.build_timeout - - self._setup_network_and_servers(dns_nameservers=[initial_dns_server]) - self.check_public_network_connectivity(should_connect=True) - - floating_ip, server = self.floating_ip_tuple - ip_address = floating_ip['floating_ip_address'] - private_key = self._get_server_key(server) - ssh_client = self.get_remote_client( - ip_address, private_key=private_key, server=server) - - dns_servers = [initial_dns_server] - servers = ssh_client.get_dns_servers() - self.assertEqual(set(dns_servers), set(servers), - 'Looking for servers: {trgt_serv}. ' - 'Retrieved DNS nameservers: {act_serv} ' - 'From host: {host}.' - .format(host=ssh_client.ssh_client.host, - act_serv=servers, - trgt_serv=dns_servers)) - - self.subnet = self.subnets_client.update_subnet( - self.subnet['id'], dns_nameservers=[alt_dns_server])['subnet'] - - # asserts that Neutron DB has updated the nameservers - self.assertEqual([alt_dns_server], self.subnet['dns_nameservers'], - "Failed to update subnet's nameservers") - - def check_new_dns_server(): - # NOTE: Server needs to renew its dhcp lease in order to get new - # definitions from subnet - # NOTE(amuller): we are renewing the lease as part of the retry - # because Neutron updates dnsmasq asynchronously after the - # subnet-update API call returns. - ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'], - dhcp_client=CONF.scenario.dhcp_client) - if ssh_client.get_dns_servers() != [alt_dns_server]: - LOG.debug("Failed to update DNS nameservers") - return False - return True - - self.assertTrue(test_utils.call_until_true(check_new_dns_server, - renew_timeout, - renew_delay), - msg="DHCP renewal failed to fetch " - "new DNS nameservers") - - @decorators.idempotent_id('f5dfcc22-45fd-409f-954c-5bd500d7890b') - @testtools.skipUnless(CONF.network_feature_enabled.port_admin_state_change, - "Changing a port's admin state is not supported " - "by the test environment") - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_update_instance_port_admin_state(self): - """Test to update admin_state_up attribute of instance port - - 1. Check public and project connectivity before updating - admin_state_up attribute of instance port to False - 2. Check public and project connectivity after updating - admin_state_up attribute of instance port to False - 3. Check public and project connectivity after updating - admin_state_up attribute of instance port to True - """ - self._setup_network_and_servers() - _, server = self.floating_ip_tuple - server_id = server['id'] - port_id = self.os_admin.ports_client.list_ports( - device_id=server_id)['ports'][0]['id'] - server_pip = server['addresses'][self.network['name']][0]['addr'] - - server2 = self._create_server(self.network) - server2_fip = self.create_floating_ip(server2) - - private_key = self._get_server_key(server2) - ssh_client = self.get_remote_client(server2_fip['floating_ip_address'], - private_key=private_key, - server=server2) - - self.check_public_network_connectivity( - should_connect=True, msg="before updating " - "admin_state_up of instance port to False") - self.check_remote_connectivity(ssh_client, dest=server_pip, - should_succeed=True) - self.ports_client.update_port(port_id, admin_state_up=False) - self.check_public_network_connectivity( - should_connect=False, msg="after updating " - "admin_state_up of instance port to False", - should_check_floating_ip_status=False) - self.check_remote_connectivity(ssh_client, dest=server_pip, - should_succeed=False) - self.ports_client.update_port(port_id, admin_state_up=True) - self.check_public_network_connectivity( - should_connect=True, msg="after updating " - "admin_state_up of instance port to True") - self.check_remote_connectivity(ssh_client, dest=server_pip, - should_succeed=True) - - @decorators.idempotent_id('759462e1-8535-46b0-ab3a-33aa45c55aaa') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_preserve_preexisting_port(self): - """Test preserve pre-existing port - - Tests that a pre-existing port provided on server boot is not deleted - if the server is deleted. - - Nova should unbind the port from the instance on delete if the port was - not created by Nova as part of the boot request. - - We should also be able to boot another server with the same port. - """ - # Setup the network, create a port and boot the server from that port. - self._setup_network_and_servers(boot_with_port=True) - _, server = self.floating_ip_tuple - self.assertEqual(1, len(self.ports), - 'There should only be one port created for ' - 'server %s.' % server['id']) - port_id = self.ports[0]['port'] - self.assertIsNotNone(port_id, - 'Server should have been created from a ' - 'pre-existing port.') - # Assert the port is bound to the server. - port_list = self.os_admin.ports_client.list_ports( - device_id=server['id'], network_id=self.network['id'])['ports'] - self.assertEqual(1, len(port_list), - 'There should only be one port created for ' - 'server %s.' % server['id']) - self.assertEqual(port_id, port_list[0]['id']) - # Delete the server. - self.servers_client.delete_server(server['id']) - waiters.wait_for_server_termination(self.servers_client, server['id']) - # Assert the port still exists on the network but is unbound from - # the deleted server. - port = self.ports_client.show_port(port_id)['port'] - self.assertEqual(self.network['id'], port['network_id']) - self.assertEqual('', port['device_id']) - self.assertEqual('', port['device_owner']) - - # Boot another server with the same port to make sure nothing was - # left around that could cause issues. - server = self._create_server(self.network, port['id']) - port_list = self.os_admin.ports_client.list_ports( - device_id=server['id'], network_id=self.network['id'])['ports'] - self.assertEqual(1, len(port_list), - 'There should only be one port created for ' - 'server %s.' % server['id']) - self.assertEqual(port['id'], port_list[0]['id']) - - @test.requires_ext(service='network', extension='l3_agent_scheduler') - @decorators.idempotent_id('2e788c46-fb3f-4ac9-8f82-0561555bea73') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_router_rescheduling(self): - """Tests that router can be removed from agent and add to a new agent. - - 1. Verify connectivity - 2. Remove router from all l3-agents - 3. Verify connectivity is down - 4. Assign router to new l3-agent (or old one if no new agent is - available) - 5. Verify connectivity - """ - - # TODO(yfried): refactor this test to be used for other agents (dhcp) - # as well - - list_hosts = (self.os_admin.routers_client. - list_l3_agents_hosting_router) - schedule_router = (self.os_admin.network_agents_client. - create_router_on_l3_agent) - unschedule_router = (self.os_admin.network_agents_client. - delete_router_from_l3_agent) - - agent_list_alive = set( - a["id"] for a in - self.os_admin.network_agents_client.list_agents( - agent_type="L3 agent")['agents'] if a["alive"] is True - ) - self._setup_network_and_servers() - - # NOTE(kevinbenton): we have to use the admin credentials to check - # for the distributed flag because self.router only has a project view. - admin = self.os_admin.routers_client.show_router( - self.router['id']) - if admin['router'].get('distributed', False): - msg = "Rescheduling test does not apply to distributed routers." - raise self.skipException(msg) - - self.check_public_network_connectivity(should_connect=True) - - # remove resource from agents - hosting_agents = set(a["id"] for a in - list_hosts(self.router['id'])['agents']) - no_migration = agent_list_alive == hosting_agents - LOG.info("Router will be assigned to {mig} hosting agent". - format(mig="the same" if no_migration else "a new")) - - for hosting_agent in hosting_agents: - unschedule_router(hosting_agent, self.router['id']) - self.assertNotIn(hosting_agent, - [a["id"] for a in - list_hosts(self.router['id'])['agents']], - 'unscheduling router failed') - - # verify resource is un-functional - self.check_public_network_connectivity( - should_connect=False, - msg='after router unscheduling', - ) - - # schedule resource to new agent - target_agent = list(hosting_agents if no_migration else - agent_list_alive - hosting_agents)[0] - schedule_router(target_agent, - router_id=self.router['id']) - self.assertEqual( - target_agent, - list_hosts(self.router['id'])['agents'][0]['id'], - "Router failed to reschedule. Hosting agent doesn't match " - "target agent") - - # verify resource is functional - self.check_public_network_connectivity( - should_connect=True, - msg='After router rescheduling') - - @test.requires_ext(service='network', extension='port-security') - @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach, - 'NIC hotplug not available') - @decorators.idempotent_id('7c0bb1a2-d053-49a4-98f9-ca1a1d849f63') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_port_security_macspoofing_port(self): - """Tests port_security extension enforces mac spoofing - - Neutron security groups always apply anti-spoof rules on the VMs. This - allows traffic to originate and terminate at the VM as expected, but - prevents traffic to pass through the VM. Anti-spoof rules are not - required in cases where the VM routes traffic through it. - - The test steps are : - 1. Create a new network. - 2. Connect (hotplug) the VM to a new network. - 3. Check the VM can ping a server on the new network ("peer") - 4. Spoof the mac address of the new VM interface. - 5. Check the Security Group enforces mac spoofing and blocks pings via - spoofed interface (VM cannot ping the peer). - 6. Disable port-security of the spoofed port- set the flag to false. - 7. Retest 3rd step and check that the Security Group allows pings via - the spoofed interface. - """ - - spoof_mac = "00:00:00:00:00:01" - - # Create server - self._setup_network_and_servers() - self.check_public_network_connectivity(should_connect=True) - self._create_new_network() - self._hotplug_server() - fip, server = self.floating_ip_tuple - new_ports = self.os_admin.ports_client.list_ports( - device_id=server["id"], network_id=self.new_net["id"])['ports'] - spoof_port = new_ports[0] - private_key = self._get_server_key(server) - ssh_client = self.get_remote_client(fip['floating_ip_address'], - private_key=private_key, - server=server) - spoof_nic = ssh_client.get_nic_name_by_mac(spoof_port["mac_address"]) - peer = self._create_server(self.new_net) - peer_address = peer['addresses'][self.new_net['name']][0]['addr'] - self.check_remote_connectivity(ssh_client, dest=peer_address, - nic=spoof_nic, should_succeed=True) - # Set a mac address by making nic down temporary - cmd = ("sudo ip link set {nic} down;" - "sudo ip link set dev {nic} address {mac};" - "sudo ip link set {nic} up").format(nic=spoof_nic, - mac=spoof_mac) - ssh_client.exec_command(cmd) - - new_mac = ssh_client.get_mac_address(nic=spoof_nic) - self.assertEqual(spoof_mac, new_mac) - self.check_remote_connectivity(ssh_client, dest=peer_address, - nic=spoof_nic, should_succeed=False) - self.ports_client.update_port(spoof_port["id"], - port_security_enabled=False, - security_groups=[]) - self.check_remote_connectivity(ssh_client, dest=peer_address, - nic=spoof_nic, should_succeed=True) diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py deleted file mode 100644 index bf26c2ef8..000000000 --- a/tempest/scenario/test_network_v6.py +++ /dev/null @@ -1,258 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import functools - -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestGettingAddress(manager.NetworkScenarioTest): - """Test Summary: - - 1. Create network with subnets: - 1.1. one IPv4 and - 1.2. one or more IPv6 in a given address mode - 2. Boot 2 VMs on this network - 3. Allocate and assign 2 FIP4 - 4. Check that vNICs of all VMs gets all addresses actually assigned - 5. Each VM will ping the other's v4 private address - 6. If ping6 available in VM, each VM will ping all of the other's v6 - addresses as well as the router's - """ - - @classmethod - def skip_checks(cls): - super(TestGettingAddress, cls).skip_checks() - if not (CONF.network_feature_enabled.ipv6 - and CONF.network_feature_enabled.ipv6_subnet_attributes): - raise cls.skipException('IPv6 or its attributes not supported') - if not (CONF.network.project_networks_reachable - or CONF.network.public_network_id): - msg = ('Either project_networks_reachable must be "true", or ' - 'public_network_id must be defined.') - raise cls.skipException(msg) - if CONF.network.shared_physical_network: - msg = 'Deployment uses a shared physical network' - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_credentials(cls): - # Create no network resources for these tests. - cls.set_network_resources() - super(TestGettingAddress, cls).setup_credentials() - - def setUp(self): - super(TestGettingAddress, self).setUp() - self.keypair = self.create_keypair() - self.sec_grp = self._create_security_group() - - def prepare_network(self, address6_mode, n_subnets6=1, dualnet=False): - """Prepare network - - Creates network with given number of IPv6 subnets in the given mode and - one IPv4 subnet. - Creates router with ports on all subnets. - if dualnet - create IPv6 subnets on a different network - :return: list of created networks - """ - network = self._create_network() - if dualnet: - network_v6 = self._create_network() - - sub4 = self._create_subnet(network=network, - namestart='sub4', - ip_version=4) - - router = self._get_router() - self.routers_client.add_router_interface(router['id'], - subnet_id=sub4['id']) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.routers_client.remove_router_interface, - router['id'], subnet_id=sub4['id']) - - self.subnets_v6 = [] - for _ in range(n_subnets6): - net6 = network_v6 if dualnet else network - sub6 = self._create_subnet(network=net6, - namestart='sub6', - ip_version=6, - ipv6_ra_mode=address6_mode, - ipv6_address_mode=address6_mode) - - self.routers_client.add_router_interface(router['id'], - subnet_id=sub6['id']) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.routers_client.remove_router_interface, - router['id'], subnet_id=sub6['id']) - - self.subnets_v6.append(sub6) - return [network, network_v6] if dualnet else [network] - - @staticmethod - def define_server_ips(srv): - ips = {'4': None, '6': []} - for nics in srv['addresses'].values(): - for nic in nics: - if nic['version'] == 6: - ips['6'].append(nic['addr']) - else: - ips['4'] = nic['addr'] - return ips - - def prepare_server(self, networks=None): - username = CONF.validation.image_ssh_user - - srv = self.create_server( - key_name=self.keypair['name'], - security_groups=[{'name': self.sec_grp['name']}], - networks=[{'uuid': n['id']} for n in networks]) - fip = self.create_floating_ip(thing=srv) - ips = self.define_server_ips(srv=srv) - ssh = self.get_remote_client( - ip_address=fip['floating_ip_address'], - username=username, server=srv) - return ssh, ips, srv["id"] - - def turn_nic6_on(self, ssh, sid, network_id): - """Turns the IPv6 vNIC on - - Required because guest images usually set only the first vNIC on boot. - Searches for the IPv6 vNIC's MAC and brings it up. - - @param ssh: RemoteClient ssh instance to server - @param sid: server uuid - @param network_id: the network id the NIC is connected to - """ - ports = [ - p["mac_address"] for p in - self.os_admin.ports_client.list_ports( - device_id=sid, network_id=network_id)['ports'] - ] - - self.assertEqual(1, len(ports), - message=("Multiple IPv6 ports found on network %s. " - "ports: %s") - % (network_id, ports)) - mac6 = ports[0] - nic = ssh.get_nic_name_by_mac(mac6) - ssh.exec_command("sudo ip link set %s up" % nic) - - def _prepare_and_test(self, address6_mode, n_subnets6=1, dualnet=False): - net_list = self.prepare_network(address6_mode=address6_mode, - n_subnets6=n_subnets6, - dualnet=dualnet) - - sshv4_1, ips_from_api_1, sid1 = self.prepare_server(networks=net_list) - sshv4_2, ips_from_api_2, sid2 = self.prepare_server(networks=net_list) - - def guest_has_address(ssh, addr): - return addr in ssh.exec_command("ip address") - - # Turn on 2nd NIC for Cirros when dualnet - if dualnet: - _, network_v6 = net_list - self.turn_nic6_on(sshv4_1, sid1, network_v6['id']) - self.turn_nic6_on(sshv4_2, sid2, network_v6['id']) - - # get addresses assigned to vNIC as reported by 'ip address' utility - ips_from_ip_1 = sshv4_1.exec_command("ip address") - ips_from_ip_2 = sshv4_2.exec_command("ip address") - self.assertIn(ips_from_api_1['4'], ips_from_ip_1) - self.assertIn(ips_from_api_2['4'], ips_from_ip_2) - for i in range(n_subnets6): - # v6 should be configured since the image supports it - # It can take time for ipv6 automatic address to get assigned - srv1_v6_addr_assigned = functools.partial( - guest_has_address, sshv4_1, ips_from_api_1['6'][i]) - - srv2_v6_addr_assigned = functools.partial( - guest_has_address, sshv4_2, ips_from_api_2['6'][i]) - - self.assertTrue(test_utils.call_until_true(srv1_v6_addr_assigned, - CONF.validation.ping_timeout, 1)) - - self.assertTrue(test_utils.call_until_true(srv2_v6_addr_assigned, - CONF.validation.ping_timeout, 1)) - - self.check_remote_connectivity(sshv4_1, ips_from_api_2['4']) - self.check_remote_connectivity(sshv4_2, ips_from_api_1['4']) - - for i in range(n_subnets6): - self.check_remote_connectivity(sshv4_1, - ips_from_api_2['6'][i]) - self.check_remote_connectivity(sshv4_1, - self.subnets_v6[i]['gateway_ip']) - self.check_remote_connectivity(sshv4_2, - ips_from_api_1['6'][i]) - self.check_remote_connectivity(sshv4_2, - self.subnets_v6[i]['gateway_ip']) - - @decorators.attr(type='slow') - @decorators.idempotent_id('2c92df61-29f0-4eaa-bee3-7c65bef62a43') - @test.services('compute', 'network') - def test_slaac_from_os(self): - self._prepare_and_test(address6_mode='slaac') - - @decorators.attr(type='slow') - @decorators.idempotent_id('d7e1f858-187c-45a6-89c9-bdafde619a9f') - @test.services('compute', 'network') - def test_dhcp6_stateless_from_os(self): - self._prepare_and_test(address6_mode='dhcpv6-stateless') - - @decorators.attr(type='slow') - @decorators.idempotent_id('7ab23f41-833b-4a16-a7c9-5b42fe6d4123') - @test.services('compute', 'network') - def test_multi_prefix_dhcpv6_stateless(self): - self._prepare_and_test(address6_mode='dhcpv6-stateless', n_subnets6=2) - - @decorators.attr(type='slow') - @decorators.idempotent_id('dec222b1-180c-4098-b8c5-cc1b8342d611') - @test.services('compute', 'network') - def test_multi_prefix_slaac(self): - self._prepare_and_test(address6_mode='slaac', n_subnets6=2) - - @decorators.attr(type='slow') - @decorators.idempotent_id('b6399d76-4438-4658-bcf5-0d6c8584fde2') - @test.services('compute', 'network') - def test_dualnet_slaac_from_os(self): - self._prepare_and_test(address6_mode='slaac', dualnet=True) - - @decorators.attr(type='slow') - @decorators.idempotent_id('76f26acd-9688-42b4-bc3e-cd134c4cb09e') - @test.services('compute', 'network') - def test_dualnet_dhcp6_stateless_from_os(self): - self._prepare_and_test(address6_mode='dhcpv6-stateless', dualnet=True) - - @decorators.attr(type='slow') - @decorators.idempotent_id('cf1c4425-766b-45b8-be35-e2959728eb00') - @test.services('compute', 'network') - def test_dualnet_multi_prefix_dhcpv6_stateless(self): - self._prepare_and_test(address6_mode='dhcpv6-stateless', n_subnets6=2, - dualnet=True) - - @decorators.idempotent_id('9178ad42-10e4-47e9-8987-e02b170cc5cd') - @test.services('compute', 'network') - def test_dualnet_multi_prefix_slaac(self): - self._prepare_and_test(address6_mode='slaac', n_subnets6=2, - dualnet=True) diff --git a/tempest/scenario/test_object_storage_basic_ops.py b/tempest/scenario/test_object_storage_basic_ops.py deleted file mode 100644 index 25e9f5c56..000000000 --- a/tempest/scenario/test_object_storage_basic_ops.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - - -class TestObjectStorageBasicOps(manager.ObjectStorageScenarioTest): - @decorators.idempotent_id('b920faf1-7b8a-4657-b9fe-9c4512bfb381') - @test.services('object_storage') - def test_swift_basic_ops(self): - """Test swift basic ops. - - * get swift stat. - * create container. - * upload a file to the created container. - * list container's objects and assure that the uploaded file is - present. - * download the object and check the content - * delete object from container. - * list container's objects and assure that the deleted file is gone. - * delete a container. - """ - self.get_swift_stat() - container_name = self.create_container() - obj_name, obj_data = self.upload_object_to_container(container_name) - self.list_and_check_container_objects(container_name, - present_obj=[obj_name]) - self.download_and_verify(container_name, obj_name, obj_data) - self.delete_object(container_name, obj_name) - self.list_and_check_container_objects(container_name, - not_present_obj=[obj_name]) - self.delete_container(container_name) - - @decorators.idempotent_id('916c7111-cb1f-44b2-816d-8f760e4ea910') - @decorators.attr(type='slow') - @test.services('object_storage') - def test_swift_acl_anonymous_download(self): - """This test will cover below steps: - - 1. Create container - 2. Upload object to the new container - 3. Change the ACL of the container - 4. Check if the object can be download by anonymous user - 5. Delete the object and container - """ - container_name = self.create_container() - obj_name, _ = self.upload_object_to_container(container_name) - obj_url = '%s/%s/%s' % (self.object_client.base_url, - container_name, obj_name) - resp, _ = self.object_client.raw_request(obj_url, 'GET') - self.assertEqual(resp.status, 401) - - self.change_container_acl(container_name, '.r:*') - resp, _ = self.object_client.raw_request(obj_url, 'GET') - self.assertEqual(resp.status, 200) diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py deleted file mode 100644 index 41c60f1e3..000000000 --- a/tempest/scenario/test_security_groups_basic_ops.py +++ /dev/null @@ -1,658 +0,0 @@ -# Copyright 2013 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -from oslo_log import log -import testtools - -from tempest.common.utils import net_info -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF -LOG = log.getLogger(__name__) - - -class TestSecurityGroupsBasicOps(manager.NetworkScenarioTest): - - """The test suite for security groups - - This test suite assumes that Nova has been configured to - boot VM's with Neutron-managed networking, and attempts to - verify cross tenant connectivity as follows - - ssh: - in order to overcome "ip namespace", each tenant has an "access point" - VM with floating-ip open to incoming ssh connection allowing network - commands (ping/ssh) to be executed from within the - tenant-network-namespace - Tempest host performs key-based authentication to the ssh server via - floating IP address - - connectivity test is done by pinging destination server via source server - ssh connection. - success - ping returns - failure - ping_timeout reached - - multi-node: - Multi-Node mode is enabled when CONF.compute.min_compute_nodes > 1. - Tests connectivity between servers on different compute nodes. - When enabled, test will boot each new server to different - compute nodes. - - setup: - for primary tenant: - 1. create a network&subnet - 2. create a router (if public router isn't configured) - 3. connect tenant network to public network via router - 4. create an access point: - a. a security group open to incoming ssh connection - b. a VM with a floating ip - 5. create a general empty security group (same as "default", but - without rules allowing in-tenant traffic) - - tests: - 1. _verify_network_details - 2. _verify_mac_addr: for each access point verify that - (subnet, fix_ip, mac address) are as defined in the port list - 3. _test_in_tenant_block: test that in-tenant traffic is disabled - without rules allowing it - 4. _test_in_tenant_allow: test that in-tenant traffic is enabled - once an appropriate rule has been created - 5. _test_cross_tenant_block: test that cross-tenant traffic is disabled - without a rule allowing it on destination tenant - 6. _test_cross_tenant_allow: - * test that cross-tenant traffic is enabled once an appropriate - rule has been created on destination tenant. - * test that reverse traffic is still blocked - * test than reverse traffic is enabled once an appropriate rule has - been created on source tenant - 7._test_port_update_new_security_group: - * test that traffic is blocked with default security group - * test that traffic is enabled after updating port with new security - group having appropriate rule - 8. _test_multiple_security_groups: test multiple security groups can be - associated with the vm - - assumptions: - 1. alt_tenant/user existed and is different from primary_tenant/user - 2. Public network is defined and reachable from the Tempest host - 3. Public router can either be: - * defined, in which case all tenants networks can connect directly - to it, and cross tenant check will be done on the private IP of the - destination tenant - or - * not defined (empty string), in which case each tenant will have - its own router connected to the public network - """ - - credentials = ['primary', 'alt', 'admin'] - - class TenantProperties(object): - """helper class to save tenant details - - id - credentials - network - subnet - security groups - servers - access point - """ - - def __init__(self, clients): - # Credentials from manager are filled with both names and IDs - self.manager = clients - self.creds = self.manager.credentials - self.network = None - self.subnet = None - self.router = None - self.security_groups = {} - self.servers = list() - self.access_point = None - - def set_network(self, network, subnet, router): - self.network = network - self.subnet = subnet - self.router = router - - @classmethod - def skip_checks(cls): - super(TestSecurityGroupsBasicOps, cls).skip_checks() - if CONF.network.port_vnic_type in ['direct', 'macvtap']: - msg = ('Not currently supported when using vnic_type' - ' direct or macvtap') - raise cls.skipException(msg) - if not (CONF.network.project_networks_reachable or - CONF.network.public_network_id): - msg = ('Either project_networks_reachable must be "true", or ' - 'public_network_id must be defined.') - raise cls.skipException(msg) - if not test.is_extension_enabled('security-group', 'network'): - msg = "security-group extension not enabled." - raise cls.skipException(msg) - if CONF.network.shared_physical_network: - msg = ('Deployment uses a shared physical network, security ' - 'groups not supported') - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_credentials(cls): - # Create no network resources for these tests. - cls.set_network_resources() - super(TestSecurityGroupsBasicOps, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(TestSecurityGroupsBasicOps, cls).resource_setup() - - cls.multi_node = CONF.compute.min_compute_nodes > 1 and \ - test.is_scheduler_filter_enabled("DifferentHostFilter") - if cls.multi_node: - LOG.info("Working in Multi Node mode") - else: - LOG.info("Working in Single Node mode") - - cls.floating_ips = {} - cls.tenants = {} - cls.primary_tenant = cls.TenantProperties(cls.os_primary) - cls.alt_tenant = cls.TenantProperties(cls.os_alt) - for tenant in [cls.primary_tenant, cls.alt_tenant]: - cls.tenants[tenant.creds.tenant_id] = tenant - - cls.floating_ip_access = not CONF.network.public_router_id - - def setUp(self): - """Set up a single tenant with an accessible server. - - If multi-host is enabled, save created server uuids. - """ - self.servers = [] - - super(TestSecurityGroupsBasicOps, self).setUp() - self._deploy_tenant(self.primary_tenant) - self._verify_network_details(self.primary_tenant) - self._verify_mac_addr(self.primary_tenant) - - def _create_tenant_keypairs(self, tenant): - keypair = self.create_keypair(tenant.manager.keypairs_client) - tenant.keypair = keypair - - def _create_tenant_security_groups(self, tenant): - access_sg = self._create_empty_security_group( - namestart='secgroup_access-', - tenant_id=tenant.creds.tenant_id, - client=tenant.manager.security_groups_client - ) - - # don't use default secgroup since it allows in-project traffic - def_sg = self._create_empty_security_group( - namestart='secgroup_general-', - tenant_id=tenant.creds.tenant_id, - client=tenant.manager.security_groups_client - ) - tenant.security_groups.update(access=access_sg, default=def_sg) - ssh_rule = dict( - protocol='tcp', - port_range_min=22, - port_range_max=22, - direction='ingress', - ) - sec_group_rules_client = tenant.manager.security_group_rules_client - self._create_security_group_rule( - secgroup=access_sg, - sec_group_rules_client=sec_group_rules_client, - **ssh_rule) - - def _verify_network_details(self, tenant): - # Checks that we see the newly created network/subnet/router via - # checking the result of list_[networks,routers,subnets] - # Check that (router, subnet) couple exist in port_list - seen_nets = self.os_admin.networks_client.list_networks() - seen_names = [n['name'] for n in seen_nets['networks']] - seen_ids = [n['id'] for n in seen_nets['networks']] - - self.assertIn(tenant.network['name'], seen_names) - self.assertIn(tenant.network['id'], seen_ids) - - seen_subnets = [ - (n['id'], n['cidr'], n['network_id']) for n in - self.os_admin.subnets_client.list_subnets()['subnets'] - ] - mysubnet = (tenant.subnet['id'], tenant.subnet['cidr'], - tenant.network['id']) - self.assertIn(mysubnet, seen_subnets) - - seen_routers = self.os_admin.routers_client.list_routers() - seen_router_ids = [n['id'] for n in seen_routers['routers']] - seen_router_names = [n['name'] for n in seen_routers['routers']] - - self.assertIn(tenant.router['name'], seen_router_names) - self.assertIn(tenant.router['id'], seen_router_ids) - - myport = (tenant.router['id'], tenant.subnet['id']) - router_ports = [ - (i['device_id'], f['subnet_id']) - for i in self.os_admin.ports_client.list_ports( - device_id=tenant.router['id'])['ports'] - if net_info.is_router_interface_port(i) - for f in i['fixed_ips'] - ] - - self.assertIn(myport, router_ports) - - def _create_server(self, name, tenant, security_groups, **kwargs): - """Creates a server and assigns it to security group. - - If multi-host is enabled, Ensures servers are created on different - compute nodes, by storing created servers' ids and uses different_host - as scheduler_hints on creation. - Validates servers are created as requested, using admin client. - """ - security_groups_names = [{'name': s['name']} for s in security_groups] - if self.multi_node: - kwargs["scheduler_hints"] = {'different_host': self.servers} - server = self.create_server( - name=name, - networks=[{'uuid': tenant.network["id"]}], - key_name=tenant.keypair['name'], - security_groups=security_groups_names, - clients=tenant.manager, - **kwargs) - if 'security_groups' in server: - self.assertEqual( - sorted([s['name'] for s in security_groups]), - sorted([s['name'] for s in server['security_groups']])) - - # Verify servers are on different compute nodes - if self.multi_node: - adm_get_server = self.os_admin.servers_client.show_server - new_host = adm_get_server(server["id"])["server"][ - "OS-EXT-SRV-ATTR:host"] - host_list = [adm_get_server(s)["server"]["OS-EXT-SRV-ATTR:host"] - for s in self.servers] - self.assertNotIn(new_host, host_list, - message="Failed to boot servers on different " - "Compute nodes.") - - self.servers.append(server["id"]) - - return server - - def _create_tenant_servers(self, tenant, num=1): - for i in range(num): - name = 'server-{tenant}-gen-{num}'.format( - tenant=tenant.creds.tenant_name, - num=i - ) - name = data_utils.rand_name(name) - server = self._create_server(name, tenant, - [tenant.security_groups['default']]) - tenant.servers.append(server) - - def _set_access_point(self, tenant): - # creates a server in a secgroup with rule allowing external ssh - # in order to access project internal network - # workaround ip namespace - secgroups = tenant.security_groups.values() - name = 'server-{tenant}-access_point'.format( - tenant=tenant.creds.tenant_name) - name = data_utils.rand_name(name) - server = self._create_server(name, tenant, - security_groups=secgroups) - tenant.access_point = server - self._assign_floating_ips(tenant, server) - - def _assign_floating_ips(self, tenant, server): - public_network_id = CONF.network.public_network_id - floating_ip = self.create_floating_ip( - server, public_network_id, - client=tenant.manager.floating_ips_client) - self.floating_ips.setdefault(server['id'], floating_ip) - - def _create_tenant_network(self, tenant, port_security_enabled=True): - network, subnet, router = self.create_networks( - networks_client=tenant.manager.networks_client, - routers_client=tenant.manager.routers_client, - subnets_client=tenant.manager.subnets_client, - port_security_enabled=port_security_enabled) - tenant.set_network(network, subnet, router) - - def _deploy_tenant(self, tenant_or_id): - """creates: - - network - subnet - router (if public not defined) - access security group - access-point server - """ - if not isinstance(tenant_or_id, self.TenantProperties): - tenant = self.tenants[tenant_or_id] - else: - tenant = tenant_or_id - self._create_tenant_keypairs(tenant) - self._create_tenant_network(tenant) - self._create_tenant_security_groups(tenant) - self._set_access_point(tenant) - - def _get_server_ip(self, server, floating=False): - """returns the ip (floating/internal) of a server""" - if floating: - server_ip = self.floating_ips[server['id']]['floating_ip_address'] - else: - server_ip = None - network_name = self.tenants[server['tenant_id']].network['name'] - if network_name in server['addresses']: - server_ip = server['addresses'][network_name][0]['addr'] - return server_ip - - def _connect_to_access_point(self, tenant): - """create ssh connection to tenant access point""" - access_point_ssh = \ - self.floating_ips[tenant.access_point['id']]['floating_ip_address'] - private_key = tenant.keypair['private_key'] - access_point_ssh = self.get_remote_client( - access_point_ssh, private_key=private_key) - return access_point_ssh - - def _test_in_tenant_block(self, tenant): - access_point_ssh = self._connect_to_access_point(tenant) - for server in tenant.servers: - self.check_remote_connectivity(source=access_point_ssh, - dest=self._get_server_ip(server), - should_succeed=False) - - def _test_in_tenant_allow(self, tenant): - ruleset = dict( - protocol='icmp', - remote_group_id=tenant.security_groups['default']['id'], - direction='ingress' - ) - self._create_security_group_rule( - secgroup=tenant.security_groups['default'], - security_groups_client=tenant.manager.security_groups_client, - **ruleset - ) - access_point_ssh = self._connect_to_access_point(tenant) - for server in tenant.servers: - self.check_remote_connectivity(source=access_point_ssh, - dest=self._get_server_ip(server)) - - def _test_cross_tenant_block(self, source_tenant, dest_tenant): - # if public router isn't defined, then dest_tenant access is via - # floating-ip - access_point_ssh = self._connect_to_access_point(source_tenant) - ip = self._get_server_ip(dest_tenant.access_point, - floating=self.floating_ip_access) - self.check_remote_connectivity(source=access_point_ssh, dest=ip, - should_succeed=False) - - def _test_cross_tenant_allow(self, source_tenant, dest_tenant): - """check for each direction: - - creating rule for tenant incoming traffic enables only 1way traffic - """ - ruleset = dict( - protocol='icmp', - direction='ingress' - ) - sec_group_rules_client = ( - dest_tenant.manager.security_group_rules_client) - self._create_security_group_rule( - secgroup=dest_tenant.security_groups['default'], - sec_group_rules_client=sec_group_rules_client, - **ruleset - ) - access_point_ssh = self._connect_to_access_point(source_tenant) - ip = self._get_server_ip(dest_tenant.access_point, - floating=self.floating_ip_access) - self.check_remote_connectivity(access_point_ssh, ip) - - # test that reverse traffic is still blocked - self._test_cross_tenant_block(dest_tenant, source_tenant) - - # allow reverse traffic and check - sec_group_rules_client = ( - source_tenant.manager.security_group_rules_client) - self._create_security_group_rule( - secgroup=source_tenant.security_groups['default'], - sec_group_rules_client=sec_group_rules_client, - **ruleset - ) - - access_point_ssh_2 = self._connect_to_access_point(dest_tenant) - ip = self._get_server_ip(source_tenant.access_point, - floating=self.floating_ip_access) - self.check_remote_connectivity(access_point_ssh_2, ip) - - def _verify_mac_addr(self, tenant): - """Verify that VM has the same ip, mac as listed in port""" - - access_point_ssh = self._connect_to_access_point(tenant) - mac_addr = access_point_ssh.get_mac_address() - mac_addr = mac_addr.strip().lower() - # Get the fixed_ips and mac_address fields of all ports. Select - # only those two columns to reduce the size of the response. - port_list = self.os_admin.ports_client.list_ports( - fields=['fixed_ips', 'mac_address'])['ports'] - port_detail_list = [ - (port['fixed_ips'][0]['subnet_id'], - port['fixed_ips'][0]['ip_address'], - port['mac_address'].lower()) - for port in port_list if port['fixed_ips'] - ] - server_ip = self._get_server_ip(tenant.access_point) - subnet_id = tenant.subnet['id'] - self.assertIn((subnet_id, server_ip, mac_addr), port_detail_list) - - def _log_console_output_for_all_tenants(self): - for tenant in self.tenants.values(): - client = tenant.manager.servers_client - self._log_console_output(servers=tenant.servers, client=client) - if tenant.access_point is not None: - self._log_console_output( - servers=[tenant.access_point], client=client) - - @decorators.idempotent_id('e79f879e-debb-440c-a7e4-efeda05b6848') - @test.services('compute', 'network') - def test_cross_tenant_traffic(self): - if not self.credentials_provider.is_multi_tenant(): - raise self.skipException("No secondary tenant defined") - try: - # deploy new project - self._deploy_tenant(self.alt_tenant) - self._verify_network_details(self.alt_tenant) - self._verify_mac_addr(self.alt_tenant) - - # cross tenant check - source_tenant = self.primary_tenant - dest_tenant = self.alt_tenant - self._test_cross_tenant_block(source_tenant, dest_tenant) - self._test_cross_tenant_allow(source_tenant, dest_tenant) - except Exception: - self._log_console_output_for_all_tenants() - raise - - @decorators.idempotent_id('63163892-bbf6-4249-aa12-d5ea1f8f421b') - @test.services('compute', 'network') - def test_in_tenant_traffic(self): - try: - self._create_tenant_servers(self.primary_tenant, num=1) - - # in-tenant check - self._test_in_tenant_block(self.primary_tenant) - self._test_in_tenant_allow(self.primary_tenant) - except Exception: - self._log_console_output_for_all_tenants() - raise - - @decorators.idempotent_id('f4d556d7-1526-42ad-bafb-6bebf48568f6') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_port_update_new_security_group(self): - """Verifies the traffic after updating the vm port - - With new security group having appropriate rule. - """ - new_tenant = self.primary_tenant - - # Create empty security group and add icmp rule in it - new_sg = self._create_empty_security_group( - namestart='secgroup_new-', - tenant_id=new_tenant.creds.tenant_id, - client=new_tenant.manager.security_groups_client) - icmp_rule = dict( - protocol='icmp', - direction='ingress', - ) - sec_group_rules_client = new_tenant.manager.security_group_rules_client - self._create_security_group_rule( - secgroup=new_sg, - sec_group_rules_client=sec_group_rules_client, - **icmp_rule) - new_tenant.security_groups.update(new_sg=new_sg) - - # Create server with default security group - name = 'server-{tenant}-gen-1'.format( - tenant=new_tenant.creds.tenant_name - ) - name = data_utils.rand_name(name) - server = self._create_server(name, new_tenant, - [new_tenant.security_groups['default']]) - - # Check connectivity failure with default security group - try: - access_point_ssh = self._connect_to_access_point(new_tenant) - self.check_remote_connectivity(source=access_point_ssh, - dest=self._get_server_ip(server), - should_succeed=False) - server_id = server['id'] - port_id = self.os_admin.ports_client.list_ports( - device_id=server_id)['ports'][0]['id'] - - # update port with new security group and check connectivity - self.ports_client.update_port(port_id, security_groups=[ - new_tenant.security_groups['new_sg']['id']]) - self.check_remote_connectivity( - source=access_point_ssh, - dest=self._get_server_ip(server)) - except Exception: - self._log_console_output_for_all_tenants() - raise - - @decorators.idempotent_id('d2f77418-fcc4-439d-b935-72eca704e293') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_multiple_security_groups(self): - """Verify multiple security groups and checks that rules - - provided in the both the groups is applied onto VM - """ - tenant = self.primary_tenant - ip = self._get_server_ip(tenant.access_point, - floating=self.floating_ip_access) - ssh_login = CONF.validation.image_ssh_user - private_key = tenant.keypair['private_key'] - self.check_vm_connectivity(ip, - should_connect=False) - ruleset = dict( - protocol='icmp', - direction='ingress' - ) - self._create_security_group_rule( - secgroup=tenant.security_groups['default'], - **ruleset - ) - # NOTE: Vm now has 2 security groups one with ssh rule( - # already added in setUp() method),and other with icmp rule - # (added in the above step).The check_vm_connectivity tests - # -that vm ping test is successful - # -ssh to vm is successful - self.check_vm_connectivity(ip, - username=ssh_login, - private_key=private_key, - should_connect=True) - - @decorators.attr(type='slow') - @test.requires_ext(service='network', extension='port-security') - @decorators.idempotent_id('7c811dcc-263b-49a3-92d2-1b4d8405f50c') - @test.services('compute', 'network') - def test_port_security_disable_security_group(self): - """Verify the default security group rules is disabled.""" - new_tenant = self.primary_tenant - - # Create server - name = 'server-{tenant}-gen-1'.format( - tenant=new_tenant.creds.tenant_name - ) - name = data_utils.rand_name(name) - server = self._create_server(name, new_tenant, - [new_tenant.security_groups['default']]) - - access_point_ssh = self._connect_to_access_point(new_tenant) - server_id = server['id'] - port_id = self.os_admin.ports_client.list_ports( - device_id=server_id)['ports'][0]['id'] - - # Flip the port's port security and check connectivity - try: - self.ports_client.update_port(port_id, - port_security_enabled=True, - security_groups=[]) - self.check_remote_connectivity(source=access_point_ssh, - dest=self._get_server_ip(server), - should_succeed=False) - - self.ports_client.update_port(port_id, - port_security_enabled=False, - security_groups=[]) - self.check_remote_connectivity( - source=access_point_ssh, - dest=self._get_server_ip(server)) - except Exception: - self._log_console_output_for_all_tenants() - raise - - @decorators.attr(type='slow') - @test.requires_ext(service='network', extension='port-security') - @decorators.idempotent_id('13ccf253-e5ad-424b-9c4a-97b88a026699') - # TODO(mriedem): We shouldn't actually need to check this since neutron - # disables the port_security extension by default, but the problem is nova - # assumes port_security_enabled=True if it's not set on the network - # resource, which will mean nova may attempt to apply a security group on - # a port on that network which would fail. This is really a bug in nova. - @testtools.skipUnless( - CONF.network_feature_enabled.port_security, - 'Port security must be enabled.') - @test.services('compute', 'network') - def test_boot_into_disabled_port_security_network_without_secgroup(self): - tenant = self.primary_tenant - self._create_tenant_network(tenant, port_security_enabled=False) - self.assertFalse(tenant.network['port_security_enabled']) - name = data_utils.rand_name('server-smoke') - sec_groups = [] - server = self._create_server(name, tenant, sec_groups) - server_id = server['id'] - ports = self.os_admin.ports_client.list_ports( - device_id=server_id)['ports'] - self.assertEqual(1, len(ports)) - for port in ports: - self.assertEmpty(port['security_groups'], - "Neutron shouldn't even use it's default sec " - "group.") diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py deleted file mode 100644 index 6d6318caa..000000000 --- a/tempest/scenario/test_server_advanced_ops.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging -import testtools - -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class TestServerAdvancedOps(manager.ScenarioTest): - - """The test suite for server advanced operations - - This test case stresses some advanced server instance operations: - * Resizing a volume-backed instance - * Sequence suspend resume - """ - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(TestServerAdvancedOps, cls).setup_credentials() - - @decorators.attr(type='slow') - @decorators.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize is not available.') - @test.services('compute', 'volume') - def test_resize_volume_backed_server_confirm(self): - # We create an instance for use in this test - instance = self.create_server(volume_backed=True) - instance_id = instance['id'] - resize_flavor = CONF.compute.flavor_ref_alt - LOG.debug("Resizing instance %s from flavor %s to flavor %s", - instance['id'], instance['flavor']['id'], resize_flavor) - self.servers_client.resize_server(instance_id, resize_flavor) - waiters.wait_for_server_status(self.servers_client, instance_id, - 'VERIFY_RESIZE') - - LOG.debug("Confirming resize of instance %s", instance_id) - self.servers_client.confirm_resize_server(instance_id) - - waiters.wait_for_server_status(self.servers_client, instance_id, - 'ACTIVE') - - @decorators.attr(type='slow') - @decorators.idempotent_id('949da7d5-72c8-4808-8802-e3d70df98e2c') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @test.services('compute') - def test_server_sequence_suspend_resume(self): - # We create an instance for use in this test - instance_id = self.create_server()['id'] - - for _ in range(2): - LOG.debug("Suspending instance %s", instance_id) - self.servers_client.suspend_server(instance_id) - waiters.wait_for_server_status(self.servers_client, instance_id, - 'SUSPENDED') - - LOG.debug("Resuming instance %s", instance_id) - self.servers_client.resume_server(instance_id) - waiters.wait_for_server_status(self.servers_client, instance_id, - 'ACTIVE') diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py deleted file mode 100644 index 0c441ab41..000000000 --- a/tempest/scenario/test_server_basic_ops.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import json -import re - -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestServerBasicOps(manager.ScenarioTest): - - """The test suite for server basic operations - - This smoke test case follows this basic set of operations: - * Create a keypair for use in launching an instance - * Create a security group to control network access in instance - * Add simple permissive rules to the security group - * Launch an instance - * Perform ssh to instance - * Verify metadata service - * Verify metadata on config_drive - * Terminate the instance - """ - - @classmethod - def skip_checks(cls): - super(TestServerBasicOps, cls).skip_checks() - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - def setUp(self): - super(TestServerBasicOps, self).setUp() - self.run_ssh = CONF.validation.run_validation - self.ssh_user = CONF.validation.image_ssh_user - - def verify_ssh(self, keypair): - if self.run_ssh: - # Obtain a floating IP - self.fip = self.create_floating_ip(self.instance)['ip'] - # Check ssh - self.ssh_client = self.get_remote_client( - ip_address=self.fip, - username=self.ssh_user, - private_key=keypair['private_key'], - server=self.instance) - - def verify_metadata(self): - if self.run_ssh and CONF.compute_feature_enabled.metadata_service: - # Verify metadata service - md_url = 'http://169.254.169.254/latest/meta-data/public-ipv4' - - def exec_cmd_and_verify_output(): - cmd = 'curl ' + md_url - result = self.ssh_client.exec_command(cmd) - if result: - msg = ('Failed while verifying metadata on server. Result ' - 'of command "%s" is NOT "%s".' % (cmd, self.fip)) - self.assertEqual(self.fip, result, msg) - return 'Verification is successful!' - - if not test_utils.call_until_true(exec_cmd_and_verify_output, - CONF.compute.build_timeout, - CONF.compute.build_interval): - raise exceptions.TimeoutException('Timed out while waiting to ' - 'verify metadata on server. ' - '%s is empty.' % md_url) - - # Also, test a POST - md_url = 'http://169.254.169.254/openstack/2013-10-17/password' - data = data_utils.arbitrary_string(100) - cmd = 'curl -X POST -d ' + data + ' ' + md_url - self.ssh_client.exec_command(cmd) - result = self.servers_client.show_password(self.instance['id']) - self.assertEqual(data, result['password']) - - def _mount_config_drive(self): - cmd_blkid = 'blkid | grep -i config-2' - result = self.ssh_client.exec_command(cmd_blkid) - dev_name = re.match('([^:]+)', result).group() - self.ssh_client.exec_command('sudo mount %s /mnt' % dev_name) - - def _unmount_config_drive(self): - self.ssh_client.exec_command('sudo umount /mnt') - - def verify_metadata_on_config_drive(self): - if self.run_ssh and CONF.compute_feature_enabled.config_drive: - # Verify metadata on config_drive - self._mount_config_drive() - cmd_md = 'sudo cat /mnt/openstack/latest/meta_data.json' - result = self.ssh_client.exec_command(cmd_md) - self._unmount_config_drive() - result = json.loads(result) - self.assertIn('meta', result) - msg = ('Failed while verifying metadata on config_drive on server.' - ' Result of command "%s" is NOT "%s".' % (cmd_md, self.md)) - self.assertEqual(self.md, result['meta'], msg) - - def verify_networkdata_on_config_drive(self): - if self.run_ssh and CONF.compute_feature_enabled.config_drive: - # Verify network data on config_drive - self._mount_config_drive() - cmd_md = 'sudo cat /mnt/openstack/latest/network_data.json' - result = self.ssh_client.exec_command(cmd_md) - self._unmount_config_drive() - result = json.loads(result) - self.assertIn('services', result) - self.assertIn('links', result) - self.assertIn('networks', result) - # TODO(clarkb) construct network_data from known network - # instance info and do direct comparison. - - @decorators.idempotent_id('7fff3fb3-91d8-4fd0-bd7d-0204f1f180ba') - @decorators.attr(type='smoke') - @test.services('compute', 'network') - def test_server_basic_ops(self): - keypair = self.create_keypair() - security_group = self._create_security_group() - self.md = {'meta1': 'data1', 'meta2': 'data2', 'metaN': 'dataN'} - self.instance = self.create_server( - key_name=keypair['name'], - security_groups=[{'name': security_group['name']}], - config_drive=CONF.compute_feature_enabled.config_drive, - metadata=self.md) - self.verify_ssh(keypair) - self.verify_metadata() - self.verify_metadata_on_config_drive() - self.verify_networkdata_on_config_drive() - self.servers_client.delete_server(self.instance['id']) - waiters.wait_for_server_termination( - self.servers_client, self.instance['id'], ignore_error=False) diff --git a/tempest/scenario/test_server_multinode.py b/tempest/scenario/test_server_multinode.py deleted file mode 100644 index 552ab27c0..000000000 --- a/tempest/scenario/test_server_multinode.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestServerMultinode(manager.ScenarioTest): - """This is a set of tests specific to multinode testing.""" - credentials = ['primary', 'admin'] - - @classmethod - def skip_checks(cls): - super(TestServerMultinode, cls).skip_checks() - - if CONF.compute.min_compute_nodes < 2: - raise cls.skipException( - "Less than 2 compute nodes, skipping multinode tests.") - - @decorators.idempotent_id('9cecbe35-b9d4-48da-a37e-7ce70aa43d30') - @decorators.attr(type='smoke') - @test.services('compute', 'network') - def test_schedule_to_all_nodes(self): - available_zone = \ - self.os_admin.availability_zone_client.list_availability_zones( - detail=True)['availabilityZoneInfo'] - hosts = [] - for zone in available_zone: - if zone['zoneState']['available']: - for host in zone['hosts']: - if 'nova-compute' in zone['hosts'][host] and \ - zone['hosts'][host]['nova-compute']['available']: - hosts.append({'zone': zone['zoneName'], - 'host_name': host}) - - # ensure we have at least as many compute hosts as we expect - if len(hosts) < CONF.compute.min_compute_nodes: - raise exceptions.InvalidConfiguration( - "Host list %s is shorter than min_compute_nodes. " - "Did a compute worker not boot correctly?" % hosts) - - # create 1 compute for each node, up to the min_compute_nodes - # threshold (so that things don't get crazy if you have 1000 - # compute nodes but set min to 3). - servers = [] - - for host in hosts[:CONF.compute.min_compute_nodes]: - # by getting to active state here, this means this has - # landed on the host in question. - # in order to use the availability_zone:host scheduler hint, - # admin client is need here. - inst = self.create_server( - clients=self.os_admin, - availability_zone='%(zone)s:%(host_name)s' % host) - server = self.os_admin.servers_client.show_server( - inst['id'])['server'] - # ensure server is located on the requested host - self.assertEqual(host['host_name'], server['OS-EXT-SRV-ATTR:host']) - servers.append(server) - - # make sure we really have the number of servers we think we should - self.assertEqual( - len(servers), CONF.compute.min_compute_nodes, - "Incorrect number of servers built %s" % servers) - - # ensure that every server ended up on a different host - host_ids = [x['hostId'] for x in servers] - self.assertEqual( - len(set(host_ids)), len(servers), - "Incorrect number of distinct host_ids scheduled to %s" % servers) diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py deleted file mode 100644 index fc04b449a..000000000 --- a/tempest/scenario/test_shelve_instance.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2014 Scality -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestShelveInstance(manager.ScenarioTest): - """This test shelves then unshelves a Nova instance - - The following is the scenario outline: - * boot an instance and create a timestamp file in it - * shelve the instance - * unshelve the instance - * check the existence of the timestamp file in the unshelved instance - - """ - - @classmethod - def skip_checks(cls): - super(TestShelveInstance, cls).skip_checks() - if not CONF.compute_feature_enabled.shelve: - raise cls.skipException("Shelve is not available.") - - def _shelve_then_unshelve_server(self, server): - compute.shelve_server(self.servers_client, server['id'], - force_shelve_offload=True) - - self.servers_client.unshelve_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - def _create_server_then_shelve_and_unshelve(self, boot_from_volume=False): - keypair = self.create_keypair() - - security_group = self._create_security_group() - security_groups = [{'name': security_group['name']}] - - server = self.create_server( - key_name=keypair['name'], - security_groups=security_groups, - volume_backed=boot_from_volume) - - instance_ip = self.get_server_ip(server) - timestamp = self.create_timestamp(instance_ip, - private_key=keypair['private_key']) - - # Prevent bug #1257594 from coming back - # Unshelve used to boot the instance with the original image, not - # with the instance snapshot - self._shelve_then_unshelve_server(server) - - timestamp2 = self.get_timestamp(instance_ip, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp2) - - @decorators.attr(type='slow') - @decorators.idempotent_id('1164e700-0af0-4a4c-8792-35909a88743c') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @test.services('compute', 'network', 'image') - def test_shelve_instance(self): - self._create_server_then_shelve_and_unshelve() - - @decorators.attr(type='slow') - @decorators.idempotent_id('c1b6318c-b9da-490b-9c67-9339b627271f') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @test.services('compute', 'volume', 'network', 'image') - def test_shelve_volume_backed_instance(self): - self._create_server_then_shelve_and_unshelve(boot_from_volume=True) diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py deleted file mode 100644 index 52767dc34..000000000 --- a/tempest/scenario/test_snapshot_pattern.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestSnapshotPattern(manager.ScenarioTest): - """This test is for snapshotting an instance and booting with it. - - The following is the scenario outline: - * boot an instance and create a timestamp file in it - * snapshot the instance - * boot a second instance from the snapshot - * check the existence of the timestamp file in the second instance - - """ - - @classmethod - def skip_checks(cls): - super(TestSnapshotPattern, cls).skip_checks() - if not CONF.compute_feature_enabled.snapshot: - raise cls.skipException("Snapshotting is not available.") - - @decorators.idempotent_id('608e604b-1d63-4a82-8e3e-91bc665c90b4') - @decorators.attr(type='slow') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @test.services('compute', 'network', 'image') - def test_snapshot_pattern(self): - # prepare for booting an instance - keypair = self.create_keypair() - security_group = self._create_security_group() - - # boot an instance and create a timestamp file in it - server = self.create_server( - key_name=keypair['name'], - security_groups=[{'name': security_group['name']}]) - - instance_ip = self.get_server_ip(server) - timestamp = self.create_timestamp(instance_ip, - private_key=keypair['private_key']) - - # snapshot the instance - snapshot_image = self.create_server_snapshot(server=server) - - # boot a second instance from the snapshot - server_from_snapshot = self.create_server( - image_id=snapshot_image['id'], - key_name=keypair['name'], - security_groups=[{'name': security_group['name']}]) - - # check the existence of the timestamp file in the second instance - server_from_snapshot_ip = self.get_server_ip(server_from_snapshot) - timestamp2 = self.get_timestamp(server_from_snapshot_ip, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp2) diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py deleted file mode 100644 index 363264859..000000000 --- a/tempest/scenario/test_stamp_pattern.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright 2013 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging -import testtools - -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class TestStampPattern(manager.ScenarioTest): - """The test suite for both snapshoting and attaching of volume - - This test is for snapshotting an instance/volume and attaching the volume - created from snapshot to the instance booted from snapshot. - The following is the scenario outline: - 1. Boot an instance "instance1" - 2. Create a volume "volume1" - 3. Attach volume1 to instance1 - 4. Create a filesystem on volume1 - 5. Mount volume1 - 6. Create a file which timestamp is written in volume1 - 7. Unmount volume1 - 8. Detach volume1 from instance1 - 9. Get a snapshot "snapshot_from_volume" of volume1 - 10. Get a snapshot "snapshot_from_instance" of instance1 - 11. Boot an instance "instance2" from snapshot_from_instance - 12. Create a volume "volume2" from snapshot_from_volume - 13. Attach volume2 to instance2 - 14. Check the existence of a file which created at 6. in volume2 - """ - - @classmethod - def skip_checks(cls): - super(TestStampPattern, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder volume snapshots are disabled") - - def _wait_for_volume_available_on_the_system(self, ip_address, - private_key): - ssh = self.get_remote_client(ip_address, private_key=private_key) - - def _func(): - disks = ssh.get_disks() - LOG.debug("Disks: %s", disks) - return CONF.compute.volume_device_name in disks - - if not test_utils.call_until_true(_func, - CONF.compute.build_timeout, - CONF.compute.build_interval): - raise lib_exc.TimeoutException - - @decorators.attr(type='slow') - @decorators.skip_because(bug="1664793") - @decorators.idempotent_id('10fd234a-515c-41e5-b092-8323060598c5') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @test.services('compute', 'network', 'volume', 'image') - def test_stamp_pattern(self): - # prepare for booting an instance - keypair = self.create_keypair() - security_group = self._create_security_group() - - # boot an instance and create a timestamp file in it - volume = self.create_volume() - server = self.create_server( - key_name=keypair['name'], - security_groups=[{'name': security_group['name']}]) - - # create and add floating IP to server1 - ip_for_server = self.get_server_ip(server) - - self.nova_volume_attach(server, volume) - self._wait_for_volume_available_on_the_system(ip_for_server, - keypair['private_key']) - timestamp = self.create_timestamp(ip_for_server, - CONF.compute.volume_device_name, - private_key=keypair['private_key']) - self.nova_volume_detach(server, volume) - - # snapshot the volume - volume_snapshot = self.create_volume_snapshot(volume['id']) - - # snapshot the instance - snapshot_image = self.create_server_snapshot(server=server) - - # create second volume from the snapshot(volume2) - volume_from_snapshot = self.create_volume( - snapshot_id=volume_snapshot['id']) - - # boot second instance from the snapshot(instance2) - server_from_snapshot = self.create_server( - image_id=snapshot_image['id'], - key_name=keypair['name'], - security_groups=[{'name': security_group['name']}]) - - # create and add floating IP to server_from_snapshot - ip_for_snapshot = self.get_server_ip(server_from_snapshot) - - # attach volume2 to instance2 - self.nova_volume_attach(server_from_snapshot, volume_from_snapshot) - self._wait_for_volume_available_on_the_system(ip_for_snapshot, - keypair['private_key']) - - # check the existence of the timestamp file in the volume2 - timestamp2 = self.get_timestamp(ip_for_snapshot, - CONF.compute.volume_device_name, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp2) diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py deleted file mode 100644 index b6f3b38cf..000000000 --- a/tempest/scenario/test_volume_boot_pattern.py +++ /dev/null @@ -1,236 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging -import testtools - -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class TestVolumeBootPattern(manager.EncryptionScenarioTest): - - # Boot from volume scenario is quite slow, and needs extra - # breathing room to get through deletes in the time allotted. - TIMEOUT_SCALING_FACTOR = 2 - - @classmethod - def skip_checks(cls): - super(TestVolumeBootPattern, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder volume snapshots are disabled") - - def _create_volume_from_image(self): - img_uuid = CONF.compute.image_ref - vol_name = data_utils.rand_name( - self.__class__.__name__ + '-volume-origin') - return self.create_volume(name=vol_name, imageRef=img_uuid) - - def _get_bdm(self, source_id, source_type, delete_on_termination=False): - bd_map_v2 = [{ - 'uuid': source_id, - 'source_type': source_type, - 'destination_type': 'volume', - 'boot_index': 0, - 'delete_on_termination': delete_on_termination}] - return {'block_device_mapping_v2': bd_map_v2} - - def _boot_instance_from_resource(self, source_id, - source_type, - keypair=None, - security_group=None, - delete_on_termination=False): - create_kwargs = dict() - if keypair: - create_kwargs['key_name'] = keypair['name'] - if security_group: - create_kwargs['security_groups'] = [ - {'name': security_group['name']}] - create_kwargs.update(self._get_bdm( - source_id, - source_type, - delete_on_termination=delete_on_termination)) - - return self.create_server(image_id='', **create_kwargs) - - def _delete_server(self, server): - self.servers_client.delete_server(server['id']) - waiters.wait_for_server_termination(self.servers_client, server['id']) - - @decorators.idempotent_id('557cd2c2-4eb8-4dce-98be-f86765ff311b') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @test.services('compute', 'volume', 'image') - def test_volume_boot_pattern(self): - - """This test case attempts to reproduce the following steps: - - * Create in Cinder some bootable volume importing a Glance image - * Boot an instance from the bootable volume - * Write content to the volume - * Delete an instance and Boot a new instance from the volume - * Check written content in the instance - * Create a volume snapshot while the instance is running - * Boot an additional instance from the new snapshot based volume - * Check written content in the instance booted from snapshot - """ - - LOG.info("Creating keypair and security group") - keypair = self.create_keypair() - security_group = self._create_security_group() - - # create an instance from volume - LOG.info("Booting instance 1 from volume") - volume_origin = self._create_volume_from_image() - instance_1st = self._boot_instance_from_resource( - source_id=volume_origin['id'], - source_type='volume', - keypair=keypair, - security_group=security_group) - LOG.info("Booted first instance: %s", instance_1st) - - # write content to volume on instance - LOG.info("Setting timestamp in instance %s", instance_1st) - ip_instance_1st = self.get_server_ip(instance_1st) - timestamp = self.create_timestamp(ip_instance_1st, - private_key=keypair['private_key']) - - # delete instance - LOG.info("Deleting first instance: %s", instance_1st) - self._delete_server(instance_1st) - - # create a 2nd instance from volume - instance_2nd = self._boot_instance_from_resource( - source_id=volume_origin['id'], - source_type='volume', - keypair=keypair, - security_group=security_group) - LOG.info("Booted second instance %s", instance_2nd) - - # check the content of written file - LOG.info("Getting timestamp in instance %s", instance_2nd) - ip_instance_2nd = self.get_server_ip(instance_2nd) - timestamp2 = self.get_timestamp(ip_instance_2nd, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp2) - - # snapshot a volume - LOG.info("Creating snapshot from volume: %s", volume_origin['id']) - snapshot = self.create_volume_snapshot(volume_origin['id'], force=True) - - # create a 3rd instance from snapshot - LOG.info("Creating third instance from snapshot: %s", snapshot['id']) - volume = self.create_volume(snapshot_id=snapshot['id'], - size=snapshot['size']) - LOG.info("Booting third instance from snapshot") - server_from_snapshot = ( - self._boot_instance_from_resource(source_id=volume['id'], - source_type='volume', - keypair=keypair, - security_group=security_group)) - LOG.info("Booted third instance %s", server_from_snapshot) - - # check the content of written file - LOG.info("Logging into third instance to get timestamp: %s", - server_from_snapshot) - server_from_snapshot_ip = self.get_server_ip(server_from_snapshot) - timestamp3 = self.get_timestamp(server_from_snapshot_ip, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp3) - - @decorators.idempotent_id('05795fb2-b2a7-4c9f-8fac-ff25aedb1489') - @decorators.attr(type='slow') - @test.services('compute', 'image', 'volume') - def test_create_server_from_volume_snapshot(self): - # Create a volume from an image - boot_volume = self._create_volume_from_image() - - # Create a snapshot - boot_snapshot = self.create_volume_snapshot(boot_volume['id']) - - # Create a server from a volume snapshot - server = self._boot_instance_from_resource( - source_id=boot_snapshot['id'], - source_type='snapshot', - delete_on_termination=True) - - server_info = self.servers_client.show_server(server['id'])['server'] - - # The created volume when creating a server from a snapshot - created_volume = server_info['os-extended-volumes:volumes_attached'] - - self.assertNotEmpty(created_volume, "No volume attachment found.") - - created_volume_info = self.volumes_client.show_volume( - created_volume[0]['id'])['volume'] - - # Verify the server was created from the snapshot - self.assertEqual( - boot_volume['volume_image_metadata']['image_id'], - created_volume_info['volume_image_metadata']['image_id']) - self.assertEqual(boot_snapshot['id'], - created_volume_info['snapshot_id']) - self.assertEqual(server['id'], - created_volume_info['attachments'][0]['server_id']) - self.assertEqual(created_volume[0]['id'], - created_volume_info['attachments'][0]['volume_id']) - - @decorators.idempotent_id('36c34c67-7b54-4b59-b188-02a2f458a63b') - @test.services('compute', 'volume', 'image') - def test_create_ebs_image_and_check_boot(self): - # create an instance from volume - volume_origin = self._create_volume_from_image() - instance = self._boot_instance_from_resource( - source_id=volume_origin['id'], - source_type='volume', - delete_on_termination=True) - # create EBS image - image = self.create_server_snapshot(instance) - - # delete instance - self._delete_server(instance) - - # boot instance from EBS image - instance = self.create_server(image_id=image['id']) - # just ensure that instance booted - - # delete instance - self._delete_server(instance) - - @decorators.idempotent_id('cb78919a-e553-4bab-b73b-10cf4d2eb125') - @testtools.skipUnless(CONF.compute_feature_enabled.attach_encrypted_volume, - 'Encrypted volume attach is not supported') - @test.services('compute', 'volume') - def test_boot_server_from_encrypted_volume_luks(self): - # Create an encrypted volume - volume = self.create_encrypted_volume('nova.volume.encryptors.' - 'luks.LuksEncryptor', - volume_type='luks') - - self.volumes_client.set_bootable_volume(volume['id'], bootable=True) - - # Boot a server from the encrypted volume - server = self._boot_instance_from_resource( - source_id=volume['id'], - source_type='volume', - delete_on_termination=False) - - server_info = self.servers_client.show_server(server['id'])['server'] - created_volume = server_info['os-extended-volumes:volumes_attached'] - self.assertEqual(volume['id'], created_volume[0]['id']) diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py deleted file mode 100644 index 5667fbb74..000000000 --- a/tempest/scenario/test_volume_migrate_attached.py +++ /dev/null @@ -1,127 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_log import log as logging - -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class TestVolumeMigrateRetypeAttached(manager.ScenarioTest): - - """This test case attempts to reproduce the following steps: - - * Create 2 volume types representing 2 different backends - * Create in Cinder some bootable volume importing a Glance image using - * volume_type_1 - * Boot an instance from the bootable volume - * Write to the volume - * Perform a cinder retype --on-demand of the volume to type of backend #2 - * Check written content of migrated volume - """ - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(TestVolumeMigrateRetypeAttached, cls).setup_clients() - cls.admin_volumes_client = cls.os_admin.volumes_v2_client - - @classmethod - def skip_checks(cls): - super(TestVolumeMigrateRetypeAttached, cls).skip_checks() - if not CONF.volume_feature_enabled.multi_backend: - raise cls.skipException("Cinder multi-backend feature disabled") - - if len(set(CONF.volume.backend_names)) < 2: - raise cls.skipException("Requires at least two different " - "backend names") - - def _boot_instance_from_volume(self, vol_id, keypair, security_group): - - key_name = keypair['name'] - security_groups = [{'name': security_group['name']}] - block_device_mapping = [{'device_name': 'vda', 'volume_id': vol_id, - 'delete_on_termination': False}] - - return self.create_server(image_id='', - key_name=key_name, - security_groups=security_groups, - block_device_mapping=block_device_mapping) - - def _create_volume_types(self): - backend_names = CONF.volume.backend_names - - backend_source = backend_names[0] - backend_dest = backend_names[1] - - source_body = self.create_volume_type(backend_name=backend_source) - dest_body = self.create_volume_type(backend_name=backend_dest) - - LOG.info("Created Volume types: %(src)s -> %(src_backend)s, %(dst)s " - "-> %(dst_backend)s", {'src': source_body['name'], - 'src_backend': backend_source, - 'dst': dest_body['name'], - 'dst_backend': backend_dest}) - return source_body['name'], dest_body['name'] - - def _volume_retype_with_migration(self, volume_id, new_volume_type): - migration_policy = 'on-demand' - self.admin_volumes_client.retype_volume( - volume_id, new_type=new_volume_type, - migration_policy=migration_policy) - waiters.wait_for_volume_retype(self.volumes_client, - volume_id, new_volume_type) - - @decorators.attr(type='slow') - @decorators.idempotent_id('deadd2c2-beef-4dce-98be-f86765ff311b') - @test.services('compute', 'volume') - def test_volume_migrate_attached(self): - LOG.info("Creating keypair and security group") - keypair = self.create_keypair() - security_group = self._create_security_group() - - # create volume types - LOG.info("Creating Volume types") - source_type, dest_type = self._create_volume_types() - - # create an instance from volume - LOG.info("Booting instance from volume") - volume_origin = self.create_volume(imageRef=CONF.compute.image_ref, - volume_type=source_type) - - instance = self._boot_instance_from_volume(volume_origin['id'], - keypair, security_group) - - # write content to volume on instance - LOG.info("Setting timestamp in instance %s", instance['id']) - ip_instance = self.get_server_ip(instance) - timestamp = self.create_timestamp(ip_instance, - private_key=keypair['private_key']) - - # retype volume with migration from backend #1 to backend #2 - LOG.info("Retyping Volume %s to new type %s", volume_origin['id'], - dest_type) - self._volume_retype_with_migration(volume_origin['id'], dest_type) - - # check the content of written file - LOG.info("Getting timestamp in postmigrated instance %s", - instance['id']) - timestamp2 = self.get_timestamp(ip_instance, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp2) diff --git a/tempest/services/__init__.py b/tempest/services/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/services/object_storage/__init__.py b/tempest/services/object_storage/__init__.py deleted file mode 100644 index 17385664b..000000000 --- a/tempest/services/object_storage/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.services.object_storage.account_client import AccountClient -from tempest.services.object_storage.bulk_middleware_client import \ - BulkMiddlewareClient -from tempest.services.object_storage.capabilities_client import \ - CapabilitiesClient -from tempest.services.object_storage.container_client import ContainerClient -from tempest.services.object_storage.object_client import ObjectClient - -__all__ = ['AccountClient', 'BulkMiddlewareClient', 'CapabilitiesClient', - 'ContainerClient', 'ObjectClient'] diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py deleted file mode 100644 index 5a1737e6a..000000000 --- a/tempest/services/object_storage/account_client.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from xml.etree import ElementTree as etree - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class AccountClient(rest_client.RestClient): - - def create_update_or_delete_account_metadata( - self, - create_update_metadata=None, - delete_metadata=None, - create_update_metadata_prefix='X-Account-Meta-', - delete_metadata_prefix='X-Remove-Account-Meta-'): - """Creates, Updates or deletes an account metadata entry. - - Account Metadata can be created, updated or deleted based on - metadata header or value. For detailed info, please refer to the - official API reference: - http://developer.openstack.org/api-ref/object-storage/?expanded=create-update-or-delete-account-metadata-detail - """ - headers = {} - if create_update_metadata: - for key in create_update_metadata: - metadata_header_name = create_update_metadata_prefix + key - headers[metadata_header_name] = create_update_metadata[key] - if delete_metadata: - for key in delete_metadata: - headers[delete_metadata_prefix + key] = delete_metadata[key] - - resp, body = self.post('', headers=headers, body=None) - self.expected_success([200, 204], resp.status) - return resp, body - - def list_account_metadata(self): - """HEAD on the storage URL - - Returns all account metadata headers - """ - resp, body = self.head('') - self.expected_success(204, resp.status) - return resp, body - - def list_account_containers(self, params=None): - """GET on the (base) storage URL - - Given valid X-Auth-Token, returns a list of all containers for the - account. - - Optional Arguments: - limit=[integer value N] - Limits the number of results to at most N values - DEFAULT: 10,000 - - marker=[string value X] - Given string value X, return object names greater in value - than the specified marker. - DEFAULT: No Marker - - prefix=[string value Y] - Given string value Y, return object names starting with that prefix - - reverse=[boolean value Z] - Reverse the result order based on the boolean value Z - DEFAULT: False - - format=[string value, either 'json' or 'xml'] - Specify either json or xml to return the respective serialized - response. - DEFAULT: Python-List returned in response body - """ - url = '?%s' % urllib.urlencode(params) if params else '' - - resp, body = self.get(url, headers={}) - if params and params.get('format') == 'json': - body = json.loads(body) - elif params and params.get('format') == 'xml': - body = etree.fromstring(body) - else: - body = body.strip().splitlines() - self.expected_success([200, 204], resp.status) - return resp, body diff --git a/tempest/services/object_storage/bulk_middleware_client.py b/tempest/services/object_storage/bulk_middleware_client.py deleted file mode 100644 index c11a105b8..000000000 --- a/tempest/services/object_storage/bulk_middleware_client.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.common import rest_client - - -class BulkMiddlewareClient(rest_client.RestClient): - - def upload_archive(self, upload_path, data, - archive_file_format='tar', headers=None): - """Expand tar files into a Swift cluster. - - To extract containers and objects on Swift cluster from - uploaded archived file. For More information please check: - https://docs.openstack.org/swift/latest/middleware.html#module-swift.common.middleware.bulk - """ - url = '%s?extract-archive=%s' % (upload_path, archive_file_format) - if headers is None: - headers = {} - resp, body = self.put(url, data, headers) - self.expected_success(200, resp.status) - return rest_client.ResponseBodyData(resp, body) - - def delete_bulk_data(self, data=None, headers=None): - """Delete multiple objects or containers from their account. - - For More information please check: - https://docs.openstack.org/swift/latest/middleware.html#module-swift.common.middleware.bulk - """ - url = '?bulk-delete' - - if headers is None: - headers = {} - resp, body = self.delete(url, headers, data) - self.expected_success(200, resp.status) - return rest_client.ResponseBodyData(resp, body) - - def delete_bulk_data_with_post(self, data=None, headers=None): - """Delete multiple objects or containers with POST request. - - For More information please check: - https://docs.openstack.org/swift/latest/middleware.html#module-swift.common.middleware.bulk - """ - url = '?bulk-delete' - - if headers is None: - headers = {} - resp, body = self.post(url, data, headers) - self.expected_success([200, 204], resp.status) - return rest_client.ResponseBodyData(resp, body) diff --git a/tempest/services/object_storage/capabilities_client.py b/tempest/services/object_storage/capabilities_client.py deleted file mode 100644 index d31bbc299..000000000 --- a/tempest/services/object_storage/capabilities_client.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class CapabilitiesClient(rest_client.RestClient): - - def list_capabilities(self): - self.skip_path() - try: - resp, body = self.get('info') - finally: - self.reset_path() - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py deleted file mode 100644 index afedd3669..000000000 --- a/tempest/services/object_storage/container_client.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from xml.etree import ElementTree as etree - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ContainerClient(rest_client.RestClient): - - def create_container( - self, container_name, - metadata=None, - remove_metadata=None, - metadata_prefix='X-Container-Meta-', - remove_metadata_prefix='X-Remove-Container-Meta-'): - """Creates a container - - with optional metadata passed in as a dictionary - """ - url = str(container_name) - headers = {} - - if metadata is not None: - for key in metadata: - headers[metadata_prefix + key] = metadata[key] - if remove_metadata is not None: - for key in remove_metadata: - headers[remove_metadata_prefix + key] = remove_metadata[key] - - resp, body = self.put(url, body=None, headers=headers) - self.expected_success([201, 202], resp.status) - return resp, body - - def delete_container(self, container_name): - """Deletes the container (if it's empty).""" - url = str(container_name) - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return resp, body - - def update_container_metadata( - self, container_name, - metadata=None, - remove_metadata=None, - metadata_prefix='X-Container-Meta-', - remove_metadata_prefix='X-Remove-Container-Meta-'): - """Updates arbitrary metadata on container.""" - url = str(container_name) - headers = {} - - if metadata is not None: - for key in metadata: - headers[metadata_prefix + key] = metadata[key] - if remove_metadata is not None: - for key in remove_metadata: - headers[remove_metadata_prefix + key] = remove_metadata[key] - - resp, body = self.post(url, body=None, headers=headers) - self.expected_success(204, resp.status) - return resp, body - - def delete_container_metadata(self, container_name, metadata, - metadata_prefix='X-Remove-Container-Meta-'): - """Deletes arbitrary metadata on container.""" - url = str(container_name) - headers = {} - - if metadata is not None: - for item in metadata: - headers[metadata_prefix + item] = metadata[item] - - resp, body = self.post(url, body=None, headers=headers) - self.expected_success(204, resp.status) - return resp, body - - def list_container_metadata(self, container_name): - """Retrieves container metadata headers""" - url = str(container_name) - resp, body = self.head(url) - self.expected_success(204, resp.status) - return resp, body - - def list_container_contents(self, container, params=None): - """List the objects in a container, given the container name - - Returns the container object listing as a plain text list, or as - xml or json if that option is specified via the 'format' argument. - - Optional Arguments: - limit = integer - For an integer value n, limits the number of results to at most - n values. - - marker = 'string' - Given a string value x, return object names greater in value - than the specified marker. - - prefix = 'string' - For a string value x, causes the results to be limited to names - beginning with the substring x. - - format = 'json' or 'xml' - Specify either json or xml to return the respective serialized - response. - If json, returns a list of json objects - if xml, returns a string of xml - - path = 'string' - For a string value x, return the object names nested in the - pseudo path (assuming preconditions are met - see below). - - delimiter = 'character' - For a character c, return all the object names nested in the - container (without the need for the directory marker objects). - """ - - url = str(container) - if params: - url += '?' - url += '&%s' % urllib.urlencode(params) - - resp, body = self.get(url, headers={}) - if params and params.get('format') == 'json': - body = json.loads(body) - elif params and params.get('format') == 'xml': - body = etree.fromstring(body) - # Else the content-type is plain/text - else: - body = [ - obj_name for obj_name in body.decode().split('\n') if obj_name - ] - - self.expected_success([200, 204], resp.status) - return resp, body diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py deleted file mode 100644 index 6d656ec57..000000000 --- a/tempest/services/object_storage/object_client.py +++ /dev/null @@ -1,231 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from six.moves import http_client as httplib -from six.moves.urllib import parse as urlparse - -from tempest.lib.common import rest_client -from tempest.lib import exceptions - - -class ObjectClient(rest_client.RestClient): - - def create_object(self, container, object_name, data, - params=None, metadata=None, headers=None): - """Create storage object.""" - - if headers is None: - headers = self.get_headers() - if not data: - headers['content-length'] = '0' - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - url = "%s/%s" % (str(container), str(object_name)) - if params: - url += '?%s' % urlparse.urlencode(params) - - resp, body = self.put(url, data, headers) - self.expected_success(201, resp.status) - return resp, body - - def delete_object(self, container, object_name, params=None): - """Delete storage object.""" - url = "%s/%s" % (str(container), str(object_name)) - if params: - url += '?%s' % urlparse.urlencode(params) - resp, body = self.delete(url, headers={}) - self.expected_success([200, 204], resp.status) - return resp, body - - def update_object_metadata(self, container, object_name, metadata, - metadata_prefix='X-Object-Meta-'): - """Add, remove, or change X-Object-Meta metadata for storage object.""" - - headers = {} - for key in metadata: - headers["%s%s" % (str(metadata_prefix), str(key))] = metadata[key] - - url = "%s/%s" % (str(container), str(object_name)) - resp, body = self.post(url, None, headers=headers) - self.expected_success(202, resp.status) - return resp, body - - def list_object_metadata(self, container, object_name): - """List all storage object X-Object-Meta- metadata.""" - - url = "%s/%s" % (str(container), str(object_name)) - resp, body = self.head(url) - self.expected_success(200, resp.status) - return resp, body - - def get_object(self, container, object_name, metadata=None): - """Retrieve object's data.""" - - headers = {} - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - - url = "{0}/{1}".format(container, object_name) - resp, body = self.get(url, headers=headers) - self.expected_success([200, 206], resp.status) - return resp, body - - def copy_object_in_same_container(self, container, src_object_name, - dest_object_name, metadata=None): - """Copy storage object's data to the new object using PUT.""" - - url = "{0}/{1}".format(container, dest_object_name) - headers = {} - headers['X-Copy-From'] = "%s/%s" % (str(container), - str(src_object_name)) - headers['content-length'] = '0' - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - - resp, body = self.put(url, None, headers=headers) - self.expected_success(201, resp.status) - return resp, body - - def copy_object_across_containers(self, src_container, src_object_name, - dst_container, dst_object_name, - metadata=None): - """Copy storage object's data to the new object using PUT.""" - - url = "{0}/{1}".format(dst_container, dst_object_name) - headers = {} - headers['X-Copy-From'] = "%s/%s" % (str(src_container), - str(src_object_name)) - headers['content-length'] = '0' - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - - resp, body = self.put(url, None, headers=headers) - self.expected_success(201, resp.status) - return resp, body - - def copy_object_2d_way(self, container, src_object_name, dest_object_name, - metadata=None): - """Copy storage object's data to the new object using COPY.""" - - url = "{0}/{1}".format(container, src_object_name) - headers = {} - headers['Destination'] = "%s/%s" % (str(container), - str(dest_object_name)) - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - - resp, body = self.copy(url, headers=headers) - self.expected_success(201, resp.status) - return resp, body - - def create_object_segments(self, container, object_name, segment, data): - """Creates object segments.""" - url = "{0}/{1}/{2}".format(container, object_name, segment) - resp, body = self.put(url, data) - self.expected_success(201, resp.status) - return resp, body - - def put_object_with_chunk(self, container, name, contents): - """Put an object with Transfer-Encoding header - - :param container: name of the container - :type container: string - :param name: name of the object - :type name: string - :param contents: object data - :type contents: iterable - """ - headers = {'Transfer-Encoding': 'chunked'} - if self.token: - headers['X-Auth-Token'] = self.token - - url = "%s/%s" % (container, name) - resp, body = self.put( - url, headers=headers, - body=contents, - chunked=True - ) - - self._error_checker(resp, body) - self.expected_success(201, resp.status) - return resp.status, resp.reason, resp - - def create_object_continue(self, container, object_name, - data, metadata=None): - """Put an object using Expect:100-continue""" - headers = {} - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - - headers['X-Auth-Token'] = self.token - headers['content-length'] = 0 if data is None else len(data) - headers['Expect'] = '100-continue' - - parsed = urlparse.urlparse(self.base_url) - path = str(parsed.path) + "/" - path += "%s/%s" % (str(container), str(object_name)) - - conn = create_connection(parsed) - - # Send the PUT request and the headers including the "Expect" header - conn.putrequest('PUT', path) - - for header, value in headers.items(): - conn.putheader(header, value) - conn.endheaders() - - # Read the 100 status prior to sending the data - response = conn.response_class(conn.sock, - method=conn._method) - _, status, _ = response._read_status() - - # toss the CRLF at the end of the response - response._safe_read(2) - - # Expecting a 100 here, if not close and throw an exception - if status != 100: - conn.close() - pattern = "%s %s" % ( - """Unexpected http success status code {0}.""", - """The expected status code is {1}""") - details = pattern.format(status, 100) - raise exceptions.UnexpectedResponseCode(details) - - # If a continue was received go ahead and send the data - # and get the final response - conn.send(data) - - resp = conn.getresponse() - - return resp.status, resp.reason - - -def create_connection(parsed_url): - """Helper function to create connection with httplib - - :param parsed_url: parsed url of the remote location - """ - if parsed_url.scheme == 'https': - conn = httplib.HTTPSConnection(parsed_url.netloc) - else: - conn = httplib.HTTPConnection(parsed_url.netloc) - - return conn diff --git a/tempest/services/orchestration/__init__.py b/tempest/services/orchestration/__init__.py deleted file mode 100644 index 5a1ffcc30..000000000 --- a/tempest/services/orchestration/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -from tempest.services.orchestration.json.orchestration_client import \ - OrchestrationClient - -__all__ = ['OrchestrationClient'] diff --git a/tempest/services/orchestration/json/__init__.py b/tempest/services/orchestration/json/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py deleted file mode 100644 index 9fec5482b..000000000 --- a/tempest/services/orchestration/json/orchestration_client.py +++ /dev/null @@ -1,413 +0,0 @@ -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import re -import time - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest import exceptions -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class OrchestrationClient(rest_client.RestClient): - - def list_stacks(self, params=None): - """Lists all stacks for a user.""" - - uri = 'stacks' - if params: - uri += '?%s' % urllib.urlencode(params) - - resp, body = self.get(uri) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_stack(self, name, disable_rollback=True, parameters=None, - timeout_mins=60, template=None, template_url=None, - environment=None, files=None): - if parameters is None: - parameters = {} - headers, body = self._prepare_update_create( - name, - disable_rollback, - parameters, - timeout_mins, - template, - template_url, - environment, - files) - uri = 'stacks' - resp, body = self.post(uri, headers=headers, body=body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_stack(self, stack_identifier, name, disable_rollback=True, - parameters=None, timeout_mins=60, template=None, - template_url=None, environment=None, files=None): - if parameters is None: - parameters = {} - headers, body = self._prepare_update_create( - name, - disable_rollback, - parameters, - timeout_mins, - template, - template_url, - environment) - - uri = "stacks/%s" % stack_identifier - resp, body = self.put(uri, headers=headers, body=body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def _prepare_update_create(self, name, disable_rollback=True, - parameters=None, timeout_mins=60, - template=None, template_url=None, - environment=None, files=None): - if parameters is None: - parameters = {} - post_body = { - "stack_name": name, - "disable_rollback": disable_rollback, - "parameters": parameters, - "timeout_mins": timeout_mins, - "template": "HeatTemplateFormatVersion: '2012-12-12'\n", - "environment": environment, - "files": files - } - if template: - post_body['template'] = template - if template_url: - post_body['template_url'] = template_url - body = json.dumps(post_body) - - # Password must be provided on stack create so that heat - # can perform future operations on behalf of the user - headers = self.get_headers() - headers['X-Auth-Key'] = self.password - headers['X-Auth-User'] = self.user - return headers, body - - def show_stack(self, stack_identifier): - """Returns the details of a single stack.""" - url = "stacks/%s" % stack_identifier - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def suspend_stack(self, stack_identifier): - """Suspend a stack.""" - url = 'stacks/%s/actions' % stack_identifier - body = {'suspend': None} - resp, body = self.post(url, json.dumps(body)) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp) - - def resume_stack(self, stack_identifier): - """Resume a stack.""" - url = 'stacks/%s/actions' % stack_identifier - body = {'resume': None} - resp, body = self.post(url, json.dumps(body)) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp) - - def list_resources(self, stack_identifier): - """Returns the details of a single resource.""" - url = "stacks/%s/resources" % stack_identifier - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_resource(self, stack_identifier, resource_name): - """Returns the details of a single resource.""" - url = "stacks/%s/resources/%s" % (stack_identifier, resource_name) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_stack(self, stack_identifier): - """Deletes the specified Stack.""" - resp, _ = self.delete("stacks/%s" % str(stack_identifier)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def wait_for_stack_status(self, stack_identifier, status, - failure_pattern='^.*_FAILED$'): - """Waits for a Stack to reach a given status.""" - start = int(time.time()) - fail_regexp = re.compile(failure_pattern) - - while True: - try: - body = self.show_stack(stack_identifier)['stack'] - except lib_exc.NotFound: - if status == 'DELETE_COMPLETE': - return - stack_name = body['stack_name'] - stack_status = body['stack_status'] - if stack_status == status: - return body - if fail_regexp.search(stack_status): - raise exceptions.StackBuildErrorException( - stack_identifier=stack_identifier, - stack_status=stack_status, - stack_status_reason=body['stack_status_reason']) - - if int(time.time()) - start >= self.build_timeout: - message = ('Stack %s failed to reach %s status (current: %s) ' - 'within the required time (%s s).' % - (stack_name, status, stack_status, - self.build_timeout)) - raise lib_exc.TimeoutException(message) - time.sleep(self.build_interval) - - def show_resource_metadata(self, stack_identifier, resource_name): - """Returns the resource's metadata.""" - url = ('stacks/{stack_identifier}/resources/{resource_name}' - '/metadata'.format(**locals())) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_events(self, stack_identifier): - """Returns list of all events for a stack.""" - url = 'stacks/{stack_identifier}/events'.format(**locals()) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_resource_events(self, stack_identifier, resource_name): - """Returns list of all events for a resource from stack.""" - url = ('stacks/{stack_identifier}/resources/{resource_name}' - '/events'.format(**locals())) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_event(self, stack_identifier, resource_name, event_id): - """Returns the details of a single stack's event.""" - url = ('stacks/{stack_identifier}/resources/{resource_name}/events' - '/{event_id}'.format(**locals())) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_template(self, stack_identifier): - """Returns the template for the stack.""" - url = ('stacks/{stack_identifier}/template'.format(**locals())) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def _validate_template(self, post_body): - """Returns the validation request result.""" - post_body = json.dumps(post_body) - resp, body = self.post('validate', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def validate_template(self, template, parameters=None): - """Returns the validation result for a template with parameters.""" - if parameters is None: - parameters = {} - post_body = { - 'template': template, - 'parameters': parameters, - } - return self._validate_template(post_body) - - def validate_template_url(self, template_url, parameters=None): - """Returns the validation result for a template with parameters.""" - if parameters is None: - parameters = {} - post_body = { - 'template_url': template_url, - 'parameters': parameters, - } - return self._validate_template(post_body) - - def list_resource_types(self): - """List resource types.""" - resp, body = self.get('resource_types') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_resource_type(self, resource_type_name): - """Return the schema of a resource type.""" - url = 'resource_types/%s' % resource_type_name - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, json.loads(body)) - - def show_resource_type_template(self, resource_type_name): - """Return the template of a resource type.""" - url = 'resource_types/%s/template' % resource_type_name - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, json.loads(body)) - - def create_software_config(self, name=None, config=None, group=None, - inputs=None, outputs=None, options=None): - headers, body = self._prep_software_config_create( - name, config, group, inputs, outputs, options) - - url = 'software_configs' - resp, body = self.post(url, headers=headers, body=body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_software_config(self, conf_id): - """Returns a software configuration resource.""" - url = 'software_configs/%s' % str(conf_id) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_software_config(self, conf_id): - """Deletes a specific software configuration.""" - url = 'software_configs/%s' % str(conf_id) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_software_deploy(self, server_id=None, config_id=None, - action=None, status=None, - input_values=None, output_values=None, - status_reason=None, signal_transport=None): - """Creates or updates a software deployment.""" - headers, body = self._prep_software_deploy_update( - None, server_id, config_id, action, status, input_values, - output_values, status_reason, signal_transport) - - url = 'software_deployments' - resp, body = self.post(url, headers=headers, body=body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_software_deploy(self, deploy_id=None, server_id=None, - config_id=None, action=None, status=None, - input_values=None, output_values=None, - status_reason=None, signal_transport=None): - """Creates or updates a software deployment.""" - headers, body = self._prep_software_deploy_update( - deploy_id, server_id, config_id, action, status, input_values, - output_values, status_reason, signal_transport) - - url = 'software_deployments/%s' % str(deploy_id) - resp, body = self.put(url, headers=headers, body=body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_software_deployments(self): - """Returns a list of all deployments.""" - url = 'software_deployments' - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_software_deployment(self, deploy_id): - """Returns a specific software deployment.""" - url = 'software_deployments/%s' % str(deploy_id) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_software_deployment_metadata(self, server_id): - """Return a config metadata for a specific server.""" - url = 'software_deployments/metadata/%s' % server_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_software_deploy(self, deploy_id): - """Deletes a specific software deployment.""" - url = 'software_deployments/%s' % str(deploy_id) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def _prep_software_config_create(self, name=None, conf=None, group=None, - inputs=None, outputs=None, options=None): - """Prepares a software configuration body.""" - post_body = {} - if name is not None: - post_body["name"] = name - if conf is not None: - post_body["config"] = conf - if group is not None: - post_body["group"] = group - if inputs is not None: - post_body["inputs"] = inputs - if outputs is not None: - post_body["outputs"] = outputs - if options is not None: - post_body["options"] = options - body = json.dumps(post_body) - - headers = self.get_headers() - return headers, body - - def _prep_software_deploy_update(self, deploy_id=None, server_id=None, - config_id=None, action=None, status=None, - input_values=None, output_values=None, - status_reason=None, - signal_transport=None): - """Prepares a deployment create or update (if an id was given).""" - post_body = {} - - if deploy_id is not None: - post_body["id"] = deploy_id - if server_id is not None: - post_body["server_id"] = server_id - if config_id is not None: - post_body["config_id"] = config_id - if action is not None: - post_body["action"] = action - if status is not None: - post_body["status"] = status - if input_values is not None: - post_body["input_values"] = input_values - if output_values is not None: - post_body["output_values"] = output_values - if status_reason is not None: - post_body["status_reason"] = status_reason - if signal_transport is not None: - post_body["signal_transport"] = signal_transport - body = json.dumps(post_body) - - headers = self.get_headers() - return headers, body diff --git a/tempest/test.py b/tempest/test.py deleted file mode 100644 index 317c0a74d..000000000 --- a/tempest/test.py +++ /dev/null @@ -1,680 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import atexit -import functools -import os -import sys - -import debtcollector.moves -import fixtures -from oslo_log import log as logging -import six -import testtools - -from tempest import clients -from tempest.common import credentials_factory as credentials -import tempest.common.validation_resources as vresources -from tempest import config -from tempest.lib.common import cred_client -from tempest.lib.common import fixed_network -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -LOG = logging.getLogger(__name__) - -CONF = config.CONF - -# TODO(oomichi): This test.idempotent_id should be removed after all projects -# switch to use decorators.idempotent_id. -idempotent_id = debtcollector.moves.moved_function( - decorators.idempotent_id, 'idempotent_id', __name__, - version='Mitaka', removal_version='?') - - -related_bug = debtcollector.moves.moved_function( - decorators.related_bug, 'related_bug', __name__, - version='Pike', removal_version='?') - - -attr = debtcollector.moves.moved_function( - decorators.attr, 'attr', __name__, - version='Pike', removal_version='?') - - -class InvalidServiceTag(lib_exc.TempestException): - message = "Invalid service tag" - - -def get_service_list(): - service_list = { - 'compute': CONF.service_available.nova, - 'image': CONF.service_available.glance, - 'volume': CONF.service_available.cinder, - # NOTE(masayukig): We have two network services which are neutron and - # nova-network. And we have no way to know whether nova-network is - # available or not. After the pending removal of nova-network from - # nova, we can treat the network/neutron case in the same manner as - # the other services. - 'network': True, - # NOTE(masayukig): Tempest tests always require the identity service. - # So we should set this True here. - 'identity': True, - 'object_storage': CONF.service_available.swift, - } - return service_list - - -def services(*args): - """A decorator used to set an attr for each service used in a test case - - This decorator applies a testtools attr for each service that gets - exercised by a test case. - """ - def decorator(f): - known_services = get_service_list() - - for service in args: - if service not in known_services: - raise InvalidServiceTag('%s is not a valid service' % service) - decorators.attr(type=list(args))(f) - - @functools.wraps(f) - def wrapper(self, *func_args, **func_kwargs): - service_list = get_service_list() - - for service in args: - if not service_list[service]: - msg = 'Skipped because the %s service is not available' % ( - service) - raise testtools.TestCase.skipException(msg) - return f(self, *func_args, **func_kwargs) - return wrapper - return decorator - - -def requires_ext(**kwargs): - """A decorator to skip tests if an extension is not enabled - - @param extension - @param service - """ - def decorator(func): - @functools.wraps(func) - def wrapper(*func_args, **func_kwargs): - if not is_extension_enabled(kwargs['extension'], - kwargs['service']): - msg = "Skipped because %s extension: %s is not enabled" % ( - kwargs['service'], kwargs['extension']) - raise testtools.TestCase.skipException(msg) - return func(*func_args, **func_kwargs) - return wrapper - return decorator - - -def is_extension_enabled(extension_name, service): - """A function that will check the list of enabled extensions from config - - """ - config_dict = { - 'compute': CONF.compute_feature_enabled.api_extensions, - 'volume': CONF.volume_feature_enabled.api_extensions, - 'network': CONF.network_feature_enabled.api_extensions, - 'object': CONF.object_storage_feature_enabled.discoverable_apis, - 'identity': CONF.identity_feature_enabled.api_extensions - } - if not config_dict[service]: - return False - if config_dict[service][0] == 'all': - return True - if extension_name in config_dict[service]: - return True - return False - - -def is_scheduler_filter_enabled(filter_name): - """Check the list of enabled compute scheduler filters from config. - - This function checks whether the given compute scheduler filter is - available and configured in the config file. If the - scheduler_available_filters option is set to 'all' (Default value. which - means default filters are configured in nova) in tempest.conf then, this - function returns True with assumption that requested filter 'filter_name' - is one of available filter in nova ("nova.scheduler.filters.all_filters"). - """ - - filters = CONF.compute_feature_enabled.scheduler_available_filters - if not filters: - return False - if 'all' in filters: - return True - if filter_name in filters: - return True - return False - - -at_exit_set = set() - - -def validate_tearDownClass(): - if at_exit_set: - LOG.error( - "tearDownClass does not call the super's " - "tearDownClass in these classes: \n" - + str(at_exit_set)) - - -atexit.register(validate_tearDownClass) - - -class BaseTestCase(testtools.testcase.WithAttributes, - testtools.TestCase): - """The test base class defines Tempest framework for class level fixtures. - - `setUpClass` and `tearDownClass` are defined here and cannot be overwritten - by subclasses (enforced via hacking rule T105). - - Set-up is split in a series of steps (setup stages), which can be - overwritten by test classes. Set-up stages are: - - skip_checks - - setup_credentials - - setup_clients - - resource_setup - - Tear-down is also split in a series of steps (teardown stages), which are - stacked for execution only if the corresponding setup stage had been - reached during the setup phase. Tear-down stages are: - - clear_credentials (defined in the base test class) - - resource_cleanup - """ - - setUpClassCalled = False - - # NOTE(andreaf) credentials holds a list of the credentials to be allocated - # at class setup time. Credential types can be 'primary', 'alt', 'admin' or - # a list of roles - the first element of the list being a label, and the - # rest the actual roles - credentials = [] - # Resources required to validate a server using ssh - validation_resources = {} - network_resources = {} - - # NOTE(sdague): log_format is defined inline here instead of using the oslo - # default because going through the config path recouples config to the - # stress tests too early, and depending on testr order will fail unit tests - log_format = ('%(asctime)s %(process)d %(levelname)-8s ' - '[%(name)s] %(message)s') - - # Client manager class to use in this test case. - client_manager = clients.Manager - - # A way to adjust slow test classes - TIMEOUT_SCALING_FACTOR = 1 - - @classmethod - def setUpClass(cls): - # It should never be overridden by descendants - if hasattr(super(BaseTestCase, cls), 'setUpClass'): - super(BaseTestCase, cls).setUpClass() - cls.setUpClassCalled = True - # Stack of (name, callable) to be invoked in reverse order at teardown - cls.teardowns = [] - # All the configuration checks that may generate a skip - cls.skip_checks() - try: - # Allocation of all required credentials and client managers - cls.teardowns.append(('credentials', cls.clear_credentials)) - cls.setup_credentials() - # Shortcuts to clients - cls.setup_clients() - # Additional class-wide test resources - cls.teardowns.append(('resources', cls.resource_cleanup)) - cls.resource_setup() - except Exception: - etype, value, trace = sys.exc_info() - LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.", - etype, cls.__name__) - cls.tearDownClass() - try: - six.reraise(etype, value, trace) - finally: - del trace # to avoid circular refs - - @classmethod - def tearDownClass(cls): - # insert pdb breakpoint when pause_teardown is enabled - if CONF.pause_teardown: - cls.insert_pdb_breakpoint() - at_exit_set.discard(cls) - # It should never be overridden by descendants - if hasattr(super(BaseTestCase, cls), 'tearDownClass'): - super(BaseTestCase, cls).tearDownClass() - # Save any existing exception, we always want to re-raise the original - # exception only - etype, value, trace = sys.exc_info() - # If there was no exception during setup we shall re-raise the first - # exception in teardown - re_raise = (etype is None) - while cls.teardowns: - name, teardown = cls.teardowns.pop() - # Catch any exception in tearDown so we can re-raise the original - # exception at the end - try: - teardown() - except Exception as te: - sys_exec_info = sys.exc_info() - tetype = sys_exec_info[0] - # TODO(andreaf): Till we have the ability to cleanup only - # resources that were successfully setup in resource_cleanup, - # log AttributeError as info instead of exception. - if tetype is AttributeError and name == 'resources': - LOG.info("tearDownClass of %s failed: %s", name, te) - else: - LOG.exception("teardown of %s failed: %s", name, te) - if not etype: - etype, value, trace = sys_exec_info - # If exceptions were raised during teardown, and not before, re-raise - # the first one - if re_raise and etype is not None: - try: - six.reraise(etype, value, trace) - finally: - del trace # to avoid circular refs - - def tearDown(self): - super(BaseTestCase, self).tearDown() - # insert pdb breakpoint when pause_teardown is enabled - if CONF.pause_teardown: - BaseTestCase.insert_pdb_breakpoint() - - @classmethod - def insert_pdb_breakpoint(cls): - """Add pdb breakpoint. - - This can help in debugging process, cleaning of resources is - paused, so they can be examined. - """ - import pdb - pdb.set_trace() - - @classmethod - def skip_checks(cls): - """Class level skip checks. - - Subclasses verify in here all conditions that might prevent the - execution of the entire test class. - Checks implemented here may not make use API calls, and should rely on - configuration alone. - In general skip checks that require an API call are discouraged. - If one is really needed it may be implemented either in the - resource_setup or at test level. - """ - identity_version = cls.get_identity_version() - if 'admin' in cls.credentials and not credentials.is_admin_available( - identity_version=identity_version): - msg = "Missing Identity Admin API credentials in configuration." - raise cls.skipException(msg) - if 'alt' in cls.credentials and not credentials.is_alt_available( - identity_version=identity_version): - msg = "Missing a 2nd set of API credentials in configuration." - raise cls.skipException(msg) - if hasattr(cls, 'identity_version'): - if cls.identity_version == 'v2': - if not CONF.identity_feature_enabled.api_v2: - raise cls.skipException("Identity api v2 is not enabled") - elif cls.identity_version == 'v3': - if not CONF.identity_feature_enabled.api_v3: - raise cls.skipException("Identity api v3 is not enabled") - - @classmethod - def setup_credentials(cls): - """Allocate credentials and create the client managers from them. - - For every element of credentials param function creates tenant/user, - Then it creates client manager for that credential. - - Network related tests must override this function with - set_network_resources() method, otherwise it will create - network resources(network resources are created in a later step). - """ - for credentials_type in cls.credentials: - # This may raise an exception in case credentials are not available - # In that case we want to let the exception through and the test - # fail accordingly - if isinstance(credentials_type, six.string_types): - manager = cls.get_client_manager( - credential_type=credentials_type) - setattr(cls, 'os_%s' % credentials_type, manager) - # NOTE(jordanP): Tempest should use os_primary, os_admin - # and os_alt throughout its code base but we keep the aliases - # around for a while for Tempest plugins. Aliases should be - # removed eventually. - # Setup some common aliases - if credentials_type == 'primary': - cls.os = debtcollector.moves.moved_read_only_property( - 'os', 'os_primary', version='Pike', - removal_version='Queens') - cls.manager =\ - debtcollector.moves.moved_read_only_property( - 'manager', 'os_primary', version='Pike', - removal_version='Queens') - if credentials_type == 'admin': - cls.os_adm = debtcollector.moves.moved_read_only_property( - 'os_adm', 'os_admin', version='Pike', - removal_version='Queens') - cls.admin_manager =\ - debtcollector.moves.moved_read_only_property( - 'admin_manager', 'os_admin', version='Pike', - removal_version='Queens') - if credentials_type == 'alt': - cls.alt_manager =\ - debtcollector.moves.moved_read_only_property( - 'alt_manager', 'os_alt', version='Pike', - removal_version='Queens') - elif isinstance(credentials_type, list): - manager = cls.get_client_manager(roles=credentials_type[1:], - force_new=True) - setattr(cls, 'os_roles_%s' % credentials_type[0], manager) - - @classmethod - def setup_clients(cls): - """Create links to the clients into the test object.""" - # TODO(andreaf) There is a fair amount of code that could me moved from - # base / test classes in here. Ideally tests should be able to only - # specify which client is `client` and nothing else. - pass - - @classmethod - def resource_setup(cls): - """Class level resource setup for test cases.""" - if hasattr(cls, "os_primary"): - cls.validation_resources = vresources.create_validation_resources( - cls.os_primary, cls.validation_resources) - else: - LOG.warning("Client manager not found, validation resources not" - " created") - - @classmethod - def resource_cleanup(cls): - """Class level resource cleanup for test cases. - - Resource cleanup must be able to handle the case of partially setup - resources, in case a failure during `resource_setup` should happen. - """ - if cls.validation_resources: - if hasattr(cls, "os_primary"): - vresources.clear_validation_resources(cls.os_primary, - cls.validation_resources) - cls.validation_resources = {} - else: - LOG.warning("Client manager not found, validation resources " - "not deleted") - - def setUp(self): - super(BaseTestCase, self).setUp() - if not self.setUpClassCalled: - raise RuntimeError("setUpClass does not calls the super's" - "setUpClass in the " - + self.__class__.__name__) - at_exit_set.add(self.__class__) - test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) - try: - test_timeout = int(test_timeout) * self.TIMEOUT_SCALING_FACTOR - except ValueError: - test_timeout = 0 - if test_timeout > 0: - self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) - - if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or - os.environ.get('OS_STDOUT_CAPTURE') == '1'): - stdout = self.useFixture(fixtures.StringStream('stdout')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) - if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or - os.environ.get('OS_STDERR_CAPTURE') == '1'): - stderr = self.useFixture(fixtures.StringStream('stderr')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) - if (os.environ.get('OS_LOG_CAPTURE') != 'False' and - os.environ.get('OS_LOG_CAPTURE') != '0'): - self.useFixture(fixtures.LoggerFixture(nuke_handlers=False, - format=self.log_format, - level=None)) - - @property - def credentials_provider(self): - return self._get_credentials_provider() - - @property - def identity_utils(self): - """A client that abstracts v2 and v3 identity operations. - - This can be used for creating and tearing down projects in tests. It - should not be used for testing identity features. - """ - if CONF.identity.auth_version == 'v2': - client = self.os_admin.identity_client - users_client = self.os_admin.users_client - project_client = self.os_admin.tenants_client - roles_client = self.os_admin.roles_client - domains_client = None - else: - client = self.os_admin.identity_v3_client - users_client = self.os_admin.users_v3_client - project_client = self.os_admin.projects_client - roles_client = self.os_admin.roles_v3_client - domains_client = self.os_admin.domains_client - - try: - domain = client.auth_provider.credentials.project_domain_name - except AttributeError: - domain = 'Default' - - return cred_client.get_creds_client(client, project_client, - users_client, - roles_client, - domains_client, - project_domain_name=domain) - - @classmethod - def get_identity_version(cls): - """Returns the identity version used by the test class""" - identity_version = getattr(cls, 'identity_version', None) - return identity_version or CONF.identity.auth_version - - @classmethod - def _get_credentials_provider(cls): - """Returns a credentials provider - - If no credential provider exists yet creates one. - It always use the configuration value from identity.auth_version, - since we always want to provision accounts with the current version - of the identity API. - """ - if (not hasattr(cls, '_creds_provider') or not cls._creds_provider or - not cls._creds_provider.name == cls.__name__): - force_tenant_isolation = getattr(cls, 'force_tenant_isolation', - False) - - cls._creds_provider = credentials.get_credentials_provider( - name=cls.__name__, network_resources=cls.network_resources, - force_tenant_isolation=force_tenant_isolation) - return cls._creds_provider - - @classmethod - def get_client_manager(cls, credential_type=None, roles=None, - force_new=None): - """Returns an OpenStack client manager - - Returns an OpenStack client manager based on either credential_type - or a list of roles. If neither is specified, it defaults to - credential_type 'primary' - :param credential_type: string - primary, alt or admin - :param roles: list of roles - - :returns: the created client manager - :raises skipException: if the requested credentials are not available - """ - if all([roles, credential_type]): - msg = "Cannot get credentials by type and roles at the same time" - raise ValueError(msg) - if not any([roles, credential_type]): - credential_type = 'primary' - cred_provider = cls._get_credentials_provider() - if roles: - for role in roles: - if not cred_provider.is_role_available(role): - skip_msg = ( - "%s skipped because the configured credential provider" - " is not able to provide credentials with the %s role " - "assigned." % (cls.__name__, role)) - raise cls.skipException(skip_msg) - params = dict(roles=roles) - if force_new is not None: - params.update(force_new=force_new) - creds = cred_provider.get_creds_by_roles(**params) - else: - credentials_method = 'get_%s_creds' % credential_type - if hasattr(cred_provider, credentials_method): - creds = getattr(cred_provider, credentials_method)() - else: - raise lib_exc.InvalidCredentials( - "Invalid credentials type %s" % credential_type) - manager = cls.client_manager(credentials=creds.credentials) - # NOTE(andreaf) Ensure credentials have user and project id fields. - # It may not be the case when using pre-provisioned credentials. - manager.auth_provider.set_auth() - return manager - - @classmethod - def clear_credentials(cls): - """Clears creds if set""" - if hasattr(cls, '_creds_provider'): - cls._creds_provider.clear_creds() - - @classmethod - def set_validation_resources(cls, keypair=None, floating_ip=None, - security_group=None, - security_group_rules=None): - """Specify which ssh server validation resources should be created. - - Each of the argument must be set to either None, True or False, with - None - use default from config (security groups and security group - rules get created when set to None) - False - Do not create the validation resource - True - create the validation resource - - @param keypair - @param security_group - @param security_group_rules - @param floating_ip - """ - if not CONF.validation.run_validation: - return - - if keypair is None: - keypair = (CONF.validation.auth_method.lower() == "keypair") - - if floating_ip is None: - floating_ip = (CONF.validation.connect_method.lower() == - "floating") - - if security_group is None: - security_group = CONF.validation.security_group - - if security_group_rules is None: - security_group_rules = CONF.validation.security_group_rules - - if not cls.validation_resources: - cls.validation_resources = { - 'keypair': keypair, - 'security_group': security_group, - 'security_group_rules': security_group_rules, - 'floating_ip': floating_ip} - - @classmethod - def set_network_resources(cls, network=False, router=False, subnet=False, - dhcp=False): - """Specify which network resources should be created - - @param network - @param router - @param subnet - @param dhcp - """ - # network resources should be set only once from callers - # in order to ensure that even if it's called multiple times in - # a chain of overloaded methods, the attribute is set only - # in the leaf class - if not cls.network_resources: - cls.network_resources = { - 'network': network, - 'router': router, - 'subnet': subnet, - 'dhcp': dhcp} - - @classmethod - def get_tenant_network(cls, credentials_type='primary'): - """Get the network to be used in testing - - :param credentials_type: The type of credentials for which to get the - tenant network - - :return: network dict including 'id' and 'name' - """ - # Get a manager for the given credentials_type, but at least - # always fall back on getting the manager for primary credentials - if isinstance(credentials_type, six.string_types): - manager = cls.get_client_manager(credential_type=credentials_type) - elif isinstance(credentials_type, list): - manager = cls.get_client_manager(roles=credentials_type[1:]) - else: - manager = cls.get_client_manager() - - # Make sure cred_provider exists and get a network client - networks_client = manager.compute_networks_client - cred_provider = cls._get_credentials_provider() - # In case of nova network, isolated tenants are not able to list the - # network configured in fixed_network_name, even if they can use it - # for their servers, so using an admin network client to validate - # the network name - if (not CONF.service_available.neutron and - credentials.is_admin_available( - identity_version=cls.get_identity_version())): - admin_creds = cred_provider.get_admin_creds() - admin_manager = clients.Manager(admin_creds.credentials) - networks_client = admin_manager.compute_networks_client - return fixed_network.get_tenant_network( - cred_provider, networks_client, CONF.compute.fixed_network_name) - - def assertEmpty(self, items, msg=None): - """Asserts whether a sequence or collection is empty - - :param items: sequence or collection to be tested - :param msg: message to be passed to the AssertionError - :raises AssertionError: when items is not empty - """ - if msg is None: - msg = "sequence or collection is not empty: %s" % items - self.assertFalse(items, msg) - - def assertNotEmpty(self, items, msg=None): - """Asserts whether a sequence or collection is not empty - - :param items: sequence or collection to be tested - :param msg: message to be passed to the AssertionError - :raises AssertionError: when items is empty - """ - if msg is None: - msg = "sequence or collection is empty." - self.assertTrue(items, msg) diff --git a/tempest/test_discover/__init__.py b/tempest/test_discover/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py deleted file mode 100644 index 1206e3fee..000000000 --- a/tempest/test_discover/plugins.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import abc - -from oslo_log import log as logging -import six -import stevedore - -from tempest.lib.common.utils import misc -from tempest.lib.services import clients - -LOG = logging.getLogger(__name__) - - -@six.add_metaclass(abc.ABCMeta) -class TempestPlugin(object): - """Provide basic hooks for an external plugin - - To provide tempest the necessary information to run the plugin. - """ - - @abc.abstractmethod - def load_tests(self): - """Return the information necessary to load the tests in the plugin. - - :return: a tuple with the first value being the test_dir and the second - being the top_level - :rtype: tuple - """ - return - - @abc.abstractmethod - def register_opts(self, conf): - """Add additional configuration options to tempest. - - This method will be run for the plugin during the register_opts() - function in tempest.config. - - :param ConfigOpts conf: The conf object that can be used to register - additional options on. - - Example:: - - # Config options are defined in a config.py module - service_option = cfg.BoolOpt( - "my_service", - default=True, - help="Whether or not my service is available") - - # Note: as long as the group is listed in get_opt_lists, - # it will be possible to access its optins in the plugin code - # via ("-" in the group name are replaces with "_"): - # CONF.my_service. - my_service_group = cfg.OptGroup(name="my-service", - title="My service options") - - MyServiceGroup = [] - # (...) More groups and options... - - # Plugin is implemented in a plugin.py module - from my_plugin import config as my_config - - def register_opts(self, conf): - conf.register_opt(my_config.service_option, - group='service_available') - conf.register_group(my_config.my_service_group) - conf.register_opts(my_config.MyService + - my_config.my_service_group) - - conf.register_group(my_config.my_service_feature_group) - conf.register_opts(my_config.MyServiceFeaturesGroup, - my_config.my_service_feature_group) - """ - return - - @abc.abstractmethod - def get_opt_lists(self): - """Get a list of options for sample config generation - - :return option_list: A list of tuples with the group name and options - in that group. - :rtype: list - - Example:: - - # Config options are defined in a config.py module - service_option = cfg.BoolOpt( - "my_service", default=True, - help="Whether or not my service is available") - - my_service_group = cfg.OptGroup(name="my-service", - title="My service options") - my_service_features_group = cfg.OptGroup( - name="my-service-features", - title="My service available features") - - MyServiceGroup = [] - MyServiceFeaturesGroup = [] - - # Plugin is implemented in a plugin.py module - from my_plugin import config as my_config - - def get_opt_lists(self, conf): - return [ - (my_service_group.name, MyServiceGroup), - (my_service_features_group.name, MyServiceFeaturesGroup) - ] - """ - return [] - - def get_service_clients(self): - """Get a list of the service clients for registration - - If the plugin implements service clients for one or more APIs, it - may return their details by this method for automatic registration - in any ServiceClients object instantiated by tests. - The default implementation returns an empty list. - - :returns: Each element of the list represents the service client for an - API. Each dict must define all parameters required for the invocation - of `service_clients.ServiceClients.register_service_client_module`. - :rtype: list of dictionaries - - Example implementation with one service client:: - - def get_service_clients(self): - # Example implementation with one service client - myservice_config = config.service_client_config('myservice') - params = { - 'name': 'myservice', - 'service_version': 'myservice', - 'module_path': 'myservice_tempest_tests.services', - 'client_names': ['API1Client', 'API2Client'], - } - params.update(myservice_config) - return [params] - - Example implementation with two service clients:: - - def get_service_clients(self): - # Example implementation with two service clients - foo1_config = config.service_client_config('foo') - params_foo1 = { - 'name': 'foo_v1', - 'service_version': 'foo.v1', - 'module_path': 'bar_tempest_tests.services.foo.v1', - 'client_names': ['API1Client', 'API2Client'], - } - params_foo1.update(foo_config) - foo2_config = config.service_client_config('foo') - params_foo2 = { - 'name': 'foo_v2', - 'service_version': 'foo.v2', - 'module_path': 'bar_tempest_tests.services.foo.v2', - 'client_names': ['API1Client', 'API2Client'], - } - params_foo2.update(foo2_config) - return [params_foo1, params_foo2] - """ - return [] - - -@misc.singleton -class TempestTestPluginManager(object): - """Tempest test plugin manager class - - This class is used to manage the lifecycle of external tempest test - plugins. It provides functions for getting set - """ - def __init__(self): - self.ext_plugins = stevedore.ExtensionManager( - 'tempest.test_plugins', invoke_on_load=True, - propagate_map_exceptions=True, - on_load_failure_callback=self.failure_hook) - - @staticmethod - def failure_hook(_, ep, err): - LOG.error('Could not load %r: %s', ep.name, err) - raise err - - def get_plugin_load_tests_tuple(self): - load_tests_dict = {} - for plug in self.ext_plugins: - load_tests_dict[plug.name] = plug.obj.load_tests() - return load_tests_dict - - def register_plugin_opts(self, conf): - for plug in self.ext_plugins: - try: - plug.obj.register_opts(conf) - except Exception: - LOG.exception('Plugin %s raised an exception trying to run ' - 'register_opts', plug.name) - - def get_plugin_options_list(self): - plugin_options = [] - for plug in self.ext_plugins: - opt_list = plug.obj.get_opt_lists() - if opt_list: - plugin_options.extend(opt_list) - return plugin_options - - def _register_service_clients(self): - registry = clients.ClientsRegistry() - for plug in self.ext_plugins: - try: - service_clients = plug.obj.get_service_clients() - if service_clients: - registry.register_service_client( - plug.name, service_clients) - except Exception: - LOG.exception('Plugin %s raised an exception trying to run ' - 'get_service_clients', plug.name) diff --git a/tempest/test_discover/test_discover.py b/tempest/test_discover/test_discover.py deleted file mode 100644 index 330f370f7..000000000 --- a/tempest/test_discover/test_discover.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import sys - -from tempest.test_discover import plugins - -if sys.version_info >= (2, 7): - import unittest -else: - import unittest2 as unittest - - -def load_tests(loader, tests, pattern): - ext_plugins = plugins.TempestTestPluginManager() - - suite = unittest.TestSuite() - base_path = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0] - base_path = os.path.split(base_path)[0] - # Load local tempest tests - for test_dir in ['tempest/api', 'tempest/scenario']: - full_test_dir = os.path.join(base_path, test_dir) - if not pattern: - suite.addTests(loader.discover(full_test_dir, - top_level_dir=base_path)) - else: - suite.addTests(loader.discover(full_test_dir, pattern=pattern, - top_level_dir=base_path)) - - plugin_load_tests = ext_plugins.get_plugin_load_tests_tuple() - if not plugin_load_tests: - return suite - - # Load any installed plugin tests - for plugin in plugin_load_tests: - test_dir, top_path = plugin_load_tests[plugin] - if not pattern: - suite.addTests(loader.discover(test_dir, top_level_dir=top_path)) - else: - suite.addTests(loader.discover(test_dir, pattern=pattern, - top_level_dir=top_path)) - return suite diff --git a/tempest/tests/README.rst b/tempest/tests/README.rst deleted file mode 100644 index 0587e7b88..000000000 --- a/tempest/tests/README.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. _unit_tests_field_guide: - -Tempest Field Guide to Unit tests -================================= - -What are these tests? ---------------------- - -Unit tests are the self checks for Tempest. They provide functional -verification and regression checking for the internal components of Tempest. -They should be used to just verify that the individual pieces of Tempest are -working as expected. They should not require an external service to be running -and should be able to run solely from the Tempest tree. - -Why are these tests in Tempest? -------------------------------- -These tests exist to make sure that the mechanisms that we use inside of -Tempest are valid and remain functional. They are only here for self -validation of Tempest. - - -Scope of these tests --------------------- -Unit tests should not require an external service to be running or any extra -configuration to run. Any state that is required for a test should either be -mocked out or created in a temporary test directory. (see test_wrappers.py for -an example of using a temporary test directory) diff --git a/tempest/tests/__init__.py b/tempest/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/api/__init__.py b/tempest/tests/api/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/api/compute/__init__.py b/tempest/tests/api/compute/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/api/compute/test_base.py b/tempest/tests/api/compute/test_base.py deleted file mode 100644 index 6345728ba..000000000 --- a/tempest/tests/api/compute/test_base.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright 2017 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock - -from oslo_utils import uuidutils -import six - -from tempest.api.compute import base as compute_base -from tempest.common import waiters -from tempest import exceptions -from tempest.lib import exceptions as lib_exc -from tempest.tests import base - - -class TestBaseV2ComputeTest(base.TestCase): - """Unit tests for utility functions in BaseV2ComputeTest.""" - - @mock.patch.multiple(compute_base.BaseV2ComputeTest, - compute_images_client=mock.DEFAULT, - images=[], create=True) - def test_create_image_from_server_no_wait(self, compute_images_client): - """Tests create_image_from_server without the wait_until kwarg.""" - # setup mocks - image_id = uuidutils.generate_uuid() - fake_image = mock.Mock(response={'location': image_id}) - compute_images_client.create_image.return_value = fake_image - # call the utility method - image = compute_base.BaseV2ComputeTest.create_image_from_server( - mock.sentinel.server_id, name='fake-snapshot-name') - self.assertEqual(fake_image, image) - # make our assertions - compute_images_client.create_image.assert_called_once_with( - mock.sentinel.server_id, name='fake-snapshot-name') - self.assertEqual(1, len(compute_base.BaseV2ComputeTest.images)) - self.assertEqual(image_id, compute_base.BaseV2ComputeTest.images[0]) - - @mock.patch.multiple(compute_base.BaseV2ComputeTest, - compute_images_client=mock.DEFAULT, - servers_client=mock.DEFAULT, - images=[], create=True) - @mock.patch.object(waiters, 'wait_for_image_status') - @mock.patch.object(waiters, 'wait_for_server_status') - def test_create_image_from_server_wait_until_active(self, - wait_for_server_status, - wait_for_image_status, - servers_client, - compute_images_client): - """Tests create_image_from_server with wait_until='ACTIVE' kwarg.""" - # setup mocks - image_id = uuidutils.generate_uuid() - fake_image = mock.Mock(response={'location': image_id}) - compute_images_client.create_image.return_value = fake_image - compute_images_client.show_image.return_value = ( - {'image': fake_image}) - # call the utility method - image = compute_base.BaseV2ComputeTest.create_image_from_server( - mock.sentinel.server_id, wait_until='ACTIVE') - self.assertEqual(fake_image, image) - # make our assertions - wait_for_image_status.assert_called_once_with( - compute_images_client, image_id, 'ACTIVE') - wait_for_server_status.assert_called_once_with( - servers_client, mock.sentinel.server_id, 'ACTIVE') - compute_images_client.show_image.assert_called_once_with(image_id) - - @mock.patch.multiple(compute_base.BaseV2ComputeTest, - compute_images_client=mock.DEFAULT, - servers_client=mock.DEFAULT, - images=[], create=True) - @mock.patch.object(waiters, 'wait_for_image_status') - @mock.patch.object(waiters, 'wait_for_server_status') - def test_create_image_from_server_wait_until_active_no_server_wait( - self, wait_for_server_status, wait_for_image_status, - servers_client, compute_images_client): - """Tests create_image_from_server with wait_until='ACTIVE' kwarg.""" - # setup mocks - image_id = uuidutils.generate_uuid() - fake_image = mock.Mock(response={'location': image_id}) - compute_images_client.create_image.return_value = fake_image - compute_images_client.show_image.return_value = ( - {'image': fake_image}) - # call the utility method - image = compute_base.BaseV2ComputeTest.create_image_from_server( - mock.sentinel.server_id, wait_until='ACTIVE', - wait_for_server=False) - self.assertEqual(fake_image, image) - # make our assertions - wait_for_image_status.assert_called_once_with( - compute_images_client, image_id, 'ACTIVE') - self.assertEqual(0, wait_for_server_status.call_count) - compute_images_client.show_image.assert_called_once_with(image_id) - - @mock.patch.multiple(compute_base.BaseV2ComputeTest, - compute_images_client=mock.DEFAULT, - servers_client=mock.DEFAULT, - images=[], create=True) - @mock.patch.object(waiters, 'wait_for_image_status', - side_effect=lib_exc.NotFound) - def _test_create_image_from_server_wait_until_active_not_found( - self, wait_for_image_status, compute_images_client, - servers_client, fault=None): - # setup mocks - image_id = uuidutils.generate_uuid() - fake_image = mock.Mock(response={'location': image_id}) - compute_images_client.create_image.return_value = fake_image - fake_server = {'id': mock.sentinel.server_id} - if fault: - fake_server['fault'] = fault - servers_client.show_server.return_value = {'server': fake_server} - # call the utility method - ex = self.assertRaises( - exceptions.SnapshotNotFoundException, - compute_base.BaseV2ComputeTest.create_image_from_server, - mock.sentinel.server_id, wait_until='active') - # make our assertions - if fault: - self.assertIn(fault, six.text_type(ex)) - else: - self.assertNotIn(fault, six.text_type(ex)) - wait_for_image_status.assert_called_once_with( - compute_images_client, image_id, 'active') - servers_client.show_server.assert_called_once_with( - mock.sentinel.server_id) - - def test_create_image_from_server_wait_until_active_not_found_no_fault( - self): - # Tests create_image_from_server with wait_until='active' kwarg and - # the a 404 is raised while waiting for the image status to change. In - # this test the server does not have a fault associated with it. - self._test_create_image_from_server_wait_until_active_not_found() - - def test_create_image_from_server_wait_until_active_not_found_with_fault( - self): - # Tests create_image_from_server with wait_until='active' kwarg and - # the a 404 is raised while waiting for the image status to change. In - # this test the server has a fault associated with it. - self._test_create_image_from_server_wait_until_active_not_found( - fault='Lost connection to hypervisor!') - - @mock.patch.multiple(compute_base.BaseV2ComputeTest, - compute_images_client=mock.DEFAULT, - images=[], create=True) - @mock.patch.object(waiters, 'wait_for_image_status', - side_effect=lib_exc.NotFound) - def test_create_image_from_server_wait_until_saving_not_found( - self, wait_for_image_status, compute_images_client): - # Tests create_image_from_server with wait_until='SAVING' kwarg and - # the a 404 is raised while waiting for the image status to change. In - # this case we do not get the server details and just re-raise the 404. - # setup mocks - image_id = uuidutils.generate_uuid() - fake_image = mock.Mock(response={'location': image_id}) - compute_images_client.create_image.return_value = fake_image - # call the utility method - self.assertRaises( - lib_exc.NotFound, - compute_base.BaseV2ComputeTest.create_image_from_server, - mock.sentinel.server_id, wait_until='SAVING') - # make our assertions - wait_for_image_status.assert_called_once_with( - compute_images_client, image_id, 'SAVING') diff --git a/tempest/tests/base.py b/tempest/tests/base.py deleted file mode 100644 index ca81d4d60..000000000 --- a/tempest/tests/base.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -from oslotest import base - - -class TestCase(base.BaseTestCase): - - def patch(self, target, **kwargs): - """Returns a started `mock.patch` object for the supplied target. - - The caller may then call the returned patcher to create a mock object. - - The caller does not need to call stop() on the returned - patcher object, as this method automatically adds a cleanup - to the test class to stop the patcher. - - :param target: String module.class or module.object expression to patch - :param **kwargs: Passed as-is to `mock.patch`. See mock documentation - for details. - """ - p = mock.patch(target, **kwargs) - m = p.start() - self.addCleanup(p.stop) - return m - - def patchobject(self, target, attribute, new=mock.DEFAULT): - """Convenient wrapper around `mock.patch.object` - - Returns a started mock that will be automatically stopped after the - test ran. - """ - - p = mock.patch.object(target, attribute, new) - m = p.start() - self.addCleanup(p.stop) - return m diff --git a/tempest/tests/cmd/__init__.py b/tempest/tests/cmd/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/cmd/sample_streams/calls.subunit b/tempest/tests/cmd/sample_streams/calls.subunit deleted file mode 100644 index d5b479036eba61a413f3ffa8f12d7249a9e4c09e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7267 zcmeHM%Wm676gAMDi!QS7g78KyqLJps;ZSV@IJKRoXzUucA(Y5lRb_Fh(& zKmPiA^!&QH^Yfx*-MfkJRzsB+A5_PFP!_}T;20#2QF^O18 zX>@ycXDw#(rXA%)9~!>A zzqi|KoPSV#+>0p2(cQiK{b=BQ)$4XC>(H2W646PMo=g(nJ)#}bHJQ*PWh`^C=84F( zR$5E=AuQ1;<=wJDYI>Up!v&IN{iPtbwr@VT^+q62^o3K_)lDz@zV&%ocz}fZ$CYdK zqL!+vVQ!Sq%cA>jQx>gu)Y>%0RsO7_57Fk>4^Y26bVca%X*tThclJi>+4^*LVRN&z z$8fieDXxw1Yg`ZEdt)-0z)Zn*5;oy~qaAGwU@-Mj-jsFdGkYMRePrW-Y6hWESu3=T zr6VlWj$py>Y1mf9o z8u(4bLPgQ7JN@}>ru^||@#pH0An+&XazD4g3IRS9f( zVq&Qcj-?DDx$K%gc!>DzWkf6uIN zo5gsg>Nr>5M)5LPoB(l&WO3nr8>bw@y1{7hcyHOa(b!t09F!Pb200+M1W8IIic@U` zSBXnveR1@RUsunU&%B>Wg44c@EcI=;9gEdgg{HpE)DDdFDc`p83K5peBh3QP)sHlX zN2BvD4S zjxhh>!#^Ea=oyhEN#d2}E#57%`cQISbyiP8A&8LWL1lsE5(SmFPzZ7^#c^f@Qn3b! zTE&qxEI~07%xD^Go7$@&(Itf-+)m|cE1vuHxPUh=P8H*-Ij3qTybc1AFSV{G0R2yL rf8q^=O9?f~U?iBsh>IjeN=St?yttCq8ikV!RH%7_O!vhPPhb2AX^@m> diff --git a/tempest/tests/cmd/test_account_generator.py b/tempest/tests/cmd/test_account_generator.py deleted file mode 100644 index f907bd081..000000000 --- a/tempest/tests/cmd/test_account_generator.py +++ /dev/null @@ -1,332 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures -import mock -from oslo_config import cfg - -from tempest.cmd import account_generator -from tempest import config -from tempest.tests import base -from tempest.tests import fake_config - - -class FakeOpts(object): - - def __init__(self, version=3): - self.os_username = 'fake_user' - self.os_password = 'fake_password' - self.os_project_name = 'fake_project_name' - self.os_tenant_name = None - self.os_domain_name = 'fake_domain' - self.tag = 'fake' - self.concurrency = 2 - self.with_admin = True - self.identity_version = version - self.accounts = 'fake_accounts.yml' - - -class MockHelpersMixin(object): - - def mock_config_and_opts(self, identity_version): - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - self.opts = FakeOpts(version=identity_version) - - def mock_resource_creation(self): - fake_resource = dict(id='id', name='name') - self.user_create_fixture = self.useFixture(fixtures.MockPatch( - self.cred_client + '.create_user', return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.cred_client + '.create_project', - return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.cred_client + '.assign_user_role')) - self.useFixture(fixtures.MockPatch( - self.cred_client + '._check_role_exists', - return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.dynamic_creds + '._create_network', - return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.dynamic_creds + '._create_subnet', - return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.dynamic_creds + '._create_router', - return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.dynamic_creds + '._add_router_interface', - return_value=fake_resource)) - - def mock_domains(self): - fake_domain_list = {'domains': [{'id': 'fake_domain', - 'name': 'Fake_Domain'}]} - self.useFixture(fixtures.MockPatch(''.join([ - 'tempest.lib.services.identity.v3.domains_client.' - 'DomainsClient.list_domains']), - return_value=fake_domain_list)) - self.useFixture(fixtures.MockPatch( - self.cred_client + '.assign_user_role_on_domain')) - - -class TestAccountGeneratorV2(base.TestCase, MockHelpersMixin): - - identity_version = 2 - - def setUp(self): - super(TestAccountGeneratorV2, self).setUp() - self.mock_config_and_opts(self.identity_version) - - def test_get_credential_provider(self): - cp = account_generator.get_credential_provider(self.opts) - admin_creds = cp.default_admin_creds - self.assertEqual(self.opts.tag, cp.name) - self.assertIn(str(self.opts.identity_version), cp.identity_version) - self.assertEqual(self.opts.os_username, admin_creds.username) - self.assertEqual(self.opts.os_project_name, admin_creds.tenant_name) - self.assertEqual(self.opts.os_password, admin_creds.password) - self.assertFalse(hasattr(admin_creds, 'domain_name')) - - def test_get_credential_provider_with_tenant(self): - self.opts.os_project_name = None - self.opts.os_tenant_name = 'fake_tenant' - cp = account_generator.get_credential_provider(self.opts) - admin_creds = cp.default_admin_creds - self.assertEqual(self.opts.os_tenant_name, admin_creds.tenant_name) - - -class TestAccountGeneratorV3(TestAccountGeneratorV2): - - identity_version = 3 - - def setUp(self): - super(TestAccountGeneratorV3, self).setUp() - fake_domain_list = {'domains': [{'id': 'fake_domain'}]} - self.useFixture(fixtures.MockPatch(''.join([ - 'tempest.lib.services.identity.v3.domains_client.' - 'DomainsClient.list_domains']), - return_value=fake_domain_list)) - - def test_get_credential_provider(self): - cp = account_generator.get_credential_provider(self.opts) - admin_creds = cp.default_admin_creds - self.assertEqual(self.opts.tag, cp.name) - self.assertIn(str(self.opts.identity_version), cp.identity_version) - self.assertEqual(self.opts.os_username, admin_creds.username) - self.assertEqual(self.opts.os_project_name, admin_creds.tenant_name) - self.assertEqual(self.opts.os_password, admin_creds.password) - self.assertEqual(self.opts.os_domain_name, admin_creds.domain_name) - - def test_get_credential_provider_without_domain(self): - self.opts.os_domain_name = None - cp = account_generator.get_credential_provider(self.opts) - admin_creds = cp.default_admin_creds - self.assertIsNotNone(admin_creds.domain_name) - - -class TestGenerateResourcesV2(base.TestCase, MockHelpersMixin): - - identity_version = 2 - cred_client = 'tempest.lib.common.cred_client.V2CredsClient' - dynamic_creds = ('tempest.lib.common.dynamic_creds.' - 'DynamicCredentialProvider') - - def setUp(self): - super(TestGenerateResourcesV2, self).setUp() - self.mock_config_and_opts(self.identity_version) - self.cred_provider = account_generator.get_credential_provider( - self.opts) - self.mock_resource_creation() - - def test_generate_resources_no_admin(self): - cfg.CONF.set_default('swift', False, group='service_available') - cfg.CONF.set_default('heat', False, group='service_available') - cfg.CONF.set_default('operator_role', 'fake_operator', - group='object-storage') - cfg.CONF.set_default('reseller_admin_role', 'fake_reseller', - group='object-storage') - cfg.CONF.set_default('stack_owner_role', 'fake_owner', - group='orchestration') - resources = account_generator.generate_resources( - self.cred_provider, admin=False) - resource_types = [k for k, _ in resources] - # No admin, no heat, no swift, expect two credentials only - self.assertEqual(2, len(resources)) - # Ensure create_user was invoked twice (two distinct users) - self.assertEqual(2, self.user_create_fixture.mock.call_count) - self.assertIn('primary', resource_types) - self.assertIn('alt', resource_types) - self.assertNotIn('admin', resource_types) - self.assertNotIn(['fake_operator'], resource_types) - self.assertNotIn(['fake_reseller'], resource_types) - self.assertNotIn(['fake_owner'], resource_types) - for resource in resources: - self.assertIsNotNone(resource[1].network) - self.assertIsNotNone(resource[1].router) - self.assertIsNotNone(resource[1].subnet) - - def test_generate_resources_admin(self): - cfg.CONF.set_default('swift', False, group='service_available') - cfg.CONF.set_default('heat', False, group='service_available') - cfg.CONF.set_default('operator_role', 'fake_operator', - group='object-storage') - cfg.CONF.set_default('reseller_admin_role', 'fake_reseller', - group='object-storage') - cfg.CONF.set_default('stack_owner_role', 'fake_owner', - group='orchestration') - resources = account_generator.generate_resources( - self.cred_provider, admin=True) - resource_types = [k for k, _ in resources] - # Admin, no heat, no swift, expect three credentials only - self.assertEqual(3, len(resources)) - # Ensure create_user was invoked 3 times (3 distinct users) - self.assertEqual(3, self.user_create_fixture.mock.call_count) - self.assertIn('primary', resource_types) - self.assertIn('alt', resource_types) - self.assertIn('admin', resource_types) - self.assertNotIn(['fake_operator'], resource_types) - self.assertNotIn(['fake_reseller'], resource_types) - self.assertNotIn(['fake_owner'], resource_types) - for resource in resources: - self.assertIsNotNone(resource[1].network) - self.assertIsNotNone(resource[1].router) - self.assertIsNotNone(resource[1].subnet) - - def test_generate_resources_swift_heat_admin(self): - cfg.CONF.set_default('swift', True, group='service_available') - cfg.CONF.set_default('heat', True, group='service_available') - cfg.CONF.set_default('operator_role', 'fake_operator', - group='object-storage') - cfg.CONF.set_default('reseller_admin_role', 'fake_reseller', - group='object-storage') - cfg.CONF.set_default('stack_owner_role', 'fake_owner', - group='orchestration') - resources = account_generator.generate_resources( - self.cred_provider, admin=True) - resource_types = [k for k, _ in resources] - # all options on, expect six credentials - self.assertEqual(6, len(resources)) - # Ensure create_user was invoked 6 times (6 distinct users) - self.assertEqual(6, self.user_create_fixture.mock.call_count) - self.assertIn('primary', resource_types) - self.assertIn('alt', resource_types) - self.assertIn('admin', resource_types) - self.assertIn(['fake_operator'], resource_types) - self.assertIn(['fake_reseller'], resource_types) - self.assertIn(['fake_owner', 'fake_operator'], resource_types) - for resource in resources: - self.assertIsNotNone(resource[1].network) - self.assertIsNotNone(resource[1].router) - self.assertIsNotNone(resource[1].subnet) - - -class TestGenerateResourcesV3(TestGenerateResourcesV2): - - identity_version = 3 - cred_client = 'tempest.lib.common.cred_client.V3CredsClient' - - def setUp(self): - self.mock_domains() - super(TestGenerateResourcesV3, self).setUp() - - -class TestDumpAccountsV2(base.TestCase, MockHelpersMixin): - - identity_version = 2 - cred_client = 'tempest.lib.common.cred_client.V2CredsClient' - dynamic_creds = ('tempest.lib.common.dynamic_creds.' - 'DynamicCredentialProvider') - domain_is_in = False - - def setUp(self): - super(TestDumpAccountsV2, self).setUp() - self.mock_config_and_opts(self.identity_version) - self.cred_provider = account_generator.get_credential_provider( - self.opts) - self.mock_resource_creation() - cfg.CONF.set_default('swift', True, group='service_available') - cfg.CONF.set_default('heat', True, group='service_available') - self.resources = account_generator.generate_resources( - self.cred_provider, admin=True) - - def test_dump_accounts(self): - self.useFixture(fixtures.MockPatch('os.path.exists', - return_value=False)) - mocked_open = mock.mock_open() - with mock.patch('{}.open'.format(account_generator.__name__), - mocked_open, create=True): - with mock.patch('yaml.safe_dump') as yaml_dump_mock: - account_generator.setup_logging() - account_generator.dump_accounts(self.resources, - self.opts.identity_version, - self.opts.accounts) - mocked_open.assert_called_once_with(self.opts.accounts, 'w') - handle = mocked_open() - # Ordered args in [0], keyword args in [1] - accounts, f = yaml_dump_mock.call_args[0] - self.assertEqual(handle, f) - self.assertEqual(6, len(accounts)) - if self.domain_is_in: - self.assertIn('domain_name', accounts[0].keys()) - else: - self.assertNotIn('domain_name', accounts[0].keys()) - self.assertEqual(1, len([x for x in accounts if - x.get('types') == ['admin']])) - self.assertEqual(3, len([x for x in accounts if 'roles' in x])) - for account in accounts: - self.assertIn('resources', account) - self.assertIn('network', account.get('resources')) - - def test_dump_accounts_existing_file(self): - self.useFixture(fixtures.MockPatch('os.path.exists', - return_value=True)) - rename_mock = self.useFixture(fixtures.MockPatch('os.rename')).mock - backup_file = '.'.join((self.opts.accounts, 'bak')) - mocked_open = mock.mock_open() - with mock.patch('{}.open'.format(account_generator.__name__), - mocked_open, create=True): - with mock.patch('yaml.safe_dump') as yaml_dump_mock: - account_generator.setup_logging() - account_generator.dump_accounts(self.resources, - self.opts.identity_version, - self.opts.accounts) - rename_mock.assert_called_once_with(self.opts.accounts, backup_file) - mocked_open.assert_called_once_with(self.opts.accounts, 'w') - handle = mocked_open() - # Ordered args in [0], keyword args in [1] - accounts, f = yaml_dump_mock.call_args[0] - self.assertEqual(handle, f) - self.assertEqual(6, len(accounts)) - if self.domain_is_in: - self.assertIn('domain_name', accounts[0].keys()) - else: - self.assertNotIn('domain_name', accounts[0].keys()) - self.assertEqual(1, len([x for x in accounts if - x.get('types') == ['admin']])) - self.assertEqual(3, len([x for x in accounts if 'roles' in x])) - for account in accounts: - self.assertIn('resources', account) - self.assertIn('network', account.get('resources')) - - -class TestDumpAccountsV3(TestDumpAccountsV2): - - identity_version = 3 - cred_client = 'tempest.lib.common.cred_client.V3CredsClient' - domain_is_in = True - - def setUp(self): - self.mock_domains() - super(TestDumpAccountsV3, self).setUp() diff --git a/tempest/tests/cmd/test_list_plugins.py b/tempest/tests/cmd/test_list_plugins.py deleted file mode 100644 index 17ddb1828..000000000 --- a/tempest/tests/cmd/test_list_plugins.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import subprocess - -from tempest.tests import base - - -class TestTempestListPlugins(base.TestCase): - def test_run_list_plugins(self): - return_code = subprocess.call( - ['tempest', 'list-plugins'], stdout=subprocess.PIPE) - self.assertEqual(return_code, 0) diff --git a/tempest/tests/cmd/test_run.py b/tempest/tests/cmd/test_run.py deleted file mode 100644 index 7ac347dea..000000000 --- a/tempest/tests/cmd/test_run.py +++ /dev/null @@ -1,154 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import os -import shutil -import subprocess -import tempfile - -import fixtures -import mock - -from tempest.cmd import run -from tempest.tests import base - -DEVNULL = open(os.devnull, 'wb') - - -class TestTempestRun(base.TestCase): - - def setUp(self): - super(TestTempestRun, self).setUp() - self.run_cmd = run.TempestRun(None, None) - - def test_build_options(self): - args = mock.Mock(spec=argparse.Namespace) - setattr(args, "subunit", True) - setattr(args, "parallel", False) - setattr(args, "concurrency", 10) - options = self.run_cmd._build_options(args) - self.assertEqual(['--subunit', - '--concurrency=10'], - options) - - def test__build_regex_default(self): - args = mock.Mock(spec=argparse.Namespace) - setattr(args, 'smoke', False) - setattr(args, 'regex', '') - setattr(args, 'whitelist_file', None) - setattr(args, 'blacklist_file', None) - self.assertEqual('', self.run_cmd._build_regex(args)) - - def test__build_regex_smoke(self): - args = mock.Mock(spec=argparse.Namespace) - setattr(args, "smoke", True) - setattr(args, 'regex', '') - setattr(args, 'whitelist_file', None) - setattr(args, 'blacklist_file', None) - self.assertEqual('smoke', self.run_cmd._build_regex(args)) - - def test__build_regex_regex(self): - args = mock.Mock(spec=argparse.Namespace) - setattr(args, 'smoke', False) - setattr(args, "regex", 'i_am_a_fun_little_regex') - setattr(args, 'whitelist_file', None) - setattr(args, 'blacklist_file', None) - self.assertEqual('i_am_a_fun_little_regex', - self.run_cmd._build_regex(args)) - - -class TestRunReturnCode(base.TestCase): - def setUp(self): - super(TestRunReturnCode, self).setUp() - # Setup test dirs - self.directory = tempfile.mkdtemp(prefix='tempest-unit') - self.addCleanup(shutil.rmtree, self.directory) - self.test_dir = os.path.join(self.directory, 'tests') - os.mkdir(self.test_dir) - # Setup Test files - self.testr_conf_file = os.path.join(self.directory, '.testr.conf') - self.setup_cfg_file = os.path.join(self.directory, 'setup.cfg') - self.passing_file = os.path.join(self.test_dir, 'test_passing.py') - self.failing_file = os.path.join(self.test_dir, 'test_failing.py') - self.init_file = os.path.join(self.test_dir, '__init__.py') - self.setup_py = os.path.join(self.directory, 'setup.py') - shutil.copy('tempest/tests/files/testr-conf', self.testr_conf_file) - shutil.copy('tempest/tests/files/passing-tests', self.passing_file) - shutil.copy('tempest/tests/files/failing-tests', self.failing_file) - shutil.copy('setup.py', self.setup_py) - shutil.copy('tempest/tests/files/setup.cfg', self.setup_cfg_file) - shutil.copy('tempest/tests/files/__init__.py', self.init_file) - # Change directory, run wrapper and check result - self.addCleanup(os.chdir, os.path.abspath(os.curdir)) - os.chdir(self.directory) - - def assertRunExit(self, cmd, expected): - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out, err = p.communicate() - msg = ("Running %s got an unexpected returncode\n" - "Stdout: %s\nStderr: %s" % (' '.join(cmd), out, err)) - self.assertEqual(p.returncode, expected, msg) - - def test_tempest_run_passes(self): - # Git init is required for the pbr testr command. pbr requires a git - # version or an sdist to work. so make the test directory a git repo - # too. - subprocess.call(['git', 'init'], stderr=DEVNULL) - self.assertRunExit(['tempest', 'run', '--regex', 'passing'], 0) - - def test_tempest_run_passes_with_testrepository(self): - # Git init is required for the pbr testr command. pbr requires a git - # version or an sdist to work. so make the test directory a git repo - # too. - subprocess.call(['git', 'init'], stderr=DEVNULL) - subprocess.call(['testr', 'init']) - self.assertRunExit(['tempest', 'run', '--regex', 'passing'], 0) - - def test_tempest_run_fails(self): - # Git init is required for the pbr testr command. pbr requires a git - # version or an sdist to work. so make the test directory a git repo - # too. - subprocess.call(['git', 'init'], stderr=DEVNULL) - self.assertRunExit(['tempest', 'run'], 1) - - -class TestTakeAction(base.TestCase): - def test_workspace_not_registered(self): - class Exception_(Exception): - pass - - m_exit = self.useFixture(fixtures.MockPatch('sys.exit')).mock - # sys.exit must not continue (or exit) - m_exit.side_effect = Exception_ - - workspace = self.getUniqueString() - - tempest_run = run.TempestRun(app=mock.Mock(), app_args=mock.Mock()) - parsed_args = mock.Mock() - parsed_args.config_file = [] - - # Override $HOME so that empty workspace gets created in temp dir. - self.useFixture(fixtures.TempHomeDir()) - - # Force use of the temporary home directory. - parsed_args.workspace_path = None - - # Simulate --workspace argument. - parsed_args.workspace = workspace - - self.assertRaises(Exception_, tempest_run.take_action, parsed_args) - exit_msg = m_exit.call_args[0][0] - self.assertIn(workspace, exit_msg) diff --git a/tempest/tests/cmd/test_subunit_describe_calls.py b/tempest/tests/cmd/test_subunit_describe_calls.py deleted file mode 100644 index 5f3d77085..000000000 --- a/tempest/tests/cmd/test_subunit_describe_calls.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright 2016 Rackspace -# -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import subprocess -import tempfile - -from tempest.cmd import subunit_describe_calls -from tempest.tests import base - - -class TestSubunitDescribeCalls(base.TestCase): - def test_return_code(self): - subunit_file = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - 'sample_streams/calls.subunit') - p = subprocess.Popen([ - 'subunit-describe-calls', '-s', subunit_file, - '-o', tempfile.mkstemp()[1]], stdin=subprocess.PIPE) - p.communicate() - self.assertEqual(0, p.returncode) - - def test_return_code_no_output(self): - subunit_file = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - 'sample_streams/calls.subunit') - p = subprocess.Popen([ - 'subunit-describe-calls', '-s', subunit_file], - stdin=subprocess.PIPE) - p.communicate() - self.assertEqual(0, p.returncode) - - def test_parse(self): - subunit_file = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - 'sample_streams/calls.subunit') - parser = subunit_describe_calls.parse( - open(subunit_file), "pythonlogging", None) - expected_result = { - 'bar': [{ - 'name': 'AgentsAdminTestJSON:setUp', - 'request_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "common", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86_64-424013832", "os": "linux"}}', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "common", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86_64-424013832", "os": "linux", ' - '"agent_id": 1}}', - 'response_headers': "{'status': '200', 'content-length': " - "'203', 'x-compute-request-id': " - "'req-25ddaae2-0ef1-40d1-8228-59bd64a7e75b', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:00 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents', - 'verb': 'POST'}, { - 'name': 'AgentsAdminTestJSON:test_create_agent', - 'request_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "kvm", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86-252246646", "os": "win"}}', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "kvm", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86-252246646", "os": "win", ' - '"agent_id": 2}}', - 'response_headers': "{'status': '200', 'content-length': " - "'195', 'x-compute-request-id': " - "'req-b4136f06-c015-4e7e-995f-c43831e3ecce', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:00 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents', - 'verb': 'POST'}, { - 'name': 'AgentsAdminTestJSON:tearDown', - 'request_body': 'None', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '', - 'response_headers': "{'status': '200', 'content-length': " - "'0', 'x-compute-request-id': " - "'req-ee905fd6-a5b5-4da4-8c37-5363cb25bd9d', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:00 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents/1', - 'verb': 'DELETE'}, { - 'name': 'AgentsAdminTestJSON:_run_cleanups', - 'request_body': 'None', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_headers': "{'status': '200', 'content-length': " - "'0', 'x-compute-request-id': " - "'req-e912cac0-63e0-4679-a68a-b6d18ddca074', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:00 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents/2', - 'verb': 'DELETE'}], - 'foo': [{ - 'name': 'AgentsAdminTestJSON:setUp', - 'request_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "common", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86_64-948635295", "os": "linux"}}', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "common", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86_64-948635295", "os": "linux", ' - '"agent_id": 3}}', - 'response_headers': "{'status': '200', 'content-length': " - "'203', 'x-compute-request-id': " - "'req-ccd2116d-04b1-4ffe-ae32-fb623f68bf1c', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:01 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents', - 'verb': 'POST'}, { - 'name': 'AgentsAdminTestJSON:test_delete_agent', - 'request_body': 'None', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '', - 'response_headers': "{'status': '200', 'content-length': " - "'0', 'x-compute-request-id': " - "'req-6e7fa28f-ae61-4388-9a78-947c58bc0588', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:01 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents/3', - 'verb': 'DELETE'}, { - 'name': 'AgentsAdminTestJSON:test_delete_agent', - 'request_body': 'None', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '{"agents": []}', - 'response_headers': "{'status': '200', 'content-length': " - "'14', 'content-location': " - "'http://23.253.76.97:8774/v2.1/" - "cf6b1933fe5b476fbbabb876f6d1b924/os-agents', " - "'x-compute-request-id': " - "'req-e41aa9b4-41a6-4138-ae04-220b768eb644', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:01 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents', - 'verb': 'GET'}, { - 'name': 'AgentsAdminTestJSON:tearDown', - 'request_body': 'None', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_headers': "{'status': '404', 'content-length': " - "'82', 'x-compute-request-id': " - "'req-e297aeea-91cf-4f26-b49c-8f46b1b7a926', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:02 GMT', 'content-type': " - "'application/json; charset=UTF-8'}", - 'service': 'Nova', - 'status_code': '404', - 'url': 'v2.1//os-agents/3', - 'verb': 'DELETE'}]} - - self.assertEqual(expected_result, parser.test_logs) diff --git a/tempest/tests/cmd/test_tempest_init.py b/tempest/tests/cmd/test_tempest_init.py deleted file mode 100644 index 79510be76..000000000 --- a/tempest/tests/cmd/test_tempest_init.py +++ /dev/null @@ -1,154 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os - -import fixtures - -from tempest.cmd import init -from tempest.tests import base - - -class TestTempestInit(base.TestCase): - - def test_generate_testr_conf(self): - # Create fake conf dir - conf_dir = self.useFixture(fixtures.TempDir()) - - init_cmd = init.TempestInit(None, None) - init_cmd.generate_testr_conf(conf_dir.path) - - # Generate expected file contents - top_level_path = os.path.dirname(os.path.dirname(init.__file__)) - discover_path = os.path.join(top_level_path, 'test_discover') - testr_conf_file = init.TESTR_CONF % (top_level_path, discover_path) - - conf_path = conf_dir.join('.testr.conf') - with open(conf_path, 'r') as conf_file: - self.assertEqual(conf_file.read(), testr_conf_file) - - def test_generate_sample_config(self): - local_dir = self.useFixture(fixtures.TempDir()) - etc_dir_path = os.path.join(local_dir.path, 'etc/') - os.mkdir(etc_dir_path) - init_cmd = init.TempestInit(None, None) - local_sample_conf_file = os.path.join(etc_dir_path, - 'tempest.conf.sample') - - # Verify no sample config file exist - self.assertFalse(os.path.isfile(local_sample_conf_file)) - init_cmd.generate_sample_config(local_dir.path) - - # Verify sample config file exist with some content - self.assertTrue(os.path.isfile(local_sample_conf_file)) - self.assertGreater(os.path.getsize(local_sample_conf_file), 0) - - def test_update_local_conf(self): - local_dir = self.useFixture(fixtures.TempDir()) - etc_dir_path = os.path.join(local_dir.path, 'etc/') - os.mkdir(etc_dir_path) - lock_dir = os.path.join(local_dir.path, 'tempest_lock') - config_path = os.path.join(etc_dir_path, 'tempest.conf') - log_dir = os.path.join(local_dir.path, 'logs') - - init_cmd = init.TempestInit(None, None) - - # Generate the config file - init_cmd.generate_sample_config(local_dir.path) - - # Create a conf file with populated values - config_parser_pre = init_cmd.get_configparser(config_path) - with open(config_path, 'w+') as conf_file: - # create the same section init will check for and add values to - config_parser_pre.add_section('oslo_concurrency') - config_parser_pre.set('oslo_concurrency', 'TEST', local_dir.path) - # create a new section - config_parser_pre.add_section('TEST') - config_parser_pre.set('TEST', 'foo', "bar") - config_parser_pre.write(conf_file) - - # Update the config file the same way tempest init does - init_cmd.update_local_conf(config_path, lock_dir, log_dir) - - # parse the new config file to verify it - config_parser_post = init_cmd.get_configparser(config_path) - - # check that our value in oslo_concurrency wasn't overwritten - self.assertTrue(config_parser_post.has_section('oslo_concurrency')) - self.assertEqual(config_parser_post.get('oslo_concurrency', 'TEST'), - local_dir.path) - # check that the lock directory was set correctly - self.assertEqual(config_parser_post.get('oslo_concurrency', - 'lock_path'), lock_dir) - - # check that our new section still exists and wasn't modified - self.assertTrue(config_parser_post.has_section('TEST')) - self.assertEqual(config_parser_post.get('TEST', 'foo'), 'bar') - - # check that the DEFAULT values are correct - # NOTE(auggy): has_section ignores DEFAULT - self.assertEqual(config_parser_post.get('DEFAULT', 'log_dir'), log_dir) - - def test_create_working_dir_with_existing_local_dir_non_empty(self): - fake_local_dir = self.useFixture(fixtures.TempDir()) - fake_local_conf_dir = self.useFixture(fixtures.TempDir()) - open("%s/foo" % fake_local_dir.path, 'w').close() - - _init = init.TempestInit(None, None) - self.assertRaises(OSError, - _init.create_working_dir, - fake_local_dir.path, - fake_local_conf_dir.path) - - def test_create_working_dir(self): - fake_local_dir = self.useFixture(fixtures.TempDir()) - fake_local_conf_dir = self.useFixture(fixtures.TempDir()) - os.rmdir(fake_local_dir.path) - # Create a fake conf file - fake_file = fake_local_conf_dir.join('conf_file.conf') - open(fake_file, 'w').close() - init_cmd = init.TempestInit(None, None) - init_cmd.create_working_dir(fake_local_dir.path, - fake_local_conf_dir.path) - # Assert directories are created - lock_path = os.path.join(fake_local_dir.path, 'tempest_lock') - etc_dir = os.path.join(fake_local_dir.path, 'etc') - log_dir = os.path.join(fake_local_dir.path, 'logs') - testr_dir = os.path.join(fake_local_dir.path, '.testrepository') - self.assertTrue(os.path.isdir(lock_path)) - self.assertTrue(os.path.isdir(etc_dir)) - self.assertTrue(os.path.isdir(log_dir)) - self.assertTrue(os.path.isdir(testr_dir)) - # Assert file creation - fake_file_moved = os.path.join(etc_dir, 'conf_file.conf') - local_conf_file = os.path.join(etc_dir, 'tempest.conf') - local_testr_conf = os.path.join(fake_local_dir.path, '.testr.conf') - self.assertTrue(os.path.isfile(fake_file_moved)) - self.assertTrue(os.path.isfile(local_conf_file)) - self.assertTrue(os.path.isfile(local_testr_conf)) - - def test_take_action_fails(self): - class ParsedArgs(object): - workspace_dir = self.useFixture(fixtures.TempDir()).path - workspace_path = os.path.join(workspace_dir, 'workspace.yaml') - name = 'test' - dir_base = self.useFixture(fixtures.TempDir()).path - dir = os.path.join(dir_base, 'foo', 'bar') - config_dir = self.useFixture(fixtures.TempDir()).path - show_global_dir = False - pa = ParsedArgs() - init_cmd = init.TempestInit(None, None) - self.assertRaises(OSError, init_cmd.take_action, pa) - # one more trying should be a same error not "workspace already exists" - self.assertRaises(OSError, init_cmd.take_action, pa) diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py deleted file mode 100644 index 1415111cc..000000000 --- a/tempest/tests/cmd/test_verify_tempest_config.py +++ /dev/null @@ -1,431 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures -import mock -from oslo_serialization import jsonutils as json - -from tempest.cmd import verify_tempest_config -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.tests import base -from tempest.tests import fake_config - - -class TestGetAPIVersions(base.TestCase): - - def test_remove_version_project(self): - f = verify_tempest_config._remove_version_project - self.assertEqual('/', f('/v2.1/%s/' % data_utils.rand_uuid_hex())) - self.assertEqual('', f('/v2.1/tenant_id')) - self.assertEqual('', f('/v3')) - self.assertEqual('/', f('/v3/')) - self.assertEqual('/something/', f('/something/v2.1/tenant_id/')) - self.assertEqual('/something', f('/something/v2.1/tenant_id')) - self.assertEqual('/something', f('/something/v3')) - self.assertEqual('/something/', f('/something/v3/')) - self.assertEqual('/', f('/')) # http://localhost/ - self.assertEqual('', f('')) # http://localhost - - def test_url_grab_versioned_nova_nossl(self): - base_url = 'http://127.0.0.1:8774/v2/' - endpoint = verify_tempest_config._get_unversioned_endpoint(base_url) - self.assertEqual('http://127.0.0.1:8774/', endpoint) - - def test_url_grab_versioned_nova_ssl(self): - base_url = 'https://127.0.0.1:8774/v3/' - endpoint = verify_tempest_config._get_unversioned_endpoint(base_url) - self.assertEqual('https://127.0.0.1:8774/', endpoint) - - def test_get_unversioned_endpoint_base(self): - base_url = 'https://127.0.0.1:5000/' - endpoint = verify_tempest_config._get_unversioned_endpoint(base_url) - self.assertEqual('https://127.0.0.1:5000/', endpoint) - - def test_get_unversioned_endpoint_subpath(self): - base_url = 'https://127.0.0.1/identity/v3' - endpoint = verify_tempest_config._get_unversioned_endpoint(base_url) - self.assertEqual('https://127.0.0.1/identity', endpoint) - - def test_get_unversioned_endpoint_subpath_trailing_solidus(self): - base_url = 'https://127.0.0.1/identity/v3/' - endpoint = verify_tempest_config._get_unversioned_endpoint(base_url) - self.assertEqual('https://127.0.0.1/identity/', endpoint) - - -class TestDiscovery(base.TestCase): - - def setUp(self): - super(TestDiscovery, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - - def test_get_keystone_api_versions(self): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': {'values': [{'id': 'v2.0'}, {'id': 'v3.0'}]}} - fake_resp = json.dumps(fake_resp) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.http.ClosingHttp.request', - return_value=(None, fake_resp))) - fake_os = mock.MagicMock() - versions = verify_tempest_config._get_api_versions(fake_os, 'keystone') - self.assertIn('v2.0', versions) - self.assertIn('v3.0', versions) - - def test_get_cinder_api_versions(self): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v2.0'}]} - fake_resp = json.dumps(fake_resp) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.http.ClosingHttp.request', - return_value=(None, fake_resp))) - fake_os = mock.MagicMock() - versions = verify_tempest_config._get_api_versions(fake_os, 'cinder') - self.assertIn('v1.0', versions) - self.assertIn('v2.0', versions) - - def test_get_nova_versions(self): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': [{'id': 'v2.0'}, {'id': 'v3.0'}]} - fake_resp = json.dumps(fake_resp) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.http.ClosingHttp.request', - return_value=(None, fake_resp))) - fake_os = mock.MagicMock() - versions = verify_tempest_config._get_api_versions(fake_os, 'nova') - self.assertIn('v2.0', versions) - self.assertIn('v3.0', versions) - - def test_get_versions_invalid_response(self): - # When the response doesn't contain a JSON response, an error is - # logged. - mock_log_error = self.useFixture(fixtures.MockPatchObject( - verify_tempest_config.LOG, 'error')).mock - - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint')) - - # Simulated response is not JSON. - sample_body = ( - 'Sample ResponseThis is the sample page ' - 'for the web server. Why are you requesting it?') - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.http.ClosingHttp.request', - return_value=(None, sample_body))) - - # service value doesn't matter, just needs to match what - # _get_api_versions puts in its client_dict. - self.assertRaises(ValueError, verify_tempest_config._get_api_versions, - os=mock.MagicMock(), service='keystone') - self.assertTrue(mock_log_error.called) - - def test_verify_api_versions(self): - api_services = ['cinder', 'glance', 'keystone'] - fake_os = mock.MagicMock() - for svc in api_services: - m = 'verify_%s_api_versions' % svc - with mock.patch.object(verify_tempest_config, m) as verify_mock: - verify_tempest_config.verify_api_versions(fake_os, svc, True) - verify_mock.assert_called_once_with(fake_os, True) - - def test_verify_api_versions_not_implemented(self): - api_services = ['cinder', 'glance', 'keystone'] - fake_os = mock.MagicMock() - for svc in api_services: - m = 'verify_%s_api_versions' % svc - with mock.patch.object(verify_tempest_config, m) as verify_mock: - verify_tempest_config.verify_api_versions(fake_os, 'foo', True) - self.assertFalse(verify_mock.called) - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_verify_keystone_api_versions_no_v3(self, mock_request): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': {'values': [{'id': 'v2.0'}]}} - fake_resp = json.dumps(fake_resp) - mock_request.return_value = (None, fake_resp) - fake_os = mock.MagicMock() - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_keystone_api_versions(fake_os, True) - print_mock.assert_called_once_with('api_v3', - 'identity-feature-enabled', - False, True) - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_verify_keystone_api_versions_no_v2(self, mock_request): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': {'values': [{'id': 'v3.0'}]}} - fake_resp = json.dumps(fake_resp) - mock_request.return_value = (None, fake_resp) - fake_os = mock.MagicMock() - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_keystone_api_versions(fake_os, True) - print_mock.assert_called_once_with('api_v2', - 'identity-feature-enabled', - False, True) - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_verify_cinder_api_versions_no_v3(self, mock_request): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': [{'id': 'v2.0'}]} - fake_resp = json.dumps(fake_resp) - mock_request.return_value = (None, fake_resp) - fake_os = mock.MagicMock() - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_cinder_api_versions(fake_os, True) - print_mock.assert_any_call('api_v3', 'volume-feature-enabled', - False, True) - self.assertEqual(1, print_mock.call_count) - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_verify_cinder_api_versions_no_v2(self, mock_request): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': [{'id': 'v3.0'}]} - fake_resp = json.dumps(fake_resp) - mock_request.return_value = (None, fake_resp) - fake_os = mock.MagicMock() - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_cinder_api_versions(fake_os, True) - print_mock.assert_any_call('api_v2', 'volume-feature-enabled', - False, True) - self.assertEqual(1, print_mock.call_count) - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_verify_cinder_api_versions_no_v1(self, mock_request): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': [{'id': 'v2.0'}, {'id': 'v3.0'}]} - fake_resp = json.dumps(fake_resp) - mock_request.return_value = (None, fake_resp) - fake_os = mock.MagicMock() - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_cinder_api_versions(fake_os, True) - print_mock.assert_not_called() - - def test_verify_glance_version_no_v2_with_v1_1(self): - def fake_get_versions(): - return (None, ['v1.1']) - fake_os = mock.MagicMock() - fake_os.image_client.get_versions = fake_get_versions - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_glance_api_versions(fake_os, True) - print_mock.assert_called_once_with('api_v2', 'image-feature-enabled', - False, True) - - def test_verify_glance_version_no_v2_with_v1_0(self): - def fake_get_versions(): - return (None, ['v1.0']) - fake_os = mock.MagicMock() - fake_os.image_client.get_versions = fake_get_versions - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_glance_api_versions(fake_os, True) - print_mock.assert_called_once_with('api_v2', 'image-feature-enabled', - False, True) - - def test_verify_glance_version_no_v1(self): - def fake_get_versions(): - return (None, ['v2.0']) - fake_os = mock.MagicMock() - fake_os.image_client.get_versions = fake_get_versions - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_glance_api_versions(fake_os, True) - print_mock.assert_called_once_with('api_v1', 'image-feature-enabled', - False, True) - - def test_verify_extensions_neutron(self): - def fake_list_extensions(): - return {'extensions': [{'alias': 'fake1'}, - {'alias': 'fake2'}, - {'alias': 'not_fake'}]} - fake_os = mock.MagicMock() - fake_os.network_extensions_client.list_extensions = ( - fake_list_extensions) - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['fake1', 'fake2', 'fake3']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'neutron', {}) - self.assertIn('neutron', results) - self.assertIn('fake1', results['neutron']) - self.assertTrue(results['neutron']['fake1']) - self.assertIn('fake2', results['neutron']) - self.assertTrue(results['neutron']['fake2']) - self.assertIn('fake3', results['neutron']) - self.assertFalse(results['neutron']['fake3']) - self.assertIn('not_fake', results['neutron']) - self.assertFalse(results['neutron']['not_fake']) - - def test_verify_extensions_neutron_all(self): - def fake_list_extensions(): - return {'extensions': [{'alias': 'fake1'}, - {'alias': 'fake2'}, - {'alias': 'not_fake'}]} - fake_os = mock.MagicMock() - fake_os.network_extensions_client.list_extensions = ( - fake_list_extensions) - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['all']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'neutron', {}) - self.assertIn('neutron', results) - self.assertIn('extensions', results['neutron']) - self.assertEqual(sorted(['fake1', 'fake2', 'not_fake']), - sorted(results['neutron']['extensions'])) - - def test_verify_extensions_cinder(self): - def fake_list_extensions(): - return {'extensions': [{'alias': 'fake1'}, - {'alias': 'fake2'}, - {'alias': 'not_fake'}]} - fake_os = mock.MagicMock() - # NOTE (e0ne): mock both v1 and v2 APIs - fake_os.volumes_extension_client.list_extensions = fake_list_extensions - fake_os.volumes_v2_extension_client.list_extensions = ( - fake_list_extensions) - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['fake1', 'fake2', 'fake3']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'cinder', {}) - self.assertIn('cinder', results) - self.assertIn('fake1', results['cinder']) - self.assertTrue(results['cinder']['fake1']) - self.assertIn('fake2', results['cinder']) - self.assertTrue(results['cinder']['fake2']) - self.assertIn('fake3', results['cinder']) - self.assertFalse(results['cinder']['fake3']) - self.assertIn('not_fake', results['cinder']) - self.assertFalse(results['cinder']['not_fake']) - - def test_verify_extensions_cinder_all(self): - def fake_list_extensions(): - return {'extensions': [{'alias': 'fake1'}, - {'alias': 'fake2'}, - {'alias': 'not_fake'}]} - fake_os = mock.MagicMock() - # NOTE (e0ne): mock both v1 and v2 APIs - fake_os.volumes_extension_client.list_extensions = fake_list_extensions - fake_os.volumes_v2_extension_client.list_extensions = ( - fake_list_extensions) - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['all']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'cinder', {}) - self.assertIn('cinder', results) - self.assertIn('extensions', results['cinder']) - self.assertEqual(sorted(['fake1', 'fake2', 'not_fake']), - sorted(results['cinder']['extensions'])) - - def test_verify_extensions_nova(self): - def fake_list_extensions(): - return ([{'alias': 'fake1'}, {'alias': 'fake2'}, - {'alias': 'not_fake'}]) - fake_os = mock.MagicMock() - fake_os.extensions_client.list_extensions = fake_list_extensions - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['fake1', 'fake2', 'fake3']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'nova', {}) - self.assertIn('nova', results) - self.assertIn('fake1', results['nova']) - self.assertTrue(results['nova']['fake1']) - self.assertIn('fake2', results['nova']) - self.assertTrue(results['nova']['fake2']) - self.assertIn('fake3', results['nova']) - self.assertFalse(results['nova']['fake3']) - self.assertIn('not_fake', results['nova']) - self.assertFalse(results['nova']['not_fake']) - - def test_verify_extensions_nova_all(self): - def fake_list_extensions(): - return ({'extensions': [{'alias': 'fake1'}, - {'alias': 'fake2'}, - {'alias': 'not_fake'}]}) - fake_os = mock.MagicMock() - fake_os.extensions_client.list_extensions = fake_list_extensions - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['all']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'nova', {}) - self.assertIn('nova', results) - self.assertIn('extensions', results['nova']) - self.assertEqual(sorted(['fake1', 'fake2', 'not_fake']), - sorted(results['nova']['extensions'])) - - def test_verify_extensions_swift(self): - def fake_list_extensions(): - return {'fake1': 'metadata', - 'fake2': 'metadata', - 'not_fake': 'metadata', - 'swift': 'metadata'} - fake_os = mock.MagicMock() - fake_os.capabilities_client.list_capabilities = fake_list_extensions - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['fake1', 'fake2', 'fake3']))) - results = verify_tempest_config.verify_extensions(fake_os, 'swift', {}) - self.assertIn('swift', results) - self.assertIn('fake1', results['swift']) - self.assertTrue(results['swift']['fake1']) - self.assertIn('fake2', results['swift']) - self.assertTrue(results['swift']['fake2']) - self.assertIn('fake3', results['swift']) - self.assertFalse(results['swift']['fake3']) - self.assertIn('not_fake', results['swift']) - self.assertFalse(results['swift']['not_fake']) - - def test_verify_extensions_swift_all(self): - def fake_list_extensions(): - return {'fake1': 'metadata', - 'fake2': 'metadata', - 'not_fake': 'metadata', - 'swift': 'metadata'} - fake_os = mock.MagicMock() - fake_os.capabilities_client.list_capabilities = fake_list_extensions - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['all']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'swift', {}) - self.assertIn('swift', results) - self.assertIn('extensions', results['swift']) - self.assertEqual(sorted(['not_fake', 'fake1', 'fake2']), - sorted(results['swift']['extensions'])) diff --git a/tempest/tests/cmd/test_workspace.py b/tempest/tests/cmd/test_workspace.py deleted file mode 100644 index a1c8c5333..000000000 --- a/tempest/tests/cmd/test_workspace.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2016 Rackspace -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import shutil -import subprocess -import tempfile - -from tempest.cmd import workspace -from tempest.lib.common.utils import data_utils -from tempest.tests import base - - -class TestTempestWorkspaceBase(base.TestCase): - def setUp(self): - super(TestTempestWorkspaceBase, self).setUp() - self.name = data_utils.rand_uuid() - self.path = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, self.path, ignore_errors=True) - store_dir = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, store_dir, ignore_errors=True) - self.store_file = os.path.join(store_dir, 'workspace.yaml') - self.workspace_manager = workspace.WorkspaceManager( - path=self.store_file) - self.workspace_manager.register_new_workspace(self.name, self.path) - - -class TestTempestWorkspace(TestTempestWorkspaceBase): - def _run_cmd_gets_return_code(self, cmd, expected): - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = process.communicate() - return_code = process.returncode - msg = ("%s failed with:\nstdout: %s\nstderr: %s" % (' '.join(cmd), - stdout, stderr)) - self.assertEqual(return_code, expected, msg) - - def test_run_workspace_list(self): - cmd = ['tempest', 'workspace', 'list', - '--workspace-path', self.store_file] - self._run_cmd_gets_return_code(cmd, 0) - - def test_run_workspace_register(self): - name = data_utils.rand_uuid() - path = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, path, ignore_errors=True) - cmd = ['tempest', 'workspace', 'register', - '--workspace-path', self.store_file, - '--name', name, '--path', path] - self._run_cmd_gets_return_code(cmd, 0) - self.assertIsNotNone(self.workspace_manager.get_workspace(name)) - - def test_run_workspace_rename(self): - new_name = data_utils.rand_uuid() - cmd = ['tempest', 'workspace', 'rename', - '--workspace-path', self.store_file, - '--old-name', self.name, '--new-name', new_name] - self._run_cmd_gets_return_code(cmd, 0) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - self.assertIsNotNone(self.workspace_manager.get_workspace(new_name)) - - def test_run_workspace_move(self): - new_path = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, new_path, ignore_errors=True) - cmd = ['tempest', 'workspace', 'move', - '--workspace-path', self.store_file, - '--name', self.name, '--path', new_path] - self._run_cmd_gets_return_code(cmd, 0) - self.assertEqual( - self.workspace_manager.get_workspace(self.name), new_path) - - def test_run_workspace_remove_entry(self): - cmd = ['tempest', 'workspace', 'remove', - '--workspace-path', self.store_file, - '--name', self.name] - self._run_cmd_gets_return_code(cmd, 0) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - - def test_run_workspace_remove_directory(self): - cmd = ['tempest', 'workspace', 'remove', - '--workspace-path', self.store_file, - '--name', self.name, '--rmdir'] - self._run_cmd_gets_return_code(cmd, 0) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - - -class TestTempestWorkspaceManager(TestTempestWorkspaceBase): - def setUp(self): - super(TestTempestWorkspaceManager, self).setUp() - self.name = data_utils.rand_uuid() - self.path = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, self.path, ignore_errors=True) - store_dir = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, store_dir, ignore_errors=True) - self.store_file = os.path.join(store_dir, 'workspace.yaml') - self.workspace_manager = workspace.WorkspaceManager( - path=self.store_file) - self.workspace_manager.register_new_workspace(self.name, self.path) - - def test_workspace_manager_get(self): - self.assertIsNotNone(self.workspace_manager.get_workspace(self.name)) - - def test_workspace_manager_rename(self): - new_name = data_utils.rand_uuid() - self.workspace_manager.rename_workspace(self.name, new_name) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - self.assertIsNotNone(self.workspace_manager.get_workspace(new_name)) - - def test_workspace_manager_move(self): - new_path = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, new_path, ignore_errors=True) - self.workspace_manager.move_workspace(self.name, new_path) - self.assertEqual( - self.workspace_manager.get_workspace(self.name), new_path) - - def test_workspace_manager_remove_entry(self): - self.workspace_manager.remove_workspace_entry(self.name) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - - def test_workspace_manager_remove_directory(self): - path = self.workspace_manager.remove_workspace_entry(self.name) - self.workspace_manager.remove_workspace_directory(path) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - - def test_path_expansion(self): - name = data_utils.rand_uuid() - path = os.path.join("~", name) - os.makedirs(os.path.expanduser(path)) - self.addCleanup(shutil.rmtree, path, ignore_errors=True) - self.workspace_manager.register_new_workspace(name, path) - self.assertIsNotNone(self.workspace_manager.get_workspace(name)) diff --git a/tempest/tests/common/__init__.py b/tempest/tests/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/common/test_admin_available.py b/tempest/tests/common/test_admin_available.py deleted file mode 100644 index 7b3b1b027..000000000 --- a/tempest/tests/common/test_admin_available.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures -from oslo_config import cfg - -from tempest.common import credentials_factory as credentials -from tempest import config -from tempest.tests import base -from tempest.tests import fake_config - - -class TestAdminAvailable(base.TestCase): - - identity_version = 'v2' - - def setUp(self): - super(TestAdminAvailable, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - - def run_test(self, dynamic_creds, use_accounts_file, admin_creds): - - cfg.CONF.set_default('use_dynamic_credentials', - dynamic_creds, group='auth') - if use_accounts_file: - accounts = [{'username': 'u1', - 'project_name': 't1', - 'password': 'p'}, - {'username': 'u2', - 'project_name': 't2', - 'password': 'p'}] - if admin_creds == 'role': - accounts.append({'username': 'admin', - 'project_name': 'admin', - 'password': 'p', - 'roles': ['admin']}) - elif admin_creds == 'type': - accounts.append({'username': 'admin', - 'project_name': 'admin', - 'password': 'p', - 'types': ['admin']}) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=accounts)) - cfg.CONF.set_default('test_accounts_file', - use_accounts_file, group='auth') - self.useFixture(fixtures.MockPatch('os.path.isfile', - return_value=True)) - else: - self.useFixture(fixtures.MockPatch('os.path.isfile', - return_value=False)) - if admin_creds: - username = 'u' - project = 't' - password = 'p' - domain = 'd' - else: - username = None - project = None - password = None - domain = None - - cfg.CONF.set_default('admin_username', username, group='auth') - cfg.CONF.set_default('admin_project_name', project, group='auth') - cfg.CONF.set_default('admin_password', password, group='auth') - cfg.CONF.set_default('admin_domain_name', domain, group='auth') - - expected = admin_creds is not None or dynamic_creds - observed = credentials.is_admin_available( - identity_version=self.identity_version) - self.assertEqual(expected, observed) - - # Dynamic credentials implies admin so only one test case for True - def test__dynamic_creds__accounts_file__no_admin(self): - self.run_test(dynamic_creds=True, - use_accounts_file=True, - admin_creds=None) - - def test__no_dynamic_creds__accounts_file__no_admin(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - admin_creds=None) - - def test__no_dynamic_creds__accounts_file__admin_role(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - admin_creds='role') - - def test__no_dynamic_creds__accounts_file__admin_type(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - admin_creds='type') - - def test__no_dynamic_creds__no_accounts_file__no_admin(self): - self.run_test(dynamic_creds=False, - use_accounts_file=False, - admin_creds=None) - - def test__no_dynamic_creds__no_accounts_file__admin(self): - self.run_test(dynamic_creds=False, - use_accounts_file=False, - admin_creds='role') - - -class TestAdminAvailableV3(TestAdminAvailable): - - identity_version = 'v3' diff --git a/tempest/tests/common/test_alt_available.py b/tempest/tests/common/test_alt_available.py deleted file mode 100644 index a425bb86d..000000000 --- a/tempest/tests/common/test_alt_available.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures -from oslo_config import cfg - -from tempest.common import credentials_factory as credentials -from tempest import config -from tempest.tests import base -from tempest.tests import fake_config - - -class TestAltAvailable(base.TestCase): - - identity_version = 'v2' - - def setUp(self): - super(TestAltAvailable, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - - def run_test(self, dynamic_creds, use_accounts_file, creds): - - cfg.CONF.set_default('use_dynamic_credentials', - dynamic_creds, group='auth') - if use_accounts_file: - accounts = [dict(username="u%s" % ii, - project_name="t%s" % ii, - password="p") for ii in creds] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=accounts)) - cfg.CONF.set_default('test_accounts_file', - use_accounts_file, group='auth') - self.useFixture(fixtures.MockPatch('os.path.isfile', - return_value=True)) - else: - self.useFixture(fixtures.MockPatch('os.path.isfile', - return_value=False)) - expected = len(set(creds)) > 1 or dynamic_creds - observed = credentials.is_alt_available( - identity_version=self.identity_version) - self.assertEqual(expected, observed) - - # Dynamic credentials implies alt so only one test case for True - def test__dynamic_creds__accounts_file__one_user(self): - self.run_test(dynamic_creds=True, - use_accounts_file=False, - creds=['1', '2']) - - def test__no_dynamic_creds__accounts_file__one_user(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - creds=['1']) - - def test__no_dynamic_creds__accounts_file__two_users(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - creds=['1', '2']) - - def test__no_dynamic_creds__accounts_file__two_users_identical(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - creds=['1', '1']) - - -class TestAltAvailableV3(TestAltAvailable): - - identity_version = 'v3' diff --git a/tempest/tests/common/test_compute.py b/tempest/tests/common/test_compute.py deleted file mode 100644 index c108be981..000000000 --- a/tempest/tests/common/test_compute.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2017 Citrix Systems -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from six.moves.urllib import parse as urlparse - -import mock - -from tempest.common import compute -from tempest.tests import base - - -class TestCompute(base.TestCase): - def setUp(self): - super(TestCompute, self).setUp() - self.client_sock = mock.Mock() - self.url = urlparse.urlparse("http://www.fake.com:80") - - def test_rfp_frame_not_cached(self): - # rfp negotiation frame arrived separately after upgrade - # response, so it's not cached. - RFP_VERSION = b'RFB.003.003\x0a' - rfp_frame_header = b'\x82\x0c' - - self.client_sock.recv.side_effect = [ - b'fake response start\r\n', - b'fake response end\r\n\r\n', - rfp_frame_header, - RFP_VERSION] - expect_response = b'fake response start\r\nfake response end\r\n\r\n' - - webSocket = compute._WebSocket(self.client_sock, self.url) - - self.assertEqual(webSocket.response, expect_response) - # no cache - self.assertEqual(webSocket.cached_stream, b'') - self.client_sock.recv.assert_has_calls([mock.call(4096), - mock.call(4096)]) - - self.client_sock.recv.reset_mock() - recv_version = webSocket.receive_frame() - - self.assertEqual(recv_version, RFP_VERSION) - self.client_sock.recv.assert_has_calls([mock.call(2), - mock.call(12)]) - - def test_rfp_frame_fully_cached(self): - RFP_VERSION = b'RFB.003.003\x0a' - rfp_version_frame = b'\x82\x0c%s' % RFP_VERSION - - self.client_sock.recv.side_effect = [ - b'fake response start\r\n', - b'fake response end\r\n\r\n%s' % rfp_version_frame] - expect_response = b'fake response start\r\nfake response end\r\n\r\n' - webSocket = compute._WebSocket(self.client_sock, self.url) - - self.client_sock.recv.assert_has_calls([mock.call(4096), - mock.call(4096)]) - self.assertEqual(webSocket.response, expect_response) - self.assertEqual(webSocket.cached_stream, rfp_version_frame) - - self.client_sock.recv.reset_mock() - recv_version = webSocket.receive_frame() - - self.client_sock.recv.assert_not_called() - self.assertEqual(recv_version, RFP_VERSION) - # cached_stream should be empty in the end. - self.assertEqual(webSocket.cached_stream, b'') - - def test_rfp_frame_partially_cached(self): - RFP_VERSION = b'RFB.003.003\x0a' - rfp_version_frame = b'\x82\x0c%s' % RFP_VERSION - frame_part1 = rfp_version_frame[:6] - frame_part2 = rfp_version_frame[6:] - - self.client_sock.recv.side_effect = [ - b'fake response start\r\n', - b'fake response end\r\n\r\n%s' % frame_part1, - frame_part2] - expect_response = b'fake response start\r\nfake response end\r\n\r\n' - webSocket = compute._WebSocket(self.client_sock, self.url) - - self.client_sock.recv.assert_has_calls([mock.call(4096), - mock.call(4096)]) - self.assertEqual(webSocket.response, expect_response) - self.assertEqual(webSocket.cached_stream, frame_part1) - - self.client_sock.recv.reset_mock() - - recv_version = webSocket.receive_frame() - - self.client_sock.recv.assert_called_once_with(len(frame_part2)) - self.assertEqual(recv_version, RFP_VERSION) - # cached_stream should be empty in the end. - self.assertEqual(webSocket.cached_stream, b'') diff --git a/tempest/tests/common/test_custom_matchers.py b/tempest/tests/common/test_custom_matchers.py deleted file mode 100644 index 1053d861a..000000000 --- a/tempest/tests/common/test_custom_matchers.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.common import custom_matchers -from tempest.tests import base - - -# Stolen from testtools/testtools/tests/matchers/helpers.py -class TestMatchersInterface(object): - - def test_matches_match(self): - matcher = self.matches_matcher - matches = self.matches_matches - mismatches = self.matches_mismatches - for candidate in matches: - self.assertIsNone(matcher.match(candidate)) - for candidate in mismatches: - mismatch = matcher.match(candidate) - self.assertIsNotNone(mismatch) - self.assertIsNotNone(getattr(mismatch, 'describe', None)) - - def test__str__(self): - # [(expected, object to __str__)]. - from testtools.matchers._doctest import DocTestMatches - examples = self.str_examples - for expected, matcher in examples: - self.assertThat(matcher, DocTestMatches(expected)) - - def test_describe_difference(self): - # [(expected, matchee, matcher), ...] - examples = self.describe_examples - for difference, matchee, matcher in examples: - mismatch = matcher.match(matchee) - self.assertEqual(difference, mismatch.describe()) - - def test_mismatch_details(self): - # The mismatch object must provide get_details, which must return a - # dictionary mapping names to Content objects. - examples = self.describe_examples - for difference, matchee, matcher in examples: - mismatch = matcher.match(matchee) - details = mismatch.get_details() - self.assertEqual(dict(details), details) - - -class TestMatchesDictExceptForKeys(base.TestCase, - TestMatchersInterface): - - matches_matcher = custom_matchers.MatchesDictExceptForKeys( - {'a': 1, 'b': 2, 'c': 3, 'd': 4}, ['c', 'd']) - matches_matches = [ - {'a': 1, 'b': 2, 'c': 3, 'd': 4}, - {'a': 1, 'b': 2, 'c': 5}, - {'a': 1, 'b': 2}, - ] - matches_mismatches = [ - {}, - {'foo': 1}, - {'a': 1, 'b': 3}, - {'a': 1, 'b': 2, 'foo': 1}, - {'a': 1, 'b': None, 'foo': 1}, - ] - - str_examples = [] - describe_examples = [ - ("Only in expected:\n" - " {'a': 1, 'b': 2}\n", - {}, - matches_matcher), - ("Only in expected:\n" - " {'a': 1, 'b': 2}\n" - "Only in actual:\n" - " {'foo': 1}\n", - {'foo': 1}, - matches_matcher), - ("Differences:\n" - " b: expected 2, actual 3\n", - {'a': 1, 'b': 3}, - matches_matcher), - ("Only in actual:\n" - " {'foo': 1}\n", - {'a': 1, 'b': 2, 'foo': 1}, - matches_matcher), - ("Only in actual:\n" - " {'foo': 1}\n" - "Differences:\n" - " b: expected 2, actual None\n", - {'a': 1, 'b': None, 'foo': 1}, - matches_matcher) - ] diff --git a/tempest/tests/common/test_image.py b/tempest/tests/common/test_image.py deleted file mode 100644 index 240df4d45..000000000 --- a/tempest/tests/common/test_image.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2016 NEC Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.common import image -from tempest.lib.common import rest_client -from tempest.tests import base - - -class TestImage(base.TestCase): - - def test_get_image_meta_from_headers(self): - resp = { - 'x-image-meta-id': 'ea30c926-0629-4400-bb6e-f8a8da6a4e56', - 'x-image-meta-owner': '8f421f9470e645b1b10f5d2db7804924', - 'x-image-meta-status': 'queued', - 'x-image-meta-name': 'New Http Image' - } - respbody = rest_client.ResponseBody(resp) - observed = image.get_image_meta_from_headers(respbody) - - expected = { - 'properties': {}, - 'id': 'ea30c926-0629-4400-bb6e-f8a8da6a4e56', - 'owner': '8f421f9470e645b1b10f5d2db7804924', - 'status': 'queued', - 'name': 'New Http Image' - } - self.assertEqual(expected, observed) - - def test_image_meta_to_headers(self): - observed = image.image_meta_to_headers( - name='test', - container_format='wrong', - disk_format='vhd', - copy_from='http://localhost/images/10', - properties={'foo': 'bar'}, - api={'abc': 'def'}, - purge_props=True) - - expected = { - 'x-image-meta-name': 'test', - 'x-image-meta-container_format': 'wrong', - 'x-image-meta-disk_format': 'vhd', - 'x-glance-api-copy-from': 'http://localhost/images/10', - 'x-image-meta-property-foo': 'bar', - 'x-glance-api-property-abc': 'def', - 'x-glance-registry-purge-props': True - } - self.assertEqual(expected, observed) diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py deleted file mode 100644 index c2f622cab..000000000 --- a/tempest/tests/common/test_waiters.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -import mock - -from tempest.common import waiters -from tempest import exceptions -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.volume.v2 import volumes_client -from tempest.tests import base -import tempest.tests.utils as utils - - -class TestImageWaiters(base.TestCase): - def setUp(self): - super(TestImageWaiters, self).setUp() - self.client = mock.MagicMock() - self.client.build_timeout = 1 - self.client.build_interval = 1 - - def test_wait_for_image_status(self): - self.client.show_image.return_value = ({'status': 'active'}) - start_time = int(time.time()) - waiters.wait_for_image_status(self.client, 'fake_image_id', 'active') - end_time = int(time.time()) - # Ensure waiter returns before build_timeout - self.assertLess((end_time - start_time), 10) - - def test_wait_for_image_status_timeout(self): - time_mock = self.patch('time.time') - time_mock.side_effect = utils.generate_timeout_series(1) - - self.client.show_image.return_value = ({'status': 'saving'}) - self.assertRaises(lib_exc.TimeoutException, - waiters.wait_for_image_status, - self.client, 'fake_image_id', 'active') - - def test_wait_for_image_status_error_on_image_create(self): - self.client.show_image.return_value = ({'status': 'ERROR'}) - self.assertRaises(exceptions.AddImageException, - waiters.wait_for_image_status, - self.client, 'fake_image_id', 'active') - - @mock.patch.object(time, 'sleep') - def test_wait_for_volume_status_error_restoring(self, mock_sleep): - # Tests that the wait method raises VolumeRestoreErrorException if - # the volume status is 'error_restoring'. - client = mock.Mock(spec=volumes_client.VolumesClient, - build_interval=1) - volume1 = {'volume': {'status': 'restoring-backup'}} - volume2 = {'volume': {'status': 'error_restoring'}} - mock_show = mock.Mock(side_effect=(volume1, volume2)) - client.show_volume = mock_show - volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa' - self.assertRaises(exceptions.VolumeRestoreErrorException, - waiters.wait_for_volume_resource_status, - client, volume_id, 'available') - mock_show.assert_has_calls([mock.call(volume_id), - mock.call(volume_id)]) - mock_sleep.assert_called_once_with(1) diff --git a/tempest/tests/common/utils/__init__.py b/tempest/tests/common/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/common/utils/linux/__init__.py b/tempest/tests/common/utils/linux/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py deleted file mode 100644 index 739357bab..000000000 --- a/tempest/tests/common/utils/linux/test_remote_client.py +++ /dev/null @@ -1,214 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import time - -import fixtures -from oslo_config import cfg - -from tempest.common.utils.linux import remote_client -from tempest import config -from tempest.lib import exceptions as lib_exc -from tempest.tests import base -from tempest.tests import fake_config - - -SERVER = { - 'id': 'server_uuid', - 'name': 'fake_server', - 'status': 'ACTIVE' -} - -BROKEN_SERVER = { - 'id': 'broken_server_uuid', - 'name': 'broken_server', - 'status': 'ERROR' -} - - -class FakeServersClient(object): - - CONSOLE_OUTPUT = "Console output for %s" - - def get_console_output(self, server_id): - status = 'ERROR' - for s in SERVER, BROKEN_SERVER: - if s['id'] == server_id: - status = s['status'] - if status == 'ERROR': - raise lib_exc.BadRequest('Server in ERROR state') - else: - return dict(output=self.CONSOLE_OUTPUT % server_id) - - -class TestRemoteClient(base.TestCase): - def setUp(self): - super(TestRemoteClient, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - cfg.CONF.set_default('ip_version_for_ssh', 4, group='validation') - cfg.CONF.set_default('network_for_ssh', 'public', group='validation') - cfg.CONF.set_default('connect_timeout', 1, group='validation') - - self.conn = remote_client.RemoteClient('127.0.0.1', 'user', 'pass') - self.ssh_mock = self.useFixture(fixtures.MockPatchObject(self.conn, - 'ssh_client')) - - def test_write_to_console_regular_str(self): - self.conn.write_to_console('test') - self._assert_exec_called_with( - 'sudo sh -c "echo \\"test\\" >/dev/console"') - - def _test_write_to_console_helper(self, message, expected_call): - self.conn.write_to_console(message) - self._assert_exec_called_with(expected_call) - - def test_write_to_console_special_chars(self): - self._test_write_to_console_helper( - '\`', - 'sudo sh -c "echo \\"\\\\\\`\\" >/dev/console"') - self.conn.write_to_console('$') - self._assert_exec_called_with( - 'sudo sh -c "echo \\"\\\\$\\" >/dev/console"') - - # NOTE(maurosr): The tests below end up closer to an output format - # assurance than a test since it's basically using comand_exec to format - # the information using gnu/linux tools. - - def _assert_exec_called_with(self, cmd): - cmd = "set -eu -o pipefail; PATH=$PATH:/sbin; " + cmd - self.ssh_mock.mock.exec_command.assert_called_with(cmd) - - def test_get_disks(self): - output_lsblk = """\ -NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT -sda 8:0 0 128035676160 0 disk -sdb 8:16 0 1000204886016 0 disk -sr0 11:0 1 1073741312 0 rom""" - result = """\ -NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT -sda 8:0 0 128035676160 0 disk -sdb 8:16 0 1000204886016 0 disk""" - - self.ssh_mock.mock.exec_command.return_value = output_lsblk - self.assertEqual(self.conn.get_disks(), result) - self._assert_exec_called_with('lsblk -lb --nodeps') - - def test_get_boot_time(self): - booted_at = 10000 - uptime_sec = 5000.02 - self.ssh_mock.mock.exec_command.return_value = uptime_sec - self.useFixture(fixtures.MockPatchObject( - time, 'time', return_value=booted_at + uptime_sec)) - self.assertEqual(self.conn.get_boot_time(), - time.localtime(booted_at)) - self._assert_exec_called_with('cut -f1 -d. /proc/uptime') - - def test_ping_host(self): - ping_response = """PING localhost (127.0.0.1) 70(98) bytes of data. -78 bytes from localhost (127.0.0.1): icmp_req=1 ttl=64 time=0.048 ms -78 bytes from localhost (127.0.0.1): icmp_req=2 ttl=64 time=0.048 ms - ---- localhost ping statistics --- -2 packets transmitted, 2 received, 0% packet loss, time 0ms -rtt min/avg/max/mdev = 0.048/0.048/0.048/0.000 ms""" - self.ssh_mock.mock.exec_command.return_value = ping_response - self.assertEqual(self.conn.ping_host('127.0.0.1', count=2, size=70), - ping_response) - self._assert_exec_called_with('ping -c2 -w2 -s70 127.0.0.1') - - def test_get_mac_address(self): - macs = """0a:0b:0c:0d:0e:0f -a0:b0:c0:d0:e0:f0""" - self.ssh_mock.mock.exec_command.return_value = macs - - self.assertEqual(self.conn.get_mac_address(), macs) - self._assert_exec_called_with( - "ip addr | awk '/ether/ {print $2}'") - - -class TestRemoteClientWithServer(base.TestCase): - - server = SERVER - - def setUp(self): - super(TestRemoteClientWithServer, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - cfg.CONF.set_default('ip_version_for_ssh', 4, group='validation') - cfg.CONF.set_default('network_for_ssh', 'public', - group='validation') - cfg.CONF.set_default('connect_timeout', 1, group='validation') - cfg.CONF.set_default('console_output', True, - group='compute-feature-enabled') - - self.conn = remote_client.RemoteClient( - '127.0.0.1', 'user', 'pass', - server=self.server, servers_client=FakeServersClient()) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.ssh.Client._get_ssh_connection', - side_effect=lib_exc.SSHTimeout(host='127.0.0.1', - user='user', - password='pass'))) - self.log = self.useFixture(fixtures.FakeLogger( - name='tempest.lib.common.utils.linux.remote_client', - level='DEBUG')) - - def test_validate_debug_ssh_console(self): - self.assertRaises(lib_exc.SSHTimeout, - self.conn.validate_authentication) - msg = 'Caller: %s. Timeout trying to ssh to server %s' % ( - 'TestRemoteClientWithServer:test_validate_debug_ssh_console', - self.server) - self.assertIn(msg, self.log.output) - self.assertIn('Console output for', self.log.output) - - def test_exec_command_debug_ssh_console(self): - self.assertRaises(lib_exc.SSHTimeout, - self.conn.exec_command, 'fake command') - self.assertIn('fake command', self.log.output) - msg = 'Caller: %s. Timeout trying to ssh to server %s' % ( - 'TestRemoteClientWithServer:test_exec_command_debug_ssh_console', - self.server) - self.assertIn(msg, self.log.output) - self.assertIn('Console output for', self.log.output) - - -class TestRemoteClientWithBrokenServer(TestRemoteClientWithServer): - - server = BROKEN_SERVER - - def test_validate_debug_ssh_console(self): - self.assertRaises(lib_exc.SSHTimeout, - self.conn.validate_authentication) - msg = 'Caller: %s. Timeout trying to ssh to server %s' % ( - 'TestRemoteClientWithBrokenServer:test_validate_debug_ssh_console', - self.server) - self.assertIn(msg, self.log.output) - msg = 'Could not get console_log for server %s' % self.server['id'] - self.assertIn(msg, self.log.output) - - def test_exec_command_debug_ssh_console(self): - self.assertRaises(lib_exc.SSHTimeout, - self.conn.exec_command, 'fake command') - self.assertIn('fake command', self.log.output) - caller = ":".join(['TestRemoteClientWithBrokenServer', - 'test_exec_command_debug_ssh_console']) - msg = 'Caller: %s. Timeout trying to ssh to server %s' % ( - caller, self.server) - self.assertIn(msg, self.log.output) - msg = 'Could not get console_log for server %s' % self.server['id'] - self.assertIn(msg, self.log.output) diff --git a/tempest/tests/common/utils/test_net_utils.py b/tempest/tests/common/utils/test_net_utils.py deleted file mode 100644 index 83c6bcc08..000000000 --- a/tempest/tests/common/utils/test_net_utils.py +++ /dev/null @@ -1,33 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock - -from tempest.common.utils import net_utils -from tempest.lib import exceptions as lib_exc -from tempest.tests import base - - -class TestGetPingPayloadSize(base.TestCase): - - def test_ipv4(self): - self.assertEqual(1422, net_utils.get_ping_payload_size(1450, 4)) - - def test_ipv6(self): - self.assertEqual(1406, net_utils.get_ping_payload_size(1450, 6)) - - def test_too_low_mtu(self): - self.assertRaises( - lib_exc.BadRequest, net_utils.get_ping_payload_size, 10, 4) - - def test_None(self): - self.assertIsNone(net_utils.get_ping_payload_size(None, mock.Mock())) diff --git a/tempest/tests/fake_config.py b/tempest/tests/fake_config.py deleted file mode 100644 index ee6368441..000000000 --- a/tempest/tests/fake_config.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os - -from oslo_concurrency import lockutils -from oslo_config import cfg -from oslo_config import fixture as conf_fixture - -from tempest import config - - -class ConfigFixture(conf_fixture.Config): - - def __init__(self): - cfg.CONF([], default_config_files=[]) - config.register_opts() - super(ConfigFixture, self).__init__() - - def setUp(self): - super(ConfigFixture, self).setUp() - self.conf.set_default('build_interval', 10, group='compute') - self.conf.set_default('build_timeout', 10, group='compute') - self.conf.set_default('disable_ssl_certificate_validation', True, - group='identity') - self.conf.set_default('uri', 'http://fake_uri.com/auth', - group='identity') - self.conf.set_default('uri_v3', 'http://fake_uri_v3.com/auth', - group='identity') - self.conf.set_default('neutron', True, group='service_available') - self.conf.set_default('heat', True, group='service_available') - if not os.path.exists(str(os.environ.get('OS_TEST_LOCK_PATH'))): - os.mkdir(str(os.environ.get('OS_TEST_LOCK_PATH'))) - lockutils.set_defaults( - lock_path=str(os.environ.get('OS_TEST_LOCK_PATH')), - ) - self.conf.set_default('auth_version', 'v2', group='identity') - for config_option in ['username', 'password', 'project_name']: - # Identity group items - self.conf.set_default('admin_' + config_option, - 'fake_' + config_option, - group='auth') - - -class FakePrivate(config.TempestConfigPrivate): - def __init__(self, parse_conf=True, config_path=None): - self._set_attrs() - self.lock_path = cfg.CONF.oslo_concurrency.lock_path - -fake_service1_group = cfg.OptGroup(name='fake-service1', title='Fake service1') - -FakeService1Group = [ - cfg.StrOpt('catalog_type', default='fake-service1'), - cfg.StrOpt('endpoint_type', default='faketype'), - cfg.StrOpt('region', default='fake_region'), - cfg.IntOpt('build_timeout', default=99), - cfg.IntOpt('build_interval', default=9)] - -fake_service2_group = cfg.OptGroup(name='fake-service2', title='Fake service2') - -FakeService2Group = [ - cfg.StrOpt('catalog_type', default='fake-service2'), - cfg.StrOpt('endpoint_type', default='faketype')] - - -class ServiceClientsConfigFixture(conf_fixture.Config): - - def __init__(self): - cfg.CONF([], default_config_files=[]) - config._opts.append((fake_service1_group, FakeService1Group)) - config._opts.append((fake_service2_group, FakeService2Group)) - config.register_opts() - super(ServiceClientsConfigFixture, self).__init__() - - def setUp(self): - super(ServiceClientsConfigFixture, self).setUp() - # Debug default values - self.conf.set_default('trace_requests', 'fake_module', 'debug') - # Identity default values - self.conf.set_default('disable_ssl_certificate_validation', True, - group='identity') - self.conf.set_default('ca_certificates_file', '/fake/certificates', - group='identity') - self.conf.set_default('region', 'fake_region', 'identity') - # Compute default values - self.conf.set_default('build_interval', 88, group='compute') - self.conf.set_default('build_timeout', 8, group='compute') - - -class ServiceClientsFakePrivate(config.TempestConfigPrivate): - def __init__(self, parse_conf=True, config_path=None): - self._set_attrs() - self.fake_service1 = cfg.CONF['fake-service1'] - self.fake_service2 = cfg.CONF['fake-service2'] - self.lock_path = cfg.CONF.oslo_concurrency.lock_path diff --git a/tempest/tests/fake_tempest_plugin.py b/tempest/tests/fake_tempest_plugin.py deleted file mode 100644 index 56aae1e97..000000000 --- a/tempest/tests/fake_tempest_plugin.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (c) 2015 Deutsche Telekom AG -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.test_discover import plugins - - -class FakePlugin(plugins.TempestPlugin): - expected_load_test = ["my/test/path", "/home/dir"] - expected_service_clients = [{'foo': 'bar'}] - - def load_tests(self): - return self.expected_load_test - - def register_opts(self, conf): - return - - def get_opt_lists(self): - return [] - - def get_service_clients(self): - return self.expected_service_clients - - -class FakeStevedoreObj(object): - obj = FakePlugin() - - @property - def name(self): - return self._name - - def __init__(self, name='Test1'): - self._name = name - - -class FakePluginNoServiceClients(plugins.TempestPlugin): - - def load_tests(self): - return [] - - def register_opts(self, conf): - return - - def get_opt_lists(self): - return [] - - -class FakeStevedoreObjNoServiceClients(object): - obj = FakePluginNoServiceClients() - - @property - def name(self): - return self._name - - def __init__(self, name='Test2'): - self._name = name diff --git a/tempest/tests/files/__init__.py b/tempest/tests/files/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/files/failing-tests b/tempest/tests/files/failing-tests deleted file mode 100644 index 78efc9383..000000000 --- a/tempest/tests/files/failing-tests +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -class FakeTestClass(testtools.TestCase): - def test_pass(self): - self.assertTrue(False) - - def test_pass_list(self): - test_list = ['test', 'a', 'b'] - self.assertIn('fail', test_list) diff --git a/tempest/tests/files/passing-tests b/tempest/tests/files/passing-tests deleted file mode 100644 index a55cb1b5b..000000000 --- a/tempest/tests/files/passing-tests +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -class FakeTestClass(testtools.TestCase): - def test_pass(self): - self.assertTrue(True) - - def test_pass_list(self): - test_list = ['test', 'a', 'b'] - self.assertIn('test', test_list) diff --git a/tempest/tests/files/setup.cfg b/tempest/tests/files/setup.cfg deleted file mode 100644 index f6f9f7388..000000000 --- a/tempest/tests/files/setup.cfg +++ /dev/null @@ -1,20 +0,0 @@ -[metadata] -name = tempest_unit_tests -version = 1 -summary = Fake Project for testing wrapper scripts -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://www.openstack.org/ -classifier = - Intended Audience :: Information Technology - Intended Audience :: System Administrators - Intended Audience :: Developers - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - -[global] -setup-hooks = - pbr.hooks.setup_hook diff --git a/tempest/tests/files/testr-conf b/tempest/tests/files/testr-conf deleted file mode 100644 index d5ad08322..000000000 --- a/tempest/tests/files/testr-conf +++ /dev/null @@ -1,5 +0,0 @@ -[DEFAULT] -test_command=${PYTHON:-python} -m subunit.run discover -t ./ ./tests $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list -group_regex=([^\.]*\.)* diff --git a/tempest/tests/lib/__init__.py b/tempest/tests/lib/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/cli/__init__.py b/tempest/tests/lib/cli/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/cli/test_command_failed.py b/tempest/tests/lib/cli/test_command_failed.py deleted file mode 100644 index 388028a9d..000000000 --- a/tempest/tests/lib/cli/test_command_failed.py +++ /dev/null @@ -1,30 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib import exceptions -from tempest.tests import base - - -class TestOutputParser(base.TestCase): - - def test_command_failed_exception(self): - returncode = 1 - cmd = "foo" - stdout = "output" - stderr = "error" - try: - raise exceptions.CommandFailed(returncode, cmd, stdout, stderr) - except exceptions.CommandFailed as e: - self.assertIn(str(returncode), str(e)) - self.assertIn(cmd, str(e)) - self.assertIn(stdout, str(e)) - self.assertIn(stderr, str(e)) diff --git a/tempest/tests/lib/cli/test_execute.py b/tempest/tests/lib/cli/test_execute.py deleted file mode 100644 index 013045448..000000000 --- a/tempest/tests/lib/cli/test_execute.py +++ /dev/null @@ -1,93 +0,0 @@ -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import subprocess - -import mock - -from tempest.lib.cli import base as cli_base -from tempest.lib import exceptions -from tempest.tests import base - - -class TestExecute(base.TestCase): - - @mock.patch('subprocess.Popen', autospec=True) - def test_execute_success(self, mock_popen): - mock_popen.return_value.returncode = 0 - mock_popen.return_value.communicate.return_value = ( - "__init__.py", "") - result = cli_base.execute("/bin/ls", action="tempest", - flags="-l -a") - args, kwargs = mock_popen.call_args - # Check merge_stderr == False - self.assertEqual(subprocess.PIPE, kwargs['stderr']) - # Check action and flags are passed - args = args[0] - # We just tests that all pieces are passed through, we cannot make - # assumptions about the order - self.assertIn("/bin/ls", args) - self.assertIn("-l", args) - self.assertIn("-a", args) - self.assertIn("tempest", args) - # The result is mocked - checking that the mock was invoked correctly - self.assertIsInstance(result, str) - self.assertIn("__init__.py", result) - - @mock.patch('subprocess.Popen', autospec=True) - def test_execute_failure(self, mock_popen): - mock_popen.return_value.returncode = 1 - mock_popen.return_value.communicate.return_value = ( - "No such option --foobar", "") - result = cli_base.execute("/bin/ls", action="tempest.lib", - flags="--foobar", merge_stderr=True, - fail_ok=True) - args, kwargs = mock_popen.call_args - # Check the merge_stderr - self.assertEqual(subprocess.STDOUT, kwargs['stderr']) - # Check action and flags are passed - args = args[0] - # We just tests that all pieces are passed through, we cannot make - # assumptions about the order - self.assertIn("/bin/ls", args) - self.assertIn("--foobar", args) - self.assertIn("tempest.lib", args) - # The result is mocked - checking that the mock was invoked correctly - self.assertIsInstance(result, str) - self.assertIn("--foobar", result) - - @mock.patch('subprocess.Popen', autospec=True) - def test_execute_failure_raise_exception(self, mock_popen): - mock_popen.return_value.returncode = 1 - mock_popen.return_value.communicate.return_value = ( - "No such option --foobar", "") - self.assertRaises(exceptions.CommandFailed, cli_base.execute, - "/bin/ls", action="tempest", flags="--foobar", - merge_stderr=True) - - def test_execute_with_prefix(self): - result = cli_base.execute("env", action="", - prefix="env NEW_VAR=1") - self.assertIsInstance(result, str) - self.assertIn("NEW_VAR=1", result) - - -class TestCLIClient(base.TestCase): - - @mock.patch.object(cli_base, 'execute') - def test_execute_with_prefix(self, mock_execute): - cli = cli_base.CLIClient(prefix='env LAC_ALL=C') - cli.glance('action') - self.assertEqual(mock_execute.call_count, 1) - self.assertEqual(mock_execute.call_args[1], - {'prefix': 'env LAC_ALL=C'}) diff --git a/tempest/tests/lib/cli/test_output_parser.py b/tempest/tests/lib/cli/test_output_parser.py deleted file mode 100644 index d88dfc36d..000000000 --- a/tempest/tests/lib/cli/test_output_parser.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright 2014 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.lib.cli import output_parser -from tempest.lib import exceptions -from tempest.tests import base - - -class TestOutputParser(base.TestCase): - OUTPUT_LINES = """ -+----+------+---------+ -| ID | Name | Status | -+----+------+---------+ -| 11 | foo | BUILD | -| 21 | bar | ERROR | -| 31 | bee | None | -+----+------+---------+ -""" - OUTPUT_LINES2 = """ -+----+-------+---------+ -| ID | Name2 | Status2 | -+----+-------+---------+ -| 41 | aaa | SSSSS | -| 51 | bbb | TTTTT | -| 61 | ccc | AAAAA | -+----+-------+---------+ -""" - - EXPECTED_TABLE = {'headers': ['ID', 'Name', 'Status'], - 'values': [['11', 'foo', 'BUILD'], - ['21', 'bar', 'ERROR'], - ['31', 'bee', 'None']]} - EXPECTED_TABLE2 = {'headers': ['ID', 'Name2', 'Status2'], - 'values': [['41', 'aaa', 'SSSSS'], - ['51', 'bbb', 'TTTTT'], - ['61', 'ccc', 'AAAAA']]} - - def test_table_with_normal_values(self): - actual = output_parser.table(self.OUTPUT_LINES) - self.assertIsInstance(actual, dict) - self.assertEqual(self.EXPECTED_TABLE, actual) - - def test_table_with_list(self): - output_lines = self.OUTPUT_LINES.split('\n') - actual = output_parser.table(output_lines) - self.assertIsInstance(actual, dict) - self.assertEqual(self.EXPECTED_TABLE, actual) - - def test_table_with_invalid_line(self): - output_lines = self.OUTPUT_LINES + "aaaa" - actual = output_parser.table(output_lines) - self.assertIsInstance(actual, dict) - self.assertEqual(self.EXPECTED_TABLE, actual) - - def test_tables_with_normal_values(self): - output_lines = ('test' + self.OUTPUT_LINES + - 'test2' + self.OUTPUT_LINES2) - expected = [{'headers': self.EXPECTED_TABLE['headers'], - 'label': 'test', - 'values': self.EXPECTED_TABLE['values']}, - {'headers': self.EXPECTED_TABLE2['headers'], - 'label': 'test2', - 'values': self.EXPECTED_TABLE2['values']}] - actual = output_parser.tables(output_lines) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) - - def test_tables_with_invalid_values(self): - output_lines = ('test' + self.OUTPUT_LINES + - 'test2' + self.OUTPUT_LINES2 + '\n') - expected = [{'headers': self.EXPECTED_TABLE['headers'], - 'label': 'test', - 'values': self.EXPECTED_TABLE['values']}, - {'headers': self.EXPECTED_TABLE2['headers'], - 'label': 'test2', - 'values': self.EXPECTED_TABLE2['values']}] - actual = output_parser.tables(output_lines) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) - - def test_tables_with_invalid_line(self): - output_lines = ('test' + self.OUTPUT_LINES + - 'test2' + self.OUTPUT_LINES2 + - '+----+-------+---------+') - expected = [{'headers': self.EXPECTED_TABLE['headers'], - 'label': 'test', - 'values': self.EXPECTED_TABLE['values']}, - {'headers': self.EXPECTED_TABLE2['headers'], - 'label': 'test2', - 'values': self.EXPECTED_TABLE2['values']}] - - actual = output_parser.tables(output_lines) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) - - LISTING_OUTPUT = """ -+----+ -| ID | -+----+ -| 11 | -| 21 | -| 31 | -+----+ -""" - - def test_listing(self): - expected = [{'ID': '11'}, {'ID': '21'}, {'ID': '31'}] - actual = output_parser.listing(self.LISTING_OUTPUT) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) - - def test_details_multiple_with_invalid_line(self): - self.assertRaises(exceptions.InvalidStructure, - output_parser.details_multiple, - self.OUTPUT_LINES) - - DETAILS_LINES1 = """First Table -+----------+--------+ -| Property | Value | -+----------+--------+ -| foo | BUILD | -| bar | ERROR | -| bee | None | -+----------+--------+ -""" - DETAILS_LINES2 = """Second Table -+----------+--------+ -| Property | Value | -+----------+--------+ -| aaa | VVVVV | -| bbb | WWWWW | -| ccc | XXXXX | -+----------+--------+ -""" - - def test_details_with_normal_line_label_false(self): - expected = {'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'} - actual = output_parser.details(self.DETAILS_LINES1) - self.assertEqual(expected, actual) - - def test_details_with_normal_line_label_true(self): - expected = {'__label': 'First Table', - 'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'} - actual = output_parser.details(self.DETAILS_LINES1, with_label=True) - self.assertEqual(expected, actual) - - def test_details_multiple_with_normal_line_label_false(self): - expected = [{'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'}, - {'aaa': 'VVVVV', 'bbb': 'WWWWW', 'ccc': 'XXXXX'}] - actual = output_parser.details_multiple(self.DETAILS_LINES1 + - self.DETAILS_LINES2) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) - - def test_details_multiple_with_normal_line_label_true(self): - expected = [{'__label': 'First Table', - 'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'}, - {'__label': 'Second Table', - 'aaa': 'VVVVV', 'bbb': 'WWWWW', 'ccc': 'XXXXX'}] - actual = output_parser.details_multiple(self.DETAILS_LINES1 + - self.DETAILS_LINES2, - with_label=True) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) diff --git a/tempest/tests/lib/common/__init__.py b/tempest/tests/lib/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/common/test_api_version_request.py b/tempest/tests/lib/common/test_api_version_request.py deleted file mode 100644 index 58e7040bb..000000000 --- a/tempest/tests/lib/common/test_api_version_request.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.common import api_version_request -from tempest.lib import exceptions -from tempest.tests import base - - -class APIVersionRequestTests(base.TestCase): - def test_valid_version_strings(self): - def _test_string(version, exp_major, exp_minor): - v = api_version_request.APIVersionRequest(version) - self.assertEqual(v.ver_major, exp_major) - self.assertEqual(v.ver_minor, exp_minor) - - _test_string("1.1", 1, 1) - _test_string("2.10", 2, 10) - _test_string("5.234", 5, 234) - _test_string("12.5", 12, 5) - _test_string("2.0", 2, 0) - _test_string("2.200", 2, 200) - - def test_null_version(self): - v = api_version_request.APIVersionRequest() - self.assertTrue(v.is_null()) - - def test_invalid_version_strings(self): - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "2") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "200") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "2.1.4") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "200.23.66.3") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "5 .3") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "5. 3") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "5.03") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "02.1") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "2.001") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, " 2.1") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "2.1 ") - - def test_version_comparisons(self): - vers2_0 = api_version_request.APIVersionRequest("2.0") - vers2_5 = api_version_request.APIVersionRequest("2.5") - vers5_23 = api_version_request.APIVersionRequest("5.23") - v_null = api_version_request.APIVersionRequest() - v_latest = api_version_request.APIVersionRequest('latest') - - self.assertTrue(v_null < vers2_5) - self.assertTrue(vers2_0 < vers2_5) - self.assertTrue(vers2_0 <= vers2_5) - self.assertTrue(vers2_0 <= vers2_0) - self.assertTrue(vers2_5 > v_null) - self.assertTrue(vers5_23 > vers2_5) - self.assertTrue(vers2_0 >= vers2_0) - self.assertTrue(vers5_23 >= vers2_5) - self.assertTrue(vers2_0 != vers2_5) - self.assertTrue(vers2_0 == vers2_0) - self.assertTrue(vers2_0 != v_null) - self.assertTrue(v_null == v_null) - self.assertTrue(vers2_0 <= v_latest) - self.assertTrue(vers2_0 != v_latest) - self.assertTrue(v_latest == v_latest) - self.assertRaises(TypeError, vers2_0.__lt__, "2.1") - - def test_version_matches(self): - vers2_0 = api_version_request.APIVersionRequest("2.0") - vers2_5 = api_version_request.APIVersionRequest("2.5") - vers2_45 = api_version_request.APIVersionRequest("2.45") - vers3_3 = api_version_request.APIVersionRequest("3.3") - vers3_23 = api_version_request.APIVersionRequest("3.23") - vers4_0 = api_version_request.APIVersionRequest("4.0") - v_null = api_version_request.APIVersionRequest() - v_latest = api_version_request.APIVersionRequest('latest') - - def _check_version_matches(version, version1, version2, check=True): - if check: - msg = "Version %s does not matches with [%s - %s] range" - self.assertTrue(version.matches(version1, version2), - msg % (version.get_string(), - version1.get_string(), - version2.get_string())) - else: - msg = "Version %s matches with [%s - %s] range" - self.assertFalse(version.matches(version1, version2), - msg % (version.get_string(), - version1.get_string(), - version2.get_string())) - - _check_version_matches(vers2_5, vers2_0, vers2_45) - _check_version_matches(vers2_5, vers2_0, v_null) - _check_version_matches(vers2_0, vers2_0, vers2_5) - _check_version_matches(vers3_3, vers2_5, vers3_3) - _check_version_matches(vers3_3, v_null, vers3_3) - _check_version_matches(vers3_3, v_null, vers4_0) - _check_version_matches(vers2_0, vers2_5, vers2_45, False) - _check_version_matches(vers3_23, vers2_5, vers3_3, False) - _check_version_matches(vers2_5, vers2_45, vers2_0, False) - _check_version_matches(vers2_5, vers2_0, v_latest) - _check_version_matches(v_latest, v_latest, v_latest) - _check_version_matches(vers2_5, v_latest, v_latest, False) - _check_version_matches(v_latest, vers2_0, vers4_0, False) - - self.assertRaises(ValueError, v_null.matches, vers2_0, vers2_45) - - def test_get_string(self): - vers_string = ["3.23", "latest"] - for ver in vers_string: - ver_obj = api_version_request.APIVersionRequest(ver) - self.assertEqual(ver, ver_obj.get_string()) - - self.assertIsNotNone( - api_version_request.APIVersionRequest().get_string) diff --git a/tempest/tests/lib/common/test_api_version_utils.py b/tempest/tests/lib/common/test_api_version_utils.py deleted file mode 100644 index 6206379d3..000000000 --- a/tempest/tests/lib/common/test_api_version_utils.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.lib.common import api_version_utils -from tempest.lib import exceptions -from tempest.tests import base - - -class TestVersionSkipLogic(base.TestCase): - - def _test_version(self, test_min_version, test_max_version, - cfg_min_version, cfg_max_version, expected_skip=False): - try: - api_version_utils.check_skip_with_microversion(test_min_version, - test_max_version, - cfg_min_version, - cfg_max_version) - except testtools.TestCase.skipException as e: - if not expected_skip: - raise testtools.TestCase.failureException(e.message) - - def test_version_min_in_range(self): - self._test_version('2.2', '2.10', '2.1', '2.7') - - def test_version_max_in_range(self): - self._test_version('2.1', '2.3', '2.2', '2.7') - - def test_version_cfg_in_range(self): - self._test_version('2.2', '2.9', '2.3', '2.7') - - def test_version_equal(self): - self._test_version('2.2', '2.2', '2.2', '2.2') - - def test_version_below_cfg_min(self): - self._test_version('2.2', '2.4', '2.5', '2.7', expected_skip=True) - - def test_version_above_cfg_max(self): - self._test_version('2.8', '2.9', '2.3', '2.7', expected_skip=True) - - def test_version_min_greater_than_max(self): - self.assertRaises(exceptions.InvalidAPIVersionRange, - self._test_version, '2.8', '2.7', '2.3', '2.7') - - def test_cfg_version_min_greater_than_max(self): - self.assertRaises(exceptions.InvalidAPIVersionRange, - self._test_version, '2.2', '2.7', '2.9', '2.7') - - -class TestSelectRequestMicroversion(base.TestCase): - - def _test_request_version(self, test_min_version, - cfg_min_version, expected_version): - selected_version = api_version_utils.select_request_microversion( - test_min_version, cfg_min_version) - self.assertEqual(expected_version, selected_version) - - def test_cfg_min_version_greater(self): - self._test_request_version('2.1', '2.3', expected_version='2.3') - - def test_class_min_version_greater(self): - self._test_request_version('2.5', '2.3', expected_version='2.5') - - def test_cfg_min_version_none(self): - self._test_request_version('2.5', None, expected_version='2.5') - - def test_class_min_version_none(self): - self._test_request_version(None, '2.3', expected_version='2.3') - - def test_both_min_version_none(self): - self._test_request_version(None, None, expected_version=None) - - def test_both_min_version_equal(self): - self._test_request_version('2.3', '2.3', expected_version='2.3') - - -class TestMicroversionHeaderMatches(base.TestCase): - - def test_header_matches(self): - microversion_header_name = 'x-openstack-xyz-api-version' - request_microversion = '2.1' - test_respose = {microversion_header_name: request_microversion} - api_version_utils.assert_version_header_matches_request( - microversion_header_name, request_microversion, test_respose) - - def test_header_does_not_match(self): - microversion_header_name = 'x-openstack-xyz-api-version' - request_microversion = '2.1' - test_respose = {microversion_header_name: '2.2'} - self.assertRaises( - exceptions.InvalidHTTPResponseHeader, - api_version_utils.assert_version_header_matches_request, - microversion_header_name, request_microversion, test_respose) - - def test_header_not_present(self): - microversion_header_name = 'x-openstack-xyz-api-version' - request_microversion = '2.1' - test_respose = {} - self.assertRaises( - exceptions.InvalidHTTPResponseHeader, - api_version_utils.assert_version_header_matches_request, - microversion_header_name, request_microversion, test_respose) diff --git a/tempest/tests/lib/common/test_cred_client.py b/tempest/tests/lib/common/test_cred_client.py deleted file mode 100644 index 3dff16fba..000000000 --- a/tempest/tests/lib/common/test_cred_client.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2016 Hewlett Packard Enterprise Development LP -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock - -from tempest.lib.common import cred_client -from tempest.tests import base - - -class TestCredClientV2(base.TestCase): - def setUp(self): - super(TestCredClientV2, self).setUp() - self.identity_client = mock.MagicMock() - self.projects_client = mock.MagicMock() - self.users_client = mock.MagicMock() - self.roles_client = mock.MagicMock() - self.creds_client = cred_client.V2CredsClient(self.identity_client, - self.projects_client, - self.users_client, - self.roles_client) - - def test_create_project(self): - self.projects_client.create_tenant.return_value = { - 'tenant': 'a_tenant' - } - res = self.creds_client.create_project('fake_name', 'desc') - self.assertEqual('a_tenant', res) - self.projects_client.create_tenant.assert_called_once_with( - name='fake_name', description='desc') - - def test_delete_project(self): - self.creds_client.delete_project('fake_id') - self.projects_client.delete_tenant.assert_called_once_with( - 'fake_id') - - -class TestCredClientV3(base.TestCase): - def setUp(self): - super(TestCredClientV3, self).setUp() - self.identity_client = mock.MagicMock() - self.projects_client = mock.MagicMock() - self.users_client = mock.MagicMock() - self.roles_client = mock.MagicMock() - self.domains_client = mock.MagicMock() - self.domains_client.list_domains.return_value = { - 'domains': [{'id': 'fake_domain_id'}] - } - self.creds_client = cred_client.V3CredsClient(self.identity_client, - self.projects_client, - self.users_client, - self.roles_client, - self.domains_client, - 'fake_domain') - - def test_create_project(self): - self.projects_client.create_project.return_value = { - 'project': 'a_tenant' - } - res = self.creds_client.create_project('fake_name', 'desc') - self.assertEqual('a_tenant', res) - self.projects_client.create_project.assert_called_once_with( - name='fake_name', description='desc', domain_id='fake_domain_id') - - def test_delete_project(self): - self.creds_client.delete_project('fake_id') - self.projects_client.delete_project.assert_called_once_with( - 'fake_id') diff --git a/tempest/tests/lib/common/test_dynamic_creds.py b/tempest/tests/lib/common/test_dynamic_creds.py deleted file mode 100644 index 6aa7a4270..000000000 --- a/tempest/tests/lib/common/test_dynamic_creds.py +++ /dev/null @@ -1,667 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures -import mock -from oslo_config import cfg - -from tempest.common import credentials_factory as credentials -from tempest import config -from tempest.lib.common import dynamic_creds -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.identity.v2 import identity_client as v2_iden_client -from tempest.lib.services.identity.v2 import roles_client as v2_roles_client -from tempest.lib.services.identity.v2 import tenants_client as \ - v2_tenants_client -from tempest.lib.services.identity.v2 import token_client as v2_token_client -from tempest.lib.services.identity.v2 import users_client as v2_users_client -from tempest.lib.services.identity.v3 import domains_client -from tempest.lib.services.identity.v3 import identity_client as v3_iden_client -from tempest.lib.services.identity.v3 import projects_client as \ - v3_projects_client -from tempest.lib.services.identity.v3 import roles_client as v3_roles_client -from tempest.lib.services.identity.v3 import token_client as v3_token_client -from tempest.lib.services.identity.v3 import users_client as \ - v3_users_client -from tempest.lib.services.network import routers_client -from tempest.tests import base -from tempest.tests import fake_config -from tempest.tests.lib import fake_http -from tempest.tests.lib import fake_identity - - -class TestDynamicCredentialProvider(base.TestCase): - - fixed_params = {'name': 'test class', - 'identity_version': 'v2', - 'admin_role': 'admin', - 'identity_uri': 'fake_uri'} - - token_client = v2_token_client - iden_client = v2_iden_client - roles_client = v2_roles_client - tenants_client = v2_tenants_client - users_client = v2_users_client - token_client_class = token_client.TokenClient - fake_response = fake_identity._fake_v2_response - tenants_client_class = tenants_client.TenantsClient - delete_tenant = 'delete_tenant' - - def setUp(self): - super(TestDynamicCredentialProvider, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - self.patchobject(self.token_client_class, 'raw_request', - self.fake_response) - cfg.CONF.set_default('operator_role', 'FakeRole', - group='object-storage') - self._mock_list_ec2_credentials('fake_user_id', 'fake_tenant_id') - self.fixed_params.update( - admin_creds=self._get_fake_admin_creds()) - - def test_tempest_client(self): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self.assertIsInstance(creds.identity_admin_client, - self.iden_client.IdentityClient) - - def _get_fake_admin_creds(self): - return credentials.get_credentials( - fill_in=False, - identity_version=self.fixed_params['identity_version'], - username='fake_username', password='fake_password', - tenant_name='fake_tenant') - - def _mock_user_create(self, id, name): - user_fix = self.useFixture(fixtures.MockPatchObject( - self.users_client.UsersClient, - 'create_user', - return_value=(rest_client.ResponseBody - (200, {'user': {'id': id, 'name': name}})))) - return user_fix - - def _mock_tenant_create(self, id, name): - tenant_fix = self.useFixture(fixtures.MockPatchObject( - self.tenants_client.TenantsClient, - 'create_tenant', - return_value=(rest_client.ResponseBody - (200, {'tenant': {'id': id, 'name': name}})))) - return tenant_fix - - def _mock_list_roles(self, id, name): - roles_fix = self.useFixture(fixtures.MockPatchObject( - self.roles_client.RolesClient, - 'list_roles', - return_value=(rest_client.ResponseBody - (200, - {'roles': [{'id': id, 'name': name}, - {'id': '1', 'name': 'FakeRole'}, - {'id': '2', 'name': 'Member'}]})))) - return roles_fix - - def _mock_list_2_roles(self): - roles_fix = self.useFixture(fixtures.MockPatchObject( - self.roles_client.RolesClient, - 'list_roles', - return_value=(rest_client.ResponseBody - (200, - {'roles': [{'id': '1234', 'name': 'role1'}, - {'id': '1', 'name': 'FakeRole'}, - {'id': '12345', 'name': 'role2'}]})))) - return roles_fix - - def _mock_assign_user_role(self): - tenant_fix = self.useFixture(fixtures.MockPatchObject( - self.roles_client.RolesClient, - 'create_user_role_on_project', - return_value=(rest_client.ResponseBody - (200, {})))) - return tenant_fix - - def _mock_list_role(self): - roles_fix = self.useFixture(fixtures.MockPatchObject( - self.roles_client.RolesClient, - 'list_roles', - return_value=(rest_client.ResponseBody - (200, {'roles': [ - {'id': '1', 'name': 'FakeRole'}, - {'id': '2', 'name': 'Member'}]})))) - return roles_fix - - def _mock_list_ec2_credentials(self, user_id, tenant_id): - ec2_creds_fix = self.useFixture(fixtures.MockPatchObject( - self.users_client.UsersClient, - 'list_user_ec2_credentials', - return_value=(rest_client.ResponseBody - (200, {'credentials': [{ - 'access': 'fake_access', - 'secret': 'fake_secret', - 'tenant_id': tenant_id, - 'user_id': user_id, - 'trust_id': None}]})))) - return ec2_creds_fix - - def _mock_network_create(self, iso_creds, id, name): - net_fix = self.useFixture(fixtures.MockPatchObject( - iso_creds.networks_admin_client, - 'create_network', - return_value={'network': {'id': id, 'name': name}})) - return net_fix - - def _mock_subnet_create(self, iso_creds, id, name): - subnet_fix = self.useFixture(fixtures.MockPatchObject( - iso_creds.subnets_admin_client, - 'create_subnet', - return_value={'subnet': {'id': id, 'name': name}})) - return subnet_fix - - def _mock_router_create(self, id, name): - router_fix = self.useFixture(fixtures.MockPatchObject( - routers_client.RoutersClient, - 'create_router', - return_value={'router': {'id': id, 'name': name}})) - return router_fix - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_primary_creds(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_tenant_create('1234', 'fake_prim_tenant') - self._mock_user_create('1234', 'fake_prim_user') - primary_creds = creds.get_primary_creds() - self.assertEqual(primary_creds.username, 'fake_prim_user') - self.assertEqual(primary_creds.tenant_name, 'fake_prim_tenant') - # Verify IDs - self.assertEqual(primary_creds.tenant_id, '1234') - self.assertEqual(primary_creds.user_id, '1234') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_admin_creds(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self._mock_list_roles('1234', 'admin') - self._mock_user_create('1234', 'fake_admin_user') - self._mock_tenant_create('1234', 'fake_admin_tenant') - - user_mock = mock.patch.object(self.roles_client.RolesClient, - 'create_user_role_on_project') - user_mock.start() - self.addCleanup(user_mock.stop) - with mock.patch.object(self.roles_client.RolesClient, - 'create_user_role_on_project') as user_mock: - admin_creds = creds.get_admin_creds() - user_mock.assert_has_calls([ - mock.call('1234', '1234', '1234')]) - self.assertEqual(admin_creds.username, 'fake_admin_user') - self.assertEqual(admin_creds.tenant_name, 'fake_admin_tenant') - # Verify IDs - self.assertEqual(admin_creds.tenant_id, '1234') - self.assertEqual(admin_creds.user_id, '1234') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_role_creds(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self._mock_list_2_roles() - self._mock_user_create('1234', 'fake_role_user') - self._mock_tenant_create('1234', 'fake_role_tenant') - - user_mock = mock.patch.object(self.roles_client.RolesClient, - 'create_user_role_on_project') - user_mock.start() - self.addCleanup(user_mock.stop) - with mock.patch.object(self.roles_client.RolesClient, - 'create_user_role_on_project') as user_mock: - role_creds = creds.get_creds_by_roles( - roles=['role1', 'role2']) - calls = user_mock.mock_calls - # Assert that the role creation is called with the 2 specified roles - self.assertEqual(len(calls), 2) - args = map(lambda x: x[1], calls) - args = list(args) - self.assertIn(('1234', '1234', '1234'), args) - self.assertIn(('1234', '1234', '12345'), args) - self.assertEqual(role_creds.username, 'fake_role_user') - self.assertEqual(role_creds.tenant_name, 'fake_role_tenant') - # Verify IDs - self.assertEqual(role_creds.tenant_id, '1234') - self.assertEqual(role_creds.user_id, '1234') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_all_cred_cleanup(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_tenant_create('1234', 'fake_prim_tenant') - self._mock_user_create('1234', 'fake_prim_user') - creds.get_primary_creds() - self._mock_tenant_create('12345', 'fake_alt_tenant') - self._mock_user_create('12345', 'fake_alt_user') - creds.get_alt_creds() - self._mock_tenant_create('123456', 'fake_admin_tenant') - self._mock_user_create('123456', 'fake_admin_user') - self._mock_list_roles('123456', 'admin') - creds.get_admin_creds() - user_mock = self.patchobject(self.users_client.UsersClient, - 'delete_user') - tenant_mock = self.patchobject(self.tenants_client_class, - self.delete_tenant) - creds.clear_creds() - # Verify user delete calls - calls = user_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('1234', args) - self.assertIn('12345', args) - self.assertIn('123456', args) - # Verify tenant delete calls - calls = tenant_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('1234', args) - self.assertIn('12345', args) - self.assertIn('123456', args) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_alt_creds(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_alt_user') - self._mock_tenant_create('1234', 'fake_alt_tenant') - alt_creds = creds.get_alt_creds() - self.assertEqual(alt_creds.username, 'fake_alt_user') - self.assertEqual(alt_creds.tenant_name, 'fake_alt_tenant') - # Verify IDs - self.assertEqual(alt_creds.tenant_id, '1234') - self.assertEqual(alt_creds.user_id, '1234') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_no_network_creation_with_config_set(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, create_networks=False, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - net = mock.patch.object(creds.networks_admin_client, - 'delete_network') - net_mock = net.start() - subnet = mock.patch.object(creds.subnets_admin_client, - 'delete_subnet') - subnet_mock = subnet.start() - router = mock.patch.object(creds.routers_admin_client, - 'delete_router') - router_mock = router.start() - - primary_creds = creds.get_primary_creds() - self.assertEqual(net_mock.mock_calls, []) - self.assertEqual(subnet_mock.mock_calls, []) - self.assertEqual(router_mock.mock_calls, []) - network = primary_creds.network - subnet = primary_creds.subnet - router = primary_creds.router - self.assertIsNone(network) - self.assertIsNone(subnet) - self.assertIsNone(router) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_network_creation(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - self._mock_network_create(creds, '1234', 'fake_net') - self._mock_subnet_create(creds, '1234', 'fake_subnet') - self._mock_router_create('1234', 'fake_router') - router_interface_mock = self.patch( - 'tempest.lib.services.network.routers_client.RoutersClient.' - 'add_router_interface') - primary_creds = creds.get_primary_creds() - router_interface_mock.assert_called_once_with('1234', subnet_id='1234') - network = primary_creds.network - subnet = primary_creds.subnet - router = primary_creds.router - self.assertEqual(network['id'], '1234') - self.assertEqual(network['name'], 'fake_net') - self.assertEqual(subnet['id'], '1234') - self.assertEqual(subnet['name'], 'fake_subnet') - self.assertEqual(router['id'], '1234') - self.assertEqual(router['name'], 'fake_router') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_network_cleanup(self, MockRestClient): - def side_effect(**args): - return {"security_groups": [{"tenant_id": args['tenant_id'], - "name": args['name'], - "description": args['name'], - "security_group_rules": [], - "id": "sg-%s" % args['tenant_id']}]} - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - **self.fixed_params) - # Create primary tenant and network - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - self._mock_network_create(creds, '1234', 'fake_net') - self._mock_subnet_create(creds, '1234', 'fake_subnet') - self._mock_router_create('1234', 'fake_router') - router_interface_mock = self.patch( - 'tempest.lib.services.network.routers_client.RoutersClient.' - 'add_router_interface') - creds.get_primary_creds() - router_interface_mock.assert_called_once_with('1234', subnet_id='1234') - router_interface_mock.reset_mock() - # Create alternate tenant and network - self._mock_user_create('12345', 'fake_alt_user') - self._mock_tenant_create('12345', 'fake_alt_tenant') - self._mock_network_create(creds, '12345', 'fake_alt_net') - self._mock_subnet_create(creds, '12345', 'fake_alt_subnet') - self._mock_router_create('12345', 'fake_alt_router') - creds.get_alt_creds() - router_interface_mock.assert_called_once_with('12345', - subnet_id='12345') - router_interface_mock.reset_mock() - # Create admin tenant and networks - self._mock_user_create('123456', 'fake_admin_user') - self._mock_tenant_create('123456', 'fake_admin_tenant') - self._mock_network_create(creds, '123456', 'fake_admin_net') - self._mock_subnet_create(creds, '123456', 'fake_admin_subnet') - self._mock_router_create('123456', 'fake_admin_router') - self._mock_list_roles('123456', 'admin') - creds.get_admin_creds() - self.patchobject(self.users_client.UsersClient, 'delete_user') - self.patchobject(self.tenants_client_class, self.delete_tenant) - net = mock.patch.object(creds.networks_admin_client, 'delete_network') - net_mock = net.start() - subnet = mock.patch.object(creds.subnets_admin_client, 'delete_subnet') - subnet_mock = subnet.start() - router = mock.patch.object(creds.routers_admin_client, 'delete_router') - router_mock = router.start() - remove_router_interface_mock = self.patch( - 'tempest.lib.services.network.routers_client.RoutersClient.' - 'remove_router_interface') - return_values = ({'status': 200}, {'ports': []}) - port_list_mock = mock.patch.object(creds.ports_admin_client, - 'list_ports', - return_value=return_values) - - port_list_mock.start() - secgroup_list_mock = mock.patch.object( - creds.security_groups_admin_client, - 'list_security_groups', - side_effect=side_effect) - secgroup_list_mock.start() - - return_values = fake_http.fake_http_response({}, status=204), '' - remove_secgroup_mock = self.patch( - 'tempest.lib.services.network.security_groups_client.' - 'SecurityGroupsClient.delete', return_value=return_values) - creds.clear_creds() - # Verify default security group delete - calls = remove_secgroup_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('v2.0/security-groups/sg-1234', args) - self.assertIn('v2.0/security-groups/sg-12345', args) - self.assertIn('v2.0/security-groups/sg-123456', args) - # Verify remove router interface calls - calls = remove_router_interface_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: (x[1][0], x[2]), calls) - args = list(args) - self.assertIn(('1234', {'subnet_id': '1234'}), args) - self.assertIn(('12345', {'subnet_id': '12345'}), args) - self.assertIn(('123456', {'subnet_id': '123456'}), args) - # Verify network delete calls - calls = net_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('1234', args) - self.assertIn('12345', args) - self.assertIn('123456', args) - # Verify subnet delete calls - calls = subnet_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('1234', args) - self.assertIn('12345', args) - self.assertIn('123456', args) - # Verify router delete calls - calls = router_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('1234', args) - self.assertIn('12345', args) - self.assertIn('123456', args) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_network_alt_creation(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_alt_user') - self._mock_tenant_create('1234', 'fake_alt_tenant') - self._mock_network_create(creds, '1234', 'fake_alt_net') - self._mock_subnet_create(creds, '1234', 'fake_alt_subnet') - self._mock_router_create('1234', 'fake_alt_router') - router_interface_mock = self.patch( - 'tempest.lib.services.network.routers_client.RoutersClient.' - 'add_router_interface') - alt_creds = creds.get_alt_creds() - router_interface_mock.assert_called_once_with('1234', subnet_id='1234') - network = alt_creds.network - subnet = alt_creds.subnet - router = alt_creds.router - self.assertEqual(network['id'], '1234') - self.assertEqual(network['name'], 'fake_alt_net') - self.assertEqual(subnet['id'], '1234') - self.assertEqual(subnet['name'], 'fake_alt_subnet') - self.assertEqual(router['id'], '1234') - self.assertEqual(router['name'], 'fake_alt_router') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_network_admin_creation(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_user_create('1234', 'fake_admin_user') - self._mock_tenant_create('1234', 'fake_admin_tenant') - self._mock_network_create(creds, '1234', 'fake_admin_net') - self._mock_subnet_create(creds, '1234', 'fake_admin_subnet') - self._mock_router_create('1234', 'fake_admin_router') - router_interface_mock = self.patch( - 'tempest.lib.services.network.routers_client.RoutersClient.' - 'add_router_interface') - self._mock_list_roles('123456', 'admin') - admin_creds = creds.get_admin_creds() - router_interface_mock.assert_called_once_with('1234', subnet_id='1234') - network = admin_creds.network - subnet = admin_creds.subnet - router = admin_creds.router - self.assertEqual(network['id'], '1234') - self.assertEqual(network['name'], 'fake_admin_net') - self.assertEqual(subnet['id'], '1234') - self.assertEqual(subnet['name'], 'fake_admin_subnet') - self.assertEqual(router['id'], '1234') - self.assertEqual(router['name'], 'fake_admin_router') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_no_network_resources(self, MockRestClient): - net_dict = { - 'network': False, - 'router': False, - 'subnet': False, - 'dhcp': False, - } - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - network_resources=net_dict, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - net = mock.patch.object(creds.networks_admin_client, - 'delete_network') - net_mock = net.start() - subnet = mock.patch.object(creds.subnets_admin_client, - 'delete_subnet') - subnet_mock = subnet.start() - router = mock.patch.object(creds.routers_admin_client, - 'delete_router') - router_mock = router.start() - - primary_creds = creds.get_primary_creds() - self.assertEqual(net_mock.mock_calls, []) - self.assertEqual(subnet_mock.mock_calls, []) - self.assertEqual(router_mock.mock_calls, []) - network = primary_creds.network - subnet = primary_creds.subnet - router = primary_creds.router - self.assertIsNone(network) - self.assertIsNone(subnet) - self.assertIsNone(router) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_router_without_network(self, MockRestClient): - net_dict = { - 'network': False, - 'router': True, - 'subnet': False, - 'dhcp': False, - } - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - network_resources=net_dict, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - self.assertRaises(lib_exc.InvalidConfiguration, - creds.get_primary_creds) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_subnet_without_network(self, MockRestClient): - net_dict = { - 'network': False, - 'router': False, - 'subnet': True, - 'dhcp': False, - } - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - network_resources=net_dict, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - self.assertRaises(lib_exc.InvalidConfiguration, - creds.get_primary_creds) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_dhcp_without_subnet(self, MockRestClient): - net_dict = { - 'network': False, - 'router': False, - 'subnet': False, - 'dhcp': True, - } - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - network_resources=net_dict, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - self.assertRaises(lib_exc.InvalidConfiguration, - creds.get_primary_creds) - - -class TestDynamicCredentialProviderV3(TestDynamicCredentialProvider): - - fixed_params = {'name': 'test class', - 'identity_version': 'v3', - 'admin_role': 'admin', - 'identity_uri': 'fake_uri'} - - token_client = v3_token_client - iden_client = v3_iden_client - roles_client = v3_roles_client - tenants_client = v3_projects_client - users_client = v3_users_client - token_client_class = token_client.V3TokenClient - fake_response = fake_identity._fake_v3_response - tenants_client_class = tenants_client.ProjectsClient - delete_tenant = 'delete_project' - - def setUp(self): - super(TestDynamicCredentialProviderV3, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.useFixture(fixtures.MockPatchObject( - domains_client.DomainsClient, 'list_domains', - return_value=dict(domains=[dict(id='default', - name='Default')]))) - self.patchobject(self.roles_client.RolesClient, - 'create_user_role_on_domain') - - def _mock_list_ec2_credentials(self, user_id, tenant_id): - pass - - def _mock_tenant_create(self, id, name): - project_fix = self.useFixture(fixtures.MockPatchObject( - self.tenants_client.ProjectsClient, - 'create_project', - return_value=(rest_client.ResponseBody - (200, {'project': {'id': id, 'name': name}})))) - return project_fix - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_member_role_creation_with_duplicate(self, rest_client_mock): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - creds.creds_client = mock.MagicMock() - creds.creds_client.create_user_role.side_effect = lib_exc.Conflict - with mock.patch('tempest.lib.common.dynamic_creds.LOG') as log_mock: - creds._create_creds() - log_mock.warning.assert_called_once_with( - "Member role already exists, ignoring conflict.") - creds.creds_client.assign_user_role.assert_called_once_with( - mock.ANY, mock.ANY, 'Member') diff --git a/tempest/tests/lib/common/test_jsonschema_validator.py b/tempest/tests/lib/common/test_jsonschema_validator.py deleted file mode 100644 index 8694f3d01..000000000 --- a/tempest/tests/lib/common/test_jsonschema_validator.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types -from tempest.lib.common import rest_client -from tempest.lib import exceptions -from tempest.tests import base -from tempest.tests.lib import fake_http - - -class TestJSONSchemaDateTimeFormat(base.TestCase): - date_time_schema = [ - { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'date-time': parameter_types.date_time - } - } - }, - { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'date-time': parameter_types.date_time_or_null - } - } - } - ] - - def test_valid_date_time_format(self): - valid_instances = ['2016-10-02T10:00:00-05:00', - '2016-10-02T10:00:00+09:00', - '2016-10-02T15:00:00Z', - '2016-10-02T15:00:00.05Z'] - resp = fake_http.fake_http_response('', status=200) - for instance in valid_instances: - body = {'date-time': instance} - for schema in self.date_time_schema: - rest_client.RestClient.validate_response(schema, resp, body) - - def test_invalid_date_time_format(self): - invalid_instances = ['2016-10-02 T10:00:00-05:00', - '2016-10-02T 15:00:00', - '2016-10-02T15:00:00.05 Z', - '2016-10-02:15:00:00.05Z', - 'T15:00:00.05Z', - '2016:10:02T15:00:00', - '2016-10-02T15-00-00', - '2016-10-02T15.05Z', - '09MAR2015 11:15', - '13 Oct 2015 05:55:36 GMT', - ''] - resp = fake_http.fake_http_response('', status=200) - for instance in invalid_instances: - body = {'date-time': instance} - for schema in self.date_time_schema: - self.assertRaises(exceptions.InvalidHTTPResponseBody, - rest_client.RestClient.validate_response, - schema, resp, body) - - def test_date_time_or_null_format(self): - instance = None - resp = fake_http.fake_http_response('', status=200) - body = {'date-time': instance} - rest_client.RestClient.validate_response(self.date_time_schema[1], - resp, body) - self.assertRaises(exceptions.InvalidHTTPResponseBody, - rest_client.RestClient.validate_response, - self.date_time_schema[0], resp, body) diff --git a/tempest/tests/lib/common/test_preprov_creds.py b/tempest/tests/lib/common/test_preprov_creds.py deleted file mode 100644 index 5402e470d..000000000 --- a/tempest/tests/lib/common/test_preprov_creds.py +++ /dev/null @@ -1,487 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import hashlib -import os -import shutil - -import mock -import six -import testtools - -import fixtures -from oslo_concurrency.fixture import lockutils as lockutils_fixtures -from oslo_config import cfg - -from tempest import config -from tempest.lib import auth -from tempest.lib.common import cred_provider -from tempest.lib.common import preprov_creds -from tempest.lib import exceptions as lib_exc -from tempest.tests import base -from tempest.tests import fake_config -from tempest.tests.lib import fake_identity - - -class TestPreProvisionedCredentials(base.TestCase): - - fixed_params = {'name': 'test class', - 'identity_version': 'v2', - 'identity_uri': 'fake_uri', - 'test_accounts_file': 'fake_accounts_file', - 'accounts_lock_dir': 'fake_locks_dir', - 'admin_role': 'admin', - 'object_storage_operator_role': 'operator', - 'object_storage_reseller_admin_role': 'reseller'} - - identity_response = fake_identity._fake_v2_response - token_client = ('tempest.lib.services.identity.v2.token_client' - '.TokenClient.raw_request') - - @classmethod - def _fake_accounts(cls, admin_role): - return [ - {'username': 'test_user1', 'tenant_name': 'test_tenant1', - 'password': 'p'}, - {'username': 'test_user2', 'project_name': 'test_tenant2', - 'password': 'p'}, - {'username': 'test_user3', 'tenant_name': 'test_tenant3', - 'password': 'p'}, - {'username': 'test_user4', 'project_name': 'test_tenant4', - 'password': 'p'}, - {'username': 'test_user5', 'tenant_name': 'test_tenant5', - 'password': 'p'}, - {'username': 'test_user6', 'project_name': 'test_tenant6', - 'password': 'p', 'roles': ['role1', 'role2']}, - {'username': 'test_user7', 'tenant_name': 'test_tenant7', - 'password': 'p', 'roles': ['role2', 'role3']}, - {'username': 'test_user8', 'project_name': 'test_tenant8', - 'password': 'p', 'roles': ['role4', 'role1']}, - {'username': 'test_user9', 'tenant_name': 'test_tenant9', - 'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_user10', 'project_name': 'test_tenant10', - 'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_admin1', 'tenant_name': 'test_tenant11', - 'password': 'p', 'roles': [admin_role]}, - {'username': 'test_admin2', 'project_name': 'test_tenant12', - 'password': 'p', 'roles': [admin_role]}, - {'username': 'test_admin3', 'project_name': 'test_tenant13', - 'password': 'p', 'types': ['admin']}] - - def setUp(self): - super(TestPreProvisionedCredentials, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - self.patch(self.token_client, side_effect=self.identity_response) - self.useFixture(lockutils_fixtures.ExternalLockFixture()) - self.test_accounts = self._fake_accounts(cfg.CONF.identity.admin_role) - self.accounts_mock = self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=self.test_accounts)) - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=True)) - # NOTE(andreaf) Ensure config is loaded so service clients are - # registered in the registry before tests - config.service_client_config() - - def tearDown(self): - super(TestPreProvisionedCredentials, self).tearDown() - shutil.rmtree(self.fixed_params['accounts_lock_dir'], - ignore_errors=True) - - def _get_hash_list(self, accounts_list): - hash_list = [] - hash_fields = ( - preprov_creds.PreProvisionedCredentialProvider.HASH_CRED_FIELDS) - for account in accounts_list: - hash = hashlib.md5() - account_for_hash = dict((k, v) for (k, v) in account.items() - if k in hash_fields) - hash.update(six.text_type(account_for_hash).encode('utf-8')) - temp_hash = hash.hexdigest() - hash_list.append(temp_hash) - return hash_list - - def test_get_hash(self): - # Test with all accounts to make sure we try all combinations - # and hide no race conditions - hash_index = 0 - for test_cred_dict in self.test_accounts: - test_account_class = ( - preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params)) - hash_list = self._get_hash_list(self.test_accounts) - test_creds = auth.get_credentials( - fake_identity.FAKE_AUTH_URL, - identity_version=self.fixed_params['identity_version'], - **test_cred_dict) - results = test_account_class.get_hash(test_creds) - self.assertEqual(hash_list[hash_index], results) - hash_index += 1 - - def test_get_hash_dict(self): - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - hash_dict = test_account_class.get_hash_dict( - self.test_accounts, self.fixed_params['admin_role']) - hash_list = self._get_hash_list(self.test_accounts) - for hash in hash_list: - self.assertIn(hash, hash_dict['creds'].keys()) - self.assertIn(hash_dict['creds'][hash], self.test_accounts) - - def test_create_hash_file_previous_file(self): - # Emulate the lock existing on the filesystem - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=True)) - with mock.patch('six.moves.builtins.open', mock.mock_open(), - create=True): - test_account_class = ( - preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params)) - res = test_account_class._create_hash_file('12345') - self.assertFalse(res, "_create_hash_file should return False if the " - "pseudo-lock file already exists") - - def test_create_hash_file_no_previous_file(self): - # Emulate the lock not existing on the filesystem - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=False)) - with mock.patch('six.moves.builtins.open', mock.mock_open(), - create=True): - test_account_class = ( - preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params)) - res = test_account_class._create_hash_file('12345') - self.assertTrue(res, "_create_hash_file should return True if the " - "pseudo-lock doesn't already exist") - - @mock.patch('oslo_concurrency.lockutils.lock') - def test_get_free_hash_no_previous_accounts(self, lock_mock): - # Emulate no pre-existing lock - self.useFixture(fixtures.MockPatch( - 'os.path.isdir', return_value=False)) - hash_list = self._get_hash_list(self.test_accounts) - mkdir_mock = self.useFixture(fixtures.MockPatch('os.mkdir')) - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=False)) - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with mock.patch('six.moves.builtins.open', mock.mock_open(), - create=True) as open_mock: - test_account_class._get_free_hash(hash_list) - lock_path = os.path.join(self.fixed_params['accounts_lock_dir'], - hash_list[0]) - open_mock.assert_called_once_with(lock_path, 'w') - mkdir_path = os.path.join(self.fixed_params['accounts_lock_dir']) - mkdir_mock.mock.assert_called_once_with(mkdir_path) - - @mock.patch('oslo_concurrency.lockutils.lock') - def test_get_free_hash_no_free_accounts(self, lock_mock): - hash_list = self._get_hash_list(self.test_accounts) - # Emulate pre-existing lock dir - self.useFixture(fixtures.MockPatch('os.path.isdir', return_value=True)) - # Emulate all locks in list are in use - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=True)) - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with mock.patch('six.moves.builtins.open', mock.mock_open(), - create=True): - self.assertRaises(lib_exc.InvalidCredentials, - test_account_class._get_free_hash, hash_list) - - @mock.patch('oslo_concurrency.lockutils.lock') - def test_get_free_hash_some_in_use_accounts(self, lock_mock): - # Emulate no pre-existing lock - self.useFixture(fixtures.MockPatch('os.path.isdir', return_value=True)) - hash_list = self._get_hash_list(self.test_accounts) - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - - def _fake_is_file(path): - # Fake isfile() to return that the path exists unless a specific - # hash is in the path - if hash_list[3] in path: - return False - return True - - self.patchobject(os.path, 'isfile', _fake_is_file) - with mock.patch('six.moves.builtins.open', mock.mock_open(), - create=True) as open_mock: - test_account_class._get_free_hash(hash_list) - lock_path = os.path.join(self.fixed_params['accounts_lock_dir'], - hash_list[3]) - open_mock.assert_has_calls([mock.call(lock_path, 'w')]) - - @mock.patch('oslo_concurrency.lockutils.lock') - def test_remove_hash_last_account(self, lock_mock): - hash_list = self._get_hash_list(self.test_accounts) - # Pretend the pseudo-lock is there - self.useFixture( - fixtures.MockPatch('os.path.isfile', return_value=True)) - # Pretend the lock dir is empty - self.useFixture(fixtures.MockPatch('os.listdir', return_value=[])) - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - remove_mock = self.useFixture(fixtures.MockPatch('os.remove')) - rmdir_mock = self.useFixture(fixtures.MockPatch('os.rmdir')) - test_account_class.remove_hash(hash_list[2]) - hash_path = os.path.join(self.fixed_params['accounts_lock_dir'], - hash_list[2]) - lock_path = self.fixed_params['accounts_lock_dir'] - remove_mock.mock.assert_called_once_with(hash_path) - rmdir_mock.mock.assert_called_once_with(lock_path) - - @mock.patch('oslo_concurrency.lockutils.lock') - def test_remove_hash_not_last_account(self, lock_mock): - hash_list = self._get_hash_list(self.test_accounts) - # Pretend the pseudo-lock is there - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=True)) - # Pretend the lock dir is empty - self.useFixture(fixtures.MockPatch('os.listdir', return_value=[ - hash_list[1], hash_list[4]])) - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - remove_mock = self.useFixture(fixtures.MockPatch('os.remove')) - rmdir_mock = self.useFixture(fixtures.MockPatch('os.rmdir')) - test_account_class.remove_hash(hash_list[2]) - hash_path = os.path.join(self.fixed_params['accounts_lock_dir'], - hash_list[2]) - remove_mock.mock.assert_called_once_with(hash_path) - rmdir_mock.mock.assert_not_called() - - def test_is_multi_user(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - self.assertTrue(test_accounts_class.is_multi_user()) - - def test_is_not_multi_user(self): - self.test_accounts = [self.test_accounts[0]] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=self.test_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - self.assertFalse(test_accounts_class.is_multi_user()) - - def test__get_creds_by_roles_one_role(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - hashes = test_accounts_class.hash_dict['roles']['role4'] - temp_hash = hashes[0] - get_free_hash_mock = self.useFixture(fixtures.MockPatchObject( - test_accounts_class, '_get_free_hash', return_value=temp_hash)) - # Test a single role returns all matching roles - test_accounts_class._get_creds(roles=['role4']) - calls = get_free_hash_mock.mock.mock_calls - self.assertEqual(len(calls), 1) - args = calls[0][1][0] - for i in hashes: - self.assertIn(i, args) - - def test__get_creds_by_roles_list_role(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - hashes = test_accounts_class.hash_dict['roles']['role4'] - hashes2 = test_accounts_class.hash_dict['roles']['role2'] - hashes = list(set(hashes) & set(hashes2)) - temp_hash = hashes[0] - get_free_hash_mock = self.useFixture(fixtures.MockPatchObject( - test_accounts_class, '_get_free_hash', return_value=temp_hash)) - # Test an intersection of multiple roles - test_accounts_class._get_creds(roles=['role2', 'role4']) - calls = get_free_hash_mock.mock.mock_calls - self.assertEqual(len(calls), 1) - args = calls[0][1][0] - for i in hashes: - self.assertIn(i, args) - - def test__get_creds_by_roles_no_admin(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - hashes = list(test_accounts_class.hash_dict['creds'].keys()) - admin_hashes = test_accounts_class.hash_dict['roles'][ - cfg.CONF.identity.admin_role] - temp_hash = hashes[0] - get_free_hash_mock = self.useFixture(fixtures.MockPatchObject( - test_accounts_class, '_get_free_hash', return_value=temp_hash)) - # Test an intersection of multiple roles - test_accounts_class._get_creds() - calls = get_free_hash_mock.mock.mock_calls - self.assertEqual(len(calls), 1) - args = calls[0][1][0] - self.assertEqual(len(args), 10) - for i in admin_hashes: - self.assertNotIn(i, args) - - def test_networks_returned_with_creds(self): - test_accounts = [ - {'username': 'test_user13', 'tenant_name': 'test_tenant13', - 'password': 'p', 'resources': {'network': 'network-1'}}, - {'username': 'test_user14', 'tenant_name': 'test_tenant14', - 'password': 'p', 'roles': ['role-7', 'role-11'], - 'resources': {'network': 'network-2'}}] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=test_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with mock.patch('tempest.lib.services.compute.networks_client.' - 'NetworksClient.list_networks', - return_value={'networks': [{'name': 'network-2', - 'id': 'fake-id', - 'label': 'network-2'}]}): - creds = test_accounts_class.get_creds_by_roles(['role-7']) - self.assertIsInstance(creds, cred_provider.TestResources) - network = creds.network - self.assertIsNotNone(network) - self.assertIn('name', network) - self.assertIn('id', network) - self.assertEqual('fake-id', network['id']) - self.assertEqual('network-2', network['name']) - - def test_get_primary_creds(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - primary_creds = test_accounts_class.get_primary_creds() - self.assertNotIn('test_admin', primary_creds.username) - - def test_get_primary_creds_none_available(self): - admin_accounts = [x for x in self.test_accounts if 'test_admin' - in x['username']] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=admin_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with testtools.ExpectedException(lib_exc.InvalidCredentials): - # Get one more - test_accounts_class.get_primary_creds() - - def test_get_alt_creds(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - alt_creds = test_accounts_class.get_alt_creds() - self.assertNotIn('test_admin', alt_creds.username) - - def test_get_alt_creds_none_available(self): - admin_accounts = [x for x in self.test_accounts if 'test_admin' - in x['username']] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=admin_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with testtools.ExpectedException(lib_exc.InvalidCredentials): - # Get one more - test_accounts_class.get_alt_creds() - - def test_get_admin_creds(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - admin_creds = test_accounts_class.get_admin_creds() - self.assertIn('test_admin', admin_creds.username) - - def test_get_admin_creds_by_type(self): - test_accounts = [ - {'username': 'test_user10', 'project_name': 'test_tenant10', - 'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_admin1', 'tenant_name': 'test_tenant11', - 'password': 'p', 'types': ['admin']}] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=test_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - admin_creds = test_accounts_class.get_admin_creds() - self.assertIn('test_admin', admin_creds.username) - - def test_get_admin_creds_by_role(self): - test_accounts = [ - {'username': 'test_user10', 'project_name': 'test_tenant10', - 'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_admin1', 'tenant_name': 'test_tenant11', - 'password': 'p', 'roles': [cfg.CONF.identity.admin_role]}] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=test_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - admin_creds = test_accounts_class.get_admin_creds() - self.assertIn('test_admin', admin_creds.username) - - def test_get_admin_creds_none_available(self): - non_admin_accounts = [x for x in self.test_accounts if 'test_admin' - not in x['username']] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=non_admin_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with testtools.ExpectedException(lib_exc.InvalidCredentials): - # Get one more - test_accounts_class.get_admin_creds() - - -class TestPreProvisionedCredentialsV3(TestPreProvisionedCredentials): - - fixed_params = {'name': 'test class', - 'identity_version': 'v3', - 'identity_uri': 'fake_uri', - 'test_accounts_file': 'fake_accounts_file', - 'accounts_lock_dir': 'fake_locks_dir_v3', - 'admin_role': 'admin', - 'object_storage_operator_role': 'operator', - 'object_storage_reseller_admin_role': 'reseller'} - - identity_response = fake_identity._fake_v3_response - token_client = ('tempest.lib.services.identity.v3.token_client' - '.V3TokenClient.raw_request') - - @classmethod - def _fake_accounts(cls, admin_role): - return [ - {'username': 'test_user1', 'project_name': 'test_project1', - 'domain_name': 'domain', 'password': 'p'}, - {'username': 'test_user2', 'project_name': 'test_project2', - 'domain_name': 'domain', 'password': 'p'}, - {'username': 'test_user3', 'project_name': 'test_project3', - 'domain_name': 'domain', 'password': 'p'}, - {'username': 'test_user4', 'project_name': 'test_project4', - 'domain_name': 'domain', 'password': 'p'}, - {'username': 'test_user5', 'project_name': 'test_project5', - 'domain_name': 'domain', 'password': 'p'}, - {'username': 'test_user6', 'project_name': 'test_project6', - 'domain_name': 'domain', 'password': 'p', - 'roles': ['role1', 'role2']}, - {'username': 'test_user7', 'project_name': 'test_project7', - 'domain_name': 'domain', 'password': 'p', - 'roles': ['role2', 'role3']}, - {'username': 'test_user8', 'project_name': 'test_project8', - 'domain_name': 'domain', 'password': 'p', - 'roles': ['role4', 'role1']}, - {'username': 'test_user9', 'project_name': 'test_project9', - 'domain_name': 'domain', 'password': 'p', - 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_user10', 'project_name': 'test_project10', - 'domain_name': 'domain', 'password': 'p', - 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_admin1', 'project_name': 'test_project11', - 'domain_name': 'domain', 'password': 'p', 'roles': [admin_role]}, - {'username': 'test_admin2', 'project_name': 'test_project12', - 'domain_name': 'domain', 'password': 'p', 'roles': [admin_role]}, - {'username': 'test_admin3', 'project_name': 'test_tenant13', - 'domain_name': 'domain', 'password': 'p', 'types': ['admin']}] diff --git a/tempest/tests/lib/common/test_rest_client.py b/tempest/tests/lib/common/test_rest_client.py deleted file mode 100644 index 4c0bb5705..000000000 --- a/tempest/tests/lib/common/test_rest_client.py +++ /dev/null @@ -1,1158 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import json - -import fixtures -import jsonschema -import six - -from tempest.lib.common import http -from tempest.lib.common import rest_client -from tempest.lib import exceptions -from tempest.tests import base -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -import tempest.tests.utils as utils - - -class BaseRestClientTestClass(base.TestCase): - - url = 'fake_endpoint' - - def setUp(self): - super(BaseRestClientTestClass, self).setUp() - self.fake_auth_provider = fake_auth_provider.FakeAuthProvider() - self.rest_client = rest_client.RestClient( - self.fake_auth_provider, None, None) - self.patchobject(http.ClosingHttp, 'request', self.fake_http.request) - self.useFixture(fixtures.MockPatchObject(self.rest_client, - '_log_request')) - - -class TestRestClientHTTPMethods(BaseRestClientTestClass): - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestRestClientHTTPMethods, self).setUp() - self.useFixture(fixtures.MockPatchObject(self.rest_client, - '_error_checker')) - - def test_post(self): - __, return_dict = self.rest_client.post(self.url, {}, {}) - self.assertEqual('POST', return_dict['method']) - - def test_get(self): - __, return_dict = self.rest_client.get(self.url) - self.assertEqual('GET', return_dict['method']) - - def test_delete(self): - __, return_dict = self.rest_client.delete(self.url) - self.assertEqual('DELETE', return_dict['method']) - - def test_patch(self): - __, return_dict = self.rest_client.patch(self.url, {}, {}) - self.assertEqual('PATCH', return_dict['method']) - - def test_put(self): - __, return_dict = self.rest_client.put(self.url, {}, {}) - self.assertEqual('PUT', return_dict['method']) - - def test_head(self): - self.useFixture(fixtures.MockPatchObject(self.rest_client, - 'response_checker')) - __, return_dict = self.rest_client.head(self.url) - self.assertEqual('HEAD', return_dict['method']) - - def test_copy(self): - __, return_dict = self.rest_client.copy(self.url) - self.assertEqual('COPY', return_dict['method']) - - -class TestRestClientNotFoundHandling(BaseRestClientTestClass): - def setUp(self): - self.fake_http = fake_http.fake_httplib2(404) - super(TestRestClientNotFoundHandling, self).setUp() - - def test_post(self): - self.assertRaises(exceptions.NotFound, self.rest_client.post, - self.url, {}, {}) - - -class TestRestClientHeadersJSON(TestRestClientHTTPMethods): - - def _verify_headers(self, resp): - resp = dict((k.lower(), v) for k, v in six.iteritems(resp)) - self.assertEqual(self.header_value, resp['accept']) - self.assertEqual(self.header_value, resp['content-type']) - - def setUp(self): - super(TestRestClientHeadersJSON, self).setUp() - self.header_value = 'application/json' - - def test_post(self): - resp, __ = self.rest_client.post(self.url, {}) - self._verify_headers(resp) - - def test_get(self): - resp, __ = self.rest_client.get(self.url) - self._verify_headers(resp) - - def test_delete(self): - resp, __ = self.rest_client.delete(self.url) - self._verify_headers(resp) - - def test_patch(self): - resp, __ = self.rest_client.patch(self.url, {}) - self._verify_headers(resp) - - def test_put(self): - resp, __ = self.rest_client.put(self.url, {}) - self._verify_headers(resp) - - def test_head(self): - self.useFixture(fixtures.MockPatchObject(self.rest_client, - 'response_checker')) - resp, __ = self.rest_client.head(self.url) - self._verify_headers(resp) - - def test_copy(self): - resp, __ = self.rest_client.copy(self.url) - self._verify_headers(resp) - - -class TestRestClientUpdateHeaders(BaseRestClientTestClass): - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestRestClientUpdateHeaders, self).setUp() - self.useFixture(fixtures.MockPatchObject(self.rest_client, - '_error_checker')) - self.headers = {'X-Configuration-Session': 'session_id'} - - def test_post_update_headers(self): - __, return_dict = self.rest_client.post(self.url, {}, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_get_update_headers(self): - __, return_dict = self.rest_client.get(self.url, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_delete_update_headers(self): - __, return_dict = self.rest_client.delete(self.url, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_patch_update_headers(self): - __, return_dict = self.rest_client.patch(self.url, {}, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_put_update_headers(self): - __, return_dict = self.rest_client.put(self.url, {}, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_head_update_headers(self): - self.useFixture(fixtures.MockPatchObject(self.rest_client, - 'response_checker')) - - __, return_dict = self.rest_client.head(self.url, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_copy_update_headers(self): - __, return_dict = self.rest_client.copy(self.url, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - -class TestRestClientParseRespJSON(BaseRestClientTestClass): - TYPE = "json" - - keys = ["fake_key1", "fake_key2"] - values = ["fake_value1", "fake_value2"] - item_expected = dict((key, value) for (key, value) in zip(keys, values)) - list_expected = {"body_list": [ - {keys[0]: values[0]}, - {keys[1]: values[1]}, - ]} - dict_expected = {"body_dict": { - keys[0]: values[0], - keys[1]: values[1], - }} - null_dict = {} - - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestRestClientParseRespJSON, self).setUp() - self.rest_client.TYPE = self.TYPE - - def test_parse_resp_body_item(self): - body = self.rest_client._parse_resp(json.dumps(self.item_expected)) - self.assertEqual(self.item_expected, body) - - def test_parse_resp_body_list(self): - body = self.rest_client._parse_resp(json.dumps(self.list_expected)) - self.assertEqual(self.list_expected["body_list"], body) - - def test_parse_resp_body_dict(self): - body = self.rest_client._parse_resp(json.dumps(self.dict_expected)) - self.assertEqual(self.dict_expected["body_dict"], body) - - def test_parse_resp_two_top_keys(self): - dict_two_keys = self.dict_expected.copy() - dict_two_keys.update({"second_key": ""}) - body = self.rest_client._parse_resp(json.dumps(dict_two_keys)) - self.assertEqual(dict_two_keys, body) - - def test_parse_resp_one_top_key_without_list_or_dict(self): - data = {"one_top_key": "not_list_or_dict_value"} - body = self.rest_client._parse_resp(json.dumps(data)) - self.assertEqual(data, body) - - def test_parse_nullable_dict(self): - body = self.rest_client._parse_resp(json.dumps(self.null_dict)) - self.assertEqual(self.null_dict, body) - - def test_parse_empty_list(self): - empty_list = [] - body = self.rest_client._parse_resp(json.dumps(empty_list)) - self.assertEqual(empty_list, body) - - -class TestRestClientErrorCheckerJSON(base.TestCase): - c_type = "application/json" - - def set_data(self, r_code, enc=None, r_body=None, absolute_limit=True): - if enc is None: - enc = self.c_type - resp_dict = {'status': r_code, 'content-type': enc} - resp_body = {'resp_body': 'fake_resp_body'} - - if absolute_limit is False: - resp_dict.update({'retry-after': 120}) - resp_body.update({'overLimit': {'message': 'fake_message'}}) - resp = fake_http.fake_http_response(headers=resp_dict, - status=int(r_code), - body=json.dumps(resp_body)) - data = { - "resp": resp, - "resp_body": json.dumps(resp_body) - } - if r_body is not None: - data.update({"resp_body": r_body}) - return data - - def setUp(self): - super(TestRestClientErrorCheckerJSON, self).setUp() - self.rest_client = rest_client.RestClient( - fake_auth_provider.FakeAuthProvider(), None, None) - - def test_response_less_than_400(self): - self.rest_client._error_checker(**self.set_data("399")) - - def _test_error_checker(self, exception_type, data): - e = self.assertRaises(exception_type, - self.rest_client._error_checker, - **data) - self.assertEqual(e.resp, data['resp']) - self.assertTrue(hasattr(e, 'resp_body')) - return e - - def test_response_400(self): - self._test_error_checker(exceptions.BadRequest, self.set_data("400")) - - def test_response_401(self): - self._test_error_checker(exceptions.Unauthorized, self.set_data("401")) - - def test_response_403(self): - self._test_error_checker(exceptions.Forbidden, self.set_data("403")) - - def test_response_404(self): - self._test_error_checker(exceptions.NotFound, self.set_data("404")) - - def test_response_409(self): - self._test_error_checker(exceptions.Conflict, self.set_data("409")) - - def test_response_410(self): - self._test_error_checker(exceptions.Gone, self.set_data("410")) - - def test_response_412(self): - self._test_error_checker(exceptions.PreconditionFailed, - self.set_data("412")) - - def test_response_413(self): - self._test_error_checker(exceptions.OverLimit, self.set_data("413")) - - def test_response_413_without_absolute_limit(self): - self._test_error_checker(exceptions.RateLimitExceeded, - self.set_data("413", absolute_limit=False)) - - def test_response_415(self): - self._test_error_checker(exceptions.InvalidContentType, - self.set_data("415")) - - def test_response_422(self): - self._test_error_checker(exceptions.UnprocessableEntity, - self.set_data("422")) - - def test_response_500_with_text(self): - # _parse_resp is expected to return 'str' - self._test_error_checker(exceptions.ServerFault, self.set_data("500")) - - def test_response_501_with_text(self): - self._test_error_checker(exceptions.NotImplemented, - self.set_data("501")) - - def test_response_400_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.BadRequest, - self.set_data("400", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_401_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.Unauthorized, - self.set_data("401", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_403_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.Forbidden, - self.set_data("403", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_404_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.NotFound, - self.set_data("404", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_404_with_invalid_dict(self): - r_body = '{"foo": "bar"]' - e = self._test_error_checker(exceptions.NotFound, - self.set_data("404", r_body=r_body)) - - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_410_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.Gone, - self.set_data("410", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_410_with_invalid_dict(self): - r_body = '{"foo": "bar"]' - e = self._test_error_checker(exceptions.Gone, - self.set_data("410", r_body=r_body)) - - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_409_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.Conflict, - self.set_data("409", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_500_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.ServerFault, - self.set_data("500", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_501_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - self._test_error_checker(exceptions.NotImplemented, - self.set_data("501", r_body=r_body)) - - def test_response_bigger_than_400(self): - # Any response code, that bigger than 400, and not in - # (401, 403, 404, 409, 412, 413, 422, 500, 501) - self._test_error_checker(exceptions.UnexpectedResponseCode, - self.set_data("402")) - - -class TestRestClientErrorCheckerTEXT(TestRestClientErrorCheckerJSON): - c_type = "text/plain" - - def test_fake_content_type(self): - # This test is required only in one exemplar - # Any response code, that bigger than 400, and not in - # (401, 403, 404, 409, 413, 422, 500, 501) - self._test_error_checker(exceptions.UnexpectedContentType, - self.set_data("405", enc="fake_enc")) - - def test_response_413_without_absolute_limit(self): - # Skip this test because rest_client cannot get overLimit message - # from text body. - pass - - -class TestRestClientUtils(BaseRestClientTestClass): - - def _is_resource_deleted(self, resource_id): - if not isinstance(self.retry_pass, int): - return False - if self.retry_count >= self.retry_pass: - return True - self.retry_count = self.retry_count + 1 - return False - - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestRestClientUtils, self).setUp() - self.retry_count = 0 - self.retry_pass = None - self.original_deleted_method = self.rest_client.is_resource_deleted - self.rest_client.is_resource_deleted = self._is_resource_deleted - - def test_wait_for_resource_deletion(self): - self.retry_pass = 2 - # Ensure timeout long enough for loop execution to hit retry count - self.rest_client.build_timeout = 500 - sleep_mock = self.patch('time.sleep') - self.rest_client.wait_for_resource_deletion('1234') - self.assertEqual(len(sleep_mock.mock_calls), 2) - - def test_wait_for_resource_deletion_not_deleted(self): - self.patch('time.sleep') - # Set timeout to be very quick to force exception faster - timeout = 1 - self.rest_client.build_timeout = timeout - - time_mock = self.patch('time.time') - time_mock.side_effect = utils.generate_timeout_series(timeout) - - self.assertRaises(exceptions.TimeoutException, - self.rest_client.wait_for_resource_deletion, - '1234') - - # time.time() should be called twice, first to start the timer - # and then to compute the timedelta - self.assertEqual(2, time_mock.call_count) - - def test_wait_for_deletion_with_unimplemented_deleted_method(self): - self.rest_client.is_resource_deleted = self.original_deleted_method - self.assertRaises(NotImplementedError, - self.rest_client.wait_for_resource_deletion, - '1234') - - def test_get_versions(self): - self.rest_client._parse_resp = lambda x: [{'id': 'v1'}, {'id': 'v2'}] - actual_resp, actual_versions = self.rest_client.get_versions() - self.assertEqual(['v1', 'v2'], list(actual_versions)) - - def test__str__(self): - def get_token(): - return "deadbeef" - - self.fake_auth_provider.get_token = get_token - self.assertIsNotNone(str(self.rest_client)) - - -class TestRateLimiting(BaseRestClientTestClass): - - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestRateLimiting, self).setUp() - - def test__get_retry_after_delay_with_integer(self): - resp = {'retry-after': '123'} - self.assertEqual(123, self.rest_client._get_retry_after_delay(resp)) - - def test__get_retry_after_delay_with_http_date(self): - resp = { - 'date': 'Mon, 4 Apr 2016 21:56:23 GMT', - 'retry-after': 'Mon, 4 Apr 2016 21:58:26 GMT', - } - self.assertEqual(123, self.rest_client._get_retry_after_delay(resp)) - - def test__get_retry_after_delay_of_zero_with_integer(self): - resp = {'retry-after': '0'} - self.assertEqual(1, self.rest_client._get_retry_after_delay(resp)) - - def test__get_retry_after_delay_of_zero_with_http_date(self): - resp = { - 'date': 'Mon, 4 Apr 2016 21:56:23 GMT', - 'retry-after': 'Mon, 4 Apr 2016 21:56:23 GMT', - } - self.assertEqual(1, self.rest_client._get_retry_after_delay(resp)) - - def test__get_retry_after_delay_with_missing_date_header(self): - resp = { - 'retry-after': 'Mon, 4 Apr 2016 21:58:26 GMT', - } - self.assertRaises(ValueError, self.rest_client._get_retry_after_delay, - resp) - - def test__get_retry_after_delay_with_invalid_http_date(self): - resp = { - 'retry-after': 'Mon, 4 AAA 2016 21:58:26 GMT', - 'date': 'Mon, 4 Apr 2016 21:56:23 GMT', - } - self.assertRaises(ValueError, self.rest_client._get_retry_after_delay, - resp) - - def test__get_retry_after_delay_with_missing_retry_after_header(self): - self.assertRaises(ValueError, self.rest_client._get_retry_after_delay, - {}) - - def test_is_absolute_limit_gives_false_with_retry_after(self): - resp = {'retry-after': 123} - - # is_absolute_limit() requires the overLimit body to be unwrapped - resp_body = self.rest_client._parse_resp("""{ - "overLimit": { - "message": "" - } - }""") - self.assertFalse(self.rest_client.is_absolute_limit(resp, resp_body)) - - -class TestProperties(BaseRestClientTestClass): - - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestProperties, self).setUp() - creds_dict = { - 'username': 'test-user', - 'user_id': 'test-user_id', - 'tenant_name': 'test-tenant_name', - 'tenant_id': 'test-tenant_id', - 'password': 'test-password' - } - self.rest_client = rest_client.RestClient( - fake_auth_provider.FakeAuthProvider(creds_dict=creds_dict), - None, None) - - def test_properties(self): - self.assertEqual('test-user', self.rest_client.user) - self.assertEqual('test-user_id', self.rest_client.user_id) - self.assertEqual('test-tenant_name', self.rest_client.tenant_name) - self.assertEqual('test-tenant_id', self.rest_client.tenant_id) - self.assertEqual('test-password', self.rest_client.password) - - self.rest_client.api_version = 'v1' - expected = {'api_version': 'v1', - 'endpoint_type': 'publicURL', - 'region': None, - 'name': None, - 'service': None, - 'skip_path': True} - self.rest_client.skip_path() - self.assertEqual(expected, self.rest_client.filters) - - self.rest_client.reset_path() - self.rest_client.api_version = 'v1' - expected = {'api_version': 'v1', - 'endpoint_type': 'publicURL', - 'region': None, - 'name': None, - 'service': None} - self.assertEqual(expected, self.rest_client.filters) - - -class TestExpectedSuccess(BaseRestClientTestClass): - - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestExpectedSuccess, self).setUp() - - def test_expected_succes_int_match(self): - expected_code = 202 - read_code = 202 - resp = self.rest_client.expected_success(expected_code, read_code) - # Assert None resp on success - self.assertFalse(resp) - - def test_expected_succes_int_no_match(self): - expected_code = 204 - read_code = 202 - self.assertRaises(exceptions.InvalidHttpSuccessCode, - self.rest_client.expected_success, - expected_code, read_code) - - def test_expected_succes_list_match(self): - expected_code = [202, 204] - read_code = 202 - resp = self.rest_client.expected_success(expected_code, read_code) - # Assert None resp on success - self.assertFalse(resp) - - def test_expected_succes_list_no_match(self): - expected_code = [202, 204] - read_code = 200 - self.assertRaises(exceptions.InvalidHttpSuccessCode, - self.rest_client.expected_success, - expected_code, read_code) - - def test_non_success_expected_int(self): - expected_code = 404 - read_code = 202 - self.assertRaises(AssertionError, self.rest_client.expected_success, - expected_code, read_code) - - def test_non_success_expected_list(self): - expected_code = [404, 202] - read_code = 202 - self.assertRaises(AssertionError, self.rest_client.expected_success, - expected_code, read_code) - - def test_non_success_read_code_as_string(self): - expected_code = 202 - read_code = '202' - self.assertRaises(TypeError, self.rest_client.expected_success, - expected_code, read_code) - - def test_non_success_read_code_as_list(self): - expected_code = 202 - read_code = [202] - self.assertRaises(TypeError, self.rest_client.expected_success, - expected_code, read_code) - - def test_non_success_expected_code_as_non_int(self): - expected_code = ['201', 202] - read_code = 202 - self.assertRaises(AssertionError, self.rest_client.expected_success, - expected_code, read_code) - - -class TestResponseBody(base.TestCase): - - def test_str(self): - response = {'status': 200} - body = {'key1': 'value1'} - actual = rest_client.ResponseBody(response, body) - self.assertEqual("response: %s\nBody: %s" % (response, body), - str(actual)) - - -class TestResponseBodyData(base.TestCase): - - def test_str(self): - response = {'status': 200} - data = 'data1' - actual = rest_client.ResponseBodyData(response, data) - self.assertEqual("response: %s\nBody: %s" % (response, data), - str(actual)) - - -class TestResponseBodyList(base.TestCase): - - def test_str(self): - response = {'status': 200} - body = ['value1', 'value2', 'value3'] - actual = rest_client.ResponseBodyList(response, body) - self.assertEqual("response: %s\nBody: %s" % (response, body), - str(actual)) - - -class TestJSONSchemaValidationBase(base.TestCase): - - class Response(dict): - - def __getattr__(self, attr): - return self[attr] - - def __setattr__(self, attr, value): - self[attr] = value - - def setUp(self): - super(TestJSONSchemaValidationBase, self).setUp() - self.fake_auth_provider = fake_auth_provider.FakeAuthProvider() - self.rest_client = rest_client.RestClient( - self.fake_auth_provider, None, None) - - def _test_validate_pass(self, schema, resp_body, status=200): - resp = self.Response() - resp.status = status - self.rest_client.validate_response(schema, resp, resp_body) - - def _test_validate_fail(self, schema, resp_body, status=200, - error_msg="HTTP response body is invalid"): - resp = self.Response() - resp.status = status - ex = self.assertRaises(exceptions.InvalidHTTPResponseBody, - self.rest_client.validate_response, - schema, resp, resp_body) - self.assertIn(error_msg, ex._error_string) - - -class TestRestClientJSONSchemaValidation(TestJSONSchemaValidationBase): - - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'integer', - }, - }, - 'required': ['foo'] - } - } - - def test_validate_pass_with_http_success_code(self): - body = {'foo': 12} - self._test_validate_pass(self.schema, body, status=200) - - def test_validate_pass_with_http_redirect_code(self): - body = {'foo': 12} - schema = copy.deepcopy(self.schema) - schema['status_code'] = 300 - self._test_validate_pass(schema, body, status=300) - - def test_validate_not_http_success_code(self): - schema = { - 'status_code': [200] - } - body = {} - self._test_validate_pass(schema, body, status=400) - - def test_validate_multiple_allowed_type(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': ['integer', 'string'], - }, - }, - 'required': ['foo'] - } - } - body = {'foo': 12} - self._test_validate_pass(schema, body) - body = {'foo': '12'} - self._test_validate_pass(schema, body) - - def test_validate_enable_additional_property_pass(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': {'type': 'integer'} - }, - 'additionalProperties': True, - 'required': ['foo'] - } - } - body = {'foo': 12, 'foo2': 'foo2value'} - self._test_validate_pass(schema, body) - - def test_validate_disable_additional_property_pass(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': {'type': 'integer'} - }, - 'additionalProperties': False, - 'required': ['foo'] - } - } - body = {'foo': 12} - self._test_validate_pass(schema, body) - - def test_validate_disable_additional_property_fail(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': {'type': 'integer'} - }, - 'additionalProperties': False, - 'required': ['foo'] - } - } - body = {'foo': 12, 'foo2': 'foo2value'} - self._test_validate_fail(schema, body) - - def test_validate_wrong_status_code(self): - schema = { - 'status_code': [202] - } - body = {} - resp = self.Response() - resp.status = 200 - ex = self.assertRaises(exceptions.InvalidHttpSuccessCode, - self.rest_client.validate_response, - schema, resp, body) - self.assertIn("Unexpected http success status code", ex._error_string) - - def test_validate_wrong_attribute_type(self): - body = {'foo': 1.2} - self._test_validate_fail(self.schema, body) - - def test_validate_unexpected_response_body(self): - schema = { - 'status_code': [200], - } - body = {'foo': 12} - self._test_validate_fail( - schema, body, - error_msg="HTTP response body should not exist") - - def test_validate_missing_response_body(self): - body = {} - self._test_validate_fail(self.schema, body) - - def test_validate_missing_required_attribute(self): - body = {'notfoo': 12} - self._test_validate_fail(self.schema, body) - - def test_validate_response_body_not_list(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'list_items': { - 'type': 'array', - 'items': {'foo': {'type': 'integer'}} - } - }, - 'required': ['list_items'], - } - } - body = {'foo': 12} - self._test_validate_fail(schema, body) - - def test_validate_response_body_list_pass(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'list_items': { - 'type': 'array', - 'items': {'foo': {'type': 'integer'}} - } - }, - 'required': ['list_items'], - } - } - body = {'list_items': [{'foo': 12}, {'foo': 10}]} - self._test_validate_pass(schema, body) - - -class TestRestClientJSONHeaderSchemaValidation(TestJSONSchemaValidationBase): - - schema = { - 'status_code': [200], - 'response_header': { - 'type': 'object', - 'properties': { - 'foo': {'type': 'integer'} - }, - 'required': ['foo'] - } - } - - def test_validate_header_schema_pass(self): - resp_body = {} - resp = self.Response() - resp.status = 200 - resp.foo = 12 - self.rest_client.validate_response(self.schema, resp, resp_body) - - def test_validate_header_schema_fail(self): - resp_body = {} - resp = self.Response() - resp.status = 200 - resp.foo = 1.2 - ex = self.assertRaises(exceptions.InvalidHTTPResponseHeader, - self.rest_client.validate_response, - self.schema, resp, resp_body) - self.assertIn("HTTP response header is invalid", ex._error_string) - - -class TestRestClientJSONSchemaFormatValidation(TestJSONSchemaValidationBase): - - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'format': 'email' - } - }, - 'required': ['foo'] - } - } - - def test_validate_format_pass(self): - body = {'foo': 'example@example.com'} - self._test_validate_pass(self.schema, body) - - def test_validate_format_fail(self): - body = {'foo': 'wrong_email'} - self._test_validate_fail(self.schema, body) - - def test_validate_formats_in_oneOf_pass(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'oneOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': '10.0.0.0'} - self._test_validate_pass(schema, body) - body = {'foo': 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329'} - self._test_validate_pass(schema, body) - - def test_validate_formats_in_oneOf_fail_both_match(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'oneOf': [ - {'format': 'ipv4'}, - {'format': 'ipv4'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': '10.0.0.0'} - self._test_validate_fail(schema, body) - - def test_validate_formats_in_oneOf_fail_no_match(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'oneOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': 'wrong_ip_format'} - self._test_validate_fail(schema, body) - - def test_validate_formats_in_anyOf_pass(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'anyOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': '10.0.0.0'} - self._test_validate_pass(schema, body) - body = {'foo': 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329'} - self._test_validate_pass(schema, body) - - def test_validate_formats_in_anyOf_pass_both_match(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'anyOf': [ - {'format': 'ipv4'}, - {'format': 'ipv4'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': '10.0.0.0'} - self._test_validate_pass(schema, body) - - def test_validate_formats_in_anyOf_fail_no_match(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'anyOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': 'wrong_ip_format'} - self._test_validate_fail(schema, body) - - def test_validate_formats_pass_for_unknow_format(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'format': 'UNKNOWN' - } - }, - 'required': ['foo'] - } - } - body = {'foo': 'example@example.com'} - self._test_validate_pass(schema, body) - - -class TestRestClientJSONSchemaValidatorVersion(TestJSONSchemaValidationBase): - - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': {'type': 'string'} - } - } - } - - def test_current_json_schema_validator_version(self): - with fixtures.MockPatchObject(jsonschema.Draft4Validator, - "check_schema") as chk_schema: - body = {'foo': 'test'} - self._test_validate_pass(self.schema, body) - chk_schema.mock.assert_called_once_with( - self.schema['response_body']) diff --git a/tempest/tests/lib/common/utils/__init__.py b/tempest/tests/lib/common/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/common/utils/linux/__init__.py b/tempest/tests/lib/common/utils/linux/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/common/utils/linux/test_remote_client.py b/tempest/tests/lib/common/utils/linux/test_remote_client.py deleted file mode 100644 index cf312f4f2..000000000 --- a/tempest/tests/lib/common/utils/linux/test_remote_client.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2017 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock - -from tempest.lib.common import ssh -from tempest.lib.common.utils.linux import remote_client -from tempest.lib import exceptions as lib_exc -from tempest.tests import base - - -class FakeServersClient(object): - - def get_console_output(self, server_id): - return {"output": "fake_output"} - - -class TestRemoteClient(base.TestCase): - - @mock.patch.object(ssh.Client, 'exec_command', return_value='success') - def test_exec_command(self, mock_ssh_exec_command): - client = remote_client.RemoteClient('192.168.1.10', 'username') - client.exec_command('ls') - mock_ssh_exec_command.assert_called_once_with( - 'set -eu -o pipefail; PATH=$$PATH:/sbin; ls') - - @mock.patch.object(ssh.Client, 'test_connection_auth') - def test_validate_authentication(self, mock_test_connection_auth): - client = remote_client.RemoteClient('192.168.1.10', 'username') - client.validate_authentication() - mock_test_connection_auth.assert_called_once_with() - - @mock.patch.object(remote_client.LOG, 'debug') - @mock.patch.object(ssh.Client, 'exec_command') - def test_debug_ssh_without_console(self, mock_exec_command, mock_debug): - mock_exec_command.side_effect = lib_exc.SSHTimeout - server = {'id': 'fake_id'} - client = remote_client.RemoteClient('192.168.1.10', 'username', - server=server) - self.assertRaises(lib_exc.SSHTimeout, client.exec_command, 'ls') - mock_debug.assert_called_with( - 'Caller: %s. Timeout trying to ssh to server %s', - 'TestRemoteClient:test_debug_ssh_without_console', server) - - @mock.patch.object(remote_client.LOG, 'debug') - @mock.patch.object(ssh.Client, 'exec_command') - def test_debug_ssh_with_console(self, mock_exec_command, mock_debug): - mock_exec_command.side_effect = lib_exc.SSHTimeout - server = {'id': 'fake_id'} - client = remote_client.RemoteClient('192.168.1.10', 'username', - server=server, - servers_client=FakeServersClient()) - self.assertRaises(lib_exc.SSHTimeout, client.exec_command, 'ls') - mock_debug.assert_called_with( - 'Console log for server %s: %s', server['id'], 'fake_output') diff --git a/tempest/tests/lib/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py deleted file mode 100644 index 8bdf70ec7..000000000 --- a/tempest/tests/lib/common/utils/test_data_utils.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2014 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import netaddr - -from tempest.lib.common.utils import data_utils -from tempest.tests import base - - -class TestDataUtils(base.TestCase): - - def test_rand_uuid(self): - actual = data_utils.rand_uuid() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]" - "{4}-[0-9a-f]{4}-[0-9a-f]{12}$") - actual2 = data_utils.rand_uuid() - self.assertNotEqual(actual, actual2) - - def test_rand_uuid_hex(self): - actual = data_utils.rand_uuid_hex() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^[0-9a-f]{32}$") - - actual2 = data_utils.rand_uuid_hex() - self.assertNotEqual(actual, actual2) - - def test_rand_name_with_default_prefix(self): - actual = data_utils.rand_name('foo') - self.assertIsInstance(actual, str) - self.assertTrue(actual.startswith('tempest-foo')) - actual2 = data_utils.rand_name('foo') - self.assertTrue(actual2.startswith('tempest-foo')) - self.assertNotEqual(actual, actual2) - - def test_rand_name_with_none_prefix(self): - actual = data_utils.rand_name('foo', prefix=None) - self.assertIsInstance(actual, str) - self.assertTrue(actual.startswith('foo')) - actual2 = data_utils.rand_name('foo', prefix=None) - self.assertTrue(actual2.startswith('foo')) - self.assertNotEqual(actual, actual2) - - def test_rand_name_with_prefix(self): - actual = data_utils.rand_name(prefix='prefix-str') - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^prefix-str-") - actual2 = data_utils.rand_name(prefix='prefix-str') - self.assertNotEqual(actual, actual2) - - def test_rand_password(self): - actual = data_utils.rand_password() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "[A-Za-z0-9~!@#%^&*_=+]{15,}") - actual2 = data_utils.rand_password() - self.assertNotEqual(actual, actual2) - - def test_rand_password_with_len(self): - actual = data_utils.rand_password(8) - self.assertIsInstance(actual, str) - self.assertEqual(len(actual), 8) - self.assertRegex(actual, "[A-Za-z0-9~!@#%^&*_=+]{8}") - actual2 = data_utils.rand_password(8) - self.assertNotEqual(actual, actual2) - - def test_rand_password_with_len_2(self): - actual = data_utils.rand_password(2) - self.assertIsInstance(actual, str) - self.assertEqual(len(actual), 3) - self.assertRegex(actual, "[A-Za-z0-9~!@#%^&*_=+]{3}") - actual2 = data_utils.rand_password(2) - self.assertNotEqual(actual, actual2) - - def test_rand_url(self): - actual = data_utils.rand_url() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^https://url-[0-9]*\.com$") - actual2 = data_utils.rand_url() - self.assertNotEqual(actual, actual2) - - def test_rand_int(self): - actual = data_utils.rand_int_id() - self.assertIsInstance(actual, int) - - actual2 = data_utils.rand_int_id() - self.assertNotEqual(actual, actual2) - - def test_rand_infiniband_guid_address(self): - actual = data_utils.rand_infiniband_guid_address() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^([0-9a-f][0-9a-f]:){7}" - "[0-9a-f][0-9a-f]$") - - actual2 = data_utils.rand_infiniband_guid_address() - self.assertNotEqual(actual, actual2) - - def test_rand_mac_address(self): - actual = data_utils.rand_mac_address() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^([0-9a-f][0-9a-f]:){5}" - "[0-9a-f][0-9a-f]$") - - actual2 = data_utils.rand_mac_address() - self.assertNotEqual(actual, actual2) - - def test_parse_image_id(self): - actual = data_utils.parse_image_id("/foo/bar/deadbeaf") - self.assertEqual("deadbeaf", actual) - - def test_arbitrary_string(self): - actual = data_utils.arbitrary_string() - self.assertEqual(actual, "test") - actual = data_utils.arbitrary_string(size=30, base_text="abc") - self.assertEqual(actual, "abc" * int(30 / len("abc"))) - actual = data_utils.arbitrary_string(size=5, base_text="deadbeaf") - self.assertEqual(actual, "deadb") - - def test_random_bytes(self): - actual = data_utils.random_bytes() # default size=1024 - self.assertIsInstance(actual, bytes) - self.assertEqual(1024, len(actual)) - actual2 = data_utils.random_bytes() - self.assertNotEqual(actual, actual2) - - actual = data_utils.random_bytes(size=2048) - self.assertEqual(2048, len(actual)) - - def test_get_ipv6_addr_by_EUI64(self): - actual = data_utils.get_ipv6_addr_by_EUI64('2001:db8::', - '00:16:3e:33:44:55') - self.assertIsInstance(actual, netaddr.IPAddress) - self.assertEqual(actual, - netaddr.IPAddress('2001:db8::216:3eff:fe33:4455')) - - def test_get_ipv6_addr_by_EUI64_with_IPv4_prefix(self): - ipv4_prefix = '10.0.8' - mac = '00:16:3e:33:44:55' - self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64, - ipv4_prefix, mac) - - def test_get_ipv6_addr_by_EUI64_bad_cidr_type(self): - bad_cidr = 123 - mac = '00:16:3e:33:44:55' - self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64, - bad_cidr, mac) - - def test_get_ipv6_addr_by_EUI64_bad_cidr_value(self): - bad_cidr = 'bb' - mac = '00:16:3e:33:44:55' - self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64, - bad_cidr, mac) - - def test_get_ipv6_addr_by_EUI64_bad_mac_value(self): - cidr = '2001:db8::' - bad_mac = '00:16:3e:33:44:5Z' - self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64, - cidr, bad_mac) - - def test_get_ipv6_addr_by_EUI64_bad_mac_type(self): - cidr = '2001:db8::' - bad_mac = 99999999999999999999 - self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64, - cidr, bad_mac) - - def test_chunkify(self): - data = "aaa" - chunks = data_utils.chunkify(data, 2) - self.assertEqual("aa", next(chunks)) - self.assertEqual("a", next(chunks)) - self.assertRaises(StopIteration, next, chunks) diff --git a/tempest/tests/lib/common/utils/test_misc.py b/tempest/tests/lib/common/utils/test_misc.py deleted file mode 100644 index 47e81d158..000000000 --- a/tempest/tests/lib/common/utils/test_misc.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2014 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.lib.common.utils import misc -from tempest.tests import base - - -@misc.singleton -class TestFoo(object): - - count = 0 - - def increment(self): - self.count += 1 - return self.count - - -@misc.singleton -class TestBar(object): - - count = 0 - - def increment(self): - self.count += 1 - return self.count - - -class TestMisc(base.TestCase): - - def test_singleton(self): - test = TestFoo() - self.assertEqual(0, test.count) - self.assertEqual(1, test.increment()) - test2 = TestFoo() - self.assertEqual(1, test.count) - self.assertEqual(1, test2.count) - self.assertEqual(test, test2) - test3 = TestBar() - self.assertNotEqual(test, test3) diff --git a/tempest/tests/lib/common/utils/test_test_utils.py b/tempest/tests/lib/common/utils/test_test_utils.py deleted file mode 100644 index 29c56841e..000000000 --- a/tempest/tests/lib/common/utils/test_test_utils.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -import mock - -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions -from tempest.tests import base -from tempest.tests import utils - - -class TestTestUtils(base.TestCase): - - def test_find_test_caller_test_case(self): - # Calling it from here should give us the method we're in. - self.assertEqual('TestTestUtils:test_find_test_caller_test_case', - test_utils.find_test_caller()) - - def test_find_test_caller_setup_self(self): - def setUp(self): - return test_utils.find_test_caller() - self.assertEqual('TestTestUtils:setUp', setUp(self)) - - def test_find_test_caller_setup_no_self(self): - def setUp(): - return test_utils.find_test_caller() - self.assertEqual(':setUp', setUp()) - - def test_find_test_caller_setupclass_cls(self): - def setUpClass(cls): # noqa - return test_utils.find_test_caller() - self.assertEqual('TestTestUtils:setUpClass', - setUpClass(self.__class__)) - - def test_find_test_caller_teardown_self(self): - def tearDown(self): - return test_utils.find_test_caller() - self.assertEqual('TestTestUtils:tearDown', tearDown(self)) - - def test_find_test_caller_teardown_no_self(self): - def tearDown(): - return test_utils.find_test_caller() - self.assertEqual(':tearDown', tearDown()) - - def test_find_test_caller_teardown_class(self): - def tearDownClass(cls): # noqa - return test_utils.find_test_caller() - self.assertEqual('TestTestUtils:tearDownClass', - tearDownClass(self.__class__)) - - def test_call_and_ignore_notfound_exc_when_notfound_raised(self): - def raise_not_found(): - raise exceptions.NotFound() - self.assertIsNone( - test_utils.call_and_ignore_notfound_exc(raise_not_found)) - - def test_call_and_ignore_notfound_exc_when_value_error_raised(self): - def raise_value_error(): - raise ValueError() - self.assertRaises(ValueError, test_utils.call_and_ignore_notfound_exc, - raise_value_error) - - def test_call_and_ignore_notfound_exc(self): - m = mock.Mock(return_value=42) - args, kwargs = (1,), {'1': None} - self.assertEqual( - 42, test_utils.call_and_ignore_notfound_exc(m, *args, **kwargs)) - m.assert_called_once_with(*args, **kwargs) - - @mock.patch('time.sleep') - @mock.patch('time.time') - def test_call_until_true_when_f_never_returns_true(self, m_time, m_sleep): - timeout = 42 # The value doesn't matter as we mock time.time() - sleep = 60 # The value doesn't matter as we mock time.sleep() - m_time.side_effect = utils.generate_timeout_series(timeout) - self.assertEqual( - False, test_utils.call_until_true(lambda: False, timeout, sleep) - ) - m_sleep.call_args_list = [mock.call(sleep)] * 2 - m_time.call_args_list = [mock.call()] * 2 - - @mock.patch('time.sleep') - @mock.patch('time.time') - def test_call_until_true_when_f_returns_true(self, m_time, m_sleep): - timeout = 42 # The value doesn't matter as we mock time.time() - sleep = 60 # The value doesn't matter as we mock time.sleep() - m_time.return_value = 0 - self.assertEqual( - True, test_utils.call_until_true(lambda: True, timeout, sleep) - ) - self.assertEqual(0, m_sleep.call_count) - self.assertEqual(1, m_time.call_count) diff --git a/tempest/tests/lib/fake_auth_provider.py b/tempest/tests/lib/fake_auth_provider.py deleted file mode 100644 index e4582f81b..000000000 --- a/tempest/tests/lib/fake_auth_provider.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -class FakeAuthProvider(object): - - def __init__(self, creds_dict=None, fake_base_url=None): - creds_dict = creds_dict or {} - self.credentials = FakeCredentials(creds_dict) - self.fake_base_url = fake_base_url - - def auth_request(self, method, url, headers=None, body=None, filters=None): - return url, headers, body - - def base_url(self, filters, auth_data=None): - return self.fake_base_url or "https://example.com" - - def get_token(self): - return "faketoken" - - -class FakeCredentials(object): - - def __init__(self, creds_dict): - for key in creds_dict: - setattr(self, key, creds_dict[key]) diff --git a/tempest/tests/lib/fake_credentials.py b/tempest/tests/lib/fake_credentials.py deleted file mode 100644 index eac4ada39..000000000 --- a/tempest/tests/lib/fake_credentials.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib import auth - - -class FakeCredentials(auth.Credentials): - - def is_valid(self): - return True - - -class FakeKeystoneV2Credentials(auth.KeystoneV2Credentials): - - def __init__(self): - creds = dict( - username='fake_username', - password='fake_password', - tenant_name='fake_tenant_name' - ) - super(FakeKeystoneV2Credentials, self).__init__(**creds) - - -class FakeKeystoneV3Credentials(auth.KeystoneV3Credentials): - """Fake credentials suitable for the Keystone Identity V3 API""" - - def __init__(self): - creds = dict( - username='fake_username', - password='fake_password', - user_domain_name='fake_domain_name', - project_name='fake_tenant_name', - project_domain_name='fake_domain_name' - ) - super(FakeKeystoneV3Credentials, self).__init__(**creds) - - -class FakeKeystoneV3DomainCredentials(auth.KeystoneV3Credentials): - """Fake credentials for the Keystone Identity V3 API, with no scope""" - - def __init__(self): - creds = dict( - username='fake_username', - password='fake_password', - user_domain_name='fake_domain_name' - ) - super(FakeKeystoneV3DomainCredentials, self).__init__(**creds) - - -class FakeKeystoneV3AllCredentials(auth.KeystoneV3Credentials): - """Fake credentials for the Keystone Identity V3 API, with no scope""" - - def __init__(self): - creds = dict( - username='fake_username', - password='fake_password', - user_domain_name='fake_domain_name', - project_name='fake_tenant_name', - project_domain_name='fake_domain_name', - domain_name='fake_domain_name' - ) - super(FakeKeystoneV3AllCredentials, self).__init__(**creds) diff --git a/tempest/tests/lib/fake_http.py b/tempest/tests/lib/fake_http.py deleted file mode 100644 index cfa4b9368..000000000 --- a/tempest/tests/lib/fake_http.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - - -class fake_httplib2(object): - - def __init__(self, return_type=None, *args, **kwargs): - self.return_type = return_type - - def request(self, uri, method="GET", body=None, headers=None, - redirections=5, connection_type=None, chunked=False): - if not self.return_type: - fake_headers = fake_http_response(headers) - return_obj = { - 'uri': uri, - 'method': method, - 'body': body, - 'headers': headers - } - return (fake_headers, return_obj) - elif isinstance(self.return_type, int): - body = body or "fake_body" - header_info = { - 'content-type': 'text/plain', - 'content-length': len(body) - } - resp_header = fake_http_response(header_info, - status=self.return_type) - return (resp_header, body) - else: - msg = "unsupported return type %s" % self.return_type - raise TypeError(msg) - - -class fake_http_response(dict): - def __init__(self, headers, body=None, - version=1.0, status=200, reason="Ok"): - """Initialization of fake HTTP Response - - :param headers: dict representing HTTP response headers - :param body: file-like object - :param version: HTTP Version - :param status: Response status code - :param reason: Status code related message. - """ - self.body = body - self.status = status - self['status'] = str(self.status) - self.reason = reason - self.version = version - self.headers = headers - - if headers: - for key, value in headers.items(): - self[key.lower()] = value - - def getheaders(self): - return copy.deepcopy(self.headers).items() - - def getheader(self, key, default): - return self.headers.get(key, default) - - def read(self, amt): - return self.body.read(amt) diff --git a/tempest/tests/lib/fake_identity.py b/tempest/tests/lib/fake_identity.py deleted file mode 100644 index 8bae34f88..000000000 --- a/tempest/tests/lib/fake_identity.py +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright 2014 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_serialization import jsonutils as json - -from tempest.tests.lib import fake_http - -FAKE_AUTH_URL = 'http://fake_uri.com/auth' - -TOKEN = "fake_token" -ALT_TOKEN = "alt_fake_token" - -# Fake Identity v2 constants -COMPUTE_ENDPOINTS_V2 = { - "endpoints": [ - { - "adminURL": "http://fake_url/v2/first_endpoint/admin", - "region": "NoMatchRegion", - "internalURL": "http://fake_url/v2/first_endpoint/internal", - "publicURL": "http://fake_url/v2/first_endpoint/public" - }, - { - "adminURL": "http://fake_url/v2/second_endpoint/admin", - "region": "FakeRegion", - "internalURL": "http://fake_url/v2/second_endpoint/internal", - "publicURL": "http://fake_url/v2/second_endpoint/public" - }, - ], - "type": "compute", - "name": "nova" -} - -CATALOG_V2 = [COMPUTE_ENDPOINTS_V2, ] - -ALT_IDENTITY_V2_RESPONSE = { - "access": { - "token": { - "expires": "2020-01-01T00:00:10Z", - "id": ALT_TOKEN, - "tenant": { - "id": "fake_alt_tenant_id" - }, - }, - "user": { - "id": "fake_alt_user_id", - "password_expires_at": None, - }, - "serviceCatalog": CATALOG_V2, - }, -} - -IDENTITY_V2_RESPONSE = { - "access": { - "token": { - "expires": "2020-01-01T00:00:10Z", - "id": TOKEN, - "tenant": { - "id": "fake_tenant_id" - }, - }, - "user": { - "id": "fake_user_id", - "password_expires_at": None, - }, - "serviceCatalog": CATALOG_V2, - }, -} - -# Fake Identity V3 constants -COMPUTE_ENDPOINTS_V3 = { - "endpoints": [ - { - "id": "first_compute_fake_service", - "interface": "public", - "region": "NoMatchRegion", - "region_id": "NoMatchRegion", - "url": "http://fake_url/v3/first_endpoint/api" - }, - { - "id": "second_fake_service", - "interface": "public", - "region": "FakeRegion", - "region_id": "FakeRegion", - "url": "http://fake_url/v3/second_endpoint/api" - }, - { - "id": "third_fake_service", - "interface": "admin", - "region": "MiddleEarthRegion", - "region_id": "MiddleEarthRegion", - "url": "http://fake_url/v3/third_endpoint/api" - } - - ], - "type": "compute", - "id": "fake_compute_endpoint", - "name": "nova" -} - -CATALOG_V3 = [COMPUTE_ENDPOINTS_V3, ] - -IDENTITY_V3_RESPONSE = { - "token": { - "audit_ids": ["ny5LA5YXToa_mAVO8Hnupw", "9NPTvsRDSkmsW61abP978Q"], - "methods": [ - "token", - "password" - ], - "expires_at": "2020-01-01T00:00:10.000123Z", - "project": { - "domain": { - "id": "fake_domain_id", - "name": "fake" - }, - "id": "project_id", - "name": "project_name" - }, - "user": { - "domain": { - "id": "fake_domain_id", - "name": "domain_name" - }, - "id": "fake_user_id", - "name": "username", - "password_expires_at": None, - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - "catalog": CATALOG_V3 - } -} - -IDENTITY_V3_RESPONSE_DOMAIN_SCOPE = { - "token": { - "audit_ids": ["ny5LA5YXToa_mAVO8Hnupw", "9NPTvsRDSkmsW61abP978Q"], - "methods": [ - "token", - "password" - ], - "expires_at": "2020-01-01T00:00:10.000123Z", - "domain": { - "id": "fake_domain_id", - "name": "domain_name" - }, - "user": { - "domain": { - "id": "fake_domain_id", - "name": "domain_name" - }, - "id": "fake_user_id", - "name": "username", - "password_expires_at": None, - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - "catalog": CATALOG_V3 - } -} - -IDENTITY_V3_RESPONSE_NO_SCOPE = { - "token": { - "audit_ids": ["ny5LA5YXToa_mAVO8Hnupw", "9NPTvsRDSkmsW61abP978Q"], - "methods": [ - "token", - "password" - ], - "expires_at": "2020-01-01T00:00:10.000123Z", - "user": { - "domain": { - "id": "fake_domain_id", - "name": "domain_name" - }, - "id": "fake_user_id", - "name": "username", - "password_expires_at": None, - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - } -} - -ALT_IDENTITY_V3 = IDENTITY_V3_RESPONSE - - -def _fake_v3_response(self, uri, method="GET", body=None, headers=None, - redirections=5, connection_type=None): - fake_headers = { - "x-subject-token": TOKEN - } - return (fake_http.fake_http_response(fake_headers, status=201), - json.dumps(IDENTITY_V3_RESPONSE)) - - -def _fake_v3_response_domain_scope(self, uri, method="GET", body=None, - headers=None, redirections=5, - connection_type=None): - fake_headers = { - "status": "201", - "x-subject-token": TOKEN - } - return (fake_http.fake_http_response(fake_headers, status=201), - json.dumps(IDENTITY_V3_RESPONSE_DOMAIN_SCOPE)) - - -def _fake_v3_response_no_scope(self, uri, method="GET", body=None, - headers=None, redirections=5, - connection_type=None): - fake_headers = { - "status": "201", - "x-subject-token": TOKEN - } - return (fake_http.fake_http_response(fake_headers, status=201), - json.dumps(IDENTITY_V3_RESPONSE_NO_SCOPE)) - - -def _fake_v2_response(self, uri, method="GET", body=None, headers=None, - redirections=5, connection_type=None): - return (fake_http.fake_http_response({}, status=200), - json.dumps(IDENTITY_V2_RESPONSE)) - - -def _fake_auth_failure_response(): - # the response body isn't really used in this case, but lets send it anyway - # to have a safe check in some future change on the rest client. - body = { - "unauthorized": { - "message": "Unauthorized", - "code": "401" - } - } - return fake_http.fake_http_response({}, status=401), json.dumps(body) diff --git a/tempest/tests/lib/services/__init__.py b/tempest/tests/lib/services/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/base.py b/tempest/tests/lib/services/base.py deleted file mode 100644 index 924f9f206..000000000 --- a/tempest/tests/lib/services/base.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2015 Deutsche Telekom AG. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures -from oslo_serialization import jsonutils as json - -from tempest.tests import base -from tempest.tests.lib import fake_http - - -class BaseServiceTest(base.TestCase): - def create_response(self, body, to_utf=False, status=200, headers=None): - json_body = {} - if body: - json_body = json.dumps(body) - if to_utf: - json_body = json_body.encode('utf-8') - resp = fake_http.fake_http_response(headers, status=status), json_body - return resp - - def check_service_client_function(self, function, function2mock, - body, to_utf=False, status=200, - headers=None, mock_args=None, - resp_as_string=False, - **kwargs): - """Mock a service client function for unit testing. - - :param function: The service client function to call. - :param function2mock: The REST call to mock inside the service client - function. - :param body: Expected response body returned by the service client - function. - :param to_utf: Whether to use UTF-8 encoding for response. - :param status: Expected response status returned by the service client - function. - :param headers: Expected headers returned by the service client - function. - :param mock_args: List/dict/value of expected args/kwargs called by - function2mock. For example: - * If mock_args=['foo'] then ``assert_called_once_with('foo')`` - is called. - * If mock_args={'foo': 'bar'} then - ``assert_called_once_with(foo='bar')`` is called. - * If mock_args='foo' then ``assert_called_once_with('foo')`` - is called. - :param resp_as_string: Whether response body is retruned as string. - This is for service client methods which return ResponseBodyData - object. - :param kwargs: kwargs that are passed to function. - """ - mocked_response = self.create_response(body, to_utf, status, headers) - fixture = self.useFixture(fixtures.MockPatch( - function2mock, return_value=mocked_response)) - if kwargs: - resp = function(**kwargs) - else: - resp = function() - if resp_as_string: - resp = resp.data - self.assertEqual(body, resp) - if isinstance(mock_args, list): - fixture.mock.assert_called_once_with(*mock_args) - elif isinstance(mock_args, dict): - fixture.mock.assert_called_once_with(**mock_args) - elif mock_args is not None: - fixture.mock.assert_called_once_with(mock_args) diff --git a/tempest/tests/lib/services/compute/__init__.py b/tempest/tests/lib/services/compute/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/compute/test_agents_client.py b/tempest/tests/lib/services/compute/test_agents_client.py deleted file mode 100644 index 880220e64..000000000 --- a/tempest/tests/lib/services/compute/test_agents_client.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import agents_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestAgentsClient(base.BaseServiceTest): - FAKE_CREATE_AGENT = { - "agent": { - "url": "http://foo.com", - "hypervisor": "kvm", - "md5hash": "md5", - "version": "2", - "architecture": "x86_64", - "os": "linux", - "agent_id": 1 - } - } - - FAKE_UPDATE_AGENT = { - "agent": { - "url": "http://foo.com", - "md5hash": "md5", - "version": "2", - "agent_id": 1 - } - } - - def setUp(self): - super(TestAgentsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = agents_client.AgentsClient(fake_auth, - 'compute', 'regionOne') - - def _test_list_agents(self, bytes_body=False): - self.check_service_client_function( - self.client.list_agents, - 'tempest.lib.common.rest_client.RestClient.get', - {"agents": []}, - bytes_body) - self.check_service_client_function( - self.client.list_agents, - 'tempest.lib.common.rest_client.RestClient.get', - {"agents": []}, - bytes_body, - hypervisor="kvm") - - def _test_create_agent(self, bytes_body=False): - self.check_service_client_function( - self.client.create_agent, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_AGENT, - bytes_body, - url="http://foo.com", hypervisor="kvm", md5hash="md5", - version="2", architecture="x86_64", os="linux") - - def _test_delete_agent(self): - self.check_service_client_function( - self.client.delete_agent, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, agent_id="1") - - def _test_update_agent(self, bytes_body=False): - self.check_service_client_function( - self.client.update_agent, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_AGENT, - bytes_body, - agent_id="1", url="http://foo.com", md5hash="md5", version="2") - - def test_list_agents_with_str_body(self): - self._test_list_agents() - - def test_list_agents_with_bytes_body(self): - self._test_list_agents(bytes_body=True) - - def test_create_agent_with_str_body(self): - self._test_create_agent() - - def test_create_agent_with_bytes_body(self): - self._test_create_agent(bytes_body=True) - - def test_delete_agent(self): - self._test_delete_agent() - - def test_update_agent_with_str_body(self): - self._test_update_agent() - - def test_update_agent_with_bytes_body(self): - self._test_update_agent(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_aggregates_client.py b/tempest/tests/lib/services/compute/test_aggregates_client.py deleted file mode 100644 index 674d92a35..000000000 --- a/tempest/tests/lib/services/compute/test_aggregates_client.py +++ /dev/null @@ -1,192 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import aggregates_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestAggregatesClient(base.BaseServiceTest): - FAKE_SHOW_AGGREGATE = { - "aggregate": - { - "name": "hoge", - "availability_zone": None, - "deleted": False, - "created_at": - "2015-07-16T03:07:32.000000", - "updated_at": None, - "hosts": [], - "deleted_at": None, - "id": 1, - "metadata": {} - } - } - - FAKE_CREATE_AGGREGATE = { - "aggregate": - { - "name": u'\xf4', - "availability_zone": None, - "deleted": False, - "created_at": "2015-07-21T04:11:18.000000", - "updated_at": None, - "deleted_at": None, - "id": 1 - } - } - - FAKE_UPDATE_AGGREGATE = { - "aggregate": - { - "name": u'\xe9', - "availability_zone": None, - "deleted": False, - "created_at": "2015-07-16T03:07:32.000000", - "updated_at": "2015-07-23T05:16:29.000000", - "hosts": [], - "deleted_at": None, - "id": 1, - "metadata": {} - } - } - - FAKE_AGGREGATE = { - "availability_zone": "nova", - "created_at": "2013-08-18T12:17:56.297823", - "deleted": False, - "deleted_at": None, - "hosts": [ - "21549b2f665945baaa7101926a00143c" - ], - "id": 1, - "metadata": { - "availability_zone": "nova" - }, - "name": u'\xe9', - "updated_at": None - } - - FAKE_ADD_HOST = {'aggregate': FAKE_AGGREGATE} - FAKE_REMOVE_HOST = {'aggregate': FAKE_AGGREGATE} - FAKE_SET_METADATA = {'aggregate': FAKE_AGGREGATE} - - def setUp(self): - super(TestAggregatesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = aggregates_client.AggregatesClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_aggregates(self, bytes_body=False): - self.check_service_client_function( - self.client.list_aggregates, - 'tempest.lib.common.rest_client.RestClient.get', - {"aggregates": []}, - bytes_body) - - def test_list_aggregates_with_str_body(self): - self._test_list_aggregates() - - def test_list_aggregates_with_bytes_body(self): - self._test_list_aggregates(bytes_body=True) - - def _test_show_aggregate(self, bytes_body=False): - self.check_service_client_function( - self.client.show_aggregate, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SHOW_AGGREGATE, - bytes_body, - aggregate_id=1) - - def test_show_aggregate_with_str_body(self): - self._test_show_aggregate() - - def test_show_aggregate_with_bytes_body(self): - self._test_show_aggregate(bytes_body=True) - - def _test_create_aggregate(self, bytes_body=False): - self.check_service_client_function( - self.client.create_aggregate, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_AGGREGATE, - bytes_body, - name='hoge') - - def test_create_aggregate_with_str_body(self): - self._test_create_aggregate() - - def test_create_aggregate_with_bytes_body(self): - self._test_create_aggregate(bytes_body=True) - - def test_delete_aggregate(self): - self.check_service_client_function( - self.client.delete_aggregate, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, aggregate_id="1") - - def _test_update_aggregate(self, bytes_body=False): - self.check_service_client_function( - self.client.update_aggregate, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_AGGREGATE, - bytes_body, - aggregate_id=1) - - def test_update_aggregate_with_str_body(self): - self._test_update_aggregate() - - def test_update_aggregate_with_bytes_body(self): - self._test_update_aggregate(bytes_body=True) - - def _test_add_host(self, bytes_body=False): - self.check_service_client_function( - self.client.add_host, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_ADD_HOST, - bytes_body, - aggregate_id=1) - - def test_add_host_with_str_body(self): - self._test_add_host() - - def test_add_host_with_bytes_body(self): - self._test_add_host(bytes_body=True) - - def _test_remove_host(self, bytes_body=False): - self.check_service_client_function( - self.client.remove_host, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_REMOVE_HOST, - bytes_body, - aggregate_id=1) - - def test_remove_host_with_str_body(self): - self._test_remove_host() - - def test_remove_host_with_bytes_body(self): - self._test_remove_host(bytes_body=True) - - def _test_set_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.set_metadata, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SET_METADATA, - bytes_body, - aggregate_id=1) - - def test_set_metadata_with_str_body(self): - self._test_set_metadata() - - def test_set_metadata_with_bytes_body(self): - self._test_set_metadata(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_availability_zone_client.py b/tempest/tests/lib/services/compute/test_availability_zone_client.py deleted file mode 100644 index 6608592da..000000000 --- a/tempest/tests/lib/services/compute/test_availability_zone_client.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import availability_zone_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestAvailabilityZoneClient(base.BaseServiceTest): - - FAKE_AVAILABIRITY_ZONE_INFO = { - "availabilityZoneInfo": - [ - { - "zoneState": { - "available": True - }, - "hosts": None, - "zoneName": u'\xf4' - } - ] - } - - def setUp(self): - super(TestAvailabilityZoneClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = availability_zone_client.AvailabilityZoneClient( - fake_auth, 'compute', 'regionOne') - - def test_list_availability_zones_with_str_body(self): - self.check_service_client_function( - self.client.list_availability_zones, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_AVAILABIRITY_ZONE_INFO) - - def test_list_availability_zones_with_bytes_body(self): - self.check_service_client_function( - self.client.list_availability_zones, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_AVAILABIRITY_ZONE_INFO, to_utf=True) diff --git a/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py b/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py deleted file mode 100644 index 81c54b5da..000000000 --- a/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.services.compute import baremetal_nodes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestBareMetalNodesClient(base.BaseServiceTest): - - FAKE_NODE_INFO = {'cpus': '8', - 'disk_gb': '64', - 'host': '10.0.2.15', - 'id': 'Identifier', - 'instance_uuid': "null", - 'interfaces': [ - { - "address": "20::01", - "datapath_id": "null", - "id": 1, - "port_no": None - } - ], - 'memory_mb': '8192', - 'task_state': None} - - def setUp(self): - super(TestBareMetalNodesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.baremetal_nodes_client = (baremetal_nodes_client. - BaremetalNodesClient - (fake_auth, 'compute', - 'regionOne')) - - def _test_bareMetal_nodes(self, operation='list', bytes_body=False): - if operation != 'list': - expected = {"node": self.FAKE_NODE_INFO} - function = self.baremetal_nodes_client.show_baremetal_node - else: - node_info = copy.deepcopy(self.FAKE_NODE_INFO) - del node_info['instance_uuid'] - expected = {"nodes": [node_info]} - function = self.baremetal_nodes_client.list_baremetal_nodes - - self.check_service_client_function( - function, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, 200, - baremetal_node_id='Identifier') - - def test_list_bareMetal_nodes_with_str_body(self): - self._test_bareMetal_nodes() - - def test_list_bareMetal_nodes_with_bytes_body(self): - self._test_bareMetal_nodes(bytes_body=True) - - def test_show_bareMetal_node_with_str_body(self): - self._test_bareMetal_nodes('show') - - def test_show_bareMetal_node_with_bytes_body(self): - self._test_bareMetal_nodes('show', True) diff --git a/tempest/tests/lib/services/compute/test_base_compute_client.py b/tempest/tests/lib/services/compute/test_base_compute_client.py deleted file mode 100644 index 69e8542c6..000000000 --- a/tempest/tests/lib/services/compute/test_base_compute_client.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock - -from tempest.lib.common import rest_client -from tempest.lib import exceptions -from tempest.lib.services.compute import base_compute_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -from tempest.tests.lib.services import base - - -class TestMicroversionHeaderCheck(base.BaseServiceTest): - - def setUp(self): - super(TestMicroversionHeaderCheck, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = base_compute_client.BaseComputeClient( - fake_auth, 'compute', 'regionOne') - base_compute_client.COMPUTE_MICROVERSION = '2.2' - - def tearDown(self): - super(TestMicroversionHeaderCheck, self).tearDown() - base_compute_client.COMPUTE_MICROVERSION = None - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_correct_microverion_in_response(self, mock_request): - response = fake_http.fake_http_response( - headers={self.client.api_microversion_header_name: '2.2'}, - ) - mock_request.return_value = response, '' - self.client.get('fake_url') - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_incorrect_microverion_in_response(self, mock_request): - response = fake_http.fake_http_response( - headers={self.client.api_microversion_header_name: '2.3'}, - ) - mock_request.return_value = response, '' - self.assertRaises(exceptions.InvalidHTTPResponseHeader, - self.client.get, 'fake_url') - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_no_microverion_header_in_response(self, mock_request): - response = fake_http.fake_http_response( - headers={}, - ) - mock_request.return_value = response, '' - self.assertRaises(exceptions.InvalidHTTPResponseHeader, - self.client.get, 'fake_url') - - -class DummyServiceClient1(base_compute_client.BaseComputeClient): - schema_versions_info = [ - {'min': None, 'max': '2.1', 'schema': 'schemav21'}, - {'min': '2.2', 'max': '2.9', 'schema': 'schemav22'}, - {'min': '2.10', 'max': None, 'schema': 'schemav210'}] - - def return_selected_schema(self): - return self.get_schema(self.schema_versions_info) - - -class TestSchemaVersionsNone(base.BaseServiceTest): - api_microversion = None - expected_schema = 'schemav21' - - def setUp(self): - super(TestSchemaVersionsNone, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = DummyServiceClient1(fake_auth, 'compute', 'regionOne') - base_compute_client.COMPUTE_MICROVERSION = self.api_microversion - - def tearDown(self): - super(TestSchemaVersionsNone, self).tearDown() - base_compute_client.COMPUTE_MICROVERSION = None - - def test_schema(self): - self.assertEqual(self.expected_schema, - self.client.return_selected_schema()) - - -class TestSchemaVersionsV21(TestSchemaVersionsNone): - api_microversion = '2.1' - expected_schema = 'schemav21' - - -class TestSchemaVersionsV22(TestSchemaVersionsNone): - api_microversion = '2.2' - expected_schema = 'schemav22' - - -class TestSchemaVersionsV25(TestSchemaVersionsNone): - api_microversion = '2.5' - expected_schema = 'schemav22' - - -class TestSchemaVersionsV29(TestSchemaVersionsNone): - api_microversion = '2.9' - expected_schema = 'schemav22' - - -class TestSchemaVersionsV210(TestSchemaVersionsNone): - api_microversion = '2.10' - expected_schema = 'schemav210' - - -class TestSchemaVersionsLatest(TestSchemaVersionsNone): - api_microversion = 'latest' - expected_schema = 'schemav210' - - -class DummyServiceClient2(base_compute_client.BaseComputeClient): - schema_versions_info = [ - {'min': None, 'max': '2.1', 'schema': 'schemav21'}, - {'min': '2.2', 'max': '2.9', 'schema': 'schemav22'}] - - def return_selected_schema(self): - return self.get_schema(self.schema_versions_info) - - -class TestSchemaVersionsNotFound(base.BaseServiceTest): - api_microversion = '2.10' - expected_schema = 'schemav210' - - def setUp(self): - super(TestSchemaVersionsNotFound, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = DummyServiceClient2(fake_auth, 'compute', 'regionOne') - base_compute_client.COMPUTE_MICROVERSION = self.api_microversion - - def tearDown(self): - super(TestSchemaVersionsNotFound, self).tearDown() - base_compute_client.COMPUTE_MICROVERSION = None - - def test_schema(self): - self.assertRaises(exceptions.JSONSchemaNotFound, - self.client.return_selected_schema) - - -class TestClientWithoutMicroversionHeader(base.BaseServiceTest): - - def setUp(self): - super(TestClientWithoutMicroversionHeader, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = base_compute_client.BaseComputeClient( - fake_auth, 'compute', 'regionOne') - - def test_no_microverion_header(self): - header = self.client.get_headers() - self.assertNotIn('X-OpenStack-Nova-API-Version', header) - - def test_no_microverion_header_in_raw_request(self): - def raw_request(*args, **kwargs): - self.assertNotIn('X-OpenStack-Nova-API-Version', kwargs['headers']) - return (fake_http.fake_http_response({}, status=200), '') - - with mock.patch.object(rest_client.RestClient, - 'raw_request') as mock_get: - mock_get.side_effect = raw_request - self.client.get('fake_url') - - -class TestClientWithMicroversionHeader(base.BaseServiceTest): - - def setUp(self): - super(TestClientWithMicroversionHeader, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = base_compute_client.BaseComputeClient( - fake_auth, 'compute', 'regionOne') - base_compute_client.COMPUTE_MICROVERSION = '2.2' - - def tearDown(self): - super(TestClientWithMicroversionHeader, self).tearDown() - base_compute_client.COMPUTE_MICROVERSION = None - - def test_microverion_header(self): - header = self.client.get_headers() - self.assertIn('X-OpenStack-Nova-API-Version', header) - self.assertEqual('2.2', - header['X-OpenStack-Nova-API-Version']) - - def test_microverion_header_in_raw_request(self): - def raw_request(*args, **kwargs): - self.assertIn('X-OpenStack-Nova-API-Version', kwargs['headers']) - self.assertEqual('2.2', - kwargs['headers']['X-OpenStack-Nova-API-Version']) - return (fake_http.fake_http_response( - headers={self.client.api_microversion_header_name: '2.2'}, - status=200), '') - - with mock.patch.object(rest_client.RestClient, - 'raw_request') as mock_get: - mock_get.side_effect = raw_request - self.client.get('fake_url') diff --git a/tempest/tests/lib/services/compute/test_certificates_client.py b/tempest/tests/lib/services/compute/test_certificates_client.py deleted file mode 100644 index 9faef6f47..000000000 --- a/tempest/tests/lib/services/compute/test_certificates_client.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.services.compute import certificates_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestCertificatesClient(base.BaseServiceTest): - - FAKE_CERTIFICATE = { - "certificate": { - "data": "-----BEGIN----MIICyzCCAjSgAwI----END CERTIFICATE-----\n", - "private_key": None - } - } - - def setUp(self): - super(TestCertificatesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = certificates_client.CertificatesClient( - fake_auth, 'compute', 'regionOne') - - def _test_show_certificate(self, bytes_body=False): - self.check_service_client_function( - self.client.show_certificate, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CERTIFICATE, - bytes_body, - certificate_id="fake-id") - - def test_show_certificate_with_str_body(self): - self._test_show_certificate() - - def test_show_certificate_with_bytes_body(self): - self._test_show_certificate(bytes_body=True) - - def _test_create_certificate(self, bytes_body=False): - cert = copy.deepcopy(self.FAKE_CERTIFICATE) - cert['certificate']['private_key'] = "my_private_key" - self.check_service_client_function( - self.client.create_certificate, - 'tempest.lib.common.rest_client.RestClient.post', - cert, - bytes_body) - - def test_create_certificate_with_str_body(self): - self._test_create_certificate() - - def test_create_certificate_with_bytes_body(self): - self._test_create_certificate(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_extensions_client.py b/tempest/tests/lib/services/compute/test_extensions_client.py deleted file mode 100644 index d7e217e52..000000000 --- a/tempest/tests/lib/services/compute/test_extensions_client.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import extensions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestExtensionsClient(base.BaseServiceTest): - - FAKE_SHOW_EXTENSION = { - "extension": { - "updated": "2011-06-09T00:00:00Z", - "name": "Multinic", - "links": [], - "namespace": - "http://docs.openstack.org/compute/ext/multinic/api/v1.1", - "alias": "NMN", - "description": u'\u2740(*\xb4\u25e1`*)\u2740' - } - } - - def setUp(self): - super(TestExtensionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = extensions_client.ExtensionsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_extensions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_extensions, - 'tempest.lib.common.rest_client.RestClient.get', - {"extensions": []}, - bytes_body) - - def test_list_extensions_with_str_body(self): - self._test_list_extensions() - - def test_list_extensions_with_bytes_body(self): - self._test_list_extensions(bytes_body=True) - - def _test_show_extension(self, bytes_body=False): - self.check_service_client_function( - self.client.show_extension, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SHOW_EXTENSION, - bytes_body, - extension_alias="NMN") - - def test_show_extension_with_str_body(self): - self._test_show_extension() - - def test_show_extension_with_bytes_body(self): - self._test_show_extension(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_fixedIPs_client.py b/tempest/tests/lib/services/compute/test_fixedIPs_client.py deleted file mode 100644 index 65bda45b8..000000000 --- a/tempest/tests/lib/services/compute/test_fixedIPs_client.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import fixed_ips_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestFixedIPsClient(base.BaseServiceTest): - FIXED_IP_INFO = {"fixed_ip": {"address": "10.0.0.1", - "cidr": "10.11.12.0/24", - "host": "localhost", - "hostname": "OpenStack"}} - - def setUp(self): - super(TestFixedIPsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.fixedIPsClient = (fixed_ips_client. - FixedIPsClient - (fake_auth, 'compute', - 'regionOne')) - - def _test_show_fixed_ip(self, bytes_body=False): - self.check_service_client_function( - self.fixedIPsClient.show_fixed_ip, - 'tempest.lib.common.rest_client.RestClient.get', - self.FIXED_IP_INFO, bytes_body, - status=200, fixed_ip='Identifier') - - def test_show_fixed_ip_with_str_body(self): - self._test_show_fixed_ip() - - def test_show_fixed_ip_with_bytes_body(self): - self._test_show_fixed_ip(True) - - def _test_reserve_fixed_ip(self, bytes_body=False): - self.check_service_client_function( - self.fixedIPsClient.reserve_fixed_ip, - 'tempest.lib.common.rest_client.RestClient.post', - {}, bytes_body, - status=202, fixed_ip='Identifier') - - def test_reserve_fixed_ip_with_str_body(self): - self._test_reserve_fixed_ip() - - def test_reserve_fixed_ip_with_bytes_body(self): - self._test_reserve_fixed_ip(True) diff --git a/tempest/tests/lib/services/compute/test_flavors_client.py b/tempest/tests/lib/services/compute/test_flavors_client.py deleted file mode 100644 index cbd17c688..000000000 --- a/tempest/tests/lib/services/compute/test_flavors_client.py +++ /dev/null @@ -1,255 +0,0 @@ -# Copyright 2015 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -import fixtures -from oslo_serialization import jsonutils as json - -from tempest.lib.services.compute import flavors_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -from tempest.tests.lib.services import base - - -class TestFlavorsClient(base.BaseServiceTest): - - FAKE_FLAVOR = { - "disk": 1, - "id": "1", - "links": [{ - "href": "http://openstack.example.com/v2/openstack/flavors/1", - "rel": "self"}, { - "href": "http://openstack.example.com/openstack/flavors/1", - "rel": "bookmark"}], - "name": "m1.tiny", - "ram": 512, - "swap": 1, - "vcpus": 1 - } - - EXTRA_SPECS = {"extra_specs": { - "key1": "value1", - "key2": "value2"} - } - - FAKE_FLAVOR_ACCESS = { - "flavor_id": "10", - "tenant_id": "1a951d988e264818afe520e78697dcbf" - } - - def setUp(self): - super(TestFlavorsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = flavors_client.FlavorsClient(fake_auth, - 'compute', 'regionOne') - - def _test_list_flavors(self, bytes_body=False): - flavor = copy.deepcopy(TestFlavorsClient.FAKE_FLAVOR) - # Remove extra attributes - for attribute in ('disk', 'vcpus', 'ram', 'swap'): - del flavor[attribute] - expected = {'flavors': [flavor]} - self.check_service_client_function( - self.client.list_flavors, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body) - - def test_list_flavors_str_body(self): - self._test_list_flavors(bytes_body=False) - - def test_list_flavors_byte_body(self): - self._test_list_flavors(bytes_body=True) - - def _test_show_flavor(self, bytes_body=False): - expected = {"flavor": TestFlavorsClient.FAKE_FLAVOR} - self.check_service_client_function( - self.client.show_flavor, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body, - flavor_id='fake-id') - - def test_show_flavor_str_body(self): - self._test_show_flavor(bytes_body=False) - - def test_show_flavor_byte_body(self): - self._test_show_flavor(bytes_body=True) - - def _test_create_flavor(self, bytes_body=False): - expected = {"flavor": TestFlavorsClient.FAKE_FLAVOR} - request = copy.deepcopy(TestFlavorsClient.FAKE_FLAVOR) - # The 'links' parameter should not be passed in - del request['links'] - self.check_service_client_function( - self.client.create_flavor, - 'tempest.lib.common.rest_client.RestClient.post', - expected, - bytes_body, - **request) - - def test_create_flavor_str_body(self): - self._test_create_flavor(bytes_body=False) - - def test_create_flavor__byte_body(self): - self._test_create_flavor(bytes_body=True) - - def test_delete_flavor(self): - self.check_service_client_function( - self.client.delete_flavor, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, flavor_id='c782b7a9-33cd-45f0-b795-7f87f456408b') - - def _test_is_resource_deleted(self, flavor_id, is_deleted=True, - bytes_body=False): - body = json.dumps({'flavors': [TestFlavorsClient.FAKE_FLAVOR]}) - if bytes_body: - body = body.encode('utf-8') - response = fake_http.fake_http_response({}, status=200), body - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.rest_client.RestClient.get', - return_value=response)) - self.assertEqual(is_deleted, - self.client.is_resource_deleted(flavor_id)) - - def test_is_resource_deleted_true_str_body(self): - self._test_is_resource_deleted('2', bytes_body=False) - - def test_is_resource_deleted_true_byte_body(self): - self._test_is_resource_deleted('2', bytes_body=True) - - def test_is_resource_deleted_false_str_body(self): - self._test_is_resource_deleted('1', is_deleted=False, bytes_body=False) - - def test_is_resource_deleted_false_byte_body(self): - self._test_is_resource_deleted('1', is_deleted=False, bytes_body=True) - - def _test_set_flavor_extra_spec(self, bytes_body=False): - self.check_service_client_function( - self.client.set_flavor_extra_spec, - 'tempest.lib.common.rest_client.RestClient.post', - TestFlavorsClient.EXTRA_SPECS, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6', - **TestFlavorsClient.EXTRA_SPECS) - - def test_set_flavor_extra_spec_str_body(self): - self._test_set_flavor_extra_spec(bytes_body=False) - - def test_set_flavor_extra_spec_byte_body(self): - self._test_set_flavor_extra_spec(bytes_body=True) - - def _test_list_flavor_extra_specs(self, bytes_body=False): - self.check_service_client_function( - self.client.list_flavor_extra_specs, - 'tempest.lib.common.rest_client.RestClient.get', - TestFlavorsClient.EXTRA_SPECS, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6') - - def test_list_flavor_extra_specs_str_body(self): - self._test_list_flavor_extra_specs(bytes_body=False) - - def test_list_flavor_extra_specs__byte_body(self): - self._test_list_flavor_extra_specs(bytes_body=True) - - def _test_show_flavor_extra_spec(self, bytes_body=False): - expected = {"key": "value"} - self.check_service_client_function( - self.client.show_flavor_extra_spec, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6', - key='key') - - def test_show_flavor_extra_spec_str_body(self): - self._test_show_flavor_extra_spec(bytes_body=False) - - def test_show_flavor_extra_spec__byte_body(self): - self._test_show_flavor_extra_spec(bytes_body=True) - - def _test_update_flavor_extra_spec(self, bytes_body=False): - expected = {"key1": "value"} - self.check_service_client_function( - self.client.update_flavor_extra_spec, - 'tempest.lib.common.rest_client.RestClient.put', - expected, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6', - key='key1', **expected) - - def test_update_flavor_extra_spec_str_body(self): - self._test_update_flavor_extra_spec(bytes_body=False) - - def test_update_flavor_extra_spec_byte_body(self): - self._test_update_flavor_extra_spec(bytes_body=True) - - def test_unset_flavor_extra_spec(self): - self.check_service_client_function( - self.client.unset_flavor_extra_spec, - 'tempest.lib.common.rest_client.RestClient.delete', {}, - flavor_id='c782b7a9-33cd-45f0-b795-7f87f456408b', key='key') - - def _test_list_flavor_access(self, bytes_body=False): - expected = {'flavor_access': [TestFlavorsClient.FAKE_FLAVOR_ACCESS]} - self.check_service_client_function( - self.client.list_flavor_access, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6') - - def test_list_flavor_access_str_body(self): - self._test_list_flavor_access(bytes_body=False) - - def test_list_flavor_access_byte_body(self): - self._test_list_flavor_access(bytes_body=True) - - def _test_add_flavor_access(self, bytes_body=False): - expected = { - "flavor_access": [TestFlavorsClient.FAKE_FLAVOR_ACCESS] - } - self.check_service_client_function( - self.client.add_flavor_access, - 'tempest.lib.common.rest_client.RestClient.post', - expected, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6', - tenant_id='1a951d988e264818afe520e78697dcbf') - - def test_add_flavor_access_str_body(self): - self._test_add_flavor_access(bytes_body=False) - - def test_add_flavor_access_byte_body(self): - self._test_add_flavor_access(bytes_body=True) - - def _test_remove_flavor_access(self, bytes_body=False): - expected = { - "flavor_access": [TestFlavorsClient.FAKE_FLAVOR_ACCESS] - } - self.check_service_client_function( - self.client.remove_flavor_access, - 'tempest.lib.common.rest_client.RestClient.post', - expected, - bytes_body, - flavor_id='10', - tenant_id='a6edd4d66ad04245b5d2d8716ecc91e3') - - def test_remove_flavor_access_str_body(self): - self._test_remove_flavor_access(bytes_body=False) - - def test_remove_flavor_access_byte_body(self): - self._test_remove_flavor_access(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py b/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py deleted file mode 100644 index b0c00f099..000000000 --- a/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import floating_ip_pools_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestFloatingIPPoolsClient(base.BaseServiceTest): - - FAKE_FLOATING_IP_POOLS = { - "floating_ip_pools": - [ - {"name": u'\u3042'}, - {"name": u'\u3044'} - ] - } - - def setUp(self): - super(TestFloatingIPPoolsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = floating_ip_pools_client.FloatingIPPoolsClient( - fake_auth, 'compute', 'regionOne') - - def test_list_floating_ip_pools_with_str_body(self): - self.check_service_client_function( - self.client.list_floating_ip_pools, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_FLOATING_IP_POOLS) - - def test_list_floating_ip_pools_with_bytes_body(self): - self.check_service_client_function( - self.client.list_floating_ip_pools, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_FLOATING_IP_POOLS, to_utf=True) diff --git a/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py b/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py deleted file mode 100644 index ace76f89a..000000000 --- a/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.tests.lib import fake_auth_provider - -from tempest.lib.services.compute import floating_ips_bulk_client -from tempest.tests.lib.services import base - - -class TestFloatingIPsBulkClient(base.BaseServiceTest): - - FAKE_FIP_BULK_LIST = {"floating_ip_info": [{ - "address": "10.10.10.1", - "instance_uuid": None, - "fixed_ip": None, - "interface": "eth0", - "pool": "nova", - "project_id": None - }, - { - "address": "10.10.10.2", - "instance_uuid": None, - "fixed_ip": None, - "interface": "eth0", - "pool": "nova", - "project_id": None - }]} - - def setUp(self): - super(TestFloatingIPsBulkClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = floating_ips_bulk_client.FloatingIPsBulkClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_floating_ips_bulk(self, bytes_body=False): - self.check_service_client_function( - self.client.list_floating_ips_bulk, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_FIP_BULK_LIST, - to_utf=bytes_body) - - def _test_create_floating_ips_bulk(self, bytes_body=False): - fake_fip_create_data = {"floating_ips_bulk_create": { - "ip_range": "192.168.1.0/24", "pool": "nova", "interface": "eth0"}} - self.check_service_client_function( - self.client.create_floating_ips_bulk, - 'tempest.lib.common.rest_client.RestClient.post', - fake_fip_create_data, - to_utf=bytes_body, - ip_range="192.168.1.0/24", pool="nova", interface="eth0") - - def _test_delete_floating_ips_bulk(self, bytes_body=False): - fake_fip_delete_data = {"floating_ips_bulk_delete": "192.168.1.0/24"} - self.check_service_client_function( - self.client.delete_floating_ips_bulk, - 'tempest.lib.common.rest_client.RestClient.put', - fake_fip_delete_data, - to_utf=bytes_body, - ip_range="192.168.1.0/24") - - def test_list_floating_ips_bulk_with_str_body(self): - self._test_list_floating_ips_bulk() - - def test_list_floating_ips_bulk_with_bytes_body(self): - self._test_list_floating_ips_bulk(True) - - def test_create_floating_ips_bulk_with_str_body(self): - self._test_create_floating_ips_bulk() - - def test_create_floating_ips_bulk_with_bytes_body(self): - self._test_create_floating_ips_bulk(True) - - def test_delete_floating_ips_bulk_with_str_body(self): - self._test_delete_floating_ips_bulk() - - def test_delete_floating_ips_bulk_with_bytes_body(self): - self._test_delete_floating_ips_bulk(True) diff --git a/tempest/tests/lib/services/compute/test_floating_ips_client.py b/tempest/tests/lib/services/compute/test_floating_ips_client.py deleted file mode 100644 index 950f9ce7b..000000000 --- a/tempest/tests/lib/services/compute/test_floating_ips_client.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2015 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures - -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import floating_ips_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestFloatingIpsClient(base.BaseServiceTest): - - floating_ip = {"fixed_ip": None, - "id": "46d61064-13ba-4bf0-9557-69de824c3d6f", - "instance_id": "a1daa443-a6bb-463e-aea2-104b7d912eb8", - "ip": "10.10.10.1", - "pool": "nova"} - - def setUp(self): - super(TestFloatingIpsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = floating_ips_client.FloatingIPsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_floating_ips(self, bytes_body=False): - expected = {'floating_ips': [TestFloatingIpsClient.floating_ip]} - self.check_service_client_function( - self.client.list_floating_ips, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body) - - def test_list_floating_ips_str_body(self): - self._test_list_floating_ips(bytes_body=False) - - def test_list_floating_ips_byte_body(self): - self._test_list_floating_ips(bytes_body=True) - - def _test_show_floating_ip(self, bytes_body=False): - expected = {"floating_ip": TestFloatingIpsClient.floating_ip} - self.check_service_client_function( - self.client.show_floating_ip, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body, - floating_ip_id='a1daa443-a6bb-463e-aea2-104b7d912eb8') - - def test_show_floating_ip_str_body(self): - self._test_show_floating_ip(bytes_body=False) - - def test_show_floating_ip_byte_body(self): - self._test_show_floating_ip(bytes_body=True) - - def _test_create_floating_ip(self, bytes_body=False): - expected = {"floating_ip": TestFloatingIpsClient.floating_ip} - self.check_service_client_function( - self.client.create_floating_ip, - 'tempest.lib.common.rest_client.RestClient.post', - expected, - bytes_body, - pool_name='nova') - - def test_create_floating_ip_str_body(self): - self._test_create_floating_ip(bytes_body=False) - - def test_create_floating_ip_byte_body(self): - self._test_create_floating_ip(bytes_body=True) - - def test_delete_floating_ip(self): - self.check_service_client_function( - self.client.delete_floating_ip, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, floating_ip_id='fake-id') - - def test_associate_floating_ip_to_server(self): - self.check_service_client_function( - self.client.associate_floating_ip_to_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, status=202, floating_ip='10.10.10.1', - server_id='c782b7a9-33cd-45f0-b795-7f87f456408b') - - def test_disassociate_floating_ip_from_server(self): - self.check_service_client_function( - self.client.disassociate_floating_ip_from_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, status=202, floating_ip='10.10.10.1', - server_id='c782b7a9-33cd-45f0-b795-7f87f456408b') - - def test_is_resource_deleted_true(self): - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.compute.floating_ips_client.' - 'FloatingIPsClient.show_floating_ip', - side_effect=lib_exc.NotFound())) - self.assertTrue(self.client.is_resource_deleted('fake-id')) - - def test_is_resource_deleted_false(self): - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.compute.floating_ips_client.' - 'FloatingIPsClient.show_floating_ip', - return_value={"floating_ip": TestFloatingIpsClient.floating_ip})) - self.assertFalse(self.client.is_resource_deleted('fake-id')) diff --git a/tempest/tests/lib/services/compute/test_hosts_client.py b/tempest/tests/lib/services/compute/test_hosts_client.py deleted file mode 100644 index 78537c297..000000000 --- a/tempest/tests/lib/services/compute/test_hosts_client.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import hosts_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestHostsClient(base.BaseServiceTest): - FAKE_HOST_DATA = { - "host": { - "resource": { - "cpu": 1, - "disk_gb": 1028, - "host": "c1a7de0ac9d94e4baceae031d05caae3", - "memory_mb": 8192, - "project": "(total)" - } - }, - "hosts": { - "host_name": "c1a7de0ac9d94e4baceae031d05caae3", - "service": "conductor", - "zone": "internal" - }, - "enable_hosts": { - "host": "65c5d5b7e3bd44308e67fc50f362aee6", - "maintenance_mode": "off_maintenance", - "status": "enabled" - } - } - - FAKE_CONTROL_DATA = { - "shutdown": { - "host": "c1a7de0ac9d94e4baceae031d05caae3", - "power_action": "shutdown" - }, - "startup": { - "host": "c1a7de0ac9d94e4baceae031d05caae3", - "power_action": "startup" - }, - "reboot": { - "host": "c1a7de0ac9d94e4baceae031d05caae3", - "power_action": "reboot" - }} - - HOST_DATA = {'host': [FAKE_HOST_DATA['host']]} - HOSTS_DATA = {'hosts': [FAKE_HOST_DATA['hosts']]} - ENABLE_HOST_DATA = FAKE_HOST_DATA['enable_hosts'] - HOST_ID = "c1a7de0ac9d94e4baceae031d05caae3" - TEST_HOST_DATA = { - "status": "enable", - "maintenance_mode": "disable" - } - - def setUp(self): - super(TestHostsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = hosts_client.HostsClient(fake_auth, 'compute', - 'regionOne') - self.params = {'hostname': self.HOST_ID} - self.func2mock = { - 'get': 'tempest.lib.common.rest_client.RestClient.get', - 'put': 'tempest.lib.common.rest_client.RestClient.put'} - - def _test_host_data(self, test_type='list', bytes_body=False): - expected_resp = self.HOST_DATA - if test_type != 'list': - function_call = self.client.show_host - else: - expected_resp = self.HOSTS_DATA - function_call = self.client.list_hosts - self.params = {'host_name': self.HOST_ID} - - self.check_service_client_function( - function_call, self.func2mock['get'], - expected_resp, bytes_body, - 200, **self.params) - - def _test_update_hosts(self, bytes_body=False): - expected_resp = self.ENABLE_HOST_DATA - self.check_service_client_function( - self.client.update_host, self.func2mock['put'], - expected_resp, bytes_body, - 200, **self.params) - - def _test_control_host(self, control_op='reboot', bytes_body=False): - if control_op == 'start': - expected_resp = self.FAKE_CONTROL_DATA['startup'] - function_call = self.client.startup_host - elif control_op == 'stop': - expected_resp = self.FAKE_CONTROL_DATA['shutdown'] - function_call = self.client.shutdown_host - else: - expected_resp = self.FAKE_CONTROL_DATA['reboot'] - function_call = self.client.reboot_host - - self.check_service_client_function( - function_call, self.func2mock['get'], - expected_resp, bytes_body, - 200, **self.params) - - def test_show_host_with_str_body(self): - self._test_host_data('show') - - def test_show_host_with_bytes_body(self): - self._test_host_data('show', True) - - def test_list_host_with_str_body(self): - self._test_host_data() - - def test_list_host_with_bytes_body(self): - self._test_host_data(bytes_body=True) - - def test_start_host_with_str_body(self): - self._test_control_host('start') - - def test_start_host_with_bytes_body(self): - self._test_control_host('start', True) - - def test_stop_host_with_str_body(self): - self._test_control_host('stop') - - def test_stop_host_with_bytes_body(self): - self._test_control_host('stop', True) - - def test_reboot_host_with_str_body(self): - self._test_control_host('reboot') - - def test_reboot_host_with_bytes_body(self): - self._test_control_host('reboot', True) - - def test_update_host_with_str_body(self): - self._test_update_hosts() - - def test_update_host_with_bytes_body(self): - self._test_update_hosts(True) diff --git a/tempest/tests/lib/services/compute/test_hypervisor_client.py b/tempest/tests/lib/services/compute/test_hypervisor_client.py deleted file mode 100644 index 89eb698a4..000000000 --- a/tempest/tests/lib/services/compute/test_hypervisor_client.py +++ /dev/null @@ -1,167 +0,0 @@ -# Copyright 2015 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import hypervisor_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestHypervisorClient(base.BaseServiceTest): - - hypervisor_id = "1" - hypervisor_name = "hyper.hostname.com" - - def setUp(self): - super(TestHypervisorClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = hypervisor_client.HypervisorClient( - fake_auth, 'compute', 'regionOne') - - def test_list_hypervisor_str_body(self): - self._test_list_hypervisor(bytes_body=False) - - def test_list_hypervisor_byte_body(self): - self._test_list_hypervisor(bytes_body=True) - - def _test_list_hypervisor(self, bytes_body=False): - expected = {"hypervisors": [{ - "id": 1, - "hypervisor_hostname": "hypervisor1.hostname.com"}, - { - "id": 2, - "hypervisor_hostname": "hypervisor2.hostname.com"}]} - self.check_service_client_function( - self.client.list_hypervisors, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body) - - def test_show_hypervisor_str_body(self): - self._test_show_hypervisor(bytes_body=False) - - def test_show_hypervisor_byte_body(self): - self._test_show_hypervisor(bytes_body=True) - - def _test_show_hypervisor(self, bytes_body=False): - expected = {"hypervisor": { - "cpu_info": "?", - "current_workload": 0, - "disk_available_least": 1, - "host_ip": "10.10.10.10", - "free_disk_gb": 1028, - "free_ram_mb": 7680, - "hypervisor_hostname": "fake-mini", - "hypervisor_type": "fake", - "hypervisor_version": 1, - "id": 1, - "local_gb": 1028, - "local_gb_used": 0, - "memory_mb": 8192, - "memory_mb_used": 512, - "running_vms": 0, - "service": { - "host": "fake_host", - "id": 2}, - "vcpus": 1, - "vcpus_used": 0}} - self.check_service_client_function( - self.client.show_hypervisor, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, - hypervisor_id=self.hypervisor_id) - - def test_list_servers_on_hypervisor_str_body(self): - self._test_list_servers_on_hypervisor(bytes_body=False) - - def test_list_servers_on_hypervisor_byte_body(self): - self._test_list_servers_on_hypervisor(bytes_body=True) - - def _test_list_servers_on_hypervisor(self, bytes_body=False): - expected = {"hypervisors": [{ - "id": 1, - "hypervisor_hostname": "hyper.hostname.com", - "servers": [{ - "uuid": "e1ae8fc4-b72d-4c2f-a427-30dd420b6277", - "name": "instance-00000001"}, - { - "uuid": "e1ae8fc4-b72d-4c2f-a427-30dd42066666", - "name": "instance-00000002"} - ]} - ]} - self.check_service_client_function( - self.client.list_servers_on_hypervisor, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, - hypervisor_name=self.hypervisor_name) - - def test_show_hypervisor_statistics_str_body(self): - self._test_show_hypervisor_statistics(bytes_body=False) - - def test_show_hypervisor_statistics_byte_body(self): - self._test_show_hypervisor_statistics(bytes_body=True) - - def _test_show_hypervisor_statistics(self, bytes_body=False): - expected = { - "hypervisor_statistics": { - "count": 1, - "current_workload": 0, - "disk_available_least": 0, - "free_disk_gb": 1028, - "free_ram_mb": 7680, - "local_gb": 1028, - "local_gb_used": 0, - "memory_mb": 8192, - "memory_mb_used": 512, - "running_vms": 0, - "vcpus": 1, - "vcpus_used": 0}} - self.check_service_client_function( - self.client.show_hypervisor_statistics, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body) - - def test_show_hypervisor_uptime_str_body(self): - self._test_show_hypervisor_uptime(bytes_body=False) - - def test_show_hypervisor_uptime_byte_body(self): - self._test_show_hypervisor_uptime(bytes_body=True) - - def _test_show_hypervisor_uptime(self, bytes_body=False): - expected = { - "hypervisor": { - "hypervisor_hostname": "fake-mini", - "id": 1, - "uptime": (" 08:32:11 up 93 days, 18:25, 12 users, " - " load average: 0.20, 0.12, 0.14") - }} - self.check_service_client_function( - self.client.show_hypervisor_uptime, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, - hypervisor_id=self.hypervisor_id) - - def test_search_hypervisor_str_body(self): - self._test_search_hypervisor(bytes_body=False) - - def test_search_hypervisor_byte_body(self): - self._test_search_hypervisor(bytes_body=True) - - def _test_search_hypervisor(self, bytes_body=False): - expected = {"hypervisors": [{ - "id": 2, - "hypervisor_hostname": "hyper.hostname.com"}]} - self.check_service_client_function( - self.client.search_hypervisor, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, - hypervisor_name=self.hypervisor_name) diff --git a/tempest/tests/lib/services/compute/test_images_client.py b/tempest/tests/lib/services/compute/test_images_client.py deleted file mode 100644 index c2c3b7618..000000000 --- a/tempest/tests/lib/services/compute/test_images_client.py +++ /dev/null @@ -1,264 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -import fixtures -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import images_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestImagesClient(base.BaseServiceTest): - # Data Dictionaries used for testing # - FAKE_IMAGE_METADATA = { - "list": - {"metadata": { - "auto_disk_config": "True", - "Label": "Changed" - }}, - "set_item": - {"meta": { - "auto_disk_config": "True" - }}, - "show_item": - {"meta": { - "kernel_id": "nokernel", - }}, - "update": - {"metadata": { - "kernel_id": "False", - "Label": "UpdatedImage" - }}, - "set": - {"metadata": { - "Label": "Changed", - "auto_disk_config": "True" - }}, - "delete_item": {} - } - - FAKE_IMAGE_DATA = { - "list": - {"images": [ - {"id": "70a599e0-31e7-49b7-b260-868f441e862b", - "links": [ - {"href": "http://openstack.example.com/v2/openstack" + - "/images/70a599e0-31e7-49b7-b260-868f441e862b", - "rel": "self" - } - ], - "name": "fakeimage7" - }]}, - "show": {"image": { - "created": "2011-01-01T01:02:03Z", - "id": "70a599e0-31e7-49b7-b260-868f441e862b", - "links": [ - { - "href": "http://openstack.example.com/v2/openstack" + - "/images/70a599e0-31e7-49b7-b260-868f441e862b", - "rel": "self" - }, - ], - "metadata": { - "architecture": "x86_64", - "auto_disk_config": "True", - "kernel_id": "nokernel", - "ramdisk_id": "nokernel" - }, - "minDisk": 0, - "minRam": 0, - "name": "fakeimage7", - "progress": 100, - "status": "ACTIVE", - "updated": "2011-01-01T01:02:03Z"}}, - "create": {}, - "delete": {} - } - func2mock = { - 'get': 'tempest.lib.common.rest_client.RestClient.get', - 'post': 'tempest.lib.common.rest_client.RestClient.post', - 'put': 'tempest.lib.common.rest_client.RestClient.put', - 'delete': 'tempest.lib.common.rest_client.RestClient.delete'} - # Variable definition - FAKE_IMAGE_ID = FAKE_IMAGE_DATA['show']['image']['id'] - FAKE_SERVER_ID = "80a599e0-31e7-49b7-b260-868f441e343f" - FAKE_CREATE_INFO = {'location': 'None'} - FAKE_METADATA = FAKE_IMAGE_METADATA['show_item']['meta'] - - def setUp(self): - super(TestImagesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = images_client.ImagesClient(fake_auth, - "compute", "regionOne") - - def _test_image_operation(self, operation="delete", bytes_body=False): - response_code = 200 - mock_operation = self.func2mock['get'] - expected_op = self.FAKE_IMAGE_DATA[operation] - params = {"image_id": self.FAKE_IMAGE_ID} - headers = None - if operation == 'list': - function = self.client.list_images - elif operation == 'show': - function = self.client.show_image - elif operation == 'create': - function = self.client.create_image - mock_operation = self.func2mock['post'] - params = {"server_id": self.FAKE_SERVER_ID} - response_code = 202 - headers = { - 'connection': 'keep-alive', - 'content-length': '0', - 'content-type': 'application/json', - 'status': '202', - 'x-compute-request-id': 'req-fake', - 'vary': 'accept-encoding', - 'x-openstack-nova-api-version': 'v2.1', - 'date': '13 Oct 2015 05:55:36 GMT', - 'location': 'http://fake.com/images/fake' - } - else: - function = self.client.delete_image - mock_operation = self.func2mock['delete'] - response_code = 204 - - self.check_service_client_function( - function, mock_operation, expected_op, - bytes_body, response_code, headers, **params) - - def _test_image_metadata(self, operation="set_item", bytes_body=False): - response_code = 200 - expected_op = self.FAKE_IMAGE_METADATA[operation] - if operation == 'list': - function = self.client.list_image_metadata - mock_operation = self.func2mock['get'] - params = {"image_id": self.FAKE_IMAGE_ID} - - elif operation == 'set': - function = self.client.set_image_metadata - mock_operation = self.func2mock['put'] - params = {"image_id": "_dummy_data", - "meta": self.FAKE_METADATA} - - elif operation == 'update': - function = self.client.update_image_metadata - mock_operation = self.func2mock['post'] - params = {"image_id": self.FAKE_IMAGE_ID, - "meta": self.FAKE_METADATA} - - elif operation == 'show_item': - mock_operation = self.func2mock['get'] - function = self.client.show_image_metadata_item - params = {"image_id": self.FAKE_IMAGE_ID, - "key": "123"} - - elif operation == 'delete_item': - function = self.client.delete_image_metadata_item - mock_operation = self.func2mock['delete'] - response_code = 204 - params = {"image_id": self.FAKE_IMAGE_ID, - "key": "123"} - - else: - function = self.client.set_image_metadata_item - mock_operation = self.func2mock['put'] - params = {"image_id": self.FAKE_IMAGE_ID, - "key": "123", - "meta": self.FAKE_METADATA} - - self.check_service_client_function( - function, mock_operation, expected_op, - bytes_body, response_code, **params) - - def _test_resource_deleted(self, bytes_body=False): - params = {"id": self.FAKE_IMAGE_ID} - expected_op = self.FAKE_IMAGE_DATA['show'] - self.useFixture(fixtures.MockPatch('tempest.lib.services.compute' - '.images_client.ImagesClient.show_image', - side_effect=lib_exc.NotFound)) - self.assertEqual(True, self.client.is_resource_deleted(**params)) - tempdata = copy.deepcopy(self.FAKE_IMAGE_DATA['show']) - tempdata['image']['id'] = None - self.useFixture(fixtures.MockPatch('tempest.lib.services.compute' - '.images_client.ImagesClient.show_image', - return_value=expected_op)) - self.assertEqual(False, self.client.is_resource_deleted(**params)) - - def test_list_images_with_str_body(self): - self._test_image_operation('list') - - def test_list_images_with_bytes_body(self): - self._test_image_operation('list', True) - - def test_show_image_with_str_body(self): - self._test_image_operation('show') - - def test_show_image_with_bytes_body(self): - self._test_image_operation('show', True) - - def test_create_image_with_str_body(self): - self._test_image_operation('create') - - def test_create_image_with_bytes_body(self): - self._test_image_operation('create', True) - - def test_delete_image_with_str_body(self): - self._test_image_operation('delete') - - def test_delete_image_with_bytes_body(self): - self._test_image_operation('delete', True) - - def test_list_image_metadata_with_str_body(self): - self._test_image_metadata('list') - - def test_list_image_metadata_with_bytes_body(self): - self._test_image_metadata('list', True) - - def test_set_image_metadata_with_str_body(self): - self._test_image_metadata('set') - - def test_set_image_metadata_with_bytes_body(self): - self._test_image_metadata('set', True) - - def test_update_image_metadata_with_str_body(self): - self._test_image_metadata('update') - - def test_update_image_metadata_with_bytes_body(self): - self._test_image_metadata('update', True) - - def test_set_image_metadata_item_with_str_body(self): - self._test_image_metadata() - - def test_set_image_metadata_item_with_bytes_body(self): - self._test_image_metadata(bytes_body=True) - - def test_show_image_metadata_item_with_str_body(self): - self._test_image_metadata('show_item') - - def test_show_image_metadata_item_with_bytes_body(self): - self._test_image_metadata('show_item', True) - - def test_delete_image_metadata_item_with_str_body(self): - self._test_image_metadata('delete_item') - - def test_delete_image_metadata_item_with_bytes_body(self): - self._test_image_metadata('delete_item', True) - - def test_resource_delete_with_str_body(self): - self._test_resource_deleted() - - def test_resource_delete_with_bytes_body(self): - self._test_resource_deleted(True) diff --git a/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py b/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py deleted file mode 100644 index 21764ff5e..000000000 --- a/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import datetime - -from tempest.lib.services.compute import instance_usage_audit_log_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestInstanceUsagesAuditLogClient(base.BaseServiceTest): - - FAKE_AUDIT_LOG = { - "hosts_not_run": [ - "f4eb7cfd155f4574967f8b55a7faed75" - ], - "log": {}, - "num_hosts": 1, - "num_hosts_done": 0, - "num_hosts_not_run": 1, - "num_hosts_running": 0, - "overall_status": "0 of 1 hosts done. 0 errors.", - "period_beginning": "2012-12-01 00:00:00", - "period_ending": "2013-01-01 00:00:00", - "total_errors": 0, - "total_instances": 0 - } - - def setUp(self): - super(TestInstanceUsagesAuditLogClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = (instance_usage_audit_log_client. - InstanceUsagesAuditLogClient(fake_auth, 'compute', - 'regionOne')) - - def _test_list_instance_usage_audit_logs(self, bytes_body=False): - self.check_service_client_function( - self.client.list_instance_usage_audit_logs, - 'tempest.lib.common.rest_client.RestClient.get', - {"instance_usage_audit_logs": self.FAKE_AUDIT_LOG}, - bytes_body) - - def test_list_instance_usage_audit_logs_with_str_body(self): - self._test_list_instance_usage_audit_logs() - - def test_list_instance_usage_audit_logs_with_bytes_body(self): - self._test_list_instance_usage_audit_logs(bytes_body=True) - - def _test_show_instance_usage_audit_log(self, bytes_body=False): - before_time = datetime.datetime(2012, 12, 1, 0, 0) - self.check_service_client_function( - self.client.show_instance_usage_audit_log, - 'tempest.lib.common.rest_client.RestClient.get', - {"instance_usage_audit_log": self.FAKE_AUDIT_LOG}, - bytes_body, - time_before=before_time) - - def test_show_instance_usage_audit_log_with_str_body(self): - self._test_show_instance_usage_audit_log() - - def test_show_network_with_bytes_body_with_bytes_body(self): - self._test_show_instance_usage_audit_log(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_interfaces_client.py b/tempest/tests/lib/services/compute/test_interfaces_client.py deleted file mode 100644 index 4d781033c..000000000 --- a/tempest/tests/lib/services/compute/test_interfaces_client.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import interfaces_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestInterfacesClient(base.BaseServiceTest): - # Data Values to be used for testing # - FAKE_INTERFACE_DATA = { - "fixed_ips": [{ - "ip_address": "192.168.1.1", - "subnet_id": "f8a6e8f8-c2ec-497c-9f23-da9616de54ef" - }], - "mac_addr": "fa:16:3e:4c:2c:30", - "net_id": "3cb9bc59-5699-4588-a4b1-b87f96708bc6", - "port_id": "ce531f90-199f-48c0-816c-13e38010b442", - "port_state": "ACTIVE"} - - FAKE_SHOW_DATA = { - "interfaceAttachment": FAKE_INTERFACE_DATA} - FAKE_LIST_DATA = { - "interfaceAttachments": [FAKE_INTERFACE_DATA]} - - FAKE_SERVER_ID = "ec14c864-096e-4e27-bb8a-2c2b4dc6f3f5" - FAKE_PORT_ID = FAKE_SHOW_DATA['interfaceAttachment']['port_id'] - func2mock = { - 'delete': 'tempest.lib.common.rest_client.RestClient.delete', - 'get': 'tempest.lib.common.rest_client.RestClient.get', - 'post': 'tempest.lib.common.rest_client.RestClient.post'} - - def setUp(self): - super(TestInterfacesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = interfaces_client.InterfacesClient(fake_auth, - "compute", - "regionOne") - - def _test_interface_operation(self, operation="create", bytes_body=False): - response_code = 200 - expected_op = self.FAKE_SHOW_DATA - mock_operation = self.func2mock['get'] - params = {'server_id': self.FAKE_SERVER_ID, - 'port_id': self.FAKE_PORT_ID} - if operation == 'list': - expected_op = self.FAKE_LIST_DATA - function = self.client.list_interfaces - params = {'server_id': self.FAKE_SERVER_ID} - elif operation == 'show': - function = self.client.show_interface - elif operation == 'delete': - expected_op = {} - mock_operation = self.func2mock['delete'] - function = self.client.delete_interface - response_code = 202 - else: - function = self.client.create_interface - mock_operation = self.func2mock['post'] - - self.check_service_client_function( - function, mock_operation, expected_op, - bytes_body, response_code, **params) - - def test_list_interfaces_with_str_body(self): - self._test_interface_operation('list') - - def test_list_interfaces_with_bytes_body(self): - self._test_interface_operation('list', True) - - def test_show_interface_with_str_body(self): - self._test_interface_operation('show') - - def test_show_interface_with_bytes_body(self): - self._test_interface_operation('show', True) - - def test_delete_interface_with_str_body(self): - self._test_interface_operation('delete') - - def test_delete_interface_with_bytes_body(self): - self._test_interface_operation('delete', True) - - def test_create_interface_with_str_body(self): - self._test_interface_operation() - - def test_create_interface_with_bytes_body(self): - self._test_interface_operation(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_keypairs_client.py b/tempest/tests/lib/services/compute/test_keypairs_client.py deleted file mode 100644 index ed3b9dd7f..000000000 --- a/tempest/tests/lib/services/compute/test_keypairs_client.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.services.compute import keypairs_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestKeyPairsClient(base.BaseServiceTest): - - FAKE_KEYPAIR = {"keypair": { - "public_key": "ssh-rsa foo Generated-by-Nova", - "name": u'\u2740(*\xb4\u25e1`*)\u2740', - "user_id": "525d55f98980415ba98e634972fa4a10", - "fingerprint": "76:24:66:49:d7:ca:6e:5c:77:ea:8e:bb:9c:15:5f:98" - }} - - def setUp(self): - super(TestKeyPairsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = keypairs_client.KeyPairsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_keypairs(self, bytes_body=False): - self.check_service_client_function( - self.client.list_keypairs, - 'tempest.lib.common.rest_client.RestClient.get', - {"keypairs": []}, - bytes_body) - - def test_list_keypairs_with_str_body(self): - self._test_list_keypairs() - - def test_list_keypairs_with_bytes_body(self): - self._test_list_keypairs(bytes_body=True) - - def _test_show_keypair(self, bytes_body=False): - fake_keypair = copy.deepcopy(self.FAKE_KEYPAIR) - fake_keypair["keypair"].update({ - "deleted": False, - "created_at": "2015-07-22T04:53:52.000000", - "updated_at": None, - "deleted_at": None, - "id": 1 - }) - - self.check_service_client_function( - self.client.show_keypair, - 'tempest.lib.common.rest_client.RestClient.get', - fake_keypair, - bytes_body, - keypair_name="test") - - def test_show_keypair_with_str_body(self): - self._test_show_keypair() - - def test_show_keypair_with_bytes_body(self): - self._test_show_keypair(bytes_body=True) - - def _test_create_keypair(self, bytes_body=False): - fake_keypair = copy.deepcopy(self.FAKE_KEYPAIR) - fake_keypair["keypair"].update({"private_key": "foo"}) - - self.check_service_client_function( - self.client.create_keypair, - 'tempest.lib.common.rest_client.RestClient.post', - fake_keypair, - bytes_body, - name="test") - - def test_create_keypair_with_str_body(self): - self._test_create_keypair() - - def test_create_keypair_with_bytes_body(self): - self._test_create_keypair(bytes_body=True) - - def test_delete_keypair(self): - self.check_service_client_function( - self.client.delete_keypair, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, keypair_name='test') diff --git a/tempest/tests/lib/services/compute/test_limits_client.py b/tempest/tests/lib/services/compute/test_limits_client.py deleted file mode 100644 index 5f3fa5a9c..000000000 --- a/tempest/tests/lib/services/compute/test_limits_client.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import limits_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestLimitsClient(base.BaseServiceTest): - - def setUp(self): - super(TestLimitsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = limits_client.LimitsClient( - fake_auth, 'compute', 'regionOne') - - def _test_show_limits(self, bytes_body=False): - expected = { - "limits": { - "rate": [], - "absolute": { - "maxServerMeta": 128, - "maxPersonality": 5, - "totalServerGroupsUsed": 0, - "maxImageMeta": 128, - "maxPersonalitySize": 10240, - "maxServerGroups": 10, - "maxSecurityGroupRules": 20, - "maxTotalKeypairs": 100, - "totalCoresUsed": 0, - "totalRAMUsed": 0, - "totalInstancesUsed": 0, - "maxSecurityGroups": 10, - "totalFloatingIpsUsed": 0, - "maxTotalCores": 20, - "totalSecurityGroupsUsed": 0, - "maxTotalFloatingIps": 10, - "maxTotalInstances": 10, - "maxTotalRAMSize": 51200, - "maxServerGroupMembers": 10 - } - } - } - - self.check_service_client_function( - self.client.show_limits, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body) - - def test_show_limits_with_str_body(self): - self._test_show_limits() - - def test_show_limits_with_bytes_body(self): - self._test_show_limits(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_migrations_client.py b/tempest/tests/lib/services/compute/test_migrations_client.py deleted file mode 100644 index be62c0cc6..000000000 --- a/tempest/tests/lib/services/compute/test_migrations_client.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import migrations_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestMigrationsClient(base.BaseServiceTest): - FAKE_MIGRATION_INFO = {"migrations": [{ - "created_at": "2012-10-29T13:42:02", - "dest_compute": "compute2", - "dest_host": "1.2.3.4", - "dest_node": "node2", - "id": 1234, - "instance_uuid": "e9e4fdd7-f956-44ff-bfeb-d654a96ab3a2", - "new_instance_type_id": 2, - "old_instance_type_id": 1, - "source_compute": "compute1", - "source_node": "node1", - "status": "finished", - "updated_at": "2012-10-29T13:42:02"}]} - - def setUp(self): - super(TestMigrationsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.mg_client_obj = migrations_client.MigrationsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_migrations(self, bytes_body=False): - self.check_service_client_function( - self.mg_client_obj.list_migrations, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_MIGRATION_INFO, - bytes_body) - - def test_list_migration_with_str_body(self): - self._test_list_migrations() - - def test_list_migration_with_bytes_body(self): - self._test_list_migrations(True) diff --git a/tempest/tests/lib/services/compute/test_networks_client.py b/tempest/tests/lib/services/compute/test_networks_client.py deleted file mode 100644 index 1908b5754..000000000 --- a/tempest/tests/lib/services/compute/test_networks_client.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import networks_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNetworksClient(base.BaseServiceTest): - - FAKE_NETWORK = { - "bridge": None, - "vpn_public_port": None, - "dhcp_start": None, - "bridge_interface": None, - "share_address": None, - "updated_at": None, - "id": "34d5ae1e-5659-49cf-af80-73bccd7d7ad3", - "cidr_v6": None, - "deleted_at": None, - "gateway": None, - "rxtx_base": None, - "label": u'30d7', - "priority": None, - "project_id": None, - "vpn_private_address": None, - "deleted": None, - "vlan": None, - "broadcast": None, - "netmask": None, - "injected": None, - "cidr": None, - "vpn_public_address": None, - "multi_host": None, - "enable_dhcp": None, - "dns2": None, - "created_at": None, - "host": None, - "mtu": None, - "gateway_v6": None, - "netmask_v6": None, - "dhcp_server": None, - "dns1": None - } - - network_id = "34d5ae1e-5659-49cf-af80-73bccd7d7ad3" - - FAKE_NETWORKS = [FAKE_NETWORK] - - def setUp(self): - super(TestNetworksClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = networks_client.NetworksClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_networks(self, bytes_body=False): - fake_list = {"networks": self.FAKE_NETWORKS} - self.check_service_client_function( - self.client.list_networks, - 'tempest.lib.common.rest_client.RestClient.get', - fake_list, - bytes_body) - - def test_list_networks_with_str_body(self): - self._test_list_networks() - - def test_list_networks_with_bytes_body(self): - self._test_list_networks(bytes_body=True) - - def _test_show_network(self, bytes_body=False): - self.check_service_client_function( - self.client.show_network, - 'tempest.lib.common.rest_client.RestClient.get', - {"network": self.FAKE_NETWORK}, - bytes_body, - network_id=self.network_id - ) - - def test_show_network_with_str_body(self): - self._test_show_network() - - def test_show_network_with_bytes_body(self): - self._test_show_network(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_quota_classes_client.py b/tempest/tests/lib/services/compute/test_quota_classes_client.py deleted file mode 100644 index 22d8b91a3..000000000 --- a/tempest/tests/lib/services/compute/test_quota_classes_client.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.services.compute import quota_classes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotaClassesClient(base.BaseServiceTest): - - FAKE_QUOTA_CLASS_SET = { - "injected_file_content_bytes": 10240, - "metadata_items": 128, - "server_group_members": 10, - "server_groups": 10, - "ram": 51200, - "floating_ips": 10, - "key_pairs": 100, - "id": u'\u2740(*\xb4\u25e1`*)\u2740', - "instances": 10, - "security_group_rules": 20, - "security_groups": 10, - "injected_files": 5, - "cores": 20, - "fixed_ips": -1, - "injected_file_path_bytes": 255, - } - - def setUp(self): - super(TestQuotaClassesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = quota_classes_client.QuotaClassesClient( - fake_auth, 'compute', 'regionOne') - - def _test_show_quota_class_set(self, bytes_body=False): - fake_body = {'quota_class_set': self.FAKE_QUOTA_CLASS_SET} - self.check_service_client_function( - self.client.show_quota_class_set, - 'tempest.lib.common.rest_client.RestClient.get', - fake_body, - bytes_body, - quota_class_id="test") - - def test_show_quota_class_set_with_str_body(self): - self._test_show_quota_class_set() - - def test_show_quota_class_set_with_bytes_body(self): - self._test_show_quota_class_set(bytes_body=True) - - def test_update_quota_class_set(self): - fake_quota_class_set = copy.deepcopy(self.FAKE_QUOTA_CLASS_SET) - fake_quota_class_set.pop("id") - fake_body = {'quota_class_set': fake_quota_class_set} - self.check_service_client_function( - self.client.update_quota_class_set, - 'tempest.lib.common.rest_client.RestClient.put', - fake_body, - quota_class_id="test") diff --git a/tempest/tests/lib/services/compute/test_quotas_client.py b/tempest/tests/lib/services/compute/test_quotas_client.py deleted file mode 100644 index bbb8eb7d2..000000000 --- a/tempest/tests/lib/services/compute/test_quotas_client.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.services.compute import quotas_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotasClient(base.BaseServiceTest): - - FAKE_QUOTA_SET = { - "quota_set": { - "injected_file_content_bytes": 10240, - "metadata_items": 128, - "server_group_members": 10, - "server_groups": 10, - "ram": 51200, - "floating_ips": 10, - "key_pairs": 100, - "id": "8421f7be61064f50b680465c07f334af", - "instances": 10, - "security_group_rules": 20, - "injected_files": 5, - "cores": 20, - "fixed_ips": -1, - "injected_file_path_bytes": 255, - "security_groups": 10} - } - - project_id = "8421f7be61064f50b680465c07f334af" - fake_user_id = "65f09168cbb04eb593f3138b63b67b67" - - def setUp(self): - super(TestQuotasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = quotas_client.QuotasClient( - fake_auth, 'compute', 'regionOne') - - def _get_quota_set(self, detail): - if not detail: - return self.FAKE_QUOTA_SET - fake_quota_set = {"quota_set": {}} - for key, val in self.FAKE_QUOTA_SET['quota_set'].items(): - fake_quota_set['quota_set'][key] = \ - {'limit': val, 'reserved': 0, 'in_use': 0} - fake_quota_set['quota_set']['id'] = "8421f7be61064f50b680465c07f334af" - return fake_quota_set - - def _test_show_quota_set(self, bytes_body=False, detail=False, - user_id=None): - if user_id: - self.check_service_client_function( - self.client.show_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self._get_quota_set(detail), - to_utf=bytes_body, - tenant_id=self.project_id, - detail=detail, - user_id=user_id) - else: - self.check_service_client_function( - self.client.show_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self._get_quota_set(detail), - to_utf=bytes_body, - tenant_id=self.project_id, - detail=detail) - - def test_show_quota_set_with_str_body(self): - self._test_show_quota_set() - - def test_show_quota_set_with_bytes_body(self): - self._test_show_quota_set(bytes_body=True) - - def test_show_quota_set_for_user_with_str_body(self): - self._test_show_quota_set(user_id=self.fake_user_id) - - def test_show_quota_set_for_user_with_bytes_body(self): - self._test_show_quota_set(bytes_body=True, user_id=self.fake_user_id) - - def test_show_quota_set_with_details(self): - self._test_show_quota_set(detail=True) - - def _test_show_default_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_QUOTA_SET, - to_utf=bytes_body, - tenant_id=self.project_id) - - def test_show_default_quota_set_with_str_body(self): - self._test_show_default_quota_set() - - def test_show_default_quota_set_with_bytes_body(self): - self._test_show_default_quota_set(bytes_body=True) - - def _test_update_quota_set(self, bytes_body=False, user_id=None): - fake_quota_set = copy.deepcopy(self.FAKE_QUOTA_SET) - fake_quota_set['quota_set'].pop("id") - if user_id: - self.check_service_client_function( - self.client.update_quota_set, - 'tempest.lib.common.rest_client.RestClient.put', - fake_quota_set, - to_utf=bytes_body, - tenant_id=self.project_id, - user_id=user_id) - else: - self.check_service_client_function( - self.client.update_quota_set, - 'tempest.lib.common.rest_client.RestClient.put', - fake_quota_set, - to_utf=bytes_body, - tenant_id=self.project_id) - - def test_update_quota_set_with_str_body(self): - self._test_update_quota_set() - - def test_update_quota_set_with_bytes_body(self): - self._test_update_quota_set(bytes_body=True) - - def test_update_quota_set_for_user_with_str_body(self): - self._test_update_quota_set(user_id=self.fake_user_id) - - def test_update_quota_set_for_user_with_bytes_body(self): - self._test_update_quota_set(bytes_body=True, user_id=self.fake_user_id) - - def test_delete_quota_set(self): - self.check_service_client_function( - self.client.delete_quota_set, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, tenant_id=self.project_id) diff --git a/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py b/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py deleted file mode 100644 index 86eee0256..000000000 --- a/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import security_group_default_rules_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSecurityGroupDefaultRulesClient(base.BaseServiceTest): - FAKE_RULE = { - "from_port": 80, - "id": 1, - "ip_protocol": "TCP", - "ip_range": { - "cidr": "10.10.10.0/24" - }, - "to_port": 80 - } - - def setUp(self): - super(TestSecurityGroupDefaultRulesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = (security_group_default_rules_client. - SecurityGroupDefaultRulesClient(fake_auth, 'compute', - 'regionOne')) - - def _test_list_security_group_default_rules(self, bytes_body=False): - self.check_service_client_function( - self.client.list_security_group_default_rules, - 'tempest.lib.common.rest_client.RestClient.get', - {"security_group_default_rules": [self.FAKE_RULE]}, - to_utf=bytes_body) - - def test_list_security_group_default_rules_with_str_body(self): - self._test_list_security_group_default_rules() - - def test_list_security_group_default_rules_with_bytes_body(self): - self._test_list_security_group_default_rules(bytes_body=True) - - def _test_show_security_group_default_rule(self, bytes_body=False): - self.check_service_client_function( - self.client.show_security_group_default_rule, - 'tempest.lib.common.rest_client.RestClient.get', - {"security_group_default_rule": self.FAKE_RULE}, - to_utf=bytes_body, - security_group_default_rule_id=1) - - def test_show_security_group_default_rule_with_str_body(self): - self._test_show_security_group_default_rule() - - def test_show_security_group_default_rule_with_bytes_body(self): - self._test_show_security_group_default_rule(bytes_body=True) - - def _test_create_security_default_group_rule(self, bytes_body=False): - request_body = { - "to_port": 80, - "from_port": 80, - "ip_protocol": "TCP", - "cidr": "10.10.10.0/24" - } - self.check_service_client_function( - self.client.create_security_default_group_rule, - 'tempest.lib.common.rest_client.RestClient.post', - {"security_group_default_rule": self.FAKE_RULE}, - to_utf=bytes_body, **request_body) - - def test_create_security_default_group_rule_with_str_body(self): - self._test_create_security_default_group_rule() - - def test_create_security_default_group_rule_with_bytes_body(self): - self._test_create_security_default_group_rule(bytes_body=True) - - def test_delete_security_group_default_rule(self): - self.check_service_client_function( - self.client.delete_security_group_default_rule, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=204, security_group_default_rule_id=1) diff --git a/tempest/tests/lib/services/compute/test_security_group_rules_client.py b/tempest/tests/lib/services/compute/test_security_group_rules_client.py deleted file mode 100644 index 2b0a94dd7..000000000 --- a/tempest/tests/lib/services/compute/test_security_group_rules_client.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import security_group_rules_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSecurityGroupRulesClient(base.BaseServiceTest): - - FAKE_SECURITY_GROUP_RULE = { - "security_group_rule": { - "id": "2d021cf1-ce4b-4292-994f-7a785d62a144", - "ip_range": { - "cidr": "0.0.0.0/0" - }, - "parent_group_id": "48700ff3-30b8-4e63-845f-a79c9633e9fb", - "to_port": 443, - "ip_protocol": "tcp", - "group": {}, - "from_port": 443 - } - } - - def setUp(self): - super(TestSecurityGroupRulesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = security_group_rules_client.SecurityGroupRulesClient( - fake_auth, 'compute', 'regionOne') - - def _test_create_security_group_rule(self, bytes_body=False): - req_body = { - "from_port": "443", - "ip_protocol": "tcp", - "to_port": "443", - "cidr": "0.0.0.0/0", - "parent_group_id": "48700ff3-30b8-4e63-845f-a79c9633e9fb" - } - self.check_service_client_function( - self.client.create_security_group_rule, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SECURITY_GROUP_RULE, - to_utf=bytes_body, **req_body) - - def test_create_security_group_rule_with_str_body(self): - self._test_create_security_group_rule() - - def test_create_security_group_rule_with_bytes_body(self): - self._test_create_security_group_rule(bytes_body=True) - - def test_delete_security_group_rule(self): - self.check_service_client_function( - self.client.delete_security_group_rule, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, group_rule_id='group-id') diff --git a/tempest/tests/lib/services/compute/test_security_groups_client.py b/tempest/tests/lib/services/compute/test_security_groups_client.py deleted file mode 100644 index 7bbf20e93..000000000 --- a/tempest/tests/lib/services/compute/test_security_groups_client.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures - -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import security_groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSecurityGroupsClient(base.BaseServiceTest): - - FAKE_SECURITY_GROUP_INFO = [{ - "description": "default", - "id": "3fb26eb3-581b-4420-9963-b0879a026506", - "name": "default", - "rules": [], - "tenant_id": "openstack" - }] - - def setUp(self): - super(TestSecurityGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = security_groups_client.SecurityGroupsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_security_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_security_groups, - 'tempest.lib.common.rest_client.RestClient.get', - {"security_groups": self.FAKE_SECURITY_GROUP_INFO}, - to_utf=bytes_body) - - def test_list_security_groups_with_str_body(self): - self._test_list_security_groups() - - def test_list_security_groups_with_bytes_body(self): - self._test_list_security_groups(bytes_body=True) - - def _test_show_security_group(self, bytes_body=False): - self.check_service_client_function( - self.client.show_security_group, - 'tempest.lib.common.rest_client.RestClient.get', - {"security_group": self.FAKE_SECURITY_GROUP_INFO[0]}, - to_utf=bytes_body, - security_group_id='fake-id') - - def test_show_security_group_with_str_body(self): - self._test_show_security_group() - - def test_show_security_group_with_bytes_body(self): - self._test_show_security_group(bytes_body=True) - - def _test_create_security_group(self, bytes_body=False): - post_body = {"name": "test", "description": "test_group"} - self.check_service_client_function( - self.client.create_security_group, - 'tempest.lib.common.rest_client.RestClient.post', - {"security_group": self.FAKE_SECURITY_GROUP_INFO[0]}, - to_utf=bytes_body, - kwargs=post_body) - - def test_create_security_group_with_str_body(self): - self._test_create_security_group() - - def test_create_security_group_with_bytes_body(self): - self._test_create_security_group(bytes_body=True) - - def _test_update_security_group(self, bytes_body=False): - req_body = {"name": "test", "description": "test_group"} - self.check_service_client_function( - self.client.update_security_group, - 'tempest.lib.common.rest_client.RestClient.put', - {"security_group": self.FAKE_SECURITY_GROUP_INFO[0]}, - to_utf=bytes_body, - security_group_id='fake-id', - kwargs=req_body) - - def test_update_security_group_with_str_body(self): - self._test_update_security_group() - - def test_update_security_group_with_bytes_body(self): - self._test_update_security_group(bytes_body=True) - - def test_delete_security_group(self): - self.check_service_client_function( - self.client.delete_security_group, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, security_group_id='fake-id') - - def test_is_resource_deleted_true(self): - mod = ('tempest.lib.services.compute.security_groups_client.' - 'SecurityGroupsClient.show_security_group') - self.useFixture(fixtures.MockPatch(mod, side_effect=lib_exc.NotFound)) - self.assertTrue(self.client.is_resource_deleted('fake-id')) - - def test_is_resource_deleted_false(self): - mod = ('tempest.lib.services.compute.security_groups_client.' - 'SecurityGroupsClient.show_security_group') - self.useFixture(fixtures.MockPatch(mod, return_value='success')) - self.assertFalse(self.client.is_resource_deleted('fake-id')) diff --git a/tempest/tests/lib/services/compute/test_server_groups_client.py b/tempest/tests/lib/services/compute/test_server_groups_client.py deleted file mode 100644 index 9055a36b8..000000000 --- a/tempest/tests/lib/services/compute/test_server_groups_client.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright 2015 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures - -from tempest.lib.services.compute import base_compute_client -from tempest.lib.services.compute import server_groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -from tempest.tests.lib.services import base - - -class TestServerGroupsClient(base.BaseServiceTest): - - server_group = { - "id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9", - "name": "test", - "policies": ["anti-affinity"], - "members": [], - "metadata": {}} - - def setUp(self): - super(TestServerGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = server_groups_client.ServerGroupsClient( - fake_auth, 'compute', 'regionOne') - - def _test_create_server_group(self, bytes_body=False): - expected = {"server_group": self.server_group} - self.check_service_client_function( - self.client.create_server_group, - 'tempest.lib.common.rest_client.RestClient.post', expected, - bytes_body, name='fake-group', policies=['affinity']) - - def test_create_server_group_str_body(self): - self._test_create_server_group(bytes_body=False) - - def test_create_server_group_byte_body(self): - self._test_create_server_group(bytes_body=True) - - def test_delete_server_group(self): - response = fake_http.fake_http_response({}, status=204), '' - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.rest_client.RestClient.delete', - return_value=response)) - self.client.delete_server_group('fake-group') - - def _test_list_server_groups(self, bytes_body=False): - expected = {"server_groups": [self.server_group]} - self.check_service_client_function( - self.client.list_server_groups, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body) - - def test_list_server_groups_str_body(self): - self._test_list_server_groups(bytes_body=False) - - def test_list_server_groups_byte_body(self): - self._test_list_server_groups(bytes_body=True) - - def _test_show_server_group(self, bytes_body=False): - expected = {"server_group": self.server_group} - self.check_service_client_function( - self.client.show_server_group, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, - server_group_id='5bbcc3c4-1da2-4437-a48a-66f15b1b13f9') - - def test_show_server_group_str_body(self): - self._test_show_server_group(bytes_body=False) - - def test_show_server_group_byte_body(self): - self._test_show_server_group(bytes_body=True) - - -class TestServerGroupsClientMinV213(TestServerGroupsClient): - - server_group = { - "id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9", - "name": "test", - "policies": ["anti-affinity"], - "members": [], - "metadata": {}, - "project_id": "0beb4bffb7a445eb8eb05fee3ee7660a", - "user_id": "86031628064a4f99bb66ec03c507dcd8"} - - def setUp(self): - super(TestServerGroupsClientMinV213, self).setUp() - self.patchobject(base_compute_client, 'COMPUTE_MICROVERSION', - new='2.13') diff --git a/tempest/tests/lib/services/compute/test_servers_client.py b/tempest/tests/lib/services/compute/test_servers_client.py deleted file mode 100644 index 86f6ad585..000000000 --- a/tempest/tests/lib/services/compute/test_servers_client.py +++ /dev/null @@ -1,1076 +0,0 @@ -# Copyright 2015 IBM Corp. -# Copyright 2017 AT&T Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -import mock - -from tempest.lib.services.compute import base_compute_client -from tempest.lib.services.compute import servers_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestServersClient(base.BaseServiceTest): - - FAKE_SERVERS = {'servers': [{ - "id": "616fb98f-46ca-475e-917e-2563e5a8cd19", - "links": [ - { - "href": "http://os.co/v2/616fb98f-46ca-475e-917e-2563e5a8cd19", - "rel": "self" - }, - { - "href": "http://os.co/616fb98f-46ca-475e-917e-2563e5a8cd19", - "rel": "bookmark" - } - ], - "name": u"new\u1234-server-test"}] - } - - FAKE_SERVER_DIAGNOSTICS = { - "cpu0_time": 17300000000, - "memory": 524288, - "vda_errors": -1, - "vda_read": 262144, - "vda_read_req": 112, - "vda_write": 5778432, - "vda_write_req": 488, - "vnet1_rx": 2070139, - "vnet1_rx_drop": 0, - "vnet1_rx_errors": 0, - "vnet1_rx_packets": 26701, - "vnet1_tx": 140208, - "vnet1_tx_drop": 0, - "vnet1_tx_errors": 0, - "vnet1_tx_packets": 662 - } - - FAKE_SERVER_GET = {'server': { - "accessIPv4": "", - "accessIPv6": "", - "addresses": { - "private": [ - { - "addr": "192.168.0.3", - "version": 4 - } - ] - }, - "created": "2012-08-20T21:11:09Z", - "flavor": { - "id": "1", - "links": [ - { - "href": "http://os.com/openstack/flavors/1", - "rel": "bookmark" - } - ] - }, - "hostId": "65201c14a29663e06d0748e561207d998b343e1d164bfa0aafa9c45d", - "id": "893c7791-f1df-4c3d-8383-3caae9656c62", - "image": { - "id": "70a599e0-31e7-49b7-b260-868f441e862b", - "links": [ - { - "href": "http://imgs/70a599e0-31e7-49b7-b260-868f441e862b", - "rel": "bookmark" - } - ] - }, - "links": [ - { - "href": "http://v2/srvs/893c7791-f1df-4c3d-8383-3caae9656c62", - "rel": "self" - }, - { - "href": "http://srvs/893c7791-f1df-4c3d-8383-3caae9656c62", - "rel": "bookmark" - } - ], - "metadata": { - u"My Server N\u1234me": u"Apa\u1234che1" - }, - "name": u"new\u1234-server-test", - "progress": 0, - "status": "ACTIVE", - "tenant_id": "openstack", - "updated": "2012-08-20T21:11:09Z", - "user_id": "fake"} - } - - FAKE_SERVER_POST = {"server": { - "id": "616fb98f-46ca-475e-917e-2563e5a8cd19", - "adminPass": "fake-admin-pass", - "security_groups": [ - 'fake-security-group-1', - 'fake-security-group-2' - ], - "links": [ - { - "href": "http://os.co/v2/616fb98f-46ca-475e-917e-2563e5a8cd19", - "rel": "self" - }, - { - "href": "http://os.co/616fb98f-46ca-475e-917e-2563e5a8cd19", - "rel": "bookmark" - } - ], - "OS-DCF:diskConfig": "fake-disk-config"} - } - - FAKE_ADDRESS = {"addresses": { - "private": [ - { - "addr": "192.168.0.3", - "version": 4 - } - ]} - } - - FAKE_COMMON_VOLUME = { - "id": "a6b0875b-6b5d-4a5a-81eb-0c3aa62e5fdb", - "device": "fake-device", - "volumeId": "a6b0875b-46ca-475e-917e-0c3aa62e5fdb", - "serverId": "616fb98f-46ca-475e-917e-2563e5a8cd19" - } - - FAKE_VIRTUAL_INTERFACES = { - "id": "a6b0875b-46ca-475e-917e-0c3aa62e5fdb", - "mac_address": "00:25:90:5b:f8:c3", - "OS-EXT-VIF-NET:net_id": "fake-os-net-id" - } - - FAKE_INSTANCE_ACTIONS = { - "action": "fake-action", - "request_id": "16fb98f-46ca-475e-917e-2563e5a8cd19", - "user_id": "16fb98f-46ca-475e-917e-2563e5a8cd12", - "project_id": "16fb98f-46ca-475e-917e-2563e5a8cd34", - "start_time": "2016-10-02T10:00:00-05:00", - "message": "fake-msg", - "instance_uuid": "16fb98f-46ca-475e-917e-2563e5a8cd12" - } - - FAKE_VNC_CONSOLE = { - "type": "fake-type", - "url": "http://os.co/v2/616fb98f-46ca-475e-917e-2563e5a8cd19" - } - - FAKE_SERVER_PASSWORD = { - "adminPass": "fake-password", - } - - FAKE_INSTANCE_ACTION_EVENTS = { - "event": "fake-event", - "start_time": "2016-10-02T10:00:00-05:00", - "finish_time": "2016-10-02T10:00:00-05:00", - "result": "fake-result", - "traceback": "fake-trace-back" - } - - FAKE_SECURITY_GROUPS = [{ - "description": "default", - "id": "3fb26eb3-581b-4420-9963-b0879a026506", - "name": "default", - "rules": [], - "tenant_id": "openstack" - }] - - FAKE_INSTANCE_WITH_EVENTS = copy.deepcopy(FAKE_INSTANCE_ACTIONS) - FAKE_INSTANCE_WITH_EVENTS['events'] = [FAKE_INSTANCE_ACTION_EVENTS] - - FAKE_REBUILD_SERVER = copy.deepcopy(FAKE_SERVER_GET) - FAKE_REBUILD_SERVER['server']['adminPass'] = 'fake-admin-pass' - - FAKE_TAGS = ["foo", "bar"] - REPLACE_FAKE_TAGS = ["baz", "qux"] - - server_id = FAKE_SERVER_GET['server']['id'] - network_id = 'a6b0875b-6b5d-4a5a-81eb-0c3aa62e5fdb' - - def setUp(self): - super(TestServersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = servers_client.ServersClient( - fake_auth, 'compute', 'regionOne') - self.addCleanup(mock.patch.stopall) - - def test_list_servers_with_str_body(self): - self._test_list_servers() - - def test_list_servers_with_bytes_body(self): - self._test_list_servers(bytes_body=True) - - def _test_list_servers(self, bytes_body=False): - self.check_service_client_function( - self.client.list_servers, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVERS, - bytes_body) - - def test_show_server_with_str_body(self): - self._test_show_server() - - def test_show_server_with_bytes_body(self): - self._test_show_server(bytes_body=True) - - def _test_show_server(self, bytes_body=False): - self.check_service_client_function( - self.client.show_server, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVER_GET, - bytes_body, - server_id=self.server_id - ) - - def test_delete_server(self): - self.check_service_client_function( - self.client.delete_server, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - server_id=self.server_id - ) - - def test_create_server_with_str_body(self): - self._test_create_server() - - def test_create_server_with_bytes_body(self): - self._test_create_server(True) - - def _test_create_server(self, bytes_body=False): - self.check_service_client_function( - self.client.create_server, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SERVER_POST, - bytes_body, - status=202, - name='fake-name', - imageRef='fake-image-ref', - flavorRef='fake-flavor-ref' - ) - - def test_list_addresses_with_str_body(self): - self._test_list_addresses() - - def test_list_addresses_with_bytes_body(self): - self._test_list_addresses(True) - - def _test_list_addresses(self, bytes_body=False): - self.check_service_client_function( - self.client.list_addresses, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ADDRESS, - bytes_body, - server_id=self.server_id - ) - - def test_list_addresses_by_network_with_str_body(self): - self._test_list_addresses_by_network() - - def test_list_addresses_by_network_with_bytes_body(self): - self._test_list_addresses_by_network(True) - - def _test_list_addresses_by_network(self, bytes_body=False): - self.check_service_client_function( - self.client.list_addresses_by_network, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ADDRESS['addresses'], - bytes_body, - server_id=self.server_id, - network_id=self.network_id - ) - - def test_action_with_str_body(self): - self._test_action() - - def test_action_with_bytes_body(self): - self._test_action(True) - - def _test_action(self, bytes_body=False): - self.check_service_client_function( - self.client.action, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - server_id=self.server_id, - action_name='fake-action-name', - schema={'status_code': 200} - ) - - def test_create_backup_with_str_body(self): - self._test_create_backup() - - def test_create_backup_with_bytes_body(self): - self._test_create_backup(True) - - def _test_create_backup(self, bytes_body=False): - self.check_service_client_function( - self.client.create_backup, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - status=202, - server_id=self.server_id, - backup_type='fake-backup', - rotation='fake-rotation', - name='fake-name' - ) - - def test_evacuate_server_with_str_body(self): - self._test_evacuate_server() - - def test_evacuate_server_with_bytes_body(self): - self._test_evacuate_server(bytes_body=True) - - def _test_evacuate_server(self, bytes_body=False): - kwargs = {'server_id': self.server_id, - 'host': 'fake-target-host'} - self.check_service_client_function( - self.client.evacuate_server, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SERVER_PASSWORD, - bytes_body, - **kwargs) - - def test_change_password_with_str_body(self): - self._test_change_password() - - def test_change_password_with_bytes_body(self): - self._test_change_password(True) - - def _test_change_password(self, bytes_body=False): - self.check_service_client_function( - self.client.change_password, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - status=202, - server_id=self.server_id, - adminPass='fake-admin-pass' - ) - - def test_show_password_with_str_body(self): - self._test_show_password() - - def test_show_password_with_bytes_body(self): - self._test_show_password(True) - - def _test_show_password(self, bytes_body=False): - self.check_service_client_function( - self.client.show_password, - 'tempest.lib.common.rest_client.RestClient.get', - {'password': 'fake-password'}, - bytes_body, - server_id=self.server_id - ) - - def test_delete_password(self): - self.check_service_client_function( - self.client.delete_password, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - server_id=self.server_id - ) - - def test_reboot_server(self): - self.check_service_client_function( - self.client.reboot_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id, - type='fake-reboot-type' - ) - - def test_rebuild_server_with_str_body(self): - self._test_rebuild_server() - - def test_rebuild_server_with_bytes_body(self): - self._test_rebuild_server(True) - - def _test_rebuild_server(self, bytes_body=False): - self.check_service_client_function( - self.client.rebuild_server, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_REBUILD_SERVER, - bytes_body, - status=202, - server_id=self.server_id, - image_ref='fake-image-ref' - ) - - def test_resize_server(self): - self.check_service_client_function( - self.client.resize_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id, - flavor_ref='fake-flavor-ref' - ) - - def test_confirm_resize_server(self): - self.check_service_client_function( - self.client.confirm_resize_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=204, - server_id=self.server_id - ) - - def test_revert_resize(self): - self.check_service_client_function( - self.client.revert_resize_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_list_server_metadata_with_str_body(self): - self._test_list_server_metadata() - - def test_list_server_metadata_with_bytes_body(self): - self._test_list_server_metadata() - - def _test_list_server_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.list_server_metadata, - 'tempest.lib.common.rest_client.RestClient.get', - {'metadata': {'fake-key': 'fake-meta-data'}}, - bytes_body, - server_id=self.server_id - ) - - def test_set_server_metadata_with_str_body(self): - self._test_set_server_metadata() - - def test_set_server_metadata_with_bytes_body(self): - self._test_set_server_metadata(True) - - def _test_set_server_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.set_server_metadata, - 'tempest.lib.common.rest_client.RestClient.put', - {'metadata': {'fake-key': 'fake-meta-data'}}, - bytes_body, - server_id=self.server_id, - meta='fake-meta' - ) - - def test_update_server_metadata_with_str_body(self): - self._test_update_server_metadata() - - def test_update_server_metadata_with_bytes_body(self): - self._test_update_server_metadata(True) - - def _test_update_server_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.update_server_metadata, - 'tempest.lib.common.rest_client.RestClient.post', - {'metadata': {'fake-key': 'fake-meta-data'}}, - bytes_body, - server_id=self.server_id, - meta='fake-meta' - ) - - def test_show_server_metadata_item_with_str_body(self): - self._test_show_server_metadata() - - def test_show_server_metadata_item_with_bytes_body(self): - self._test_show_server_metadata(True) - - def _test_show_server_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.show_server_metadata_item, - 'tempest.lib.common.rest_client.RestClient.get', - {'meta': {'fake-key': 'fake-meta-data'}}, - bytes_body, - server_id=self.server_id, - key='fake-key' - ) - - def test_set_server_metadata_item_with_str_body(self): - self._test_set_server_metadata_item() - - def test_set_server_metadata_item_with_bytes_body(self): - self._test_set_server_metadata_item(True) - - def _test_set_server_metadata_item(self, bytes_body=False): - self.check_service_client_function( - self.client.set_server_metadata_item, - 'tempest.lib.common.rest_client.RestClient.put', - {'meta': {'fake-key': 'fake-meta-data'}}, - bytes_body, - server_id=self.server_id, - key='fake-key', - meta='fake-meta' - ) - - def test_delete_server_metadata(self): - self.check_service_client_function( - self.client.delete_server_metadata_item, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - server_id=self.server_id, - key='fake-key' - ) - - def test_stop_server(self): - self.check_service_client_function( - self.client.stop_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_start_server(self): - self.check_service_client_function( - self.client.start_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_attach_volume_with_str_body(self): - self._test_attach_volume_server() - - def test_attach_volume_with_bytes_body(self): - self._test_attach_volume_server(True) - - def _test_attach_volume_server(self, bytes_body=False): - self.check_service_client_function( - self.client.attach_volume, - 'tempest.lib.common.rest_client.RestClient.post', - {'volumeAttachment': self.FAKE_COMMON_VOLUME}, - bytes_body, - server_id=self.server_id - ) - - def test_update_attached_volume(self): - self.check_service_client_function( - self.client.update_attached_volume, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - status=202, - server_id=self.server_id, - attachment_id='fake-attachment-id', - volumeId='fake-volume-id' - ) - - def test_detach_volume_with_str_body(self): - self._test_detach_volume_server() - - def test_detach_volume_with_bytes_body(self): - self._test_detach_volume_server(True) - - def _test_detach_volume_server(self, bytes_body=False): - self.check_service_client_function( - self.client.detach_volume, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - bytes_body, - status=202, - server_id=self.server_id, - volume_id=self.FAKE_COMMON_VOLUME['volumeId'] - ) - - def test_show_volume_attachment_with_str_body(self): - self._test_show_volume_attachment() - - def test_show_volume_attachment_with_bytes_body(self): - self._test_show_volume_attachment(True) - - def _test_show_volume_attachment(self, bytes_body=False): - self.check_service_client_function( - self.client.show_volume_attachment, - 'tempest.lib.common.rest_client.RestClient.get', - {'volumeAttachment': self.FAKE_COMMON_VOLUME}, - bytes_body, - server_id=self.server_id, - volume_id=self.FAKE_COMMON_VOLUME['volumeId'] - ) - - def test_list_volume_attachments_with_str_body(self): - self._test_list_volume_attachments() - - def test_list_volume_attachments_with_bytes_body(self): - self._test_list_volume_attachments(True) - - def _test_list_volume_attachments(self, bytes_body=False): - self.check_service_client_function( - self.client.list_volume_attachments, - 'tempest.lib.common.rest_client.RestClient.get', - {'volumeAttachments': [self.FAKE_COMMON_VOLUME]}, - bytes_body, - server_id=self.server_id - ) - - def test_add_security_group_with_str_body(self): - self._test_add_security_group() - - def test_add_security_group_with_bytes_body(self): - self._test_add_security_group(True) - - def _test_add_security_group(self, bytes_body=False): - self.check_service_client_function( - self.client.add_security_group, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - status=202, - server_id=self.server_id, - name='fake-name' - ) - - def test_remove_security_group(self): - self.check_service_client_function( - self.client.remove_security_group, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id, - name='fake-name' - ) - - def test_live_migrate_server_with_str_body(self): - self._test_live_migrate_server() - - def test_live_migrate_server_with_bytes_body(self): - self._test_live_migrate_server(True) - - def _test_live_migrate_server(self, bytes_body=False): - self.check_service_client_function( - self.client.live_migrate_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - status=202, - server_id=self.server_id - ) - - def test_migrate_server_with_str_body(self): - self._test_migrate_server() - - def test_migrate_server_with_bytes_body(self): - self._test_migrate_server(True) - - def _test_migrate_server(self, bytes_body=False): - self.check_service_client_function( - self.client.migrate_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - status=202, - server_id=self.server_id - ) - - def test_lock_server(self): - self.check_service_client_function( - self.client.lock_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_unlock_server(self): - self.check_service_client_function( - self.client.unlock_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_suspend_server(self): - self.check_service_client_function( - self.client.suspend_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_resume_server(self): - self.check_service_client_function( - self.client.resume_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_pause_server(self): - self.check_service_client_function( - self.client.pause_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_unpause_server(self): - self.check_service_client_function( - self.client.unpause_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_reset_state(self): - self.check_service_client_function( - self.client.reset_state, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id, - state='fake-state' - ) - - def test_shelve_server(self): - self.check_service_client_function( - self.client.shelve_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_unshelve_server(self): - self.check_service_client_function( - self.client.unshelve_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_shelve_offload_server(self): - self.check_service_client_function( - self.client.shelve_offload_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_get_console_output_with_str_body(self): - self._test_get_console_output() - - def test_get_console_output_with_bytes_body(self): - self._test_get_console_output(True) - - def _test_get_console_output(self, bytes_body=False): - self.check_service_client_function( - self.client.get_console_output, - 'tempest.lib.common.rest_client.RestClient.post', - {'output': 'fake-output'}, - bytes_body, - server_id=self.server_id, - length='fake-length' - ) - - def test_list_virtual_interfaces_with_str_body(self): - self._test_list_virtual_interfaces() - - def test_list_virtual_interfaces_with_bytes_body(self): - self._test_list_virtual_interfaces(True) - - def _test_list_virtual_interfaces(self, bytes_body=False): - self.check_service_client_function( - self.client.list_virtual_interfaces, - 'tempest.lib.common.rest_client.RestClient.get', - {'virtual_interfaces': [self.FAKE_VIRTUAL_INTERFACES]}, - bytes_body, - server_id=self.server_id - ) - - def test_rescue_server_with_str_body(self): - self._test_rescue_server() - - def test_rescue_server_with_bytes_body(self): - self._test_rescue_server(True) - - def _test_rescue_server(self, bytes_body=False): - self.check_service_client_function( - self.client.rescue_server, - 'tempest.lib.common.rest_client.RestClient.post', - {'adminPass': 'fake-admin-pass'}, - bytes_body, - server_id=self.server_id - ) - - def test_unrescue_server(self): - self.check_service_client_function( - self.client.unrescue_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_show_server_diagnostics_with_str_body(self): - self._test_show_server_diagnostics() - - def test_show_server_diagnostics_with_bytes_body(self): - self._test_show_server_diagnostics(True) - - def _test_show_server_diagnostics(self, bytes_body=False): - self.check_service_client_function( - self.client.show_server_diagnostics, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVER_DIAGNOSTICS, - bytes_body, - status=200, - server_id=self.server_id - ) - - def test_list_instance_actions_with_str_body(self): - self._test_list_instance_actions() - - def test_list_instance_actions_with_bytes_body(self): - self._test_list_instance_actions(True) - - def _test_list_instance_actions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_instance_actions, - 'tempest.lib.common.rest_client.RestClient.get', - {'instanceActions': [self.FAKE_INSTANCE_ACTIONS]}, - bytes_body, - server_id=self.server_id - ) - - def test_show_instance_action_with_str_body(self): - self._test_show_instance_action() - - def test_show_instance_action_with_bytes_body(self): - self._test_show_instance_action(True) - - def _test_show_instance_action(self, bytes_body=False): - self.check_service_client_function( - self.client.show_instance_action, - 'tempest.lib.common.rest_client.RestClient.get', - {'instanceAction': self.FAKE_INSTANCE_WITH_EVENTS}, - bytes_body, - server_id=self.server_id, - request_id='fake-request-id' - ) - - def test_force_delete_server(self): - self.check_service_client_function( - self.client.force_delete_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_restore_soft_deleted_server(self): - self.check_service_client_function( - self.client.restore_soft_deleted_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_reset_network(self): - self.check_service_client_function( - self.client.reset_network, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_inject_network_info(self): - self.check_service_client_function( - self.client.inject_network_info, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_get_vnc_console_with_str_body(self): - self._test_get_vnc_console() - - def test_get_vnc_console_with_bytes_body(self): - self._test_get_vnc_console(True) - - def _test_get_vnc_console(self, bytes_body=False): - self.check_service_client_function( - self.client.get_vnc_console, - 'tempest.lib.common.rest_client.RestClient.post', - {'console': self.FAKE_VNC_CONSOLE}, - bytes_body, - server_id=self.server_id, - type='fake-console-type' - ) - - def test_list_security_groups_by_server_with_str_body(self): - self._test_list_security_groups_by_server() - - def test_list_security_groups_by_server_with_bytes_body(self): - self._test_list_security_groups_by_server(True) - - def _test_list_security_groups_by_server(self, bytes_body=False): - self.check_service_client_function( - self.client.list_security_groups_by_server, - 'tempest.lib.common.rest_client.RestClient.get', - {'security_groups': self.FAKE_SECURITY_GROUPS}, - bytes_body, - server_id=self.server_id - ) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_list_tags_str_body(self, _): - self._test_list_tags() - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_list_tags_byte_body(self, _): - self._test_list_tags(bytes_body=True) - - def _test_list_tags(self, bytes_body=False): - expected = {"tags": self.FAKE_TAGS} - self.check_service_client_function( - self.client.list_tags, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - server_id=self.server_id, - to_utf=bytes_body) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_update_all_tags_str_body(self, _): - self._test_update_all_tags() - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_update_all_tags_byte_body(self, _): - self._test_update_all_tags(bytes_body=True) - - def _test_update_all_tags(self, bytes_body=False): - expected = {"tags": self.REPLACE_FAKE_TAGS} - self.check_service_client_function( - self.client.update_all_tags, - 'tempest.lib.common.rest_client.RestClient.put', - expected, - server_id=self.server_id, - tags=self.REPLACE_FAKE_TAGS, - to_utf=bytes_body) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_delete_all_tags(self, _): - self.check_service_client_function( - self.client.delete_all_tags, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - server_id=self.server_id, - status=204) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_check_tag_existence_str_body(self, _): - self._test_check_tag_existence() - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_check_tag_existence_byte_body(self, _): - self._test_check_tag_existence(bytes_body=True) - - def _test_check_tag_existence(self, bytes_body=False): - self.check_service_client_function( - self.client.check_tag_existence, - 'tempest.lib.common.rest_client.RestClient.get', - {}, - server_id=self.server_id, - tag=self.FAKE_TAGS[0], - status=204, - to_utf=bytes_body) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_update_tag_str_body(self, _): - self._test_update_tag() - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_update_tag_byte_body(self, _): - self._test_update_tag(bytes_body=True) - - def _test_update_tag(self, bytes_body=False): - self.check_service_client_function( - self.client.update_tag, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - server_id=self.server_id, - tag=self.FAKE_TAGS[0], - status=201, - headers={'location': 'fake_location'}, - to_utf=bytes_body) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_delete_tag(self, _): - self.check_service_client_function( - self.client.delete_tag, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - server_id=self.server_id, - tag=self.FAKE_TAGS[0], - status=204, - ) - - -class TestServersClientMinV26(base.BaseServiceTest): - - def setUp(self): - super(TestServersClientMinV26, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = servers_client.ServersClient(fake_auth, 'compute', - 'regionOne') - base_compute_client.COMPUTE_MICROVERSION = '2.6' - self.server_id = "920eaac8-a284-4fd1-9c2c-b30f0181b125" - - def tearDown(self): - super(TestServersClientMinV26, self).tearDown() - base_compute_client.COMPUTE_MICROVERSION = None - - def test_get_remote_consoles(self): - self.check_service_client_function( - self.client.get_remote_console, - 'tempest.lib.common.rest_client.RestClient.post', - { - 'remote_console': { - 'protocol': 'serial', - 'type': 'serial', - 'url': 'ws://127.0.0.1:6083/?token=IllAllowIt' - } - }, - server_id=self.server_id, - console_type='serial', - protocol='serial', - ) diff --git a/tempest/tests/lib/services/compute/test_services_client.py b/tempest/tests/lib/services/compute/test_services_client.py deleted file mode 100644 index 2dd981c00..000000000 --- a/tempest/tests/lib/services/compute/test_services_client.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -import mock - -from tempest.lib.services.compute import base_compute_client -from tempest.lib.services.compute import services_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestServicesClient(base.BaseServiceTest): - - FAKE_SERVICES = { - "services": - [{ - "status": "enabled", - "binary": "nova-conductor", - "zone": "internal", - "state": "up", - "updated_at": "2015-08-19T06:50:55.000000", - "host": "controller", - "disabled_reason": None, - "id": 1 - }] - } - - FAKE_SERVICE = { - "service": - { - "status": "enabled", - "binary": "nova-conductor", - "host": "controller" - } - } - - FAKE_UPDATE_FORCED_DOWN = { - "service": - { - "forced_down": True, - "binary": "nova-conductor", - "host": "controller" - } - } - - def setUp(self): - super(TestServicesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = services_client.ServicesClient( - fake_auth, 'compute', 'regionOne') - self.addCleanup(mock.patch.stopall) - - def test_list_services_with_str_body(self): - self.check_service_client_function( - self.client.list_services, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVICES) - - def test_list_services_with_bytes_body(self): - self.check_service_client_function( - self.client.list_services, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVICES, to_utf=True) - - def _test_enable_service(self, bytes_body=False): - self.check_service_client_function( - self.client.enable_service, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_SERVICE, - bytes_body, - host="nova-conductor", binary="controller") - - def test_enable_service_with_str_body(self): - self._test_enable_service() - - def test_enable_service_with_bytes_body(self): - self._test_enable_service(bytes_body=True) - - def _test_disable_service(self, bytes_body=False): - fake_service = copy.deepcopy(self.FAKE_SERVICE) - fake_service["service"]["status"] = "disable" - - self.check_service_client_function( - self.client.disable_service, - 'tempest.lib.common.rest_client.RestClient.put', - fake_service, - bytes_body, - host="nova-conductor", binary="controller") - - def test_disable_service_with_str_body(self): - self._test_disable_service() - - def test_disable_service_with_bytes_body(self): - self._test_disable_service(bytes_body=True) - - def _test_log_reason_disabled_service(self, bytes_body=False): - resp_body = copy.deepcopy(self.FAKE_SERVICE) - resp_body['service']['disabled_reason'] = 'test reason' - - self.check_service_client_function( - self.client.disable_log_reason, - 'tempest.lib.common.rest_client.RestClient.put', - resp_body, - bytes_body, - host="nova-conductor", - binary="controller", - disabled_reason='test reason') - - def test_log_reason_disabled_service_with_str_body(self): - self._test_log_reason_disabled_service() - - def test_log_reason_disabled_service_with_bytes_body(self): - self._test_log_reason_disabled_service(bytes_body=True) - - def _test_update_forced_down(self, bytes_body=False): - self.check_service_client_function( - self.client.update_forced_down, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_FORCED_DOWN, - bytes_body, - host="nova-conductor", - binary="controller", - forced_down=True) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.11')) - def test_update_forced_down_with_str_body(self, _): - self._test_update_forced_down() - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.11')) - def test_update_forced_down_with_bytes_body(self, _): - self._test_update_forced_down(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_snapshots_client.py b/tempest/tests/lib/services/compute/test_snapshots_client.py deleted file mode 100644 index 1e2902c6b..000000000 --- a/tempest/tests/lib/services/compute/test_snapshots_client.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures - -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import snapshots_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSnapshotsClient(base.BaseServiceTest): - - FAKE_SNAPSHOT = { - "createdAt": "2015-10-02T16:27:54.724209", - "displayDescription": u"Another \u1234.", - "displayName": u"v\u1234-001", - "id": "100", - "size": 100, - "status": "available", - "volumeId": "12" - } - - FAKE_SNAPSHOTS = {"snapshots": [FAKE_SNAPSHOT]} - - def setUp(self): - super(TestSnapshotsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = snapshots_client.SnapshotsClient( - fake_auth, 'compute', 'regionOne') - - def _test_create_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.create_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - {"snapshot": self.FAKE_SNAPSHOT}, - to_utf=bytes_body, status=200, - volume_id=self.FAKE_SNAPSHOT["volumeId"]) - - def test_create_snapshot_with_str_body(self): - self._test_create_snapshot() - - def test_create_shapshot_with_bytes_body(self): - self._test_create_snapshot(bytes_body=True) - - def _test_show_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot, - 'tempest.lib.common.rest_client.RestClient.get', - {"snapshot": self.FAKE_SNAPSHOT}, - to_utf=bytes_body, snapshot_id=self.FAKE_SNAPSHOT["id"]) - - def test_show_snapshot_with_str_body(self): - self._test_show_snapshot() - - def test_show_snapshot_with_bytes_body(self): - self._test_show_snapshot(bytes_body=True) - - def _test_list_snapshots(self, bytes_body=False, **params): - self.check_service_client_function( - self.client.list_snapshots, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SNAPSHOTS, to_utf=bytes_body, **params) - - def test_list_snapshots_with_str_body(self): - self._test_list_snapshots() - - def test_list_snapshots_with_byte_body(self): - self._test_list_snapshots(bytes_body=True) - - def test_list_snapshots_with_params(self): - self._test_list_snapshots('fake') - - def test_delete_snapshot(self): - self.check_service_client_function( - self.client.delete_snapshot, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, snapshot_id=self.FAKE_SNAPSHOT['id']) - - def test_is_resource_deleted_true(self): - module = ('tempest.lib.services.compute.snapshots_client.' - 'SnapshotsClient.show_snapshot') - self.useFixture(fixtures.MockPatch( - module, side_effect=lib_exc.NotFound)) - self.assertTrue(self.client.is_resource_deleted('fake-id')) - - def test_is_resource_deleted_false(self): - module = ('tempest.lib.services.compute.snapshots_client.' - 'SnapshotsClient.show_snapshot') - self.useFixture(fixtures.MockPatch( - module, return_value={})) - self.assertFalse(self.client.is_resource_deleted('fake-id')) diff --git a/tempest/tests/lib/services/compute/test_tenant_networks_client.py b/tempest/tests/lib/services/compute/test_tenant_networks_client.py deleted file mode 100644 index f71aad9b0..000000000 --- a/tempest/tests/lib/services/compute/test_tenant_networks_client.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import tenant_networks_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTenantNetworksClient(base.BaseServiceTest): - - FAKE_NETWORK = { - "cidr": "None", - "id": "c2329eb4-cc8e-4439-ac4c-932369309e36", - "label": u'\u30d7' - } - - FAKE_NETWORKS = [FAKE_NETWORK] - - NETWORK_ID = FAKE_NETWORK['id'] - - def setUp(self): - super(TestTenantNetworksClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = tenant_networks_client.TenantNetworksClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_tenant_networks(self, bytes_body=False): - self.check_service_client_function( - self.client.list_tenant_networks, - 'tempest.lib.common.rest_client.RestClient.get', - {"networks": self.FAKE_NETWORKS}, - bytes_body) - - def test_list_tenant_networks_with_str_body(self): - self._test_list_tenant_networks() - - def test_list_tenant_networks_with_bytes_body(self): - self._test_list_tenant_networks(bytes_body=True) - - def _test_show_tenant_network(self, bytes_body=False): - self.check_service_client_function( - self.client.show_tenant_network, - 'tempest.lib.common.rest_client.RestClient.get', - {"network": self.FAKE_NETWORK}, - bytes_body, - network_id=self.NETWORK_ID) - - def test_show_tenant_network_with_str_body(self): - self._test_show_tenant_network() - - def test_show_tenant_network_with_bytes_body(self): - self._test_show_tenant_network(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_tenant_usages_client.py b/tempest/tests/lib/services/compute/test_tenant_usages_client.py deleted file mode 100644 index 49eae0872..000000000 --- a/tempest/tests/lib/services/compute/test_tenant_usages_client.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.compute import tenant_usages_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTenantUsagesClient(base.BaseServiceTest): - - FAKE_SERVER_USAGES = [{ - "ended_at": None, - "flavor": "m1.tiny", - "hours": 1.0, - "instance_id": "1f1deceb-17b5-4c04-84c7-e0d4499c8fe0", - "local_gb": 1, - "memory_mb": 512, - "name": "new-server-test", - "started_at": "2012-10-08T20:10:44.541277", - "state": "active", - "tenant_id": "openstack", - "uptime": 3600, - "vcpus": 1 - }] - - FAKE_TENANT_USAGES = [{ - "server_usages": FAKE_SERVER_USAGES, - "start": "2012-10-08T21:10:44.587336", - "stop": "2012-10-08T22:10:44.587336", - "tenant_id": "openstack", - "total_hours": 1, - "total_local_gb_usage": 1, - "total_memory_mb_usage": 512, - "total_vcpus_usage": 1 - }] - - def setUp(self): - super(TestTenantUsagesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = tenant_usages_client.TenantUsagesClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_tenant_usages(self, bytes_body=False): - self.check_service_client_function( - self.client.list_tenant_usages, - 'tempest.lib.common.rest_client.RestClient.get', - {"tenant_usages": self.FAKE_TENANT_USAGES}, - to_utf=bytes_body) - - def test_list_tenant_usages_with_str_body(self): - self._test_list_tenant_usages() - - def test_list_tenant_usages_with_bytes_body(self): - self._test_list_tenant_usages(bytes_body=True) - - def _test_show_tenant_usage(self, bytes_body=False): - self.check_service_client_function( - self.client.show_tenant_usage, - 'tempest.lib.common.rest_client.RestClient.get', - {"tenant_usage": self.FAKE_TENANT_USAGES[0]}, - to_utf=bytes_body, - tenant_id='openstack') - - def test_show_tenant_usage_with_str_body(self): - self._test_show_tenant_usage() - - def test_show_tenant_usage_with_bytes_body(self): - self._test_show_tenant_usage(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_versions_client.py b/tempest/tests/lib/services/compute/test_versions_client.py deleted file mode 100644 index 40d424f76..000000000 --- a/tempest/tests/lib/services/compute/test_versions_client.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -import fixtures - -from tempest.lib.services.compute import versions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVersionsClient(base.BaseServiceTest): - - FAKE_INIT_VERSION = { - "version": { - "id": "v2.1", - "links": [ - { - "href": "http://openstack.example.com/v2.1/", - "rel": "self" - }, - { - "href": "http://docs.openstack.org/", - "rel": "describedby", - "type": "text/html" - } - ], - "status": "CURRENT", - "updated": "2013-07-23T11:33:21Z", - "version": "2.1", - "min_version": "2.1" - } - } - - FAKE_VERSIONS_INFO = { - "versions": [FAKE_INIT_VERSION["version"]] - } - - FAKE_VERSION_INFO = copy.deepcopy(FAKE_INIT_VERSION) - - FAKE_VERSION_INFO["version"]["media-types"] = [ - { - "base": "application/json", - "type": "application/vnd.openstack.compute+json;version=2.1" - } - ] - - def setUp(self): - super(TestVersionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.versions_client = ( - versions_client.VersionsClient - (fake_auth, 'compute', 'regionOne')) - - def _test_versions_client(self, bytes_body=False): - self.check_service_client_function( - self.versions_client.list_versions, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSIONS_INFO, - bytes_body, - 200) - - def _test_get_version_by_url(self, bytes_body=False): - self.useFixture(fixtures.MockPatch( - "tempest.lib.common.rest_client.RestClient.token", - return_value="Dummy Token")) - params = {"version_url": self.versions_client._get_base_version_url()} - self.check_service_client_function( - self.versions_client.get_version_by_url, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSION_INFO, - bytes_body, - 200, **params) - - def test_list_versions_client_with_str_body(self): - self._test_versions_client() - - def test_list_versions_client_with_bytes_body(self): - self._test_versions_client(bytes_body=True) - - def test_get_version_by_url_with_str_body(self): - self._test_get_version_by_url() - - def test_get_version_by_url_with_bytes_body(self): - self._test_get_version_by_url(bytes_body=True) - - def _test_get_base_version_url(self, url, expected_base_url): - auth = fake_auth_provider.FakeAuthProvider(fake_base_url=url) - client = versions_client.VersionsClient(auth, 'compute', 'regionOne') - self.assertEqual(expected_base_url, client._get_base_version_url()) - - def test_get_base_version_url(self): - self._test_get_base_version_url('https://bar.org/v2/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org/v2.1/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org/v2.15/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org/v22.2/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org/v22/123', - 'https://bar.org/') - - def test_get_base_version_url_app_name(self): - self._test_get_base_version_url('https://bar.org/compute/v2/123', - 'https://bar.org/compute/') - self._test_get_base_version_url('https://bar.org/compute/v2.1/123', - 'https://bar.org/compute/') - self._test_get_base_version_url('https://bar.org/compute/v2.15/123', - 'https://bar.org/compute/') - self._test_get_base_version_url('https://bar.org/compute/v22.2/123', - 'https://bar.org/compute/') - self._test_get_base_version_url('https://bar.org/compute/v22/123', - 'https://bar.org/compute/') - - def test_get_base_version_url_double_slash(self): - self._test_get_base_version_url('https://bar.org//v2/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org//v2.1/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org/compute//v2/123', - 'https://bar.org/compute/') - self._test_get_base_version_url('https://bar.org/compute//v2.1/123', - 'https://bar.org/compute/') diff --git a/tempest/tests/lib/services/compute/test_volumes_client.py b/tempest/tests/lib/services/compute/test_volumes_client.py deleted file mode 100644 index 4b4f02ede..000000000 --- a/tempest/tests/lib/services/compute/test_volumes_client.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -import fixtures - -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import volumes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVolumesClient(base.BaseServiceTest): - - FAKE_VOLUME = { - "id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "displayName": u"v\u12345ol-001", - "displayDescription": u"Another \u1234volume.", - "size": 30, - "status": "Active", - "volumeType": "289da7f8-6440-407c-9fb4-7db01ec49164", - "metadata": { - "contents": "junk" - }, - "availabilityZone": "us-east1", - "snapshotId": None, - "attachments": [], - "createdAt": "2012-02-14T20:53:07Z" - } - - FAKE_VOLUMES = {"volumes": [FAKE_VOLUME]} - - def setUp(self): - super(TestVolumesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = volumes_client.VolumesClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_volumes(self, bytes_body=False, **params): - self.check_service_client_function( - self.client.list_volumes, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_VOLUMES, to_utf=bytes_body, **params) - - def test_list_volumes_with_str_body(self): - self._test_list_volumes() - - def test_list_volumes_with_byte_body(self): - self._test_list_volumes(bytes_body=True) - - def test_list_volumes_with_params(self): - self._test_list_volumes(name='fake') - - def _test_show_volume(self, bytes_body=False): - self.check_service_client_function( - self.client.show_volume, - 'tempest.lib.common.rest_client.RestClient.get', - {"volume": self.FAKE_VOLUME}, - to_utf=bytes_body, volume_id=self.FAKE_VOLUME['id']) - - def test_show_volume_with_str_body(self): - self._test_show_volume() - - def test_show_volume_with_bytes_body(self): - self._test_show_volume(bytes_body=True) - - def _test_create_volume(self, bytes_body=False): - post_body = copy.deepcopy(self.FAKE_VOLUME) - del post_body['id'] - del post_body['createdAt'] - del post_body['status'] - self.check_service_client_function( - self.client.create_volume, - 'tempest.lib.common.rest_client.RestClient.post', - {"volume": self.FAKE_VOLUME}, - to_utf=bytes_body, status=200, **post_body) - - def test_create_volume_with_str_body(self): - self._test_create_volume() - - def test_create_volume_with_bytes_body(self): - self._test_create_volume(bytes_body=True) - - def test_delete_volume(self): - self.check_service_client_function( - self.client.delete_volume, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, volume_id=self.FAKE_VOLUME['id']) - - def test_is_resource_deleted_true(self): - module = ('tempest.lib.services.compute.volumes_client.' - 'VolumesClient.show_volume') - self.useFixture(fixtures.MockPatch( - module, side_effect=lib_exc.NotFound)) - self.assertTrue(self.client.is_resource_deleted('fake-id')) - - def test_is_resource_deleted_false(self): - module = ('tempest.lib.services.compute.volumes_client.' - 'VolumesClient.show_volume') - self.useFixture(fixtures.MockPatch( - module, return_value={})) - self.assertFalse(self.client.is_resource_deleted('fake-id')) diff --git a/tempest/tests/lib/services/identity/__init__.py b/tempest/tests/lib/services/identity/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/identity/v2/__init__.py b/tempest/tests/lib/services/identity/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/identity/v2/test_endpoints_client.py b/tempest/tests/lib/services/identity/v2/test_endpoints_client.py deleted file mode 100644 index 7d2cac275..000000000 --- a/tempest/tests/lib/services/identity/v2/test_endpoints_client.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v2 import endpoints_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEndpointsClient(base.BaseServiceTest): - FAKE_CREATE_ENDPOINT = { - "endpoint": { - "id": 1, - "tenantId": 1, - "region": "North", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - } - } - - FAKE_LIST_ENDPOINTS = { - "endpoints": [ - { - "id": 1, - "tenantId": "1", - "region": "North", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - }, - { - "id": 2, - "tenantId": "1", - "region": "South", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - } - ] - } - - def setUp(self): - super(TestEndpointsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = endpoints_client.EndpointsClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_endpoint(self, bytes_body=False): - self.check_service_client_function( - self.client.create_endpoint, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ENDPOINT, - bytes_body, - service_id="b344506af7644f6794d9cb316600b020", - region="region-demo", - publicurl="https://compute.north.public.com/v1", - adminurl="https://compute.north.internal.com/v1", - internalurl="https://compute.north.internal.com/v1") - - def _test_list_endpoints(self, bytes_body=False): - self.check_service_client_function( - self.client.list_endpoints, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ENDPOINTS, - bytes_body) - - def test_create_endpoint_with_str_body(self): - self._test_create_endpoint() - - def test_create_endpoint_with_bytes_body(self): - self._test_create_endpoint(bytes_body=True) - - def test_list_endpoints_with_str_body(self): - self._test_list_endpoints() - - def test_list_endpoints_with_bytes_body(self): - self._test_list_endpoints(bytes_body=True) - - def test_delete_endpoint(self): - self.check_service_client_function( - self.client.delete_endpoint, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - endpoint_id="b344506af7644f6794d9cb316600b020", - status=204) diff --git a/tempest/tests/lib/services/identity/v2/test_identity_client.py b/tempest/tests/lib/services/identity/v2/test_identity_client.py deleted file mode 100644 index 303d1f733..000000000 --- a/tempest/tests/lib/services/identity/v2/test_identity_client.py +++ /dev/null @@ -1,230 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v2 import identity_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestIdentityClient(base.BaseServiceTest): - FAKE_TOKEN = { - "tokens": { - "id": "cbc36478b0bd8e67e89", - "name": "FakeToken", - "type": "token", - } - } - - FAKE_ENDPOINTS_FOR_TOKEN = { - "endpoints_links": [], - "endpoints": [ - { - "name": "nova", - "adminURL": "https://nova.region-one.internal.com/" + - "v2/be1319401cfa4a0aa590b97cc7b64d8d", - "region": "RegionOne", - "internalURL": "https://nova.region-one.internal.com/" + - "v2/be1319401cfa4a0aa590b97cc7b64d8d", - "type": "compute", - "id": "11b41ee1b00841128b7333d4bf1a6140", - "publicURL": "https://nova.region-one.public.com/v2/" + - "be1319401cfa4a0aa590b97cc7b64d8d" - }, - { - "name": "neutron", - "adminURL": "https://neutron.region-one.internal.com/", - "region": "RegionOne", - "internalURL": "https://neutron.region-one.internal.com/", - "type": "network", - "id": "cdbfa3c416d741a9b5c968f2dc628acb", - "publicURL": "https://neutron.region-one.public.com/" - } - ] - } - - FAKE_API_INFO = { - "name": "API_info", - "type": "API", - "description": "test_description" - } - - FAKE_LIST_EXTENSIONS = { - "extensions": { - "values": [ - { - "updated": "2013-07-07T12:00:0-00:00", - "name": "OpenStack S3 API", - "links": [ - { - "href": "https://github.com/openstack/" + - "identity-api", - "type": "text/html", - "rel": "describedby" - } - ], - "namespace": "http://docs.openstack.org/identity/" + - "api/ext/s3tokens/v1.0", - "alias": "s3tokens", - "description": "OpenStack S3 API." - }, - { - "updated": "2013-12-17T12:00:0-00:00", - "name": "OpenStack Federation APIs", - "links": [ - { - "href": "https://github.com/openstack/" + - "identity-api", - "type": "text/html", - "rel": "describedby" - } - ], - "namespace": "http://docs.openstack.org/identity/" + - "api/ext/OS-FEDERATION/v1.0", - "alias": "OS-FEDERATION", - "description": "OpenStack Identity Providers Mechanism." - }, - { - "updated": "2014-01-20T12:00:0-00:00", - "name": "OpenStack Simple Certificate API", - "links": [ - { - "href": "https://github.com/openstack/" + - "identity-api", - "type": "text/html", - "rel": "describedby" - } - ], - "namespace": "http://docs.openstack.org/identity/api/" + - "ext/OS-SIMPLE-CERT/v1.0", - "alias": "OS-SIMPLE-CERT", - "description": "OpenStack simple certificate extension" - }, - { - "updated": "2013-07-07T12:00:0-00:00", - "name": "OpenStack OAUTH1 API", - "links": [ - { - "href": "https://github.com/openstack/" + - "identity-api", - "type": "text/html", - "rel": "describedby" - } - ], - "namespace": "http://docs.openstack.org/identity/" + - "api/ext/OS-OAUTH1/v1.0", - "alias": "OS-OAUTH1", - "description": "OpenStack OAuth Delegated Auth Mechanism." - }, - { - "updated": "2013-07-07T12:00:0-00:00", - "name": "OpenStack EC2 API", - "links": [ - { - "href": "https://github.com/openstack/" + - "identity-api", - "type": "text/html", - "rel": "describedby" - } - ], - "namespace": "http://docs.openstack.org/identity/api/" + - "ext/OS-EC2/v1.0", - "alias": "OS-EC2", - "description": "OpenStack EC2 Credentials backend." - } - ] - } - } - - def setUp(self): - super(TestIdentityClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = identity_client.IdentityClient(fake_auth, - 'identity', - 'regionOne') - - def _test_show_api_description(self, bytes_body=False): - self.check_service_client_function( - self.client.show_api_description, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_API_INFO, - bytes_body) - - def _test_list_extensions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_extensions, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_EXTENSIONS, - bytes_body) - - def _test_show_token(self, bytes_body=False): - self.check_service_client_function( - self.client.show_token, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_TOKEN, - bytes_body, - token_id="cbc36478b0bd8e67e89") - - def _test_list_endpoints_for_token(self, bytes_body=False): - self.check_service_client_function( - self.client.list_endpoints_for_token, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ENDPOINTS_FOR_TOKEN, - bytes_body, - token_id="cbc36478b0bd8e67e89") - - def _test_check_token_existence(self, bytes_body=False): - self.check_service_client_function( - self.client.check_token_existence, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - bytes_body, - token_id="cbc36478b0bd8e67e89") - - def test_show_api_description_with_str_body(self): - self._test_show_api_description() - - def test_show_api_description_with_bytes_body(self): - self._test_show_api_description(bytes_body=True) - - def test_show_list_extensions_with_str_body(self): - self._test_list_extensions() - - def test_show_list_extensions_with_bytes_body(self): - self._test_list_extensions(bytes_body=True) - - def test_show_token_with_str_body(self): - self._test_show_token() - - def test_show_token_with_bytes_body(self): - self._test_show_token(bytes_body=True) - - def test_list_endpoints_for_token_with_str_body(self): - self._test_list_endpoints_for_token() - - def test_list_endpoints_for_token_with_bytes_body(self): - self._test_list_endpoints_for_token(bytes_body=True) - - def test_check_token_existence_with_bytes_body(self): - self._test_check_token_existence(bytes_body=True) - - def test_check_token_existence_with_str_body(self): - self._test_check_token_existence() - - def test_delete_token(self): - self.check_service_client_function( - self.client.delete_token, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - token_id="cbc36478b0bd8e67e89", - status=204) diff --git a/tempest/tests/lib/services/identity/v2/test_roles_client.py b/tempest/tests/lib/services/identity/v2/test_roles_client.py deleted file mode 100644 index 464a71500..000000000 --- a/tempest/tests/lib/services/identity/v2/test_roles_client.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v2 import roles_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestRolesClient(base.BaseServiceTest): - FAKE_ROLE_INFO = { - "role": { - "id": "1", - "name": "test", - "description": "test_description" - } - } - - FAKE_LIST_ROLES = { - "roles": [ - { - "id": "1", - "name": "test", - "description": "test_description" - }, - { - "id": "2", - "name": "test2", - "description": "test2_description" - } - ] - } - - def setUp(self): - super(TestRolesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = roles_client.RolesClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_role(self, bytes_body=False): - self.check_service_client_function( - self.client.create_role, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_ROLE_INFO, - bytes_body, - id="1", - name="test", - description="test_description") - - def _test_show_role(self, bytes_body=False): - self.check_service_client_function( - self.client.show_role, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ROLE_INFO, - bytes_body, - role_id_or_name="1") - - def _test_list_roles(self, bytes_body=False): - self.check_service_client_function( - self.client.list_roles, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body) - - def _test_create_user_role_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user_role_on_project, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_ROLE_INFO, - bytes_body, - tenant_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=200) - - def _test_list_user_roles_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.list_user_roles_on_project, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body, - tenant_id="b344506af7644f6794d9cb316600b020", - user_id="123") - - def test_create_role_with_str_body(self): - self._test_create_role() - - def test_create_role_with_bytes_body(self): - self._test_create_role(bytes_body=True) - - def test_show_role_with_str_body(self): - self._test_show_role() - - def test_show_role_with_bytes_body(self): - self._test_show_role(bytes_body=True) - - def test_list_roles_with_str_body(self): - self._test_list_roles() - - def test_list_roles_with_bytes_body(self): - self._test_list_roles(bytes_body=True) - - def test_delete_role(self): - self.check_service_client_function( - self.client.delete_role, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - role_id="1", - status=204) - - def test_create_user_role_on_project_with_str_body(self): - self._test_create_user_role_on_project() - - def test_create_user_role_on_project_with_bytes_body(self): - self._test_create_user_role_on_project(bytes_body=True) - - def test_list_user_roles_on_project_with_str_body(self): - self._test_list_user_roles_on_project() - - def test_list_user_roles_on_project_with_bytes_body(self): - self._test_list_user_roles_on_project(bytes_body=True) - - def test_delete_role_from_user_on_project(self): - self.check_service_client_function( - self.client.delete_role_from_user_on_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - tenant_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) diff --git a/tempest/tests/lib/services/identity/v2/test_services_client.py b/tempest/tests/lib/services/identity/v2/test_services_client.py deleted file mode 100644 index bafb6b1e8..000000000 --- a/tempest/tests/lib/services/identity/v2/test_services_client.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v2 import services_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestServicesClient(base.BaseServiceTest): - FAKE_SERVICE_INFO = { - "OS-KSADM:service": { - "id": "1", - "name": "test", - "type": "compute", - "description": "test_description" - } - } - - FAKE_LIST_SERVICES = { - "OS-KSADM:services": [ - { - "id": "1", - "name": "test", - "type": "compute", - "description": "test_description" - }, - { - "id": "2", - "name": "test2", - "type": "compute", - "description": "test2_description" - } - ] - } - - def setUp(self): - super(TestServicesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = services_client.ServicesClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_service(self, bytes_body=False): - self.check_service_client_function( - self.client.create_service, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SERVICE_INFO, - bytes_body, - id="1", - name="test", - type="compute", - description="test_description") - - def _test_show_service(self, bytes_body=False): - self.check_service_client_function( - self.client.show_service, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVICE_INFO, - bytes_body, - service_id="1") - - def _test_list_services(self, bytes_body=False): - self.check_service_client_function( - self.client.list_services, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_SERVICES, - bytes_body) - - def test_create_service_with_str_body(self): - self._test_create_service() - - def test_create_service_with_bytes_body(self): - self._test_create_service(bytes_body=True) - - def test_show_service_with_str_body(self): - self._test_show_service() - - def test_show_service_with_bytes_body(self): - self._test_show_service(bytes_body=True) - - def test_delete_service(self): - self.check_service_client_function( - self.client.delete_service, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - service_id="1", - status=204) diff --git a/tempest/tests/lib/services/identity/v2/test_tenants_client.py b/tempest/tests/lib/services/identity/v2/test_tenants_client.py deleted file mode 100644 index ae3d13ab6..000000000 --- a/tempest/tests/lib/services/identity/v2/test_tenants_client.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v2 import tenants_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTenantsClient(base.BaseServiceTest): - FAKE_TENANT_INFO = { - "tenant": { - "id": "1", - "name": "test", - "description": "test_description", - "enabled": True - } - } - - FAKE_LIST_TENANTS = { - "tenants": [ - { - "id": "1", - "name": "test", - "description": "test_description", - "enabled": True - }, - { - "id": "2", - "name": "test2", - "description": "test2_description", - "enabled": True - } - ] - } - - def setUp(self): - super(TestTenantsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = tenants_client.TenantsClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_tenant(self, bytes_body=False): - self.check_service_client_function( - self.client.create_tenant, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_TENANT_INFO, - bytes_body, - name="test", - description="test_description") - - def _test_show_tenant(self, bytes_body=False): - self.check_service_client_function( - self.client.show_tenant, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_TENANT_INFO, - bytes_body, - tenant_id="1") - - def _test_update_tenant(self, bytes_body=False): - self.check_service_client_function( - self.client.update_tenant, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_TENANT_INFO, - bytes_body, - tenant_id="1", - name="test", - description="test_description") - - def _test_list_tenants(self, bytes_body=False): - self.check_service_client_function( - self.client.list_tenants, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_TENANTS, - bytes_body) - - def _test_list_tenant_users(self, bytes_body=False): - self.check_service_client_function( - self.client.list_tenant_users, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_TENANTS, - bytes_body, - tenant_id="1") - - def test_create_tenant_with_str_body(self): - self._test_create_tenant() - - def test_create_tenant_with_bytes_body(self): - self._test_create_tenant(bytes_body=True) - - def test_show_tenant_with_str_body(self): - self._test_show_tenant() - - def test_show_tenant_with_bytes_body(self): - self._test_show_tenant(bytes_body=True) - - def test_update_tenant_with_str_body(self): - self._test_update_tenant() - - def test_update_tenant_with_bytes_body(self): - self._test_update_tenant(bytes_body=True) - - def test_list_tenants_with_str_body(self): - self._test_list_tenants() - - def test_list_tenants_with_bytes_body(self): - self._test_list_tenants(bytes_body=True) - - def test_delete_tenant(self): - self.check_service_client_function( - self.client.delete_tenant, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - tenant_id="1", - status=204) - - def test_list_tenant_users_with_str_body(self): - self._test_list_tenant_users() - - def test_list_tenant_users_with_bytes_body(self): - self._test_list_tenant_users(bytes_body=True) diff --git a/tempest/tests/lib/services/identity/v2/test_token_client.py b/tempest/tests/lib/services/identity/v2/test_token_client.py deleted file mode 100644 index dfce9b37b..000000000 --- a/tempest/tests/lib/services/identity/v2/test_token_client.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import json - -import mock - -from tempest.lib.common import rest_client -from tempest.lib import exceptions -from tempest.lib.services.identity.v2 import token_client -from tempest.tests import base -from tempest.tests.lib import fake_http - - -class TestTokenClientV2(base.TestCase): - - def test_init_without_authurl(self): - self.assertRaises(exceptions.IdentityError, - token_client.TokenClient, None) - - def test_auth(self): - token_client_v2 = token_client.TokenClient('fake_url') - response = fake_http.fake_http_response( - None, status=200, - ) - body = {'access': {'token': 'fake_token'}} - - with mock.patch.object(token_client_v2, 'post') as post_mock: - post_mock.return_value = response, body - resp = token_client_v2.auth('fake_user', 'fake_pass') - - self.assertIsInstance(resp, rest_client.ResponseBody) - req_dict = json.dumps({ - 'auth': { - 'passwordCredentials': { - 'username': 'fake_user', - 'password': 'fake_pass', - }, - } - }, sort_keys=True) - post_mock.assert_called_once_with('fake_url/tokens', - body=req_dict) - - def test_auth_with_tenant(self): - token_client_v2 = token_client.TokenClient('fake_url') - response = fake_http.fake_http_response( - None, status=200, - ) - body = {'access': {'token': 'fake_token'}} - - with mock.patch.object(token_client_v2, 'post') as post_mock: - post_mock.return_value = response, body - resp = token_client_v2.auth('fake_user', 'fake_pass', - 'fake_tenant') - - self.assertIsInstance(resp, rest_client.ResponseBody) - req_dict = json.dumps({ - 'auth': { - 'tenantName': 'fake_tenant', - 'passwordCredentials': { - 'username': 'fake_user', - 'password': 'fake_pass', - }, - } - }, sort_keys=True) - post_mock.assert_called_once_with('fake_url/tokens', - body=req_dict) - - def test_request_with_str_body(self): - token_client_v2 = token_client.TokenClient('fake_url') - response = fake_http.fake_http_response( - None, status=200, - ) - body = str('{"access": {"token": "fake_token"}}') - - with mock.patch.object(token_client_v2, 'raw_request') as mock_raw_r: - mock_raw_r.return_value = response, body - resp, body = token_client_v2.request('GET', 'fake_uri') - self.assertIsInstance(body, dict) - - def test_request_with_bytes_body(self): - token_client_v2 = token_client.TokenClient('fake_url') - - response = fake_http.fake_http_response( - None, status=200, - ) - body = b'{"access": {"token": "fake_token"}}' - - with mock.patch.object(token_client_v2, 'raw_request') as mock_raw_r: - mock_raw_r.return_value = response, body - resp, body = token_client_v2.request('GET', 'fake_uri') - - self.assertIsInstance(body, dict) diff --git a/tempest/tests/lib/services/identity/v2/test_users_client.py b/tempest/tests/lib/services/identity/v2/test_users_client.py deleted file mode 100644 index 9534e4414..000000000 --- a/tempest/tests/lib/services/identity/v2/test_users_client.py +++ /dev/null @@ -1,243 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v2 import users_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestUsersClient(base.BaseServiceTest): - FAKE_USER_INFO = { - "user": { - "id": "1", - "name": "test", - "email": "john.smith@example.org", - "enabled": True - } - } - - FAKE_LIST_USERS = { - "users": [ - { - "id": "1", - "name": "test", - "email": "john.smith@example.org", - "enabled": True - }, - { - "id": "2", - "name": "test2", - "email": "john.smith@example.org", - "enabled": True - } - ] - } - - FAKE_USER_EC2_CREDENTIAL_INFO = { - "credential": { - 'user_id': '9beb0e12f3e5416db8d7cccfc785db3b', - 'access': '79abf59acc77492a86170cbe2f1feafa', - 'secret': 'c4e7d3a691fd4563873d381a40320f46', - 'trust_id': None, - 'tenant_id': '596557269d7b4dd78631a602eb9f151d' - } - } - - FAKE_LIST_USER_EC2_CREDENTIALS = { - "credentials": [ - { - 'user_id': '9beb0e12f3e5416db8d7cccfc785db3b', - 'access': '79abf59acc77492a86170cbe2f1feafa', - 'secret': 'c4e7d3a691fd4563873d381a40320f46', - 'trust_id': None, - 'tenant_id': '596557269d7b4dd78631a602eb9f151d' - }, - { - 'user_id': '3beb0e12f3e5416db8d7cccfc785de4r', - 'access': '45abf59acc77492a86170cbe2f1fesde', - 'secret': 'g4e7d3a691fd4563873d381a40320e45', - 'trust_id': None, - 'tenant_id': '123557269d7b4dd78631a602eb9f112f' - } - ] - } - - def setUp(self): - super(TestUsersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = users_client.UsersClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_user(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_USER_INFO, - bytes_body, - name="test", - email="john.smith@example.org") - - def _test_update_user(self, bytes_body=False): - self.check_service_client_function( - self.client.update_user, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_USER_INFO, - bytes_body, - user_id="1", - name="test") - - def _test_show_user(self, bytes_body=False): - self.check_service_client_function( - self.client.show_user, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_INFO, - bytes_body, - user_id="1") - - def _test_list_users(self, bytes_body=False): - self.check_service_client_function( - self.client.list_users, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_USERS, - bytes_body) - - def _test_update_user_enabled(self, bytes_body=False): - self.check_service_client_function( - self.client.update_user_enabled, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_USER_INFO, - bytes_body, - user_id="1", - enabled=True) - - def _test_update_user_password(self, bytes_body=False): - self.check_service_client_function( - self.client.update_user_password, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_USER_INFO, - bytes_body, - user_id="1", - password="pass") - - def _test_update_user_own_password(self, bytes_body=False): - self.check_service_client_function( - self.client.update_user_own_password, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_USER_INFO, - bytes_body, - user_id="1", - password="pass") - - def _test_create_user_ec2_credential(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user_ec2_credential, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_USER_EC2_CREDENTIAL_INFO, - bytes_body, - user_id="1", - tenant_id="123") - - def _test_show_user_ec2_credential(self, bytes_body=False): - self.check_service_client_function( - self.client.show_user_ec2_credential, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_EC2_CREDENTIAL_INFO, - bytes_body, - user_id="1", - access="123") - - def _test_list_user_ec2_credentials(self, bytes_body=False): - self.check_service_client_function( - self.client.list_user_ec2_credentials, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_USER_EC2_CREDENTIALS, - bytes_body, - user_id="1") - - def test_create_user_with_str_body(self): - self._test_create_user() - - def test_create_user_with_bytes_body(self): - self._test_create_user(bytes_body=True) - - def test_update_user_with_str_body(self): - self._test_update_user() - - def test_update_user_with_bytes_body(self): - self._test_update_user(bytes_body=True) - - def test_show_user_with_str_body(self): - self._test_show_user() - - def test_show_user_with_bytes_body(self): - self._test_show_user(bytes_body=True) - - def test_list_users_with_str_body(self): - self._test_list_users() - - def test_list_users_with_bytes_body(self): - self._test_list_users(bytes_body=True) - - def test_delete_user(self): - self.check_service_client_function( - self.client.delete_user, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - user_id="1", - status=204) - - def test_update_user_enabled_with_str_body(self): - self._test_update_user_enabled() - - def test_update_user_enabled_with_bytes_body(self): - self._test_update_user_enabled(bytes_body=True) - - def test_update_user_password_with_str_body(self): - self._test_update_user_password() - - def test_update_user_password_with_bytes_body(self): - self._test_update_user_password(bytes_body=True) - - def test_update_user_own_password_with_str_body(self): - self._test_update_user_own_password() - - def test_update_user_own_password_with_bytes_body(self): - self._test_update_user_own_password(bytes_body=True) - - def test_create_user_ec2_credential_with_str_body(self): - self._test_create_user_ec2_credential() - - def test_create_user_ec2_credential_with_bytes_body(self): - self._test_create_user_ec2_credential(bytes_body=True) - - def test_show_user_ec2_credential_with_str_body(self): - self._test_show_user_ec2_credential() - - def test_show_user_ec2_credential_with_bytes_body(self): - self._test_show_user_ec2_credential(bytes_body=True) - - def test_list_user_ec2_credentials_with_str_body(self): - self._test_list_user_ec2_credentials() - - def test_list_user_ec2_credentials_with_bytes_body(self): - self._test_list_user_ec2_credentials(bytes_body=True) - - def test_delete_user_ec2_credential(self): - self.check_service_client_function( - self.client.delete_user_ec2_credential, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - user_id="123", - access="1234", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/__init__.py b/tempest/tests/lib/services/identity/v3/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/identity/v3/test_catalog_client.py b/tempest/tests/lib/services/identity/v3/test_catalog_client.py deleted file mode 100644 index 0ac8fe426..000000000 --- a/tempest/tests/lib/services/identity/v3/test_catalog_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import catalog_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestCatalogClient(base.BaseServiceTest): - FAKE_CATALOG_INFO = { - 'catalog': [ - { - 'endpoints': [ - { - 'id': '39dc322ce86c4111b4f06c2eeae0841b', - 'interface': 'public', - 'region': 'RegionOne', - 'url': 'http://localhost:5000' - }, - ], - 'id': 'ac58672276f848a7b1727850b3ebe826', - 'type': 'compute', - 'name': 'nova' - }, - { - 'endpoints': [ - { - 'id': '39dc322ce86c4111b4f06c2eeae0841b', - 'interface': 'public', - 'region': 'RegionOne', - 'url': 'http://localhost:5000' - }, - ], - 'id': 'b7c5ed2b486a46dbb4c221499d22991c', - 'type': 'image', - 'name': 'glance' - }, - { - 'endpoints': [ - { - 'id': '39dc322ce86c4111b4f06c2eeae0841b', - 'interface': 'public', - 'region': 'RegionOne', - 'url': 'http://localhost:5000' - }, - ], - 'id': '4363ae44bdf34a3981fde3b823cb9aa2', - 'type': 'identity', - 'name': 'keystone' - } - - ], - 'links': { - 'self': 'http://localhost/identity/v3/catalog', - 'previous': None, - 'next': None - } - } - - def setUp(self): - super(TestCatalogClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = catalog_client.CatalogClient(fake_auth, 'identity', - 'RegionOne') - - def test_show_catalog_with_bytes_body(self): - self._test_show_catalog(bytes_body=True) - - def test_show_catalog_with_str_body(self): - self._test_show_catalog() - - def _test_show_catalog(self, bytes_body=False): - self.check_service_client_function( - self.client.show_catalog, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CATALOG_INFO, - bytes_body) diff --git a/tempest/tests/lib/services/identity/v3/test_credentials_client.py b/tempest/tests/lib/services/identity/v3/test_credentials_client.py deleted file mode 100644 index 29d749665..000000000 --- a/tempest/tests/lib/services/identity/v3/test_credentials_client.py +++ /dev/null @@ -1,179 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v3 import credentials_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestCredentialsClient(base.BaseServiceTest): - FAKE_CREATE_CREDENTIAL = { - "credential": { - "blob": "{\"access\":\"181920\",\"secret\":\"secretKey\"}", - "project_id": "731fc6f265cd486d900f16e84c5cb594", - "type": "ec2", - "user_id": "bb5476fd12884539b41d5a88f838d773" - } - } - - FAKE_INFO_CREDENTIAL = { - "credential": { - "user_id": "bb5476fd12884539b41d5a88f838d773", - "links": { - "self": "http://example.com/identity/v3/credentials/" + - "207e9b76935efc03804d3dd6ab52d22e9b22a0711e4" + - "ada4ff8b76165a07311d7" - }, - "blob": "{\"access\": \"a42a27755ce6442596b049bd7dd8a563\"," + - " \"secret\": \"71faf1d40bb24c82b479b1c6fbbd9f0c\"}", - "project_id": "6e01855f345f4c59812999b5e459137d", - "type": "ec2", - "id": "207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f" - } - } - - FAKE_LIST_CREDENTIALS = { - "credentials": [ - { - "user_id": "bb5476fd12884539b41d5a88f838d773", - "links": { - "self": "http://example.com/identity/v3/credentials/" + - "207e9b76935efc03804d3dd6ab52d22e9b22a0711e4" + - "ada4ff8b76165a07311d7" - }, - "blob": "{\"access\": \"a42a27755ce6442596b049bd7dd8a563\"," + - " \"secret\": \"71faf1d40bb24c82b479b1c6fbbd9f0c\"," + - " \"trust_id\": null}", - "project_id": "6e01855f345f4c59812999b5e459137d", - "type": "ec2", - "id": "207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f" - }, - { - "user_id": "6f556708d04b4ea6bc72d7df2296b71a", - "links": { - "self": "http://example.com/identity/v3/credentials/" + - "2441494e52ab6d594a34d74586075cb299489bdd1e9" + - "389e3ab06467a4f460609" - }, - "blob": "{\"access\": \"7da79ff0aa364e1396f067e352b9b79a\"," + - " \"secret\": \"7a18d68ba8834b799d396f3ff6f1e98c\"," + - " \"trust_id\": null}", - "project_id": "1a1d14690f3c4ec5bf5f321c5fde3c16", - "type": "ec2", - "id": "2441494e52ab6d594a34d74586075cb299489bdd1e9389e3" - }, - { - "user_id": "c14107e65d5c4a7f8894fc4b3fc209ff", - "links": { - "self": "http://example.com/identity/v3/credentials/" + - "3397b204b5f04c495bcdc8f34c8a39996f280f91726" + - "58241873e15f070ec79d7" - }, - "blob": "{\"access\": \"db9c58a558534a10a070110de4f9f20c\"," + - " \"secret\": \"973e790b88db447ba6f93bca02bc745b\"," + - " \"trust_id\": null}", - "project_id": "7396e43183db40dcbf40dd727637b548", - "type": "ec2", - "id": "3397b204b5f04c495bcdc8f34c8a39996f280f9172658241" - }, - { - "user_id": "bb5476fd12884539b41d5a88f838d773", - "links": { - "self": "http://example.com/identity/v3/credentials/" + - "7ef4faa904ae7b8b4ddc7bad15b05ee359dad7d7a9b" + - "82861d4ad92fdbbb2eb4e" - }, - "blob": "{\"access\": \"7d7559359b57419eb5f5f5dcd65ab57d\"," + - " \"secret\": \"570652bcf8c2483c86eb29e9734eed3c\"," + - " \"trust_id\": null}", - "project_id": "731fc6f265cd486d900f16e84c5cb594", - "type": "ec2", - "id": "7ef4faa904ae7b8b4ddc7bad15b05ee359dad7d7a9b82861" - }, - ], - "links": { - "self": "http://example.com/identity/v3/credentials", - "previous": None, - "next": None - } - } - - def setUp(self): - super(TestCredentialsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = credentials_client.CredentialsClient(fake_auth, - 'identity', - 'regionOne') - - def _test_create_credential(self, bytes_body=False): - self.check_service_client_function( - self.client.create_credential, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_CREDENTIAL, - bytes_body, status=201) - - def _test_show_credential(self, bytes_body=False): - self.check_service_client_function( - self.client.show_credential, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_CREDENTIAL, - bytes_body, - credential_id="207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f") - - def _test_update_credential(self, bytes_body=False): - self.check_service_client_function( - self.client.update_credential, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_INFO_CREDENTIAL, - bytes_body, - credential_id="207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f") - - def _test_list_credentials(self, bytes_body=False): - self.check_service_client_function( - self.client.list_credentials, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_CREDENTIALS, - bytes_body) - - def test_create_credential_with_str_body(self): - self._test_create_credential() - - def test_create_credential_with_bytes_body(self): - self._test_create_credential(bytes_body=True) - - def test_show_credential_with_str_body(self): - self._test_show_credential() - - def test_show_credential_with_bytes_body(self): - self._test_show_credential(bytes_body=True) - - def test_update_credential_with_str_body(self): - self._test_update_credential() - - def test_update_credential_with_bytes_body(self): - self._test_update_credential(bytes_body=True) - - def test_list_credentials_with_str_body(self): - self._test_list_credentials() - - def test_list_credentials_with_bytes_body(self): - self._test_list_credentials(bytes_body=True) - - def test_delete_credential(self): - self.check_service_client_function( - self.client.delete_credential, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - credential_id="207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_domain_configuration_client.py b/tempest/tests/lib/services/identity/v3/test_domain_configuration_client.py deleted file mode 100644 index 72e5bd2d5..000000000 --- a/tempest/tests/lib/services/identity/v3/test_domain_configuration_client.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import domain_configuration_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestDomainConfigurationClient(base.BaseServiceTest): - - FAKE_CONFIG_SETTINGS = { - "config": { - "identity": { - "driver": "ldap" - }, - "ldap": { - "url": "ldap://localhost", - "user": "", - "suffix": "cn=example,cn=com", - } - } - } - - FAKE_DOMAIN_ID = '07ef7d04-2941-4bee-8551-f79f08a021de' - - def setUp(self): - super(TestDomainConfigurationClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = domain_configuration_client.DomainConfigurationClient( - fake_auth, 'identity', 'regionOne') - - def _test_show_default_config_settings(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_config_settings, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CONFIG_SETTINGS, - bytes_body) - - def _test_show_default_group_config(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_group_config, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CONFIG_SETTINGS['config']['ldap'], - bytes_body, - group='ldap') - - def _test_show_default_group_option(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_group_option, - 'tempest.lib.common.rest_client.RestClient.get', - {'driver': 'ldap'}, - bytes_body, - group='identity', - option='driver') - - def _test_show_domain_group_option_config(self, bytes_body=False): - self.check_service_client_function( - self.client.show_domain_group_option_config, - 'tempest.lib.common.rest_client.RestClient.get', - {'driver': 'ldap'}, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - group='identity', - option='driver') - - def _test_update_domain_group_option_config(self, bytes_body=False): - self.check_service_client_function( - self.client.update_domain_group_option_config, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_CONFIG_SETTINGS, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - group='identity', - option='driver', - url='http://myldap/my_other_root') - - def _test_show_domain_group_config(self, bytes_body=False): - self.check_service_client_function( - self.client.show_domain_group_config, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CONFIG_SETTINGS['config']['ldap'], - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - group='ldap') - - def _test_update_domain_group_config(self, bytes_body=False): - self.check_service_client_function( - self.client.update_domain_group_config, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_CONFIG_SETTINGS['config']['ldap'], - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - group='ldap', - **self.FAKE_CONFIG_SETTINGS['config']) - - def _test_create_domain_config(self, bytes_body=False): - self.check_service_client_function( - self.client.create_domain_config, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_CONFIG_SETTINGS, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - status=201) - - def _test_show_domain_config(self, bytes_body=False): - self.check_service_client_function( - self.client.show_domain_config, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CONFIG_SETTINGS, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID) - - def _test_update_domain_config(self, bytes_body=False): - self.check_service_client_function( - self.client.update_domain_config, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_CONFIG_SETTINGS, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID) - - def test_show_default_config_settings_with_str_body(self): - self._test_show_default_config_settings() - - def test_show_default_config_settings_with_bytes_body(self): - self._test_show_default_config_settings(bytes_body=True) - - def test_show_default_group_config_with_str_body(self): - self._test_show_default_group_config() - - def test_show_default_group_config_with_bytes_body(self): - self._test_show_default_group_config(bytes_body=True) - - def test_show_default_group_option_with_str_body(self): - self._test_show_default_group_option() - - def test_show_default_group_option_with_bytes_body(self): - self._test_show_default_group_option(bytes_body=True) - - def test_show_domain_group_option_config_with_str_body(self): - self._test_show_domain_group_option_config() - - def test_show_domain_group_option_config_with_bytes_body(self): - self._test_show_domain_group_option_config(bytes_body=True) - - def test_update_domain_group_option_config_with_str_body(self): - self._test_update_domain_group_option_config() - - def test_update_domain_group_option_config_with_bytes_body(self): - self._test_update_domain_group_option_config(bytes_body=True) - - def test_delete_domain_group_option_config(self): - self.check_service_client_function( - self.client.delete_domain_group_option_config, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - domain_id=self.FAKE_DOMAIN_ID, - group='identity', - option='driver') - - def test_show_domain_group_config_with_str_body(self): - self._test_show_domain_group_config() - - def test_show_domain_group_config_with_bytes_body(self): - self._test_show_domain_group_config(bytes_body=True) - - def test_test_update_domain_group_config_with_str_body(self): - self._test_update_domain_group_config() - - def test_update_domain_group_config_with_bytes_body(self): - self._test_update_domain_group_config(bytes_body=True) - - def test_delete_domain_group_config(self): - self.check_service_client_function( - self.client.delete_domain_group_config, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - domain_id=self.FAKE_DOMAIN_ID, - group='identity') - - def test_create_domain_config_with_str_body(self): - self._test_create_domain_config() - - def test_create_domain_config_with_bytes_body(self): - self._test_create_domain_config(bytes_body=True) - - def test_show_domain_config_with_str_body(self): - self._test_show_domain_config() - - def test_show_domain_config_with_bytes_body(self): - self._test_show_domain_config(bytes_body=True) - - def test_update_domain_config_with_str_body(self): - self._test_update_domain_config() - - def test_update_domain_config_with_bytes_body(self): - self._test_update_domain_config(bytes_body=True) - - def test_delete_domain_config(self): - self.check_service_client_function( - self.client.delete_domain_config, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - domain_id=self.FAKE_DOMAIN_ID) diff --git a/tempest/tests/lib/services/identity/v3/test_domains_client.py b/tempest/tests/lib/services/identity/v3/test_domains_client.py deleted file mode 100644 index f89ced7c8..000000000 --- a/tempest/tests/lib/services/identity/v3/test_domains_client.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import domains_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestDomainsClient(base.BaseServiceTest): - FAKE_CREATE_DOMAIN = { - "domain": { - "description": "Domain description", - "enabled": True, - "name": "myDomain" - } - } - - FAKE_DOMAIN_INFO = { - "domain": { - "description": "Used for swift functional testing", - "enabled": True, - "id": "5a75994a3", - "links": { - "self": "http://example.com/identity/v3/domains/5a75994a3" - }, - "name": "swift_test" - } - } - - FAKE_LIST_DOMAINS = { - "domains": [ - { - "description": "Used for swift functional testing", - "enabled": True, - "id": "5a75994a3", - "links": { - "self": "http://example.com/identity/v3/domains/5a75994a3" - }, - "name": "swift_test" - }, - { - "description": "Owns users and tenants available on " + - "Identity API", - "enabled": True, - "id": "default", - "links": { - "self": "http://example.com/identity/v3/domains/default" - }, - "name": "Default" - } - ], - "links": { - "next": None, - "previous": None, - "self": "http://example.com/identity/v3/domains" - } - } - - def setUp(self): - super(TestDomainsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = domains_client.DomainsClient(fake_auth, - 'identity', - 'regionOne') - - def _test_create_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.create_domain, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_DOMAIN, - bytes_body, - status=201) - - def _test_show_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.show_domain, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_DOMAIN_INFO, - bytes_body, - domain_id="5a75994a3") - - def _test_list_domains(self, bytes_body=False): - self.check_service_client_function( - self.client.list_domains, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_DOMAINS, - bytes_body) - - def _test_update_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.update_domain, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_DOMAIN_INFO, - bytes_body, - domain_id="5a75994a3") - - def test_create_domain_with_str_body(self): - self._test_create_domain() - - def test_create_domain_with_bytes_body(self): - self._test_create_domain(bytes_body=True) - - def test_show_domain_with_str_body(self): - self._test_show_domain() - - def test_show_domain_with_bytes_body(self): - self._test_show_domain(bytes_body=True) - - def test_list_domain_with_str_body(self): - self._test_list_domains() - - def test_list_domain_with_bytes_body(self): - self._test_list_domains(bytes_body=True) - - def test_update_domain_with_str_body(self): - self._test_update_domain() - - def test_update_domain_with_bytes_body(self): - self._test_update_domain(bytes_body=True) - - def test_delete_domain(self): - self.check_service_client_function( - self.client.delete_domain, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - domain_id="5a75994a3", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py b/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py deleted file mode 100644 index 7faf6a02f..000000000 --- a/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright 2017 AT&T Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v3 import endpoint_filter_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEndPointsFilterClient(base.BaseServiceTest): - FAKE_LIST_PROJECTS_FOR_ENDPOINTS = { - "projects": [ - { - "domain_id": "1777c7", - "enabled": True, - "id": "1234ab1", - "type": "compute", - "links": { - "self": "http://example.com/identity/v3/projects/1234ab1" - }, - "name": "Project 1", - "description": "Project 1 description", - }, - { - "domain_id": "1777c7", - "enabled": True, - "id": "5678cd2", - "type": "compute", - "links": { - "self": "http://example.com/identity/v3/projects/5678cd2" - }, - "name": "Project 2", - "description": "Project 2 description", - } - ], - "links": { - "self": "http://example.com/identity/v3/OS-EP-FILTER/endpoints/\ - u6ay5u/projects", - "previous": None, - "next": None - } - } - - FAKE_LIST_ENDPOINTS_FOR_PROJECTS = { - "endpoints": [ - { - "id": "u6ay5u", - "interface": "public", - "url": "http://example.com/identity/", - "region": "north", - "links": { - "self": "http://example.com/identity/v3/endpoints/u6ay5u" - }, - "service_id": "5um4r", - }, - { - "id": "u6ay5u", - "interface": "internal", - "url": "http://example.com/identity/", - "region": "south", - "links": { - "self": "http://example.com/identity/v3/endpoints/u6ay5u" - }, - "service_id": "5um4r", - }, - ], - "links": { - "self": "http://example.com/identity/v3/OS-EP-FILTER/projects/\ - 1234ab1/endpoints", - "previous": None, - "next": None - } - } - - def setUp(self): - super(TestEndPointsFilterClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = endpoint_filter_client.EndPointsFilterClient( - fake_auth, 'identity', 'regionOne') - - def _test_add_endpoint_to_project(self, bytes_body=False): - self.check_service_client_function( - self.client.add_endpoint_to_project, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - status=204, - project_id=3, - endpoint_id=4) - - def _test_check_endpoint_in_project(self, bytes_body=False): - self.check_service_client_function( - self.client.check_endpoint_in_project, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - bytes_body, - status=204, - project_id=3, - endpoint_id=4) - - def _test_list_projects_for_endpoint(self, bytes_body=False): - self.check_service_client_function( - self.client.list_projects_for_endpoint, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_PROJECTS_FOR_ENDPOINTS, - bytes_body, - status=200, - endpoint_id=3) - - def _test_list_endpoints_in_project(self, bytes_body=False): - self.check_service_client_function( - self.client.list_endpoints_in_project, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ENDPOINTS_FOR_PROJECTS, - bytes_body, - status=200, - project_id=4) - - def _test_delete_endpoint_from_project(self, bytes_body=False): - self.check_service_client_function( - self.client.delete_endpoint_from_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - bytes_body, - status=204, - project_id=3, - endpoint_id=4) - - def test_add_endpoint_to_project_with_str_body(self): - self._test_add_endpoint_to_project() - - def test_add_endpoint_to_project_with_bytes_body(self): - self._test_add_endpoint_to_project(bytes_body=True) - - def test_check_endpoint_in_project_with_str_body(self): - self._test_check_endpoint_in_project() - - def test_check_endpoint_in_project_with_bytes_body(self): - self._test_check_endpoint_in_project(bytes_body=True) - - def test_list_projects_for_endpoint_with_str_body(self): - self._test_list_projects_for_endpoint() - - def test_list_projects_for_endpoint_with_bytes_body(self): - self._test_list_projects_for_endpoint(bytes_body=True) - - def test_list_endpoints_in_project_with_str_body(self): - self._test_list_endpoints_in_project() - - def test_list_endpoints_in_project_with_bytes_body(self): - self._test_list_endpoints_in_project(bytes_body=True) - - def test_delete_endpoint_from_project(self): - self._test_delete_endpoint_from_project() diff --git a/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py b/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py deleted file mode 100644 index c724f0a33..000000000 --- a/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v3 import endpoint_groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEndPointGroupsClient(base.BaseServiceTest): - FAKE_CREATE_ENDPOINT_GROUP = { - "endpoint_group": { - "id": 1, - "name": "FAKE_ENDPOINT_GROUP", - "description": "FAKE SERVICE ENDPOINT GROUP", - "filters": { - "service_id": 1 - } - } - } - - FAKE_ENDPOINT_GROUP_INFO = { - "endpoint_group": { - "id": 1, - "name": "FAKE_ENDPOINT_GROUP", - "description": "FAKE SERVICE ENDPOINT GROUP", - "links": { - "self": "http://example.com/identity/v3/OS-EP-FILTER/" + - "endpoint_groups/1" - }, - "filters": { - "service_id": 1 - } - } - } - - FAKE_LIST_ENDPOINT_GROUPS = { - "endpoint_groups": [ - { - "id": 1, - "name": "SERVICE_GROUP1", - "description": "FAKE SERVICE ENDPOINT GROUP", - "links": { - "self": "http://example.com/identity/v3/OS-EP-FILTER/" + - "endpoint_groups/1" - }, - "filters": { - "service_id": 1 - } - }, - { - "id": 2, - "name": "SERVICE_GROUP2", - "description": "FAKE SERVICE ENDPOINT GROUP", - "links": { - "self": "http://example.com/identity/v3/OS-EP-FILTER/" + - "endpoint_groups/2" - }, - "filters": { - "service_id": 2 - } - } - ] - } - - def setUp(self): - super(TestEndPointGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = endpoint_groups_client.EndPointGroupsClient( - fake_auth, 'identity', 'regionOne') - - def _test_create_endpoint_group(self, bytes_body=False): - self.check_service_client_function( - self.client.create_endpoint_group, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ENDPOINT_GROUP, - bytes_body, - status=201, - name="FAKE_ENDPOINT_GROUP", - filters={'service_id': "1"}) - - def _test_show_endpoint_group(self, bytes_body=False): - self.check_service_client_function( - self.client.show_endpoint_group, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ENDPOINT_GROUP_INFO, - bytes_body, - endpoint_group_id="1") - - def _test_check_endpoint_group(self, bytes_body=False): - self.check_service_client_function( - self.client.check_endpoint_group, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - bytes_body, - status=200, - endpoint_group_id="1") - - def _test_update_endpoint_group(self, bytes_body=False): - self.check_service_client_function( - self.client.update_endpoint_group, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_ENDPOINT_GROUP_INFO, - bytes_body, - endpoint_group_id="1", - name="NewName") - - def _test_list_endpoint_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_endpoint_groups, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ENDPOINT_GROUPS, - bytes_body) - - def test_create_endpoint_group_with_str_body(self): - self._test_create_endpoint_group() - - def test_create_endpoint_group_with_bytes_body(self): - self._test_create_endpoint_group(bytes_body=True) - - def test_show_endpoint_group_with_str_body(self): - self._test_show_endpoint_group() - - def test_show_endpoint_group_with_bytes_body(self): - self._test_show_endpoint_group(bytes_body=True) - - def test_check_endpoint_group_with_str_body(self): - self._test_check_endpoint_group() - - def test_check_endpoint_group_with_bytes_body(self): - self._test_check_endpoint_group(bytes_body=True) - - def test_list_endpoint_groups_with_str_body(self): - self._test_list_endpoint_groups() - - def test_list_endpoint_groups_with_bytes_body(self): - self._test_list_endpoint_groups(bytes_body=True) - - def test_update_endpoint_group_with_str_body(self): - self._test_update_endpoint_group() - - def test_update_endpoint_group_with_bytes_body(self): - self._test_update_endpoint_group(bytes_body=True) - - def test_delete_endpoint_group(self): - self.check_service_client_function( - self.client.delete_endpoint_group, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - endpoint_group_id="1", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_endpoints_client.py b/tempest/tests/lib/services/identity/v3/test_endpoints_client.py deleted file mode 100644 index ca15dd160..000000000 --- a/tempest/tests/lib/services/identity/v3/test_endpoints_client.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import endpoints_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEndpointsClient(base.BaseServiceTest): - FAKE_CREATE_ENDPOINT = { - "endpoint": { - "id": 1, - "tenantId": 1, - "region": "North", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - } - } - - FAKE_LIST_ENDPOINTS = { - "endpoints": [ - { - "id": 1, - "tenantId": "1", - "region": "North", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - }, - { - "id": 2, - "tenantId": "1", - "region": "South", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - } - ] - } - - FAKE_SERVICE_ID = "a4dc5060-f757-4662-b658-edd2aefbb41d" - - def setUp(self): - super(TestEndpointsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = endpoints_client.EndPointsClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_endpoint(self, bytes_body=False): - self.check_service_client_function( - self.client.create_endpoint, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ENDPOINT, - bytes_body, - status=201, - service_id="b344506af7644f6794d9cb316600b020", - region="region-demo", - publicurl="https://compute.north.public.com/v1", - adminurl="https://compute.north.internal.com/v1", - internalurl="https://compute.north.internal.com/v1") - - def _test_list_endpoints(self, bytes_body=False, mock_args='endpoints', - **params): - self.check_service_client_function( - self.client.list_endpoints, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ENDPOINTS, - bytes_body, - mock_args=[mock_args], - **params) - - def test_create_endpoint_with_str_body(self): - self._test_create_endpoint() - - def test_create_endpoint_with_bytes_body(self): - self._test_create_endpoint(bytes_body=True) - - def test_list_endpoints_with_str_body(self): - self._test_list_endpoints() - - def test_list_endpoints_with_bytes_body(self): - self._test_list_endpoints(bytes_body=True) - - def test_list_endpoints_with_params(self): - # Run the test separately for each param, to avoid assertion error - # resulting from randomized params order. - mock_args = 'endpoints?service_id=%s' % self.FAKE_SERVICE_ID - self._test_list_endpoints(mock_args=mock_args, - service_id=self.FAKE_SERVICE_ID) - - mock_args = 'endpoints?interface=public' - self._test_list_endpoints(mock_args=mock_args, interface='public') - - def test_delete_endpoint(self): - self.check_service_client_function( - self.client.delete_endpoint, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - endpoint_id="b344506af7644f6794d9cb316600b020", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_groups_client.py b/tempest/tests/lib/services/identity/v3/test_groups_client.py deleted file mode 100644 index 38cf3ae1c..000000000 --- a/tempest/tests/lib/services/identity/v3/test_groups_client.py +++ /dev/null @@ -1,213 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestGroupsClient(base.BaseServiceTest): - FAKE_CREATE_GROUP = { - 'group': { - 'description': 'Tempest Group Description', - 'domain_id': 'TempestDomain', - 'name': 'Tempest Group', - } - } - - FAKE_GROUP_INFO = { - 'group': { - 'description': 'Tempest Group Description', - 'domain_id': 'TempestDomain', - 'id': '6e13e2068cf9466e98950595baf6bb35', - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - '6e13e2068cf9466e98950595baf6bb35' - }, - 'name': 'Tempest Group', - } - } - - FAKE_GROUP_LIST = { - 'links': { - 'self': 'http://example.com/identity/v3/groups', - 'previous': None, - 'next': None, - }, - 'groups': [ - { - 'description': 'Tempest Group One Description', - 'domain_id': 'TempestDomain', - 'id': '1c92f3453ed34291a074b87493455b8f', - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - '1c92f3453ed34291a074b87493455b8f' - }, - 'name': 'Tempest Group One', - }, - { - 'description': 'Tempest Group Two Description', - 'domain_id': 'TempestDomain', - 'id': 'ce9e7dafed3b4877a7d4466ed730a9ee', - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - 'ce9e7dafed3b4877a7d4466ed730a9ee' - }, - 'name': 'Tempest Group Two', - }, - ] - } - - FAKE_USER_LIST = { - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - '6e13e2068cf9466e98950595baf6bb35/users', - 'previous': None, - 'next': None, - }, - 'users': [ - { - 'domain_id': 'TempestDomain', - 'description': 'Tempest Test User One Description', - 'enabled': True, - 'id': '642688fa65a84217b86cef3c063de2b9', - 'name': 'TempestUserOne', - 'links': { - 'self': 'http://example.com/identity/v3/users/' + - '642688fa65a84217b86cef3c063de2b9' - } - }, - { - 'domain_id': 'TempestDomain', - 'description': 'Tempest Test User Two Description', - 'enabled': True, - 'id': '1048ead6f8ef4a859b44ffbce3ac0b52', - 'name': 'TempestUserTwo', - 'links': { - 'self': 'http://example.com/identity/v3/users/' + - '1048ead6f8ef4a859b44ffbce3ac0b52' - } - }, - ] - } - - def setUp(self): - super(TestGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = groups_client.GroupsClient(fake_auth, 'identity', - 'regionOne') - - def _test_create_group(self, bytes_body=False): - self.check_service_client_function( - self.client.create_group, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_GROUP, - bytes_body, - status=201, - ) - - def _test_show_group(self, bytes_body=False): - self.check_service_client_function( - self.client.show_group, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_GROUP_INFO, - bytes_body, - group_id='6e13e2068cf9466e98950595baf6bb35', - ) - - def _test_list_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_groups, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_GROUP_LIST, - bytes_body, - ) - - def _test_update_group(self, bytes_body=False): - self.check_service_client_function( - self.client.update_group, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_GROUP_INFO, - bytes_body, - group_id='6e13e2068cf9466e98950595baf6bb35', - name='NewName', - ) - - def _test_list_users_in_group(self, bytes_body=False): - self.check_service_client_function( - self.client.list_group_users, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_LIST, - bytes_body, - group_id='6e13e2068cf9466e98950595baf6bb35', - ) - - def test_create_group_with_string_body(self): - self._test_create_group() - - def test_create_group_with_bytes_body(self): - self._test_create_group(bytes_body=True) - - def test_show_group_with_string_body(self): - self._test_show_group() - - def test_show_group_with_bytes_body(self): - self._test_show_group(bytes_body=True) - - def test_list_groups_with_string_body(self): - self._test_list_groups() - - def test_list_groups_with_bytes_body(self): - self._test_list_groups(bytes_body=True) - - def test_update_group_with_string_body(self): - self._test_update_group() - - def test_update_group_with_bytes_body(self): - self._test_update_group(bytes_body=True) - - def test_list_users_in_group_with_string_body(self): - self._test_list_users_in_group() - - def test_list_users_in_group_with_bytes_body(self): - self._test_list_users_in_group(bytes_body=True) - - def test_delete_group(self): - self.check_service_client_function( - self.client.delete_group, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - group_id='6e13e2068cf9466e98950595baf6bb35', - status=204, - ) - - def test_add_user_to_group(self): - self.check_service_client_function( - self.client.add_group_user, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - status=204, - group_id='6e13e2068cf9466e98950595baf6bb35', - user_id='642688fa65a84217b86cef3c063de2b9', - ) - - def test_check_user_in_group(self): - self.check_service_client_function( - self.client.check_group_user_existence, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - status=204, - group_id='6e13e2068cf9466e98950595baf6bb35', - user_id='642688fa65a84217b86cef3c063de2b9', - ) diff --git a/tempest/tests/lib/services/identity/v3/test_identity_client.py b/tempest/tests/lib/services/identity/v3/test_identity_client.py deleted file mode 100644 index 6572947fe..000000000 --- a/tempest/tests/lib/services/identity/v3/test_identity_client.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v3 import identity_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestIdentityClient(base.BaseServiceTest): - FAKE_TOKEN = { - "tokens": { - "id": "cbc36478b0bd8e67e89", - "name": "FakeToken", - "type": "token", - } - } - - FAKE_API_INFO = { - "name": "API_info", - "type": "API", - "description": "test_description" - } - - FAKE_AUTH_PROJECTS = { - "projects": [ - { - "domain_id": "1789d1", - "enabled": True, - "id": "263fd9", - "links": { - "self": "https://example.com/identity/v3/projects/263fd9" - }, - "name": "Test Group" - }, - { - "domain_id": "1789d1", - "enabled": True, - "id": "50ef01", - "links": { - "self": "https://example.com/identity/v3/projects/50ef01" - }, - "name": "Build Group" - } - ], - "links": { - "self": "https://example.com/identity/v3/auth/projects", - "previous": None, - "next": None - } - } - - def setUp(self): - super(TestIdentityClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = identity_client.IdentityClient(fake_auth, - 'identity', - 'regionOne') - - def _test_show_api_description(self, bytes_body=False): - self.check_service_client_function( - self.client.show_api_description, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_API_INFO, - bytes_body) - - def _test_show_token(self, bytes_body=False): - self.check_service_client_function( - self.client.show_token, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_TOKEN, - bytes_body, - resp_token="cbc36478b0bd8e67e89") - - def _test_list_auth_projects(self, bytes_body=False): - self.check_service_client_function( - self.client.list_auth_projects, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_AUTH_PROJECTS, - bytes_body) - - def test_show_api_description_with_str_body(self): - self._test_show_api_description() - - def test_show_api_description_with_bytes_body(self): - self._test_show_api_description(bytes_body=True) - - def test_show_token_with_str_body(self): - self._test_show_token() - - def test_show_token_with_bytes_body(self): - self._test_show_token(bytes_body=True) - - def test_delete_token(self): - self.check_service_client_function( - self.client.delete_token, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - resp_token="cbc36478b0bd8e67e89", - status=204) - - def test_check_token_existence(self): - self.check_service_client_function( - self.client.check_token_existence, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - resp_token="cbc36478b0bd8e67e89", - status=200) - - def test_list_auth_projects_with_str_body(self): - self._test_list_auth_projects() - - def test_list_auth_projects_with_bytes_body(self): - self._test_list_auth_projects(bytes_body=True) diff --git a/tempest/tests/lib/services/identity/v3/test_inherited_roles_client.py b/tempest/tests/lib/services/identity/v3/test_inherited_roles_client.py deleted file mode 100644 index 9da3cce61..000000000 --- a/tempest/tests/lib/services/identity/v3/test_inherited_roles_client.py +++ /dev/null @@ -1,220 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v3 import inherited_roles_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestInheritedRolesClient(base.BaseServiceTest): - FAKE_LIST_INHERITED_ROLES = { - "roles": [ - { - "id": "1", - "name": "test", - "links": "example.com" - }, - { - "id": "2", - "name": "test2", - "links": "example.com" - } - ] - } - - def setUp(self): - super(TestInheritedRolesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = inherited_roles_client.InheritedRolesClient( - fake_auth, 'identity', 'regionOne') - - def _test_create_inherited_role_on_domains_user(self, bytes_body=False): - self.check_service_client_function( - self.client.create_inherited_role_on_domains_user, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def _test_list_inherited_project_role_for_user_on_domain( - self, bytes_body=False): - self.check_service_client_function( - self.client.list_inherited_project_role_for_user_on_domain, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_INHERITED_ROLES, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123") - - def _test_create_inherited_role_on_domains_group(self, bytes_body=False): - self.check_service_client_function( - self.client.create_inherited_role_on_domains_group, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def _test_list_inherited_project_role_for_group_on_domain( - self, bytes_body=False): - self.check_service_client_function( - self.client.list_inherited_project_role_for_group_on_domain, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_INHERITED_ROLES, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123") - - def _test_create_inherited_role_on_projects_user(self, bytes_body=False): - self.check_service_client_function( - self.client.create_inherited_role_on_projects_user, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def _test_create_inherited_role_on_projects_group(self, bytes_body=False): - self.check_service_client_function( - self.client.create_inherited_role_on_projects_group, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_create_inherited_role_on_domains_user_with_str_body(self): - self._test_create_inherited_role_on_domains_user() - - def test_create_inherited_role_on_domains_user_with_bytes_body(self): - self._test_create_inherited_role_on_domains_user(bytes_body=True) - - def test_create_inherited_role_on_domains_group_with_str_body(self): - self._test_create_inherited_role_on_domains_group() - - def test_create_inherited_role_on_domains_group_with_bytes_body(self): - self._test_create_inherited_role_on_domains_group(bytes_body=True) - - def test_create_inherited_role_on_projects_user_with_str_body(self): - self._test_create_inherited_role_on_projects_user() - - def test_create_inherited_role_on_projects_group_with_bytes_body(self): - self._test_create_inherited_role_on_projects_group(bytes_body=True) - - def test_list_inherited_project_role_for_user_on_domain_with_str_body( - self): - self._test_list_inherited_project_role_for_user_on_domain() - - def test_list_inherited_project_role_for_user_on_domain_with_bytes_body( - self): - self._test_list_inherited_project_role_for_user_on_domain( - bytes_body=True) - - def test_list_inherited_project_role_for_group_on_domain_with_str_body( - self): - self._test_list_inherited_project_role_for_group_on_domain() - - def test_list_inherited_project_role_for_group_on_domain_with_bytes_body( - self): - self._test_list_inherited_project_role_for_group_on_domain( - bytes_body=True) - - def test_delete_inherited_role_from_user_on_domain(self): - self.check_service_client_function( - self.client.delete_inherited_role_from_user_on_domain, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_check_user_inherited_project_role_on_domain(self): - self.check_service_client_function( - self.client.check_user_inherited_project_role_on_domain, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_delete_inherited_role_from_group_on_domain(self): - self.check_service_client_function( - self.client.delete_inherited_role_from_group_on_domain, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_check_group_inherited_project_role_on_domain(self): - self.check_service_client_function( - self.client.check_group_inherited_project_role_on_domain, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_delete_inherited_role_from_user_on_project(self): - self.check_service_client_function( - self.client.delete_inherited_role_from_user_on_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_check_user_has_flag_on_inherited_to_project(self): - self.check_service_client_function( - self.client.check_user_has_flag_on_inherited_to_project, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_delete_inherited_role_from_group_on_project(self): - self.check_service_client_function( - self.client.delete_inherited_role_from_group_on_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_check_group_has_flag_on_inherited_to_project(self): - self.check_service_client_function( - self.client.check_group_has_flag_on_inherited_to_project, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_oauth_consumers_client.py b/tempest/tests/lib/services/identity/v3/test_oauth_consumers_client.py deleted file mode 100644 index 8d5379254..000000000 --- a/tempest/tests/lib/services/identity/v3/test_oauth_consumers_client.py +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v3 import oauth_consumers_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestOAUTHConsumerClient(base.BaseServiceTest): - FAKE_CREATE_CONSUMER = { - "consumer": { - 'description': 'A fake description 1' - } - - } - - FAKE_CONSUMER_INFO = { - "consumer": { - 'id': '6392c7d3b7a2062e09a07aa377', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/g6f2l9' - }, - 'description': 'A description that is fake' - } - - } - - FAKE_LIST_CONSUMERS = { - 'links': { - 'self': 'http://example.com/identity/v3/OS-OAUTH1/consumers/', - 'next': None, - 'previous': None - }, - 'consumers': [ - { - 'id': '6392c7d3b7a2062e09a07aa377', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/6b9f2g5' - }, - 'description': 'A description that is fake' - }, - { - 'id': '677a855c9e3eb3a3954b36aca6', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/6a9f2366' - }, - 'description': 'A very fake description 2' - }, - { - 'id': '9d3ac57b08d65e07826b5e506', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/626b5e506' - }, - 'description': 'A very fake description 3' - }, - { - 'id': 'b522d163b1a18e928aca9y426', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/g7ca9426' - }, - 'description': 'A very fake description 4' - }, - { - 'id': 'b7e47321b5ef9051f93c2049e', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/23d82049e' - }, - 'description': 'A very fake description 5' - } - ] - } - - def setUp(self): - super(TestOAUTHConsumerClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = oauth_consumers_client.OAUTHConsumerClient(fake_auth, - 'identity', - 'regionOne') - - def _test_create_consumer(self, bytes_body=False): - self.check_service_client_function( - self.client.create_consumer, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_CONSUMER, - bytes_body, - description=self.FAKE_CREATE_CONSUMER["consumer"]["description"], - status=201) - - def _test_show_consumer(self, bytes_body=False): - self.check_service_client_function( - self.client.show_consumer, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CONSUMER_INFO, - bytes_body, - consumer_id="6392c7d3b7a2062e09a07aa377") - - def _test_list_consumers(self, bytes_body=False): - self.check_service_client_function( - self.client.list_consumers, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_CONSUMERS, - bytes_body) - - def _test_update_consumer(self, bytes_body=False): - self.check_service_client_function( - self.client.update_consumer, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_CONSUMER_INFO, - bytes_body, - consumer_id="6392c7d3b7a2062e09a07aa377") - - def test_create_consumer_with_str_body(self): - self._test_create_consumer() - - def test_create_consumer_with_bytes_body(self): - self._test_create_consumer(bytes_body=True) - - def test_show_consumer_with_str_body(self): - self._test_show_consumer() - - def test_show_consumer_with_bytes_body(self): - self._test_show_consumer(bytes_body=True) - - def test_list_consumers_with_str_body(self): - self._test_list_consumers() - - def test_list_consumers_with_bytes_body(self): - self._test_list_consumers(bytes_body=True) - - def test_update_consumer_with_str_body(self): - self._test_update_consumer() - - def test_update_consumer_with_bytes_body(self): - self._test_update_consumer(bytes_body=True) - - def test_delete_consumer(self): - self.check_service_client_function( - self.client.delete_consumer, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - consumer_id="6392c7d3b7a2062e09a07aa377", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_oauth_token_client.py b/tempest/tests/lib/services/identity/v3/test_oauth_token_client.py deleted file mode 100644 index 420ea5f24..000000000 --- a/tempest/tests/lib/services/identity/v3/test_oauth_token_client.py +++ /dev/null @@ -1,215 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures - -from tempest.lib.services.identity.v3 import oauth_token_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -from tempest.tests.lib.services import base - - -class TestOAUTHTokenClient(base.BaseServiceTest): - FAKE_CREATE_REQUEST_TOKEN = { - 'oauth_token': '29971f', - 'oauth_token_secret': '238eb8', - 'oauth_expires_at': '2013-09-11T06:07:51.501805Z' - } - - FAKE_AUTHORIZE_REQUEST_TOKEN = { - 'token': { - 'oauth_verifier': '8171' - } - } - - FAKE_CREATE_ACCESS_TOKEN = { - 'oauth_token': 'accd36', - 'oauth_token_secret': 'aa47da', - 'oauth_expires_at': '2013-09-11T06:07:51.501805Z' - } - - FAKE_ACCESS_TOKEN_INFO = { - 'access_token': { - 'consumer_id': '7fea2d', - 'id': '6be26a', - 'expires_at': '2013-09-11T06:07:51.501805Z', - 'links': { - 'roles': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens/6be26a/roles', - 'self': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens/6be26a' - }, - 'project_id': 'b9fca3', - 'authorizing_user_id': 'ce9e07' - } - } - - FAKE_LIST_ACCESS_TOKENS = { - 'access_tokens': [ - { - 'consumer_id': '7fea2d', - 'id': '6be26a', - 'expires_at': '2013-09-11T06:07:51.501805Z', - 'links': { - 'roles': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens/' + - '6be26a/roles', - 'self': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens/6be26a' - }, - 'project_id': 'b9fca3', - 'authorizing_user_id': 'ce9e07' - } - ], - 'links': { - 'next': None, - 'previous': None, - 'self': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens' - } - } - - FAKE_LIST_ACCESS_TOKEN_ROLES = { - 'roles': [ - { - 'id': '26b860', - 'domain_id': 'fake_domain', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'roles/26b860' - }, - 'name': 'fake_role' - } - ], - 'links': { - 'next': None, - 'previous': None, - 'self': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens/6be26a/roles' - } - } - - FAKE_ACCESS_TOKEN_ROLE_INFO = { - 'role': { - 'id': '26b860', - 'domain_id': 'fake_domain', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'roles/26b860' - }, - 'name': 'fake_role' - } - } - - def setUp(self): - super(TestOAUTHTokenClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = oauth_token_client.OAUTHTokenClient(fake_auth, - 'identity', - 'regionOne') - - def _mock_token_response(self, body): - temp_response = [key + '=' + value for key, value in body.items()] - return '&'.join(temp_response) - - def _test_authorize_request_token(self, bytes_body=False): - self.check_service_client_function( - self.client.authorize_request_token, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_AUTHORIZE_REQUEST_TOKEN, - bytes_body, - request_token_id=self.FAKE_CREATE_REQUEST_TOKEN['oauth_token'], - role_ids=['26b860'], - status=200) - - def test_create_request_token(self): - mock_resp = self._mock_token_response(self.FAKE_CREATE_REQUEST_TOKEN) - resp = fake_http.fake_http_response(None, status=201), mock_resp - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.rest_client.RestClient.post', - return_value=resp)) - - resp = self.client.create_request_token( - consumer_key='12345', - consumer_secret='23456', - project_id='c8f58432c6f00162f04d3250f') - self.assertEqual(self.FAKE_CREATE_REQUEST_TOKEN, resp) - - def test_authorize_token_request_with_str_body(self): - self._test_authorize_request_token() - - def test_authorize_token_request_with_bytes_body(self): - self._test_authorize_request_token(bytes_body=True) - - def test_create_access_token(self): - mock_resp = self._mock_token_response(self.FAKE_CREATE_ACCESS_TOKEN) - req_secret = self.FAKE_CREATE_REQUEST_TOKEN['oauth_token_secret'] - resp = fake_http.fake_http_response(None, status=201), mock_resp - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.rest_client.RestClient.post', - return_value=resp)) - - resp = self.client.create_access_token( - consumer_key='12345', - consumer_secret='23456', - request_key=self.FAKE_CREATE_REQUEST_TOKEN['oauth_token'], - request_secret=req_secret, - oauth_verifier='8171') - self.assertEqual(self.FAKE_CREATE_ACCESS_TOKEN, resp) - - def test_get_access_token(self): - self.check_service_client_function( - self.client.get_access_token, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ACCESS_TOKEN_INFO, - user_id='ce9e07', - access_token_id=self.FAKE_ACCESS_TOKEN_INFO['access_token']['id'], - status=200) - - def test_list_access_tokens(self): - self.check_service_client_function( - self.client.list_access_tokens, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ACCESS_TOKENS, - user_id='ce9e07', - status=200) - - def test_revoke_access_token(self): - self.check_service_client_function( - self.client.revoke_access_token, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - user_id=self.FAKE_ACCESS_TOKEN_INFO['access_token']['consumer_id'], - access_token_id=self.FAKE_ACCESS_TOKEN_INFO['access_token']['id'], - status=204) - - def test_list_access_token_roles(self): - self.check_service_client_function( - self.client.list_access_token_roles, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ACCESS_TOKEN_ROLES, - user_id='ce9e07', - access_token_id=self.FAKE_ACCESS_TOKEN_INFO['access_token']['id'], - status=200) - - def test_get_access_token_role(self): - self.check_service_client_function( - self.client.get_access_token_role, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ACCESS_TOKEN_ROLE_INFO, - user_id='ce9e07', - access_token_id=self.FAKE_ACCESS_TOKEN_INFO['access_token']['id'], - role_id=self.FAKE_ACCESS_TOKEN_ROLE_INFO['role']['id'], - status=200) diff --git a/tempest/tests/lib/services/identity/v3/test_policies_client.py b/tempest/tests/lib/services/identity/v3/test_policies_client.py deleted file mode 100644 index 66c3d6540..000000000 --- a/tempest/tests/lib/services/identity/v3/test_policies_client.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import policies_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestPoliciesClient(base.BaseServiceTest): - FAKE_CREATE_POLICY = { - "policy": { - "blob": "{'foobar_user': 'role:compute-user'}", - "project_id": "0426ac1e48f642ef9544c2251e07e261", - "type": "application/json", - "user_id": "0ffd248c55b443eaac5253b4e9cbf9b5" - } - } - - FAKE_POLICY_INFO = { - "policy": { - "blob": { - "foobar_user": [ - "role:compute-user" - ] - }, - "id": "717273", - "links": { - "self": "http://example.com/identity/v3/policies/717273" - }, - "project_id": "456789", - "type": "application/json", - "user_id": "616263" - } - } - - FAKE_LIST_POLICIES = { - "links": { - "next": None, - "previous": None, - "self": "http://example.com/identity/v3/policies" - }, - "policies": [ - { - "blob": { - "foobar_user": [ - "role:compute-user" - ] - }, - "id": "717273", - "links": { - "self": "http://example.com/identity/v3/policies/717273" - }, - "project_id": "456789", - "type": "application/json", - "user_id": "616263" - }, - { - "blob": { - "foobar_user": [ - "role:compute-user" - ] - }, - "id": "717274", - "links": { - "self": "http://example.com/identity/v3/policies/717274" - }, - "project_id": "456789", - "type": "application/json", - "user_id": "616263" - } - ] - } - - def setUp(self): - super(TestPoliciesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = policies_client.PoliciesClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_policy(self, bytes_body=False): - self.check_service_client_function( - self.client.create_policy, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_POLICY, - bytes_body, - status=201) - - def _test_show_policy(self, bytes_body=False): - self.check_service_client_function( - self.client.show_policy, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_POLICY_INFO, - bytes_body, - policy_id="717273") - - def _test_list_policies(self, bytes_body=False): - self.check_service_client_function( - self.client.list_policies, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_POLICIES, - bytes_body) - - def _test_update_policy(self, bytes_body=False): - self.check_service_client_function( - self.client.update_policy, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_POLICY_INFO, - bytes_body, - policy_id="717273") - - def test_create_policy_with_str_body(self): - self._test_create_policy() - - def test_create_policy_with_bytes_body(self): - self._test_create_policy(bytes_body=True) - - def test_show_policy_with_str_body(self): - self._test_show_policy() - - def test_show_policy_with_bytes_body(self): - self._test_show_policy(bytes_body=True) - - def test_list_policies_with_str_body(self): - self._test_list_policies() - - def test_list_policies_with_bytes_body(self): - self._test_list_policies(bytes_body=True) - - def test_update_policy_with_str_body(self): - self._test_update_policy() - - def test_update_policy_with_bytes_body(self): - self._test_update_policy(bytes_body=True) - - def test_delete_policy(self): - self.check_service_client_function( - self.client.delete_policy, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - policy_id="717273", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_projects_client.py b/tempest/tests/lib/services/identity/v3/test_projects_client.py deleted file mode 100644 index 6ffbcdef2..000000000 --- a/tempest/tests/lib/services/identity/v3/test_projects_client.py +++ /dev/null @@ -1,178 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import projects_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestProjectsClient(base.BaseServiceTest): - FAKE_CREATE_PROJECT = { - "project": { - "description": "My new project", - "domain_id": "default", - "enabled": True, - "is_domain": False, - "name": "myNewProject" - } - } - - FAKE_PROJECT_INFO = { - "project": { - "is_domain": False, - "description": None, - "domain_id": "default", - "enabled": True, - "id": "0c4e939acacf4376bdcd1129f1a054ad", - "links": { - "self": "http://example.com/identity/v3/projects/0c4e" + - "939acacf4376bdcd1129f1a054ad" - }, - "name": "admin", - "parent_id": "default" - } - } - - FAKE_LIST_PROJECTS = { - "links": { - "next": None, - "previous": None, - "self": "http://example.com/identity/v3/projects" - }, - "projects": [ - { - "is_domain": False, - "description": None, - "domain_id": "default", - "enabled": True, - "id": "0c4e939acacf4376bdcd1129f1a054ad", - "links": { - "self": "http://example.com/identity/v3/projects" + - "/0c4e939acacf4376bdcd1129f1a054ad" - }, - "name": "admin", - "parent_id": None - }, - { - "is_domain": False, - "description": None, - "domain_id": "default", - "enabled": True, - "id": "0cbd49cbf76d405d9c86562e1d579bd3", - "links": { - "self": "http://example.com/identity/v3/projects" + - "/0cbd49cbf76d405d9c86562e1d579bd3" - }, - "name": "demo", - "parent_id": None - }, - { - "is_domain": False, - "description": None, - "domain_id": "default", - "enabled": True, - "id": "2db68fed84324f29bb73130c6c2094fb", - "links": { - "self": "http://example.com/identity/v3/projects" + - "/2db68fed84324f29bb73130c6c2094fb" - }, - "name": "swifttenanttest2", - "parent_id": None - }, - { - "is_domain": False, - "description": None, - "domain_id": "default", - "enabled": True, - "id": "3d594eb0f04741069dbbb521635b21c7", - "links": { - "self": "http://example.com/identity/v3/projects" + - "/3d594eb0f04741069dbbb521635b21c7" - }, - "name": "service", - "parent_id": None - } - ] - } - - def setUp(self): - super(TestProjectsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = projects_client.ProjectsClient(fake_auth, - 'identity', - 'regionOne') - - def _test_create_project(self, bytes_body=False): - self.check_service_client_function( - self.client.create_project, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_PROJECT, - bytes_body, - name=self.FAKE_CREATE_PROJECT["project"]["name"], - status=201) - - def _test_show_project(self, bytes_body=False): - self.check_service_client_function( - self.client.show_project, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_PROJECT_INFO, - bytes_body, - project_id="0c4e939acacf4376bdcd1129f1a054ad") - - def _test_list_projects(self, bytes_body=False): - self.check_service_client_function( - self.client.list_projects, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_PROJECTS, - bytes_body) - - def _test_update_project(self, bytes_body=False): - self.check_service_client_function( - self.client.update_project, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_PROJECT_INFO, - bytes_body, - project_id="0c4e939acacf4376bdcd1129f1a054ad") - - def test_create_project_with_str_body(self): - self._test_create_project() - - def test_create_project_with_bytes_body(self): - self._test_create_project(bytes_body=True) - - def test_show_project_with_str_body(self): - self._test_show_project() - - def test_show_project_with_bytes_body(self): - self._test_show_project(bytes_body=True) - - def test_list_projects_with_str_body(self): - self._test_list_projects() - - def test_list_projects_with_bytes_body(self): - self._test_list_projects(bytes_body=True) - - def test_update_project_with_str_body(self): - self._test_update_project() - - def test_update_project_with_bytes_body(self): - self._test_update_project(bytes_body=True) - - def test_delete_project(self): - self.check_service_client_function( - self.client.delete_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - project_id="0c4e939acacf4376bdcd1129f1a054ad", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_regions_client.py b/tempest/tests/lib/services/identity/v3/test_regions_client.py deleted file mode 100644 index a2cb86fe2..000000000 --- a/tempest/tests/lib/services/identity/v3/test_regions_client.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import regions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestRegionsClient(base.BaseServiceTest): - FAKE_CREATE_REGION = { - "region": { - "description": "My subregion", - "id": "RegionOneSubRegion", - "parent_region_id": "RegionOne" - } - } - - FAKE_REGION_INFO = { - "region": { - "description": "My subregion 3", - "id": "RegionThree", - "links": { - "self": "http://example.com/identity/v3/regions/RegionThree" - }, - "parent_region_id": "RegionOne" - } - } - - FAKE_LIST_REGIONS = { - "links": { - "next": None, - "previous": None, - "self": "http://example.com/identity/v3/regions" - }, - "regions": [ - { - "description": "", - "id": "RegionOne", - "links": { - "self": "http://example.com/identity/v3/regions/RegionOne" - }, - "parent_region_id": None - } - ] - } - - def setUp(self): - super(TestRegionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = regions_client.RegionsClient(fake_auth, 'identity', - 'regionOne') - - def _test_create_region(self, bytes_body=False): - self.check_service_client_function( - self.client.create_region, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_REGION, - bytes_body, - status=201) - - def _test_show_region(self, bytes_body=False): - self.check_service_client_function( - self.client.show_region, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_REGION_INFO, - bytes_body, - region_id="RegionThree") - - def _test_list_regions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_regions, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_REGIONS, - bytes_body) - - def _test_update_region(self, bytes_body=False): - self.check_service_client_function( - self.client.update_region, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_REGION_INFO, - bytes_body, - region_id="RegionThree") - - def test_create_region_with_str_body(self): - self._test_create_region() - - def test_create_region_with_bytes_body(self): - self._test_create_region(bytes_body=True) - - def test_show_region_with_str_body(self): - self._test_show_region() - - def test_show_region_with_bytes_body(self): - self._test_show_region(bytes_body=True) - - def test_list_regions_with_str_body(self): - self._test_list_regions() - - def test_list_regions_with_bytes_body(self): - self._test_list_regions(bytes_body=True) - - def test_update_region_with_str_body(self): - self._test_update_region() - - def test_update_region_with_bytes_body(self): - self._test_update_region(bytes_body=True) - - def test_delete_region(self): - self.check_service_client_function( - self.client.delete_region, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - region_id="RegionThree", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_role_assignments_client.py b/tempest/tests/lib/services/identity/v3/test_role_assignments_client.py deleted file mode 100644 index 7d304c12e..000000000 --- a/tempest/tests/lib/services/identity/v3/test_role_assignments_client.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import role_assignments_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestRoleAssignmentsClient(base.BaseServiceTest): - - FAKE_USER_ID = "313234" - FAKE_GROUP_ID = "101112" - - FAKE_ROLE1_ID = "123456" - FAKE_ROLE2_ID = "123457" - - FAKE_PROJECT_ID = "456789" - FAKE_DOMAIN_ID = "102030" - - FAKE_USER_PROJECT_ASSIGNMENT = { - "links": { - "assignment": "http://example.com/identity/v3/projects/" - "%s/users/%s/roles/%s" % (FAKE_PROJECT_ID, - FAKE_USER_ID, - FAKE_ROLE2_ID) - }, - "role": { - "id": FAKE_ROLE2_ID - }, - "scope": { - "project": { - "id": FAKE_PROJECT_ID - } - }, - "user": { - "id": FAKE_USER_ID - } - } - - FAKE_GROUP_PROJECT_ASSIGNMENT = { - "links": { - "assignment": "http://example.com/identity/v3/projects/" - "%s/groups/%s/roles/%s" % (FAKE_PROJECT_ID, - FAKE_GROUP_ID, - FAKE_ROLE1_ID) - }, - "role": { - "id": FAKE_ROLE1_ID - }, - "scope": { - "project": { - "id": FAKE_PROJECT_ID - } - }, - "group": { - "id": FAKE_GROUP_ID - } - } - - FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENT = { - "links": { - "assignment": "http://example.com/identity/v3/projects/" - "%s/groups/%s/roles/%s" % (FAKE_PROJECT_ID, - FAKE_GROUP_ID, - FAKE_ROLE1_ID), - "membership": "http://example.com/identity/v3/groups/" - "%s/users/%s" % (FAKE_GROUP_ID, FAKE_USER_ID) - }, - "role": { - "id": FAKE_ROLE1_ID - }, - "scope": { - "project": { - "id": FAKE_PROJECT_ID - } - }, - "user": { - "id": FAKE_USER_ID - } - } - - FAKE_USER_DOMAIN_ASSIGNMENT = { - "links": { - "assignment": "http://example.com/identity/v3/domains/" - "%s/users/%s/roles/%s" % (FAKE_DOMAIN_ID, - FAKE_USER_ID, - FAKE_ROLE1_ID) - }, - "role": { - "id": FAKE_ROLE1_ID - }, - "scope": { - "domain": { - "id": FAKE_DOMAIN_ID - } - }, - "user": { - "id": FAKE_USER_ID - } - } - - FAKE_GROUP_PROJECT_ASSIGNMENTS = { - "role_assignments": [ - FAKE_GROUP_PROJECT_ASSIGNMENT - ], - "links": { - "self": "http://example.com/identity/v3/role_assignments?" - "scope.project.id=%s&group.id=%s&effective" % ( - FAKE_PROJECT_ID, FAKE_GROUP_ID), - "previous": None, - "next": None - } - } - - FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENTS = { - "role_assignments": [ - FAKE_USER_PROJECT_ASSIGNMENT, - FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENT - ], - "links": { - "self": "http://example.com/identity/v3/role_assignments?" - "scope.project.id=%s&user.id=%s&effective" % ( - FAKE_PROJECT_ID, FAKE_USER_ID), - "previous": None, - "next": None - } - } - - FAKE_USER_DOMAIN_ASSIGNMENTS = { - "role_assignments": [ - FAKE_USER_DOMAIN_ASSIGNMENT - ], - "links": { - "self": "http://example.com/identity/v3/role_assignments?" - "scope.domain.id=%s&user.id=%s&effective" % ( - FAKE_DOMAIN_ID, FAKE_USER_ID), - "previous": None, - "next": None - } - } - - def setUp(self): - super(TestRoleAssignmentsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = role_assignments_client.RoleAssignmentsClient( - fake_auth, 'identity', 'regionOne') - - def _test_list_user_project_effective_assignments(self, bytes_body=False): - params = {'scope.project.id': self.FAKE_PROJECT_ID, - 'user.id': self.FAKE_USER_ID} - self.check_service_client_function( - self.client.list_role_assignments, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENTS, - bytes_body, - effective=True, - **params) - - def test_list_user_project_effective_assignments_with_str_body(self): - self._test_list_user_project_effective_assignments() - - def test_list_user_project_effective_assignments_with_bytes_body(self): - self._test_list_user_project_effective_assignments(bytes_body=True) - - def _test_list_group_project_assignments(self, bytes_body=False): - params = {'scope.project.id': self.FAKE_PROJECT_ID, - 'group.id': self.FAKE_GROUP_ID} - self.check_service_client_function( - self.client.list_role_assignments, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_GROUP_PROJECT_ASSIGNMENTS, - bytes_body, - **params) - - def test_list_group_project_assignments_with_str_body(self): - self._test_list_group_project_assignments() - - def test_list_group_project_assignments_with_bytes_body(self): - self._test_list_group_project_assignments(bytes_body=True) - - def _test_list_user_domain_assignments(self, bytes_body=False): - params = {'scope.domain.id': self.FAKE_DOMAIN_ID, - 'user.id': self.FAKE_USER_ID} - self.check_service_client_function( - self.client.list_role_assignments, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_GROUP_PROJECT_ASSIGNMENTS, - bytes_body, - **params) - - def test_list_user_domain_assignments_with_str_body(self): - self._test_list_user_domain_assignments() - - def test_list_user_domain_assignments_with_bytes_body(self): - self._test_list_user_domain_assignments(bytes_body=True) diff --git a/tempest/tests/lib/services/identity/v3/test_roles_client.py b/tempest/tests/lib/services/identity/v3/test_roles_client.py deleted file mode 100644 index 8d6bb423a..000000000 --- a/tempest/tests/lib/services/identity/v3/test_roles_client.py +++ /dev/null @@ -1,508 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v3 import roles_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestRolesClient(base.BaseServiceTest): - - FAKE_ROLE_ID = "1" - FAKE_ROLE_NAME = "test" - FAKE_DOMAIN_ID = "1" - - FAKE_ROLE_ID_2 = "2" - FAKE_ROLE_NAME_2 = "test2" - - FAKE_ROLE_ID_3 = "3" - FAKE_ROLE_NAME_3 = "test3" - - FAKE_ROLE_ID_4 = "4" - FAKE_ROLE_NAME_4 = "test4" - - FAKE_ROLE_ID_5 = "5" - FAKE_ROLE_NAME_5 = "test5" - - FAKE_ROLE_ID_6 = "6" - FAKE_ROLE_NAME_6 = "test6" - - FAKE_ROLE_INFO = { - "role": { - "domain_id": FAKE_DOMAIN_ID, - "id": FAKE_ROLE_ID, - "name": FAKE_ROLE_NAME, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID) - } - } - } - - FAKE_ROLE_INFO_2 = { - "role": { - "domain_id": FAKE_DOMAIN_ID, - "id": FAKE_ROLE_ID_2, - "name": FAKE_ROLE_NAME_2, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_2) - } - } - } - - FAKE_LIST_ROLES = {"roles": [FAKE_ROLE_INFO, FAKE_ROLE_INFO_2]} - - FAKE_ROLE_INFERENCE_RULE = { - "role_inference": { - "prior_role": { - "id": FAKE_ROLE_ID, - "name": FAKE_ROLE_NAME, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID) - } - }, - "implies": { - "id": FAKE_ROLE_ID_2, - "name": FAKE_ROLE_NAME_2, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_2) - } - } - }, - "links": { - "self": "http://example.com/identity/v3/roles/" - "%s/implies/%s" % (FAKE_ROLE_ID, FAKE_ROLE_ID_2) - } - } - - COMMON_FAKE_LIST_ROLE_INFERENCE_RULES = [ - { - "prior_role": { - "id": FAKE_ROLE_ID, - "name": FAKE_ROLE_NAME, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID) - } - }, - "implies": [ - { - "id": FAKE_ROLE_ID_2, - "name": FAKE_ROLE_NAME_2, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_2) - } - }, - { - "id": FAKE_ROLE_ID_3, - "name": FAKE_ROLE_NAME_3, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_3) - } - } - ] - }, - { - "prior_role": { - "id": FAKE_ROLE_ID_4, - "name": FAKE_ROLE_NAME_4, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_4) - } - }, - "implies": [ - { - "id": FAKE_ROLE_ID_5, - "name": FAKE_ROLE_NAME_5, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_5) - } - }, - { - "id": FAKE_ROLE_ID_6, - "name": FAKE_ROLE_NAME_6, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_6) - } - } - ] - } - ] - - FAKE_LIST_ROLE_INFERENCE_RULES = { - "role_inference": COMMON_FAKE_LIST_ROLE_INFERENCE_RULES[0], - "links": { - "self": "http://example.com/identity/v3/roles/" - "%s/implies" % FAKE_ROLE_ID - } - } - - FAKE_LIST_ALL_ROLE_INFERENCE_RULES = { - "role_inferences": COMMON_FAKE_LIST_ROLE_INFERENCE_RULES, - "links": { - "self": "http://example.com/identity/v3/role_inferences" - } - } - - def setUp(self): - super(TestRolesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = roles_client.RolesClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_role(self, bytes_body=False): - self.check_service_client_function( - self.client.create_role, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_ROLE_INFO, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - name=self.FAKE_ROLE_NAME, - status=201) - - def _test_show_role(self, bytes_body=False): - self.check_service_client_function( - self.client.show_role, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ROLE_INFO, - bytes_body, - role_id=self.FAKE_ROLE_ID) - - def _test_list_roles(self, bytes_body=False): - self.check_service_client_function( - self.client.list_roles, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body) - - def _test_update_role(self, bytes_body=False): - self.check_service_client_function( - self.client.update_role, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_ROLE_INFO, - bytes_body, - role_id=self.FAKE_ROLE_ID, - name=self.FAKE_ROLE_NAME) - - def _test_create_user_role_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user_role_on_project, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def _test_create_user_role_on_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user_role_on_domain, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def _test_list_user_roles_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.list_user_roles_on_project, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123") - - def _test_list_user_roles_on_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.list_user_roles_on_domain, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123") - - def _test_create_group_role_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.create_group_role_on_project, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def _test_create_group_role_on_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.create_group_role_on_domain, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def _test_list_group_roles_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.list_group_roles_on_project, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123") - - def _test_list_group_roles_on_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.list_group_roles_on_domain, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123") - - def _test_create_role_inference_rule(self, bytes_body=False): - self.check_service_client_function( - self.client.create_role_inference_rule, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_ROLE_INFERENCE_RULE, - bytes_body, - status=201, - prior_role=self.FAKE_ROLE_ID, - implies_role=self.FAKE_ROLE_ID_2) - - def _test_show_role_inference_rule(self, bytes_body=False): - self.check_service_client_function( - self.client.show_role_inference_rule, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ROLE_INFERENCE_RULE, - bytes_body, - prior_role=self.FAKE_ROLE_ID, - implies_role=self.FAKE_ROLE_ID_2) - - def _test_list_role_inferences_rules(self, bytes_body=False): - self.check_service_client_function( - self.client.list_role_inferences_rules, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLE_INFERENCE_RULES, - bytes_body, - prior_role=self.FAKE_ROLE_ID) - - def _test_list_all_role_inference_rules(self, bytes_body=False): - self.check_service_client_function( - self.client.list_all_role_inference_rules, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ALL_ROLE_INFERENCE_RULES, - bytes_body) - - def test_create_role_with_str_body(self): - self._test_create_role() - - def test_create_role_with_bytes_body(self): - self._test_create_role(bytes_body=True) - - def test_show_role_with_str_body(self): - self._test_show_role() - - def test_show_role_with_bytes_body(self): - self._test_show_role(bytes_body=True) - - def test_list_roles_with_str_body(self): - self._test_list_roles() - - def test_list_roles_with_bytes_body(self): - self._test_list_roles(bytes_body=True) - - def test_update_role_with_str_body(self): - self._test_update_role() - - def test_update_role_with_bytes_body(self): - self._test_update_role(bytes_body=True) - - def test_delete_role(self): - self.check_service_client_function( - self.client.delete_role, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - role_id=self.FAKE_ROLE_ID, - status=204) - - def test_create_user_role_on_project_with_str_body(self): - self._test_create_user_role_on_project() - - def test_create_user_role_on_project_with_bytes_body(self): - self._test_create_user_role_on_project(bytes_body=True) - - def test_create_user_role_on_domain_with_str_body(self): - self._test_create_user_role_on_domain() - - def test_create_user_role_on_domain_with_bytes_body(self): - self._test_create_user_role_on_domain(bytes_body=True) - - def test_create_group_role_on_domain_with_str_body(self): - self._test_create_group_role_on_domain() - - def test_create_group_role_on_domain_with_bytes_body(self): - self._test_create_group_role_on_domain(bytes_body=True) - - def test_list_user_roles_on_project_with_str_body(self): - self._test_list_user_roles_on_project() - - def test_list_user_roles_on_project_with_bytes_body(self): - self._test_list_user_roles_on_project(bytes_body=True) - - def test_list_user_roles_on_domain_with_str_body(self): - self._test_list_user_roles_on_domain() - - def test_list_user_roles_on_domain_with_bytes_body(self): - self._test_list_user_roles_on_domain(bytes_body=True) - - def test_list_group_roles_on_domain_with_str_body(self): - self._test_list_group_roles_on_domain() - - def test_list_group_roles_on_domain_with_bytes_body(self): - self._test_list_group_roles_on_domain(bytes_body=True) - - def test_delete_role_from_user_on_project(self): - self.check_service_client_function( - self.client.delete_role_from_user_on_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_delete_role_from_user_on_domain(self): - self.check_service_client_function( - self.client.delete_role_from_user_on_domain, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_delete_role_from_group_on_project(self): - self.check_service_client_function( - self.client.delete_role_from_group_on_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_delete_role_from_group_on_domain(self): - self.check_service_client_function( - self.client.delete_role_from_group_on_domain, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_check_user_role_existence_on_project(self): - self.check_service_client_function( - self.client.check_user_role_existence_on_project, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_check_user_role_existence_on_domain(self): - self.check_service_client_function( - self.client.check_user_role_existence_on_domain, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_check_role_from_group_on_project_existence(self): - self.check_service_client_function( - self.client.check_role_from_group_on_project_existence, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_check_role_from_group_on_domain_existence(self): - self.check_service_client_function( - self.client.check_role_from_group_on_domain_existence, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_create_role_inference_rule_with_str_body(self): - self._test_create_role_inference_rule() - - def test_create_role_inference_rule_with_bytes_body(self): - self._test_create_role_inference_rule(bytes_body=True) - - def test_show_role_inference_rule_with_str_body(self): - self._test_show_role_inference_rule() - - def test_show_role_inference_rule_with_bytes_body(self): - self._test_show_role_inference_rule(bytes_body=True) - - def test_list_role_inferences_rules_with_str_body(self): - self._test_list_role_inferences_rules() - - def test_list_role_inferences_rules_with_bytes_body(self): - self._test_list_role_inferences_rules(bytes_body=True) - - def test_check_role_inference_rule(self): - self.check_service_client_function( - self.client.check_role_inference_rule, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - status=204, - prior_role=self.FAKE_ROLE_ID, - implies_role=self.FAKE_ROLE_ID_2) - - def test_delete_role_inference_rule(self): - self.check_service_client_function( - self.client.delete_role_inference_rule, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - prior_role=self.FAKE_ROLE_ID, - implies_role=self.FAKE_ROLE_ID_2) - - def test_list_all_role_inference_rules_with_str_body(self): - self._test_list_all_role_inference_rules() - - def test_list_all_role_inference_rules_with_bytes_body(self): - self._test_list_all_role_inference_rules(bytes_body=True) diff --git a/tempest/tests/lib/services/identity/v3/test_services_client.py b/tempest/tests/lib/services/identity/v3/test_services_client.py deleted file mode 100644 index b464644f4..000000000 --- a/tempest/tests/lib/services/identity/v3/test_services_client.py +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import services_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestServicesClient(base.BaseServiceTest): - FAKE_CREATE_SERVICE = { - "service": { - "type": "compute", - "name": "compute2", - "description": "Compute service 2" - } - } - - FAKE_SERVICE_INFO = { - "service": { - "description": "Keystone Identity Service", - "enabled": True, - "id": "686766", - "links": { - "self": "http://example.com/identity/v3/services/686766" - }, - "name": "keystone", - "type": "identity" - } - } - - FAKE_LIST_SERVICES = { - "links": { - "next": None, - "previous": None, - "self": "http://example.com/identity/v3/services" - }, - "services": [ - { - "description": "Nova Compute Service", - "enabled": True, - "id": "1999c3", - "links": { - "self": "http://example.com/identity/v3/services/1999c3" - }, - "name": "nova", - "type": "compute" - }, - { - "description": "Cinder Volume Service V2", - "enabled": True, - "id": "392166", - "links": { - "self": "http://example.com/identity/v3/services/392166" - }, - "name": "cinderv2", - "type": "volumev2" - }, - { - "description": "Neutron Service", - "enabled": True, - "id": "4fe41a", - "links": { - "self": "http://example.com/identity/v3/services/4fe41a" - }, - "name": "neutron", - "type": "network" - } - ] - } - - def setUp(self): - super(TestServicesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = services_client.ServicesClient(fake_auth, 'identity', - 'regionOne') - - def _test_create_service(self, bytes_body=False): - self.check_service_client_function( - self.client.create_service, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SERVICE, - bytes_body, - status=201) - - def _test_show_service(self, bytes_body=False): - self.check_service_client_function( - self.client.show_service, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVICE_INFO, - bytes_body, - service_id="686766") - - def _test_list_services(self, bytes_body=False, mock_args='services', - **params): - self.check_service_client_function( - self.client.list_services, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_SERVICES, - bytes_body, - mock_args=[mock_args], - **params) - - def _test_update_service(self, bytes_body=False): - self.check_service_client_function( - self.client.update_service, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_SERVICE_INFO, - bytes_body, - service_id="686766") - - def test_create_service_with_str_body(self): - self._test_create_service() - - def test_create_service_with_bytes_body(self): - self._test_create_service(bytes_body=True) - - def test_show_service_with_str_body(self): - self._test_show_service() - - def test_show_service_with_bytes_body(self): - self._test_show_service(bytes_body=True) - - def test_list_services_with_str_body(self): - self._test_list_services() - - def test_list_services_with_bytes_body(self): - self._test_list_services(bytes_body=True) - - def test_list_services_with_params(self): - self._test_list_services( - type='fake-type', mock_args='services?type=fake-type') - - def test_update_service_with_str_body(self): - self._test_update_service() - - def test_update_service_with_bytes_body(self): - self._test_update_service(bytes_body=True) - - def test_delete_service(self): - self.check_service_client_function( - self.client.delete_service, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - service_id="686766", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_token_client.py b/tempest/tests/lib/services/identity/v3/test_token_client.py deleted file mode 100644 index 38e8c4a4e..000000000 --- a/tempest/tests/lib/services/identity/v3/test_token_client.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import json - -import mock - -from tempest.lib.common import rest_client -from tempest.lib import exceptions -from tempest.lib.services.identity.v3 import token_client -from tempest.tests import base -from tempest.tests.lib import fake_identity - - -class TestTokenClientV3(base.TestCase): - - def test_init_without_authurl(self): - self.assertRaises(exceptions.IdentityError, - token_client.V3TokenClient, None) - - def test_auth(self): - token_client_v3 = token_client.V3TokenClient('fake_url') - response, body_text = fake_identity._fake_v3_response(None, None) - body = json.loads(body_text) - - with mock.patch.object(token_client_v3, 'post') as post_mock: - post_mock.return_value = response, body - resp = token_client_v3.auth(username='fake_user', - password='fake_pass') - - self.assertIsInstance(resp, rest_client.ResponseBody) - req_dict = json.dumps({ - 'auth': { - 'identity': { - 'methods': ['password'], - 'password': { - 'user': { - 'name': 'fake_user', - 'password': 'fake_pass', - } - } - }, - } - }, sort_keys=True) - post_mock.assert_called_once_with('fake_url/auth/tokens', - body=req_dict) - - def test_auth_with_project_id_and_domain_id(self): - token_client_v3 = token_client.V3TokenClient('fake_url') - response, body_text = fake_identity._fake_v3_response(None, None) - body = json.loads(body_text) - - with mock.patch.object(token_client_v3, 'post') as post_mock: - post_mock.return_value = response, body - resp = token_client_v3.auth( - username='fake_user', password='fake_pass', - project_id='fcac2a055a294e4c82d0a9c21c620eb4', - user_domain_id='14f4a9a99973404d8c20ba1d2af163ff', - project_domain_id='291f63ae9ac54ee292ca09e5f72d9676') - - self.assertIsInstance(resp, rest_client.ResponseBody) - req_dict = json.dumps({ - 'auth': { - 'identity': { - 'methods': ['password'], - 'password': { - 'user': { - 'name': 'fake_user', - 'password': 'fake_pass', - 'domain': { - 'id': '14f4a9a99973404d8c20ba1d2af163ff' - } - } - } - }, - 'scope': { - 'project': { - 'id': 'fcac2a055a294e4c82d0a9c21c620eb4', - 'domain': { - 'id': '291f63ae9ac54ee292ca09e5f72d9676' - } - } - } - } - }, sort_keys=True) - post_mock.assert_called_once_with('fake_url/auth/tokens', - body=req_dict) - - def test_auth_with_tenant(self): - token_client_v3 = token_client.V3TokenClient('fake_url') - response, body_text = fake_identity._fake_v3_response(None, None) - body = json.loads(body_text) - - with mock.patch.object(token_client_v3, 'post') as post_mock: - post_mock.return_value = response, body - resp = token_client_v3.auth(username='fake_user', - password='fake_pass', - project_name='fake_tenant') - - self.assertIsInstance(resp, rest_client.ResponseBody) - req_dict = json.dumps({ - 'auth': { - 'identity': { - 'methods': ['password'], - 'password': { - 'user': { - 'name': 'fake_user', - 'password': 'fake_pass', - } - }}, - 'scope': { - 'project': { - 'name': 'fake_tenant' - } - }, - } - }, sort_keys=True) - - post_mock.assert_called_once_with('fake_url/auth/tokens', - body=req_dict) - - def test_request_with_str_body(self): - token_client_v3 = token_client.V3TokenClient('fake_url') - - with mock.patch.object(token_client_v3, 'raw_request') as mock_raw_r: - mock_raw_r.return_value = ( - fake_identity._fake_v3_response(None, None)) - resp, body = token_client_v3.request('GET', 'fake_uri') - - self.assertIsInstance(body, dict) - - def test_request_with_bytes_body(self): - token_client_v3 = token_client.V3TokenClient('fake_url') - - response, body_text = fake_identity._fake_v3_response(None, None) - body = body_text.encode('utf-8') - - with mock.patch.object(token_client_v3, 'raw_request') as mock_raw_r: - mock_raw_r.return_value = response, body - resp, body = token_client_v3.request('GET', 'fake_uri') - - self.assertIsInstance(body, dict) diff --git a/tempest/tests/lib/services/identity/v3/test_trusts_client.py b/tempest/tests/lib/services/identity/v3/test_trusts_client.py deleted file mode 100644 index a1ca0204c..000000000 --- a/tempest/tests/lib/services/identity/v3/test_trusts_client.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import trusts_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTrustsClient(base.BaseServiceTest): - FAKE_CREATE_TRUST = { - "trust": { - "expires_at": "2013-02-27T18:30:59.999999Z", - "impersonation": True, - "allow_redelegation": True, - "project_id": "ddef321", - "roles": [ - { - "name": "member" - } - ], - "trustee_user_id": "86c0d5", - "trustor_user_id": "a0fdfd" - } - } - - FAKE_LIST_TRUSTS = { - "trusts": [ - { - "id": "1ff900", - "expires_at": - "2013-02-27T18:30:59.999999Z", - "impersonation": True, - "links": { - "self": - "http://example.com/identity/v3/OS-TRUST/trusts/1ff900" - }, - "project_id": "0f1233", - "trustee_user_id": "86c0d5", - "trustor_user_id": "a0fdfd" - }, - { - "id": "f4513a", - "impersonation": False, - "links": { - "self": - "http://example.com/identity/v3/OS-TRUST/trusts/f45513a" - }, - "project_id": "0f1233", - "trustee_user_id": "86c0d5", - "trustor_user_id": "3cd2ce" - } - ] - } - - FAKE_TRUST_INFO = { - "trust": { - "id": "987fe8", - "expires_at": "2013-02-27T18:30:59.999999Z", - "impersonation": True, - "links": { - "self": - "http://example.com/identity/v3/OS-TRUST/trusts/987fe8" - }, - "roles": [ - { - "id": "ed7b78", - "links": { - "self": - "http://example.com/identity/v3/roles/ed7b78" - }, - "name": "member" - } - ], - "roles_links": { - "next": None, - "previous": None, - "self": - "http://example.com/identity/v3/OS-TRUST/trusts/1ff900/roles" - }, - "project_id": "0f1233", - "trustee_user_id": "be34d1", - "trustor_user_id": "56ae32" - } - } - - def setUp(self): - super(TestTrustsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = trusts_client.TrustsClient(fake_auth, 'identity', - 'regionOne') - - def _test_create_trust(self, bytes_body=False): - self.check_service_client_function( - self.client.create_trust, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_TRUST, - bytes_body, - status=201) - - def _test_show_trust(self, bytes_body=False): - self.check_service_client_function( - self.client.show_trust, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_TRUST_INFO, - bytes_body, - trust_id="1ff900") - - def _test_list_trusts(self, bytes_body=False): - self.check_service_client_function( - self.client.list_trusts, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_TRUSTS, - bytes_body) - - def test_create_trust_with_str_body(self): - self._test_create_trust() - - def test_create_trust_with_bytes_body(self): - self._test_create_trust(bytes_body=True) - - def test_show_trust_with_str_body(self): - self._test_show_trust() - - def test_show_trust_with_bytes_body(self): - self._test_show_trust(bytes_body=True) - - def test_list_trusts_with_str_body(self): - self._test_list_trusts() - - def test_list_trusts_with_bytes_body(self): - self._test_list_trusts(bytes_body=True) - - def test_delete_trust(self): - self.check_service_client_function( - self.client.delete_trust, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - trust_id="1ff900", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_users_client.py b/tempest/tests/lib/services/identity/v3/test_users_client.py deleted file mode 100644 index 5b572f5e5..000000000 --- a/tempest/tests/lib/services/identity/v3/test_users_client.py +++ /dev/null @@ -1,205 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from tempest.lib.services.identity.v3 import users_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestUsersClient(base.BaseServiceTest): - FAKE_CREATE_USER = { - 'user': { - 'default_project_id': '95f8c3f8e7b54409a418fc30717f9ae0', - 'domain_id': '8347b31afc3545c4b311cb4cce788a08', - 'enabled': True, - 'name': 'Tempest User', - 'password': 'TempestPassword', - } - } - - FAKE_USER_INFO = { - 'user': { - 'default_project_id': '95f8c3f8e7b54409a418fc30717f9ae0', - 'domain_id': '8347b31afc3545c4b311cb4cce788a08', - 'enabled': True, - 'id': '817fb3c23fd7465ba6d7fe1b1320121d', - 'links': { - 'self': 'http://example.com/identity', - }, - 'name': 'Tempest User', - 'password_expires_at': '2016-11-06T15:32:17.000000', - } - } - - FAKE_USER_LIST = { - 'links': { - 'next': None, - 'previous': None, - 'self': 'http://example.com/identity/v3/users', - }, - 'users': [ - { - 'domain_id': 'TempestDomain', - 'enabled': True, - 'id': '817fb3c23fd7465ba6d7fe1b1320121d', - 'links': { - 'self': 'http://example.com/identity/v3/users/' + - '817fb3c23fd7465ba6d7fe1b1320121d', - }, - 'name': 'Tempest User', - 'password_expires_at': '2016-11-06T15:32:17.000000', - }, - { - 'domain_id': 'TempestDomain', - 'enabled': True, - 'id': 'bdbfb1e2f1344be197e90a778379cca1', - 'links': { - 'self': 'http://example.com/identity/v3/users/' + - 'bdbfb1e2f1344be197e90a778379cca1', - }, - 'name': 'Tempest User', - 'password_expires_at': None, - }, - ] - } - - FAKE_GROUP_LIST = { - 'links': { - 'self': 'http://example.com/identity/v3/groups', - 'previous': None, - 'next': None, - }, - 'groups': [ - { - 'description': 'Tempest Group One Description', - 'domain_id': 'TempestDomain', - 'id': '1c92f3453ed34291a074b87493455b8f', - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - '1c92f3453ed34291a074b87493455b8f' - }, - 'name': 'Tempest Group One', - }, - { - 'description': 'Tempest Group Two Description', - 'domain_id': 'TempestDomain', - 'id': 'ce9e7dafed3b4877a7d4466ed730a9ee', - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - 'ce9e7dafed3b4877a7d4466ed730a9ee' - }, - 'name': 'Tempest Group Two', - }, - ] - } - - def setUp(self): - super(TestUsersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = users_client.UsersClient(fake_auth, 'identity', - 'regionOne') - - def _test_create_user(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_USER, - bytes_body, - status=201, - ) - - def _test_show_user(self, bytes_body=False): - self.check_service_client_function( - self.client.show_user, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_INFO, - bytes_body, - user_id='817fb3c23fd7465ba6d7fe1b1320121d', - ) - - def _test_list_users(self, bytes_body=False): - self.check_service_client_function( - self.client.list_users, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_LIST, - bytes_body, - ) - - def _test_update_user(self, bytes_body=False): - self.check_service_client_function( - self.client.update_user, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_USER_INFO, - bytes_body, - user_id='817fb3c23fd7465ba6d7fe1b1320121d', - name='NewName', - ) - - def _test_list_user_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_user_groups, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_GROUP_LIST, - bytes_body, - user_id='817fb3c23fd7465ba6d7fe1b1320121d', - ) - - def test_create_user_with_string_body(self): - self._test_create_user() - - def test_create_user_with_bytes_body(self): - self._test_create_user(bytes_body=True) - - def test_show_user_with_string_body(self): - self._test_show_user() - - def test_show_user_with_bytes_body(self): - self._test_show_user(bytes_body=True) - - def test_list_users_with_string_body(self): - self._test_list_users() - - def test_list_users_with_bytes_body(self): - self._test_list_users(bytes_body=True) - - def test_update_user_with_string_body(self): - self._test_update_user() - - def test_update_user_with_bytes_body(self): - self._test_update_user(bytes_body=True) - - def test_list_user_groups_with_string_body(self): - self._test_list_user_groups() - - def test_list_user_groups_with_bytes_body(self): - self._test_list_user_groups(bytes_body=True) - - def test_delete_user(self): - self.check_service_client_function( - self.client.delete_user, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - user_id='817fb3c23fd7465ba6d7fe1b1320121d', - status=204, - ) - - def test_change_user_password(self): - self.check_service_client_function( - self.client.update_user_password, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=204, - user_id='817fb3c23fd7465ba6d7fe1b1320121d', - password='NewTempestPassword', - original_password='OldTempestPassword') diff --git a/tempest/tests/lib/services/identity/v3/test_versions_client.py b/tempest/tests/lib/services/identity/v3/test_versions_client.py deleted file mode 100644 index 3bfaf1ea3..000000000 --- a/tempest/tests/lib/services/identity/v3/test_versions_client.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2017 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.identity.v3 import versions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestIdentityClient(base.BaseServiceTest): - - FAKE_VERSIONS_INFO = { - "versions": { - "values": [ - {"status": "stable", "updated": "2017-02-22T00:00:00Z", - "media-types": [ - {"base": "application/json", "type": - "application/vnd.openstack.identity-v3+json"} - ], - "id": "v3.8", - "links": [ - {"href": "https://15.184.67.226/identity_admin/v3/", - "rel": "self"} - ]}, - {"status": "deprecated", "updated": "2016-08-04T00:00:00Z", - "media-types": [ - {"base": "application/json", - "type": "application/vnd.openstack.identity-v2.0+json"} - ], - "id": "v2.0", - "links": [ - {"href": "https://15.184.67.226/identity_admin/v2.0/", - "rel": "self"}, - {"href": "https://docs.openstack.org/", - "type": "text/html", "rel": "describedby"} - ]} - ] - } - } - - def setUp(self): - super(TestIdentityClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = versions_client.VersionsClient(fake_auth, - 'identity', - 'regionOne') - - def _test_list_versions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_versions, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSIONS_INFO, - bytes_body, - 300) - - def test_list_versions_with_str_body(self): - self._test_list_versions() - - def test_list_versions_with_bytes_body(self): - self._test_list_versions(bytes_body=True) diff --git a/tempest/tests/lib/services/image/__init__.py b/tempest/tests/lib/services/image/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/image/v1/__init__.py b/tempest/tests/lib/services/image/v1/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/image/v1/test_image_members_client.py b/tempest/tests/lib/services/image/v1/test_image_members_client.py deleted file mode 100644 index a5a6128c0..000000000 --- a/tempest/tests/lib/services/image/v1/test_image_members_client.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.image.v1 import image_members_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestImageMembersClient(base.BaseServiceTest): - FAKE_LIST_IMAGE_MEMBERS = { - "members": [ - { - "created_at": "2013-10-07T17:58:03Z", - "image_id": "dbc999e3-c52f-4200-bedd-3b18fe7f87fe", - "member_id": "123456789", - "status": "pending", - "updated_at": "2013-10-07T17:58:03Z" - }, - { - "created_at": "2013-10-07T17:58:55Z", - "image_id": "dbc999e3-c52f-4200-bedd-3b18fe7f87fe", - "member_id": "987654321", - "status": "accepted", - "updated_at": "2013-10-08T12:08:55Z" - } - ] - } - - def setUp(self): - super(TestImageMembersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = image_members_client.ImageMembersClient(fake_auth, - 'image', - 'regionOne') - - def _test_list_image_members(self, bytes_body=False): - self.check_service_client_function( - self.client.list_image_members, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_IMAGE_MEMBERS, - bytes_body, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e") - - def _test_create_image_member(self, bytes_body=False): - self.check_service_client_function( - self.client.create_image_member, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7", - status=204) - - def test_list_image_members_with_str_body(self): - self._test_list_image_members() - - def test_list_image_members_with_bytes_body(self): - self._test_list_image_members(bytes_body=True) - - def test_create_image_member_with_str_body(self): - self._test_create_image_member() - - def test_create_image_member_with_bytes_body(self): - self._test_create_image_member(bytes_body=True) - - def test_delete_image_member(self): - self.check_service_client_function( - self.client.delete_image_member, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7", - status=204) diff --git a/tempest/tests/lib/services/image/v2/__init__.py b/tempest/tests/lib/services/image/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/image/v2/test_image_members_client.py b/tempest/tests/lib/services/image/v2/test_image_members_client.py deleted file mode 100644 index 703b6e1c8..000000000 --- a/tempest/tests/lib/services/image/v2/test_image_members_client.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.image.v2 import image_members_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestImageMembersClient(base.BaseServiceTest): - FAKE_CREATE_SHOW_UPDATE_IMAGE_MEMBER = { - "status": "pending", - "created_at": "2013-11-26T07:21:21Z", - "updated_at": "2013-11-26T07:21:21Z", - "image_id": "0ae74cc5-5147-4239-9ce2-b0c580f7067e", - "member_id": "8989447062e04a818baf9e073fd04fa7", - "schema": "/v2/schemas/member" - } - - def setUp(self): - super(TestImageMembersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = image_members_client.ImageMembersClient(fake_auth, - 'image', - 'regionOne') - - def _test_show_image_member(self, bytes_body=False): - self.check_service_client_function( - self.client.show_image_member, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_SHOW_UPDATE_IMAGE_MEMBER, - bytes_body, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7") - - def _test_create_image_member(self, bytes_body=False): - self.check_service_client_function( - self.client.create_image_member, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_UPDATE_IMAGE_MEMBER, - bytes_body, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7") - - def _test_update_image_member(self, bytes_body=False): - self.check_service_client_function( - self.client.update_image_member, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_CREATE_SHOW_UPDATE_IMAGE_MEMBER, - bytes_body, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7", - schema="/v2/schemas/member2") - - def test_show_image_member_with_str_body(self): - self._test_show_image_member() - - def test_show_image_member_with_bytes_body(self): - self._test_show_image_member(bytes_body=True) - - def test_create_image_member_with_str_body(self): - self._test_create_image_member() - - def test_create_image_member_with_bytes_body(self): - self._test_create_image_member(bytes_body=True) - - def test_delete_image_member(self): - self.check_service_client_function( - self.client.delete_image_member, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7", - status=204) - - def test_update_image_member_with_str_body(self): - self._test_update_image_member() - - def test_update_image_member_with_bytes_body(self): - self._test_update_image_member(bytes_body=True) diff --git a/tempest/tests/lib/services/image/v2/test_images_client.py b/tempest/tests/lib/services/image/v2/test_images_client.py deleted file mode 100644 index 964898557..000000000 --- a/tempest/tests/lib/services/image/v2/test_images_client.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.image.v2 import images_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestImagesClient(base.BaseServiceTest): - FAKE_CREATE_UPDATE_SHOW_IMAGE = { - "id": "e485aab9-0907-4973-921c-bb6da8a8fcf8", - "name": u"\u2740(*\xb4\u25e2`*)\u2740", - "status": "active", - "visibility": "public", - "size": 2254249, - "checksum": "2cec138d7dae2aa59038ef8c9aec2390", - "tags": [ - "fedora", - "beefy" - ], - "created_at": "2012-08-10T19:23:50Z", - "updated_at": "2012-08-12T11:11:33Z", - "self": "/v2/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea", - "file": "/v2/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/file", - "schema": "/v2/schemas/image", - "owner": None, - "min_ram": None, - "min_disk": None, - "disk_format": None, - "virtual_size": None, - "container_format": None - } - - def setUp(self): - super(TestImagesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = images_client.ImagesClient(fake_auth, - 'image', 'regionOne') - - def _test_update_image(self, bytes_body=False): - self.check_service_client_function( - self.client.update_image, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_CREATE_UPDATE_SHOW_IMAGE, - bytes_body, - image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8", - patch=[{"op": "add", "path": "/a/b/c", "value": ["foo", "bar"]}]) - - def _test_create_image(self, bytes_body=False): - self.check_service_client_function( - self.client.create_image, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_UPDATE_SHOW_IMAGE, - bytes_body, - name="virtual machine image", - status=201) - - def _test_show_image(self, bytes_body=False): - self.check_service_client_function( - self.client.show_image, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_UPDATE_SHOW_IMAGE, - bytes_body, - image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8") - - def test_create_image_with_str_body(self): - self._test_create_image() - - def test_create_image_with_bytes_body(self): - self._test_create_image(bytes_body=True) - - def test_update_image_with_str_body(self): - self._test_update_image() - - def test_update_image_with_bytes_body(self): - self._test_update_image(bytes_body=True) - - def test_deactivate_image(self): - self.check_service_client_function( - self.client.deactivate_image, - 'tempest.lib.common.rest_client.RestClient.post', - {}, image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8", status=204) - - def test_reactivate_image(self): - self.check_service_client_function( - self.client.reactivate_image, - 'tempest.lib.common.rest_client.RestClient.post', - {}, image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8", status=204) - - def test_delete_image(self): - self.check_service_client_function( - self.client.delete_image, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8", status=204) - - def test_show_image_with_str_body(self): - self._test_show_image() - - def test_show_image_with_bytes_body(self): - self._test_show_image(bytes_body=True) diff --git a/tempest/tests/lib/services/image/v2/test_namespace_object_client.py b/tempest/tests/lib/services/image/v2/test_namespace_object_client.py deleted file mode 100644 index 8d2966041..000000000 --- a/tempest/tests/lib/services/image/v2/test_namespace_object_client.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright 2016 EasyStack. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.image.v2 import namespace_objects_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNamespaceObjectClient(base.BaseServiceTest): - FAKE_CREATE_SHOW_OBJECTS = { - "created_at": "2016-09-19T18:20:56Z", - "description": "You can configure the CPU limits.", - "name": "CPU Limits", - "properties": { - "quota:cpu_period": { - "description": "Specifies the enforcement interval", - "maximum": 1000000, - "minimum": 1000, - "title": "Quota: CPU Period", - "type": "integer" - }, - "quota:cpu_quota": { - "description": "Specifies the maximum allowed bandwidth ", - "title": "Quota: CPU Quota", - "type": "integer" - }, - "quota:cpu_shares": { - "description": "Specifies the proportional weighted share.", - "title": "Quota: CPU Shares", - "type": "integer" - } - }, - "required": [], - "schema": "/v2/schemas/metadefs/object", - "self": "/v2/metadefs/namespaces/OS::Compute::Quota/objects/CPU", - "updated_at": "2016-09-19T18:20:56Z" - } - - FAKE_LIST_OBJECTS = { - "objects": [ - { - "created_at": "2016-09-18T18:16:35Z", - "description": "You can configure the CPU limits.", - "name": "CPU Limits", - "properties": { - "quota:cpu_period": { - "description": "Specifies the enforcement interval ", - "maximum": 1000000, - "minimum": 1000, - "title": "Quota: CPU Period", - "type": "integer" - }, - "quota:cpu_quota": { - "description": "Specifies the maximum.", - "title": "Quota: CPU Quota", - "type": "integer" - }, - "quota:cpu_shares": { - "description": " Desc.", - "title": "Quota: CPU Shares", - "type": "integer" - } - }, - "required": [], - "schema": "/v2/schemas/metadefs/object", - "self": - "/v2/metadefs/namespaces/OS::Compute::Quota/objects/CPU" - }, - { - "created_at": "2016-09-18T18:16:35Z", - "description": "Using disk I/O quotas.", - "name": "Disk QoS", - "properties": { - "quota:disk_read_bytes_sec": { - "description": "Sets disk I/O quota.", - "title": "Quota: Disk read bytes / sec", - "type": "integer" - }, - "quota:disk_read_iops_sec": { - "description": "Sets disk I/O quota", - "title": "Quota: Disk read IOPS / sec", - "type": "integer" - }, - "quota:disk_total_bytes_sec": { - "description": "Sets disk I/O quota.", - "title": "Quota: Disk Total Bytes / sec", - "type": "integer" - }, - "quota:disk_total_iops_sec": { - "description": "Sets disk I/O quota.", - "title": "Quota: Disk Total IOPS / sec", - "type": "integer" - }, - "quota:disk_write_bytes_sec": { - "description": "Sets disk I/O quota.", - "title": "Quota: Disk Write Bytes / sec", - "type": "integer" - }, - "quota:disk_write_iops_sec": { - "description": "Sets disk I/O quota.", - "title": "Quota: Disk Write IOPS / sec", - "type": "integer" - } - }, - "required": [], - "schema": "/v2/schemas/metadefs/object", - "self": - "/v2/metadefs/namespaces/OS::Compute::Quota/objects/Disk QoS" - }, - ], - "schema": "v2/schemas/metadefs/objects" - } - - FAKE_UPDATE_OBJECTS = { - "description": "You can configure the CPU limits.", - "name": "CPU", - "properties": { - "quota:cpu_shares": { - "description": "Specify.", - "title": "Quota: CPU Shares", - "type": "integer" - } - }, - "required": [] - } - - def setUp(self): - super(TestNamespaceObjectClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = namespace_objects_client.NamespaceObjectsClient( - fake_auth, 'image', 'regionOne') - - def _test_create_namespace_objects(self, bytes_body=False): - self.check_service_client_function( - self.client.create_namespace_object, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_OBJECTS, - bytes_body, status=201, - namespace="OS::Compute::Hypervisor", - object_name="OS::Glance::Image") - - def _test_list_namespace_objects(self, bytes_body=False): - self.check_service_client_function( - self.client.list_namespace_objects, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_OBJECTS, - bytes_body, - namespace="OS::Compute::Hypervisor") - - def _test_show_namespace_objects(self, bytes_body=False): - self.check_service_client_function( - self.client.show_namespace_object, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_SHOW_OBJECTS, - bytes_body, - namespace="OS::Compute::Hypervisor", - object_name="OS::Glance::Image") - - def _test_update_namespace_objects(self, bytes_body=False): - self.check_service_client_function( - self.client.update_namespace_object, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_OBJECTS, - bytes_body, - namespace="OS::Compute::Hypervisor", - object_name="OS::Glance::Image", - name="CPU") - - def test_create_namespace_object_with_str_body(self): - self._test_create_namespace_objects() - - def test_create_namespace_object_with_bytes_body(self): - self._test_create_namespace_objects(bytes_body=True) - - def test_list_namespace_object_with_str_body(self): - self._test_list_namespace_objects() - - def test_list_namespace_object_with_bytes_body(self): - self._test_list_namespace_objects(bytes_body=True) - - def test_show_namespace_object_with_str_body(self): - self._test_show_namespace_objects() - - def test_show_namespace_object_with_bytes_body(self): - self._test_show_namespace_objects(bytes_body=True) - - def test_update_namespace_object_with_str_body(self): - self._test_update_namespace_objects() - - def test_update_namespace_object_with_bytes_body(self): - self._test_update_namespace_objects(bytes_body=True) - - def test_delete_namespace_objects(self): - self.check_service_client_function( - self.client.delete_namespace_object, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, namespace="OS::Compute::Hypervisor", - object_name="OS::Glance::Image", - status=204) diff --git a/tempest/tests/lib/services/image/v2/test_namespace_properties_client.py b/tempest/tests/lib/services/image/v2/test_namespace_properties_client.py deleted file mode 100644 index 1d56db6da..000000000 --- a/tempest/tests/lib/services/image/v2/test_namespace_properties_client.py +++ /dev/null @@ -1,191 +0,0 @@ -# Copyright 2016 EasyStack. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.image.v2 import namespace_properties_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNamespacePropertiesClient(base.BaseServiceTest): - FAKE_CREATE_SHOW_NAMESPACE_PROPERTY = { - "description": "property", - "enum": ["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"], - "name": "OS::Glance::Image", - "title": "Hypervisor Type", - "type": "string" - } - - FAKE_LIST_NAMESPACE_PROPERTY = { - "properties": { - "hw_disk_bus": { - "description": "property.", - "enum": ["scsi", "virtio", "uml", "xen", "ide", "usb"], - "title": "Disk Bus", - "type": "string" - }, - "hw_machine_type": { - "description": "desc.", - "title": "Machine Type", - "type": "string" - }, - "hw_qemu_guest_agent": { - "description": "desc.", - "enum": [ - "yes", - "no" - ], - "title": "QEMU Guest Agent", - "type": "string" - }, - "hw_rng_model": { - "default": "virtio", - "description": "desc", - "title": "Random Number Generator Device", - "type": "string" - }, - "hw_scsi_model": { - "default": "virtio-scsi", - "description": "desc.", - "title": "SCSI Model", - "type": "string" - }, - "hw_video_model": { - "description": "The video image driver used.", - "enum": [ - "vga", - "cirrus", - "vmvga", - "xen", - "qxl" - ], - "title": "Video Model", - "type": "string" - }, - "hw_video_ram": { - "description": "desc.", - "title": "Max Video Ram", - "type": "integer" - }, - "hw_vif_model": { - "description": "desc.", - "enum": ["e1000", - "ne2k_pci", - "pcnet", - "rtl8139", - "virtio", - "e1000", - "e1000e", - "VirtualE1000", - "VirtualE1000e", - "VirtualPCNet32", - "VirtualSriovEthernetCard", - "VirtualVmxnet", - "netfront", - "ne2k_pci" - ], - "title": "Virtual Network Interface", - "type": "string" - }, - "os_command_line": { - "description": "desc.", - "title": "Kernel Command Line", - "type": "string" - } - } - } - - FAKE_UPDATE_NAMESPACE_PROPERTY = { - "description": "property", - "enum": ["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"], - "name": "OS::Glance::Image", - "title": "update Hypervisor Type", - "type": "string" - } - - def setUp(self): - super(TestNamespacePropertiesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = namespace_properties_client.NamespacePropertiesClient( - fake_auth, 'image', 'regionOne') - - def _test_create_namespace_property(self, bytes_body=False): - self.check_service_client_function( - self.client.create_namespace_property, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_NAMESPACE_PROPERTY, - bytes_body, status=201, - namespace="OS::Compute::Hypervisor", - title="Hypervisor Type", name="OS::Glance::Image", - type="string", - enum=["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"]) - - def _test_list_namespace_property(self, bytes_body=False): - self.check_service_client_function( - self.client.list_namespace_properties, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_NAMESPACE_PROPERTY, - bytes_body, - namespace="OS::Compute::Hypervisor") - - def _test_show_namespace_property(self, bytes_body=False): - self.check_service_client_function( - self.client.show_namespace_properties, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_SHOW_NAMESPACE_PROPERTY, - bytes_body, - namespace="OS::Compute::Hypervisor", - property_name="OS::Glance::Image") - - def _test_update_namespace_property(self, bytes_body=False): - self.check_service_client_function( - self.client.update_namespace_properties, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_NAMESPACE_PROPERTY, - bytes_body, - namespace="OS::Compute::Hypervisor", - property_name="OS::Glance::Image", - title="update Hypervisor Type", type="string", - enum=["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"], - name="OS::Glance::Image") - - def test_create_namespace_property_with_str_body(self): - self._test_create_namespace_property() - - def test_create_namespace_property_with_bytes_body(self): - self._test_create_namespace_property(bytes_body=True) - - def test_list_namespace_property_with_str_body(self): - self._test_list_namespace_property() - - def test_list_namespace_property_with_bytes_body(self): - self._test_list_namespace_property(bytes_body=True) - - def test_show_namespace_property_with_str_body(self): - self._test_show_namespace_property() - - def test_show_namespace_property_with_bytes_body(self): - self._test_show_namespace_property(bytes_body=True) - - def test_update_namespace_property_with_str_body(self): - self._test_update_namespace_property() - - def test_update_namespace_property_with_bytes_body(self): - self._test_update_namespace_property(bytes_body=True) - - def test_delete_namespace(self): - self.check_service_client_function( - self.client.delete_namespace_property, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, namespace="OS::Compute::Hypervisor", - property_name="OS::Glance::Image", status=204) diff --git a/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py b/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py deleted file mode 100644 index 2faa5be1d..000000000 --- a/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2016 EasyStack. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.image.v2 import namespace_tags_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNamespaceTagsClient(base.BaseServiceTest): - FAKE_CREATE_SHOW_TAGS = { - "created_at": "2015-05-09T01:12:31Z", - "name": "added-sample-tag", - "updated_at": "2015-05-09T01:12:31Z" - } - - FAKE_LIST_TAGS = { - "tags": [ - { - "name": "sample-tag1" - }, - { - "name": "sample-tag2" - }, - { - "name": "sample-tag3" - } - ] - } - - FAKE_UPDATE_TAGS = {"name": "new-tag-name"} - - def setUp(self): - super(TestNamespaceTagsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = namespace_tags_client.NamespaceTagsClient( - fake_auth, 'image', 'regionOne') - - def _test_create_namespace_tags(self, bytes_body=False): - self.check_service_client_function( - self.client.create_namespace_tags, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_TAGS, - bytes_body, status=201, - namespace="OS::Compute::Hypervisor", - tags=[{"name": "sample-tag1"}, - {"name": "sample-tag2"}, - {"name": "sample-tag3"}]) - - def _test_list_namespace_tags(self, bytes_body=False): - self.check_service_client_function( - self.client.list_namespace_tags, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_TAGS, - bytes_body, - namespace="OS::Compute::Hypervisor") - - def _test_create_namespace_tag_definition(self, bytes_body=False): - self.check_service_client_function( - self.client.create_namespace_tag, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_TAGS, - bytes_body, - status=201, - namespace="OS::Compute::Hypervisor", - tag_name="added-sample-tag") - - def _test_show_namespace_tag_definition(self, bytes_body=False): - self.check_service_client_function( - self.client.show_namespace_tag, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_SHOW_TAGS, - bytes_body, - namespace="OS::Compute::Hypervisor", - tag_name="added-sample-tag") - - def _test_update_namespace_tag_definition(self, bytes_body=False): - self.check_service_client_function( - self.client.update_namespace_tag, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_OBJECTS, - bytes_body, - namespace="OS::Compute::Hypervisor", - tag_name="added-sample-tag", - name="new-tag-name") - - def test_create_namespace_tags_with_str_body(self): - self._test_create_namespace_tags() - - def test_create_namespace_tags_with_bytes_body(self): - self._test_create_namespace_tags(bytes_body=True) - - def test_list_namespace_tags_with_str_body(self): - self._test_list_namespace_tags() - - def test_list_namespace_tags_with_bytes_body(self): - self._test_list_namespace_tags(bytes_body=True) - - def test_create_namespace_tag_with_str_body(self): - self._test_create_namespace_tag_definition() - - def test_create_namespace_tag_with_bytes_body(self): - self._test_create_namespace_tag_definition(bytes_body=True) - - def test_show_namespace_tag_with_str_body(self): - self._test_show_namespace_tag_definition() - - def test_show_namespace_tag_with_bytes_body(self): - self._test_show_namespace_tag_definition(bytes_body=True) - - def test_delete_all_namespace_tags(self): - self.check_service_client_function( - self.client.delete_namespace_tags, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=200, - namespace="OS::Compute::Hypervisor") diff --git a/tempest/tests/lib/services/image/v2/test_namespaces_client.py b/tempest/tests/lib/services/image/v2/test_namespaces_client.py deleted file mode 100644 index 4cb9d01a7..000000000 --- a/tempest/tests/lib/services/image/v2/test_namespaces_client.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.image.v2 import namespaces_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNamespacesClient(base.BaseServiceTest): - FAKE_CREATE_SHOW_NAMESPACE = { - "namespace": "OS::Compute::Hypervisor", - "visibility": "public", - "description": "Tempest", - "display_name": u"\u2740(*\xb4\u25e1`*)\u2740", - "protected": True - } - - FAKE_UPDATE_NAMESPACE = { - "namespace": "OS::Compute::Hypervisor", - "visibility": "public", - "description": "Tempest", - "display_name": u"\u2740(*\xb4\u25e2`*)\u2740", - "protected": True - } - - def setUp(self): - super(TestNamespacesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = namespaces_client.NamespacesClient(fake_auth, - 'image', 'regionOne') - - def _test_show_namespace(self, bytes_body=False): - self.check_service_client_function( - self.client.show_namespace, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_SHOW_NAMESPACE, - bytes_body, - namespace="OS::Compute::Hypervisor") - - def _test_create_namespace(self, bytes_body=False): - self.check_service_client_function( - self.client.create_namespace, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_NAMESPACE, - bytes_body, - namespace="OS::Compute::Hypervisor", - visibility="public", description="Tempest", - display_name=u"\u2740(*\xb4\u25e1`*)\u2740", protected=True, - status=201) - - def _test_update_namespace(self, bytes_body=False): - self.check_service_client_function( - self.client.update_namespace, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_NAMESPACE, - bytes_body, - namespace="OS::Compute::Hypervisor", - display_name=u"\u2740(*\xb4\u25e2`*)\u2740", protected=True) - - def test_show_namespace_with_str_body(self): - self._test_show_namespace() - - def test_show_namespace_with_bytes_body(self): - self._test_show_namespace(bytes_body=True) - - def test_create_namespace_with_str_body(self): - self._test_create_namespace() - - def test_create_namespace_with_bytes_body(self): - self._test_create_namespace(bytes_body=True) - - def test_delete_namespace(self): - self.check_service_client_function( - self.client.delete_namespace, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, namespace="OS::Compute::Hypervisor", status=204) - - def test_update_namespace_with_str_body(self): - self._test_update_namespace() - - def test_update_namespace_with_bytes_body(self): - self._test_update_namespace(bytes_body=True) diff --git a/tempest/tests/lib/services/image/v2/test_resource_types_client.py b/tempest/tests/lib/services/image/v2/test_resource_types_client.py deleted file mode 100644 index 2e3b117f5..000000000 --- a/tempest/tests/lib/services/image/v2/test_resource_types_client.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.image.v2 import resource_types_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestResouceTypesClient(base.BaseServiceTest): - FAKE_LIST_RESOURCETYPES = { - "resource_types": [ - { - "created_at": "2014-08-28T18:13:04Z", - "name": "OS::Glance::Image", - "updated_at": "2014-08-28T18:13:04Z" - }, - { - "created_at": "2014-08-28T18:13:04Z", - "name": "OS::Cinder::Volume", - "updated_at": "2014-08-28T18:13:04Z" - }, - { - "created_at": "2014-08-28T18:13:04Z", - "name": "OS::Nova::Flavor", - "updated_at": "2014-08-28T18:13:04Z" - }, - { - "created_at": "2014-08-28T18:13:04Z", - "name": "OS::Nova::Aggregate", - "updated_at": "2014-08-28T18:13:04Z" - }, - { - "created_at": "2014-08-28T18:13:04Z", - "name": u"\u2740(*\xb4\u25e1`*)\u2740", - "updated_at": "2014-08-28T18:13:04Z" - } - ] - } - - def setUp(self): - super(TestResouceTypesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = resource_types_client.ResourceTypesClient(fake_auth, - 'image', - 'regionOne') - - def _test_list_resouce_types(self, bytes_body=False): - self.check_service_client_function( - self.client.list_resource_types, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_RESOURCETYPES, - bytes_body) - - def test_list_resouce_types_with_str_body(self): - self._test_list_resouce_types() - - def test_list_resouce_types_with_bytes_body(self): - self._test_list_resouce_types(bytes_body=True) diff --git a/tempest/tests/lib/services/image/v2/test_schemas_client.py b/tempest/tests/lib/services/image/v2/test_schemas_client.py deleted file mode 100644 index 4c4b86acd..000000000 --- a/tempest/tests/lib/services/image/v2/test_schemas_client.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.image.v2 import schemas_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSchemasClient(base.BaseServiceTest): - FAKE_SHOW_SCHEMA = { - "links": [ - { - "href": "{schema}", - "rel": "describedby" - } - ], - "name": "members", - "properties": { - "members": { - "items": { - "name": "member", - "properties": { - "created_at": { - "description": ("Date and time of image member" - " creation"), - "type": "string" - }, - "image_id": { - "description": "An identifier for the image", - "pattern": ("^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}" - "-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}" - "-([0-9a-fA-F]){12}$"), - "type": "string" - }, - "member_id": { - "description": ("An identifier for the image" - " member (tenantId)"), - "type": "string" - }, - "schema": { - "type": "string" - }, - "status": { - "description": "The status of this image member", - "enum": [ - "pending", - "accepted", - "rejected" - ], - "type": "string" - }, - "updated_at": { - "description": ("Date and time of last" - " modification of image member"), - "type": "string" - } - } - }, - "type": "array" - }, - "schema": { - "type": "string" - } - } - } - - def setUp(self): - super(TestSchemasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = schemas_client.SchemasClient(fake_auth, - 'image', 'regionOne') - - def _test_show_schema(self, bytes_body=False): - self.check_service_client_function( - self.client.show_schema, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SHOW_SCHEMA, - bytes_body, - schema="member") - - def test_show_schema_with_str_body(self): - self._test_show_schema() - - def test_show_schema_with_bytes_body(self): - self._test_show_schema(bytes_body=True) diff --git a/tempest/tests/lib/services/image/v2/test_versions_client.py b/tempest/tests/lib/services/image/v2/test_versions_client.py deleted file mode 100644 index 6234b0699..000000000 --- a/tempest/tests/lib/services/image/v2/test_versions_client.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2017 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.image.v2 import versions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVersionsClient(base.BaseServiceTest): - - FAKE_VERSIONS_INFO = { - "versions": [ - { - "status": "CURRENT", "id": "v2.5", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "SUPPORTED", "id": "v2.4", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "SUPPORTED", "id": "v2.3", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "SUPPORTED", "id": "v2.2", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "SUPPORTED", "id": "v2.1", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "SUPPORTED", "id": "v2.0", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "DEPRECATED", "id": "v1.1", - "links": [ - {"href": "https://10.220.1.21:9292/v1/", "rel": "self"} - ] - }, - { - "status": "DEPRECATED", "id": "v1.0", - "links": [ - {"href": "https://10.220.1.21:9292/v1/", "rel": "self"} - ] - } - ] - } - - def setUp(self): - super(TestVersionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = versions_client.VersionsClient(fake_auth, - 'image', - 'regionOne') - - def _test_list_versions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_versions, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSIONS_INFO, - bytes_body, - 300) - - def test_list_versions_with_str_body(self): - self._test_list_versions() - - def test_list_versions_with_bytes_body(self): - self._test_list_versions(bytes_body=True) diff --git a/tempest/tests/lib/services/network/__init__.py b/tempest/tests/lib/services/network/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/network/test_base_network_client.py b/tempest/tests/lib/services/network/test_base_network_client.py deleted file mode 100644 index e121cec9d..000000000 --- a/tempest/tests/lib/services/network/test_base_network_client.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock - -from tempest.lib.services.network import base as base_network_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -from tempest.tests.lib.services import base - - -class TestBaseNetworkClient(base.BaseServiceTest): - - def setUp(self): - super(TestBaseNetworkClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = base_network_client.BaseNetworkClient( - fake_auth, 'compute', 'regionOne') - - self.mock_expected_success = mock.patch.object( - self.client, 'expected_success').start() - - def _assert_empty(self, resp): - self.assertEqual([], list(resp.keys())) - - @mock.patch('tempest.lib.common.rest_client.RestClient.post') - def test_create_resource(self, mock_post): - response = fake_http.fake_http_response(headers=None, status=201) - mock_post.return_value = response, '{"baz": "qux"}' - - post_data = {'foo': 'bar'} - resp = self.client.create_resource('/fake_url', post_data) - - self.assertEqual({'status': '201'}, resp.response) - self.assertEqual("qux", resp["baz"]) - mock_post.assert_called_once_with('v2.0/fake_url', '{"foo": "bar"}') - self.mock_expected_success.assert_called_once_with( - 201, 201) - - @mock.patch('tempest.lib.common.rest_client.RestClient.post') - def test_create_resource_expect_different_values(self, mock_post): - response = fake_http.fake_http_response(headers=None, status=200) - mock_post.return_value = response, '{}' - - post_data = {'foo': 'bar'} - resp = self.client.create_resource('/fake_url', post_data, - expect_response_code=200, - expect_empty_body=True) - - self.assertEqual({'status': '200'}, resp.response) - self._assert_empty(resp) - mock_post.assert_called_once_with('v2.0/fake_url', '{"foo": "bar"}') - self.mock_expected_success.assert_called_once_with( - 200, 200) - - @mock.patch('tempest.lib.common.rest_client.RestClient.put') - def test_update_resource(self, mock_put): - response = fake_http.fake_http_response(headers=None, status=200) - mock_put.return_value = response, '{"baz": "qux"}' - - put_data = {'foo': 'bar'} - resp = self.client.update_resource('/fake_url', put_data) - - self.assertEqual({'status': '200'}, resp.response) - self.assertEqual("qux", resp["baz"]) - mock_put.assert_called_once_with('v2.0/fake_url', '{"foo": "bar"}') - self.mock_expected_success.assert_called_once_with( - 200, 200) - - @mock.patch('tempest.lib.common.rest_client.RestClient.put') - def test_update_resource_expect_different_values(self, mock_put): - response = fake_http.fake_http_response(headers=None, status=201) - mock_put.return_value = response, '{}' - - put_data = {'foo': 'bar'} - resp = self.client.update_resource('/fake_url', put_data, - expect_response_code=201, - expect_empty_body=True) - - self.assertEqual({'status': '201'}, resp.response) - self._assert_empty(resp) - mock_put.assert_called_once_with('v2.0/fake_url', '{"foo": "bar"}') - self.mock_expected_success.assert_called_once_with( - 201, 201) diff --git a/tempest/tests/lib/services/network/test_extensions_client.py b/tempest/tests/lib/services/network/test_extensions_client.py deleted file mode 100644 index 27eb4858d..000000000 --- a/tempest/tests/lib/services/network/test_extensions_client.py +++ /dev/null @@ -1,201 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import extensions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestExtensionsClient(base.BaseServiceTest): - - FAKE_EXTENSIONS = { - "extensions": [ - { - "updated": "2013-01-20T00:00:00-00:00", - "name": "Neutron Service Type Management", - "links": [], - "alias": "service-type", - "description": "API for retrieving service providers for" - " Neutron advanced services" - }, - { - "updated": "2012-10-05T10:00:00-00:00", - "name": "security-group", - "links": [], - "alias": "security-group", - "description": "The security groups extension." - }, - { - "updated": "2013-02-07T10:00:00-00:00", - "name": "L3 Agent Scheduler", - "links": [], - "alias": "l3_agent_scheduler", - "description": "Schedule routers among l3 agents" - }, - { - "updated": "2013-02-07T10:00:00-00:00", - "name": "Loadbalancer Agent Scheduler", - "links": [], - "alias": "lbaas_agent_scheduler", - "description": "Schedule pools among lbaas agents" - }, - { - "updated": "2013-03-28T10:00:00-00:00", - "name": "Neutron L3 Configurable external gateway mode", - "links": [], - "alias": "ext-gw-mode", - "description": - "Extension of the router abstraction for specifying whether" - " SNAT should occur on the external gateway" - }, - { - "updated": "2014-02-03T10:00:00-00:00", - "name": "Port Binding", - "links": [], - "alias": "binding", - "description": "Expose port bindings of a virtual port to" - " external application" - }, - { - "updated": "2012-09-07T10:00:00-00:00", - "name": "Provider Network", - "links": [], - "alias": "provider", - "description": "Expose mapping of virtual networks to" - " physical networks" - }, - { - "updated": "2013-02-03T10:00:00-00:00", - "name": "agent", - "links": [], - "alias": "agent", - "description": "The agent management extension." - }, - { - "updated": "2012-07-29T10:00:00-00:00", - "name": "Quota management support", - "links": [], - "alias": "quotas", - "description": "Expose functions for quotas management per" - " tenant" - }, - { - "updated": "2013-02-07T10:00:00-00:00", - "name": "DHCP Agent Scheduler", - "links": [], - "alias": "dhcp_agent_scheduler", - "description": "Schedule networks among dhcp agents" - }, - { - "updated": "2013-06-27T10:00:00-00:00", - "name": "Multi Provider Network", - "links": [], - "alias": "multi-provider", - "description": "Expose mapping of virtual networks to" - " multiple physical networks" - }, - { - "updated": "2013-01-14T10:00:00-00:00", - "name": "Neutron external network", - "links": [], - "alias": "external-net", - "description": "Adds external network attribute to network" - " resource." - }, - { - "updated": "2012-07-20T10:00:00-00:00", - "name": "Neutron L3 Router", - "links": [], - "alias": "router", - "description": "Router abstraction for basic L3 forwarding" - " between L2 Neutron networks and access to external" - " networks via a NAT gateway." - }, - { - "updated": "2013-07-23T10:00:00-00:00", - "name": "Allowed Address Pairs", - "links": [], - "alias": "allowed-address-pairs", - "description": "Provides allowed address pairs" - }, - { - "updated": "2013-03-17T12:00:00-00:00", - "name": "Neutron Extra DHCP opts", - "links": [], - "alias": "extra_dhcp_opt", - "description": "Extra options configuration for DHCP. For" - " example PXE boot options to DHCP clients can be specified" - " (e.g. tftp-server, server-ip-address, bootfile-name)" - }, - { - "updated": "2012-10-07T10:00:00-00:00", - "name": "LoadBalancing service", - "links": [], - "alias": "lbaas", - "description": "Extension for LoadBalancing service" - }, - { - "updated": "2013-02-01T10:00:00-00:00", - "name": "Neutron Extra Route", - "links": [], - "alias": "extraroute", - "description": "Extra routes configuration for L3 router" - }, - { - "updated": "2016-01-24T10:00:00-00:00", - "name": "Neutron Port Data Plane Status", - "links": [], - "alias": "data-plane-status", - "description": "Status of the underlying data plane." - } - ] - } - - FAKE_EXTENSION_ALIAS = "service-type" - - def setUp(self): - super(TestExtensionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.extensions_client = extensions_client.ExtensionsClient( - fake_auth, "network", "regionOne") - - def _test_list_extensions(self, bytes_body=False): - self.check_service_client_function( - self.extensions_client.list_extensions, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_EXTENSIONS, - bytes_body, - 200) - - def _test_show_extension(self, bytes_body=False): - self.check_service_client_function( - self.extensions_client.show_extension, - "tempest.lib.common.rest_client.RestClient.get", - {"extension": self.FAKE_EXTENSIONS["extensions"][0]}, - bytes_body, - 200, - ext_alias=self.FAKE_EXTENSION_ALIAS) - - def test_list_extensions_with_str_body(self): - self._test_list_extensions() - - def test_list_extensions_with_bytes_body(self): - self._test_list_extensions(bytes_body=True) - - def test_show_extension_with_str_body(self): - self._test_show_extension() - - def test_show_extension_with_bytes_body(self): - self._test_show_extension(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_floating_ips_client.py b/tempest/tests/lib/services/network/test_floating_ips_client.py deleted file mode 100644 index c5b1845ae..000000000 --- a/tempest/tests/lib/services/network/test_floating_ips_client.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.services.network import floating_ips_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestFloatingIPsClient(base.BaseServiceTest): - - FAKE_FLOATING_IPS = { - "floatingips": [ - { - "router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f", - "description": "for test", - "created_at": "2016-12-21T10:55:50Z", - "updated_at": "2016-12-21T10:55:53Z", - "revision_number": 1, - "project_id": "4969c491a3c74ee4af974e6d800c62de", - "tenant_id": "4969c491a3c74ee4af974e6d800c62de", - "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57", - "fixed_ip_address": "10.0.0.3", - "floating_ip_address": "172.24.4.228", - "port_id": "ce705c24-c1ef-408a-bda3-7bbd946164ab", - "id": "2f245a7b-796b-4f26-9cf9-9e82d248fda7", - "status": "ACTIVE" - }, - { - "router_id": None, - "description": "for test", - "created_at": "2016-12-21T11:55:50Z", - "updated_at": "2016-12-21T11:55:53Z", - "revision_number": 2, - "project_id": "4969c491a3c74ee4af974e6d800c62de", - "tenant_id": "4969c491a3c74ee4af974e6d800c62de", - "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57", - "fixed_ip_address": None, - "floating_ip_address": "172.24.4.227", - "port_id": None, - "id": "61cea855-49cb-4846-997d-801b70c71bdd", - "status": "DOWN" - } - ] - } - - FAKE_FLOATING_IP_ID = "2f245a7b-796b-4f26-9cf9-9e82d248fda7" - - def setUp(self): - super(TestFloatingIPsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.floating_ips_client = floating_ips_client.FloatingIPsClient( - fake_auth, "compute", "regionOne") - - def _test_list_floatingips(self, bytes_body=False): - self.check_service_client_function( - self.floating_ips_client.list_floatingips, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_FLOATING_IPS, - bytes_body, - 200) - - def _test_create_floatingip(self, bytes_body=False): - self.check_service_client_function( - self.floating_ips_client.create_floatingip, - "tempest.lib.common.rest_client.RestClient.post", - {"floatingip": self.FAKE_FLOATING_IPS["floatingips"][1]}, - bytes_body, - 201, - floating_network_id="172.24.4.228") - - def _test_show_floatingip(self, bytes_body=False): - self.check_service_client_function( - self.floating_ips_client.show_floatingip, - "tempest.lib.common.rest_client.RestClient.get", - {"floatingip": self.FAKE_FLOATING_IPS["floatingips"][0]}, - bytes_body, - 200, - floatingip_id=self.FAKE_FLOATING_IP_ID) - - def _test_update_floatingip(self, bytes_body=False): - update_kwargs = { - "port_id": "fc861431-0e6c-4842-a0ed-e2363f9bc3a8" - } - - resp_body = { - "floatingip": copy.deepcopy( - self.FAKE_FLOATING_IPS["floatingips"][0] - ) - } - resp_body["floatingip"].update(update_kwargs) - - self.check_service_client_function( - self.floating_ips_client.update_floatingip, - "tempest.lib.common.rest_client.RestClient.put", - resp_body, - bytes_body, - 200, - floatingip_id=self.FAKE_FLOATING_IP_ID, - **update_kwargs) - - def test_list_floatingips_with_str_body(self): - self._test_list_floatingips() - - def test_list_floatingips_with_bytes_body(self): - self._test_list_floatingips(bytes_body=True) - - def test_create_floatingip_with_str_body(self): - self._test_create_floatingip() - - def test_create_floatingip_with_bytes_body(self): - self._test_create_floatingip(bytes_body=True) - - def test_show_floatingips_with_str_body(self): - self._test_show_floatingip() - - def test_show_floatingips_with_bytes_body(self): - self._test_show_floatingip(bytes_body=True) - - def test_update_floatingip_with_str_body(self): - self._test_update_floatingip() - - def test_update_floatingip_with_bytes_body(self): - self._test_update_floatingip(bytes_body=True) - - def test_delete_floatingip(self): - self.check_service_client_function( - self.floating_ips_client.delete_floatingip, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - floatingip_id=self.FAKE_FLOATING_IP_ID) diff --git a/tempest/tests/lib/services/network/test_metering_label_rules_client.py b/tempest/tests/lib/services/network/test_metering_label_rules_client.py deleted file mode 100644 index 047c34f5a..000000000 --- a/tempest/tests/lib/services/network/test_metering_label_rules_client.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import metering_label_rules_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestMeteringLabelRulesClient(base.BaseServiceTest): - - FAKE_METERING_LABEL_RULES = { - "metering_label_rules": [ - { - "remote_ip_prefix": "20.0.0.0/24", - "direction": "ingress", - "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812", - "id": "9536641a-7d14-4dc5-afaf-93a973ce0eb8", - "excluded": False - }, - { - "remote_ip_prefix": "10.0.0.0/24", - "direction": "ingress", - "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812", - "id": "ffc6fd15-40de-4e7d-b617-34d3f7a93aec", - "excluded": False - } - ] - } - - FAKE_METERING_LABEL_RULE = { - "remote_ip_prefix": "20.0.0.0/24", - "direction": "ingress", - "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812" - } - - FAKE_METERING_LABEL_ID = "e131d186-b02d-4c0b-83d5-0c0725c4f812" - FAKE_METERING_LABEL_RULE_ID = "9536641a-7d14-4dc5-afaf-93a973ce0eb8" - - def setUp(self): - super(TestMeteringLabelRulesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.metering_label_rules_client = \ - metering_label_rules_client.MeteringLabelRulesClient( - fake_auth, "network", "regionOne") - - def _test_list_metering_label_rules(self, bytes_body=False): - self.check_service_client_function( - self.metering_label_rules_client.list_metering_label_rules, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_METERING_LABEL_RULES, - bytes_body, - 200) - - def _test_create_metering_label_rule(self, bytes_body=False): - self.check_service_client_function( - self.metering_label_rules_client.create_metering_label_rule, - "tempest.lib.common.rest_client.RestClient.post", - {"metering_label_rule": self.FAKE_METERING_LABEL_RULES[ - "metering_label_rules"][0]}, - bytes_body, - 201, - **self.FAKE_METERING_LABEL_RULE) - - def _test_show_metering_label_rule(self, bytes_body=False): - self.check_service_client_function( - self.metering_label_rules_client.show_metering_label_rule, - "tempest.lib.common.rest_client.RestClient.get", - {"metering_label_rule": self.FAKE_METERING_LABEL_RULES[ - "metering_label_rules"][0]}, - bytes_body, - 200, - metering_label_rule_id=self.FAKE_METERING_LABEL_RULE_ID) - - def test_delete_metering_label_rule(self): - self.check_service_client_function( - self.metering_label_rules_client.delete_metering_label_rule, - "tempest.lib.common.rest_client.RestClient.delete", - {}, - status=204, - metering_label_rule_id=self.FAKE_METERING_LABEL_RULE_ID) - - def test_list_metering_label_rules_with_str_body(self): - self._test_list_metering_label_rules() - - def test_list_metering_label_rules_with_bytes_body(self): - self._test_list_metering_label_rules(bytes_body=True) - - def test_create_metering_label_rule_with_str_body(self): - self._test_create_metering_label_rule() - - def test_create_metering_label_rule_with_bytes_body(self): - self._test_create_metering_label_rule(bytes_body=True) - - def test_show_metering_label_rule_with_str_body(self): - self._test_show_metering_label_rule() - - def test_show_metering_label_rule_with_bytes_body(self): - self._test_show_metering_label_rule(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_metering_labels_client.py b/tempest/tests/lib/services/network/test_metering_labels_client.py deleted file mode 100644 index a048326d1..000000000 --- a/tempest/tests/lib/services/network/test_metering_labels_client.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import metering_labels_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestMeteringLabelsClient(base.BaseServiceTest): - - FAKE_METERING_LABELS = { - "metering_labels": [ - { - "project_id": "45345b0ee1ea477fac0f541b2cb79cd4", - "tenant_id": "45345b0ee1ea477fac0f541b2cb79cd4", - "description": "label1 description", - "name": "label1", - "id": "a6700594-5b7a-4105-8bfe-723b346ce866", - "shared": False - }, - { - "project_id": "45345b0ee1ea477fac0f541b2cb79cd4", - "tenant_id": "45345b0ee1ea477fac0f541b2cb79cd4", - "description": "label2 description", - "name": "label2", - "id": "e131d186-b02d-4c0b-83d5-0c0725c4f812", - "shared": False - } - ] - } - - FAKE_METERING_LABEL_ID = "a6700594-5b7a-4105-8bfe-723b346ce866" - - def setUp(self): - super(TestMeteringLabelsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.metering_labels_client = \ - metering_labels_client.MeteringLabelsClient( - fake_auth, "network", "regionOne") - - def _test_list_metering_labels(self, bytes_body=False): - self.check_service_client_function( - self.metering_labels_client.list_metering_labels, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_METERING_LABELS, - bytes_body, - 200) - - def _test_create_metering_label(self, bytes_body=False): - self.check_service_client_function( - self.metering_labels_client.create_metering_label, - "tempest.lib.common.rest_client.RestClient.post", - {"metering_label": self.FAKE_METERING_LABELS[ - "metering_labels"][1]}, - bytes_body, - 201, - name="label1", - description="label1 description", - shared=False) - - def _test_show_metering_label(self, bytes_body=False): - self.check_service_client_function( - self.metering_labels_client.show_metering_label, - "tempest.lib.common.rest_client.RestClient.get", - {"metering_label": self.FAKE_METERING_LABELS[ - "metering_labels"][0]}, - bytes_body, - 200, - metering_label_id=self.FAKE_METERING_LABEL_ID) - - def test_delete_metering_label(self): - self.check_service_client_function( - self.metering_labels_client.delete_metering_label, - "tempest.lib.common.rest_client.RestClient.delete", - {}, - status=204, - metering_label_id=self.FAKE_METERING_LABEL_ID) - - def test_list_metering_labels_with_str_body(self): - self._test_list_metering_labels() - - def test_list_metering_labels_with_bytes_body(self): - self._test_list_metering_labels(bytes_body=True) - - def test_create_metering_label_with_str_body(self): - self._test_create_metering_label() - - def test_create_metering_label_with_bytes_body(self): - self._test_create_metering_label(bytes_body=True) - - def test_show_metering_label_with_str_body(self): - self._test_show_metering_label() - - def test_show_metering_label_with_bytes_body(self): - self._test_show_metering_label(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_ports_client.py b/tempest/tests/lib/services/network/test_ports_client.py deleted file mode 100644 index 20ef3f1e6..000000000 --- a/tempest/tests/lib/services/network/test_ports_client.py +++ /dev/null @@ -1,198 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.services.network import ports_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestPortsClient(base.BaseServiceTest): - - FAKE_PORTS = { - "ports": [ - { - "admin_state_up": True, - "allowed_address_pairs": [], - "data_plane_status": None, - "description": "", - "device_id": "9ae135f4-b6e0-4dad-9e91-3c223e385824", - "device_owner": "network:router_gateway", - "extra_dhcp_opts": [], - "fixed_ips": [ - { - "ip_address": "172.24.4.2", - "subnet_id": "008ba151-0b8c-4a67-98b5-0d2b87666062" - } - ], - "id": "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b", - "mac_address": "fa:16:3e:58:42:ed", - "name": "", - "network_id": "70c1db1f-b701-45bd-96e0-a313ee3430b3", - "project_id": "", - "security_groups": [], - "status": "ACTIVE", - "tenant_id": "" - }, - { - "admin_state_up": True, - "allowed_address_pairs": [], - "data_plane_status": None, - "description": "", - "device_id": "9ae135f4-b6e0-4dad-9e91-3c223e385824", - "device_owner": "network:router_interface", - "extra_dhcp_opts": [], - "fixed_ips": [ - { - "ip_address": "10.0.0.1", - "subnet_id": "288bf4a1-51ba-43b6-9d0a-520e9005db17" - } - ], - "id": "f71a6703-d6de-4be1-a91a-a570ede1d159", - "mac_address": "fa:16:3e:bb:3c:e4", - "name": "", - "network_id": "f27aa545-cbdd-4907-b0c6-c9e8b039dcc2", - "project_id": "d397de8a63f341818f198abb0966f6f3", - "security_groups": [], - "status": "ACTIVE", - "tenant_id": "d397de8a63f341818f198abb0966f6f3" - } - ] - } - - FAKE_PORT_ID = "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b" - - FAKE_PORT1 = { - "admin_state_up": True, - "name": "", - "network_id": "70c1db1f-b701-45bd-96e0-a313ee3430b3" - } - - FAKE_PORT2 = { - "admin_state_up": True, - "name": "", - "network_id": "f27aa545-cbdd-4907-b0c6-c9e8b039dcc2" - } - - FAKE_PORTS_REQ = { - "ports": [ - FAKE_PORT1, - FAKE_PORT2 - ] - } - - def setUp(self): - super(TestPortsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.ports_client = ports_client.PortsClient( - fake_auth, "network", "regionOne") - - def _test_list_ports(self, bytes_body=False): - self.check_service_client_function( - self.ports_client.list_ports, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_PORTS, - bytes_body, - 200) - - def _test_create_port(self, bytes_body=False): - self.check_service_client_function( - self.ports_client.create_port, - "tempest.lib.common.rest_client.RestClient.post", - {"port": self.FAKE_PORTS["ports"][0]}, - bytes_body, - 201, - **self.FAKE_PORT1) - - def _test_create_bulk_ports(self, bytes_body=False): - self.check_service_client_function( - self.ports_client.create_bulk_ports, - "tempest.lib.common.rest_client.RestClient.post", - self.FAKE_PORTS, - bytes_body, - 201, - ports=self.FAKE_PORTS_REQ) - - def _test_show_port(self, bytes_body=False): - self.check_service_client_function( - self.ports_client.show_port, - "tempest.lib.common.rest_client.RestClient.get", - {"port": self.FAKE_PORTS["ports"][0]}, - bytes_body, - 200, - port_id=self.FAKE_PORT_ID) - - def _test_update_port(self, bytes_body=False): - update_kwargs = { - "admin_state_up": True, - "device_id": "d90a13da-be41-461f-9f99-1dbcf438fdf2", - "device_owner": "compute:nova", - "name": "test-for-port-update" - } - - resp_body = { - "port": copy.deepcopy( - self.FAKE_PORTS["ports"][0] - ) - } - resp_body["port"].update(update_kwargs) - - self.check_service_client_function( - self.ports_client.update_port, - "tempest.lib.common.rest_client.RestClient.put", - resp_body, - bytes_body, - 200, - port_id=self.FAKE_PORT_ID, - **update_kwargs) - - def test_delete_port(self): - self.check_service_client_function( - self.ports_client.delete_port, - "tempest.lib.common.rest_client.RestClient.delete", - {}, - status=204, - port_id=self.FAKE_PORT_ID) - - def test_list_ports_with_str_body(self): - self._test_list_ports() - - def test_list_ports_with_bytes_body(self): - self._test_list_ports(bytes_body=True) - - def test_create_port_with_str_body(self): - self._test_create_port() - - def test_create_port_with_bytes_body(self): - self._test_create_port(bytes_body=True) - - def test_create_bulk_port_with_str_body(self): - self._test_create_bulk_ports() - - def test_create_bulk_port_with_bytes_body(self): - self._test_create_bulk_ports(bytes_body=True) - - def test_show_port_with_str_body(self): - self._test_show_port() - - def test_show_port_with_bytes_body(self): - self._test_show_port(bytes_body=True) - - def test_update_port_with_str_body(self): - self._test_update_port() - - def test_update_port_with_bytes_body(self): - self._test_update_port(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_quotas_client.py b/tempest/tests/lib/services/network/test_quotas_client.py deleted file mode 100644 index e76bc9c17..000000000 --- a/tempest/tests/lib/services/network/test_quotas_client.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import quotas_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotasClient(base.BaseServiceTest): - - FAKE_QUOTAS = { - "quotas": [ - { - "floatingip": 50, - "network": 15, - "port": 50, - "project_id": "bab7d5c60cd041a0a36f7c4b6e1dd978", - "rbac_policy": -1, - "router": 10, - "security_group": 10, - "security_group_rule": 100, - "subnet": 10, - "subnetpool": -1, - "tenant_id": "bab7d5c60cd041a0a36f7c4b6e1dd978" - } - ] - } - - FAKE_QUOTA_TENANT_ID = "bab7d5c60cd041a0a36f7c4b6e1dd978" - - def setUp(self): - super(TestQuotasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.quotas_client = quotas_client.QuotasClient( - fake_auth, "network", "regionOne") - - def _test_list_quotas(self, bytes_body=False): - self.check_service_client_function( - self.quotas_client.list_quotas, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_QUOTAS, - bytes_body, - 200) - - def _test_show_quotas(self, bytes_body=False): - self.check_service_client_function( - self.quotas_client.show_quotas, - "tempest.lib.common.rest_client.RestClient.get", - {"quota": self.FAKE_QUOTAS["quotas"][0]}, - bytes_body, - 200, - tenant_id=self.FAKE_QUOTA_TENANT_ID) - - def _test_update_quotas(self, bytes_body=False): - self.check_service_client_function( - self.quotas_client.update_quotas, - "tempest.lib.common.rest_client.RestClient.put", - {"quota": self.FAKE_QUOTAS["quotas"][0]}, - bytes_body, - 200, - tenant_id=self.FAKE_QUOTA_TENANT_ID) - - def test_reset_quotas(self): - self.check_service_client_function( - self.quotas_client.reset_quotas, - "tempest.lib.common.rest_client.RestClient.delete", - {}, - status=204, - tenant_id=self.FAKE_QUOTA_TENANT_ID) - - def test_list_quotas_with_str_body(self): - self._test_list_quotas() - - def test_list_quotas_with_bytes_body(self): - self._test_list_quotas(bytes_body=True) - - def test_show_quotas_with_str_body(self): - self._test_show_quotas() - - def test_show_quotas_with_bytes_body(self): - self._test_show_quotas(bytes_body=True) - - def test_update_quotas_with_str_body(self): - self._test_update_quotas() - - def test_update_quotas_with_bytes_body(self): - self._test_update_quotas(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_routers_client.py b/tempest/tests/lib/services/network/test_routers_client.py deleted file mode 100644 index 2fa599343..000000000 --- a/tempest/tests/lib/services/network/test_routers_client.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.network import routers_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestRoutersClient(base.BaseServiceTest): - FAKE_CREATE_ROUTER = { - "router": { - "name": u'\u2740(*\xb4\u25e1`*)\u2740', - "external_gateway_info": { - "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b", - "enable_snat": True, - "external_fixed_ips": [ - { - "subnet_id": "255.255.255.0", - "ip": "192.168.10.1" - } - ] - }, - "admin_state_up": True, - "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e" - } - } - - FAKE_UPDATE_ROUTER = { - "router": { - "name": u'\u2740(*\xb4\u25e1`*)\u2740', - "external_gateway_info": { - "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b", - "enable_snat": True, - "external_fixed_ips": [ - { - "subnet_id": "255.255.255.0", - "ip": "192.168.10.1" - } - ] - }, - "admin_state_up": False, - "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e" - } - } - - def setUp(self): - super(TestRoutersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = routers_client.RoutersClient(fake_auth, - 'network', 'regionOne') - - def _test_list_routers(self, bytes_body=False): - self.check_service_client_function( - self.client.list_routers, - 'tempest.lib.common.rest_client.RestClient.get', - {"routers": []}, - bytes_body) - - def _test_create_router(self, bytes_body=False): - self.check_service_client_function( - self.client.create_router, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ROUTER, - bytes_body, - name="another_router", admin_state_up="true", status=201) - - def _test_update_router(self, bytes_body=False): - self.check_service_client_function( - self.client.update_router, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_ROUTER, - bytes_body, - router_id="8604a0de-7f6b-409a-a47c-a1cc7bc77b2e", - admin_state_up=False) - - def test_list_routers_with_str_body(self): - self._test_list_routers() - - def test_list_routers_with_bytes_body(self): - self._test_list_routers(bytes_body=True) - - def test_create_router_with_str_body(self): - self._test_create_router() - - def test_create_router_with_bytes_body(self): - self._test_create_router(bytes_body=True) - - def test_delete_router(self): - self.check_service_client_function( - self.client.delete_router, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, router_id="1", status=204) - - def test_update_router_with_str_body(self): - self._test_update_router() - - def test_update_router_with_bytes_body(self): - self._test_update_router(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_security_group_rules_client.py b/tempest/tests/lib/services/network/test_security_group_rules_client.py deleted file mode 100644 index b9c17a15f..000000000 --- a/tempest/tests/lib/services/network/test_security_group_rules_client.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -import mock -from oslo_serialization import jsonutils as json - -from tempest.lib.services.network import base as network_base -from tempest.lib.services.network import security_group_rules_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSecurityGroupsClient(base.BaseServiceTest): - - FAKE_SEC_GROUP_RULE_ID = "3c0e45ff-adaf-4124-b083-bf390e5482ff" - - FAKE_SECURITY_GROUP_RULES = { - "security_group_rules": [ - { - "direction": "egress", - "ethertype": "IPv6", - "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff", - "port_range_max": None, - "port_range_min": None, - "protocol": None, - "remote_group_id": None, - "remote_ip_prefix": None, - "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", - "project_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "description": "" - }, - { - "direction": "egress", - "ethertype": "IPv4", - "id": "93aa42e5-80db-4581-9391-3a608bd0e448", - "port_range_max": None, - "port_range_min": None, - "protocol": None, - "remote_group_id": None, - "remote_ip_prefix": None, - "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", - "project_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "description": "" - } - ] - } - - FAKE_SECURITY_GROUP_RULE = copy.copy( - FAKE_SECURITY_GROUP_RULES['security_group_rules'][0]) - - def setUp(self): - super(TestSecurityGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = security_group_rules_client.SecurityGroupRulesClient( - fake_auth, 'network', 'regionOne') - - def _test_list_security_group_rules(self, bytes_body=False): - self.check_service_client_function( - self.client.list_security_group_rules, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SECURITY_GROUP_RULES, - bytes_body, - mock_args='v2.0/security-group-rules') - - def _test_create_security_group_rule(self, bytes_body=False): - kwargs = {'direction': 'egress', - 'security_group_id': '85cc3048-abc3-43cc-89b3-377341426ac5', - 'remote_ip_prefix': None} - payload = json.dumps({"security_group_rule": kwargs}, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(network_base.json, 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.create_security_group_rule, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SECURITY_GROUP_RULE, - bytes_body, - status=201, - mock_args=['v2.0/security-group-rules', payload], - **kwargs) - - def _test_show_security_group_rule(self, bytes_body=False): - self.check_service_client_function( - self.client.show_security_group_rule, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SECURITY_GROUP_RULE, - bytes_body, - security_group_rule_id=self.FAKE_SEC_GROUP_RULE_ID, - mock_args='v2.0/security-group-rules/%s' - % self.FAKE_SEC_GROUP_RULE_ID) - - def test_list_security_group_rules_with_str_body(self): - self._test_list_security_group_rules() - - def test_list_security_group_rules_with_bytes_body(self): - self._test_list_security_group_rules(bytes_body=True) - - def test_create_security_group_rule_with_str_body(self): - self._test_create_security_group_rule() - - def test_create_security_group_rule_with_bytes_body(self): - self._test_create_security_group_rule(bytes_body=True) - - def test_show_security_group_rule_with_str_body(self): - self._test_show_security_group_rule() - - def test_show_security_group_rule_with_bytes_body(self): - self._test_show_security_group_rule(bytes_body=True) - - def test_delete_security_group_rule(self): - self.check_service_client_function( - self.client.delete_security_group_rule, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - security_group_rule_id=self.FAKE_SEC_GROUP_RULE_ID, - mock_args='v2.0/security-group-rules/%s' - % self.FAKE_SEC_GROUP_RULE_ID) diff --git a/tempest/tests/lib/services/network/test_security_groups_client.py b/tempest/tests/lib/services/network/test_security_groups_client.py deleted file mode 100644 index f96805f3b..000000000 --- a/tempest/tests/lib/services/network/test_security_groups_client.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -import mock -from oslo_serialization import jsonutils as json - -from tempest.lib.services.network import base as network_base -from tempest.lib.services.network import security_groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSecurityGroupsClient(base.BaseServiceTest): - - FAKE_SEC_GROUP_ID = "85cc3048-abc3-43cc-89b3-377341426ac5" - - FAKE_SECURITY_GROUPS = { - "security_groups": [ - { - "description": "default", - "id": FAKE_SEC_GROUP_ID, - "name": "fake-security-group-name", - "security_group_rules": [ - { - "direction": "egress", - "ethertype": "IPv4", - "id": "38ce2d8e-e8f1-48bd-83c2-d33cb9f50c3d", - "port_range_max": None, - "port_range_min": None, - "protocol": None, - "remote_group_id": None, - "remote_ip_prefix": None, - "security_group_id": FAKE_SEC_GROUP_ID, - "project_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "description": "" - }, - { - "direction": "egress", - "ethertype": "IPv6", - "id": "565b9502-12de-4ffd-91e9-68885cff6ae1", - "port_range_max": None, - "port_range_min": None, - "protocol": None, - "remote_group_id": None, - "remote_ip_prefix": None, - "security_group_id": FAKE_SEC_GROUP_ID, - "project_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "description": "" - } - ], - "project_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" - } - ] - } - - FAKE_SECURITY_GROUP = { - "security_group": copy.deepcopy( - FAKE_SECURITY_GROUPS["security_groups"][0]) - } - - def setUp(self): - super(TestSecurityGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = security_groups_client.SecurityGroupsClient( - fake_auth, 'network', 'regionOne') - - def _test_list_security_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_security_groups, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SECURITY_GROUPS, - bytes_body, - mock_args='v2.0/security-groups') - - def _test_create_security_group(self, bytes_body=False): - kwargs = {'name': 'fake-security-group-name'} - payload = json.dumps({"security_group": kwargs}, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(network_base.json, 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.create_security_group, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SECURITY_GROUP, - bytes_body, - status=201, - mock_args=['v2.0/security-groups', payload], - **kwargs) - - def _test_show_security_group(self, bytes_body=False): - self.check_service_client_function( - self.client.show_security_group, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SECURITY_GROUP, - bytes_body, - security_group_id=self.FAKE_SEC_GROUP_ID, - mock_args='v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID) - - def _test_update_security_group(self, bytes_body=False): - kwargs = {'name': 'updated-security-group-name'} - resp_body = copy.deepcopy(self.FAKE_SECURITY_GROUP) - resp_body["security_group"]["name"] = 'updated-security-group-name' - - payload = json.dumps({'security_group': kwargs}, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(network_base.json, 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.update_security_group, - 'tempest.lib.common.rest_client.RestClient.put', - resp_body, - bytes_body, - security_group_id=self.FAKE_SEC_GROUP_ID, - mock_args=['v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID, - payload], - **kwargs) - - def test_list_security_groups_with_str_body(self): - self._test_list_security_groups() - - def test_list_security_groups_with_bytes_body(self): - self._test_list_security_groups(bytes_body=True) - - def test_create_security_group_with_str_body(self): - self._test_create_security_group() - - def test_create_security_group_with_bytes_body(self): - self._test_create_security_group(bytes_body=True) - - def test_show_security_group_with_str_body(self): - self._test_show_security_group() - - def test_show_security_group_with_bytes_body(self): - self._test_show_security_group(bytes_body=True) - - def test_update_security_group_with_str_body(self): - self._test_update_security_group() - - def test_update_security_group_with_bytes_body(self): - self._test_update_security_group(bytes_body=True) - - def test_delete_security_group(self): - self.check_service_client_function( - self.client.delete_security_group, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - security_group_id=self.FAKE_SEC_GROUP_ID, - mock_args='v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID) diff --git a/tempest/tests/lib/services/network/test_service_providers_client.py b/tempest/tests/lib/services/network/test_service_providers_client.py deleted file mode 100644 index ae11ef0c7..000000000 --- a/tempest/tests/lib/services/network/test_service_providers_client.py +++ /dev/null @@ -1,37 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.lib.services.network import service_providers_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestServiceProvidersClient(base.BaseServiceTest): - def setUp(self): - super(TestServiceProvidersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = service_providers_client.ServiceProvidersClient( - fake_auth, 'network', 'regionOne') - - def _test_list_service_providers(self, bytes_body=False): - self.check_service_client_function( - self.client.list_service_providers, - 'tempest.lib.common.rest_client.RestClient.get', - {"service_providers": []}, - bytes_body) - - def test_list_service_providers_with_str_body(self): - self._test_list_service_providers() - - def test_list_service_providers_with_bytes_body(self): - self._test_list_service_providers(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_subnetpools_client.py b/tempest/tests/lib/services/network/test_subnetpools_client.py deleted file mode 100644 index 3abb43844..000000000 --- a/tempest/tests/lib/services/network/test_subnetpools_client.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.services.network import subnetpools_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSubnetsClient(base.BaseServiceTest): - - FAKE_SUBNETPOOLS = { - "subnetpools": [ - { - "min_prefixlen": "64", - "address_scope_id": None, - "default_prefixlen": "64", - "id": "03f761e6-eee0-43fc-a921-8acf64c14988", - "max_prefixlen": "64", - "name": "my-subnet-pool-ipv6", - "default_quota": None, - "is_default": False, - "project_id": "9fadcee8aa7c40cdb2114fff7d569c08", - "tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08", - "prefixes": [ - "2001:db8:0:2::/64", - "2001:db8::/63" - ], - "ip_version": 6, - "shared": False, - "description": "", - "revision_number": 2 - }, - { - "min_prefixlen": "24", - "address_scope_id": None, - "default_prefixlen": "25", - "id": "f49a1319-423a-4ee6-ba54-1d95a4f6cc68", - "max_prefixlen": "30", - "name": "my-subnet-pool-ipv4", - "default_quota": None, - "is_default": False, - "project_id": "9fadcee8aa7c40cdb2114fff7d569c08", - "tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08", - "prefixes": [ - "10.10.0.0/21", - "192.168.0.0/16" - ], - "ip_version": 4, - "shared": False, - "description": "", - "revision_number": 2 - } - ] - } - - FAKE_SUBNETPOOL_ID = "03f761e6-eee0-43fc-a921-8acf64c14988" - - def setUp(self): - super(TestSubnetsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.subnetpools_client = subnetpools_client.SubnetpoolsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_subnetpools(self, bytes_body=False): - self.check_service_client_function( - self.subnetpools_client.list_subnetpools, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SUBNETPOOLS, - bytes_body, - 200) - - def _test_create_subnetpool(self, bytes_body=False): - self.check_service_client_function( - self.subnetpools_client.create_subnetpool, - 'tempest.lib.common.rest_client.RestClient.post', - {'subnetpool': self.FAKE_SUBNETPOOLS['subnetpools'][1]}, - bytes_body, - 201, - name="my-subnet-pool-ipv4", - prefixes=["192.168.0.0/16", "10.10.0.0/21"]) - - def _test_show_subnetpool(self, bytes_body=False): - self.check_service_client_function( - self.subnetpools_client.show_subnetpool, - 'tempest.lib.common.rest_client.RestClient.get', - {'subnetpool': self.FAKE_SUBNETPOOLS['subnetpools'][0]}, - bytes_body, - 200, - subnetpool_id=self.FAKE_SUBNETPOOL_ID) - - def _test_update_subnetpool(self, bytes_body=False): - update_kwargs = { - "name": "my-new-subnetpool-name", - "prefixes": [ - "2001:db8::/64", - "2001:db8:0:1::/64", - "2001:db8:0:2::/64" - ], - "min_prefixlen": 64, - "default_prefixlen": 64, - "max_prefixlen": 64 - } - - resp_body = { - 'subnetpool': copy.deepcopy( - self.FAKE_SUBNETPOOLS['subnetpools'][0]) - } - resp_body['subnetpool'].update(update_kwargs) - - self.check_service_client_function( - self.subnetpools_client.update_subnetpool, - 'tempest.lib.common.rest_client.RestClient.put', - resp_body, - bytes_body, - 200, - subnetpool_id=self.FAKE_SUBNETPOOL_ID, - **update_kwargs) - - def test_list_subnetpools_with_str_body(self): - self._test_list_subnetpools() - - def test_list_subnetpools_with_bytes_body(self): - self._test_list_subnetpools(bytes_body=True) - - def test_create_subnetpool_with_str_body(self): - self._test_create_subnetpool() - - def test_create_subnetpool_with_bytes_body(self): - self._test_create_subnetpool(bytes_body=True) - - def test_show_subnetpool_with_str_body(self): - self._test_show_subnetpool() - - def test_show_subnetpool_with_bytes_body(self): - self._test_show_subnetpool(bytes_body=True) - - def test_update_subnet_with_str_body(self): - self._test_update_subnetpool() - - def test_update_subnet_with_bytes_body(self): - self._test_update_subnetpool(bytes_body=True) - - def test_delete_subnetpool(self): - self.check_service_client_function( - self.subnetpools_client.delete_subnetpool, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - subnetpool_id=self.FAKE_SUBNETPOOL_ID) diff --git a/tempest/tests/lib/services/network/test_subnets_client.py b/tempest/tests/lib/services/network/test_subnets_client.py deleted file mode 100644 index 0aadf5482..000000000 --- a/tempest/tests/lib/services/network/test_subnets_client.py +++ /dev/null @@ -1,250 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.services.network import subnets_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSubnetsClient(base.BaseServiceTest): - - FAKE_SUBNET = { - "subnet": { - "name": "", - "enable_dhcp": True, - "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22", - "segment_id": None, - "project_id": "4fd44f30292945e481c7b8a0c8908869", - "tenant_id": "4fd44f30292945e481c7b8a0c8908869", - "dns_nameservers": [], - "allocation_pools": [ - { - "start": "192.168.199.2", - "end": "192.168.199.254" - } - ], - "host_routes": [], - "ip_version": 4, - "gateway_ip": "192.168.199.1", - "cidr": "192.168.199.0/24", - "id": "3b80198d-4f7b-4f77-9ef5-774d54e17126", - "created_at": "2016-10-10T14:35:47Z", - "description": "", - "ipv6_address_mode": None, - "ipv6_ra_mode": None, - "revision_number": 2, - "service_types": [], - "subnetpool_id": None, - "updated_at": "2016-10-10T14:35:47Z" - } - } - - FAKE_UPDATED_SUBNET = { - "subnet": { - "name": "my_subnet", - "enable_dhcp": True, - "network_id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324", - "segment_id": None, - "project_id": "26a7980765d0414dbc1fc1f88cdb7e6e", - "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e", - "dns_nameservers": [], - "allocation_pools": [ - { - "start": "10.0.0.2", - "end": "10.0.0.254" - } - ], - "host_routes": [], - "ip_version": 4, - "gateway_ip": "10.0.0.1", - "cidr": "10.0.0.0/24", - "id": "08eae331-0402-425a-923c-34f7cfe39c1b", - "description": "" - } - } - - FAKE_SUBNETS = { - "subnets": [ - { - "name": "private-subnet", - "enable_dhcp": True, - "network_id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324", - "segment_id": None, - "project_id": "26a7980765d0414dbc1fc1f88cdb7e6e", - "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e", - "dns_nameservers": [], - "allocation_pools": [ - { - "start": "10.0.0.2", - "end": "10.0.0.254" - } - ], - "host_routes": [], - "ip_version": 4, - "gateway_ip": "10.0.0.1", - "cidr": "10.0.0.0/24", - "id": "08eae331-0402-425a-923c-34f7cfe39c1b", - "created_at": "2016-10-10T14:35:34Z", - "description": "", - "ipv6_address_mode": None, - "ipv6_ra_mode": None, - "revision_number": 2, - "service_types": [], - "subnetpool_id": None, - "updated_at": "2016-10-10T14:35:34Z" - }, - { - "name": "my_subnet", - "enable_dhcp": True, - "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22", - "segment_id": None, - "project_id": "4fd44f30292945e481c7b8a0c8908869", - "tenant_id": "4fd44f30292945e481c7b8a0c8908869", - "dns_nameservers": [], - "allocation_pools": [ - { - "start": "192.0.0.2", - "end": "192.255.255.254" - } - ], - "host_routes": [], - "ip_version": 4, - "gateway_ip": "192.0.0.1", - "cidr": "192.0.0.0/8", - "id": "54d6f61d-db07-451c-9ab3-b9609b6b6f0b", - "created_at": "2016-10-10T14:35:47Z", - "description": "", - "ipv6_address_mode": None, - "ipv6_ra_mode": None, - "revision_number": 2, - "service_types": [], - "subnetpool_id": None, - "updated_at": "2016-10-10T14:35:47Z" - } - ] - } - - FAKE_BULK_SUBNETS = copy.deepcopy(FAKE_SUBNETS) - - FAKE_SUBNET_ID = "54d6f61d-db07-451c-9ab3-b9609b6b6f0b" - - FAKE_NETWORK_ID = "d32019d3-bc6e-4319-9c1d-6722fc136a22" - - def setUp(self): - super(TestSubnetsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.subnets_client = subnets_client.SubnetsClient( - fake_auth, 'compute', 'regionOne') - - def _test_create_subnet(self, bytes_body=False): - self.check_service_client_function( - self.subnets_client.create_subnet, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SUBNET, - bytes_body, - 201, - network_id=self.FAKE_NETWORK_ID, - ip_version=4, - cidr="192.168.199.0/24") - - def _test_update_subnet(self, bytes_body=False): - self.check_service_client_function( - self.subnets_client.update_subnet, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATED_SUBNET, - bytes_body, - 200, - subnet_id=self.FAKE_SUBNET_ID, - name="fake_updated_subnet_name") - - def _test_show_subnet(self, bytes_body=False): - self.check_service_client_function( - self.subnets_client.show_subnet, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SUBNET, - bytes_body, - 200, - subnet_id=self.FAKE_SUBNET_ID) - - def _test_list_subnets(self, bytes_body=False): - self.check_service_client_function( - self.subnets_client.list_subnets, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SUBNETS, - bytes_body, - 200) - - def _test_create_bulk_subnets(self, bytes_body=False): - kwargs = { - "subnets": [ - { - "cidr": "192.168.199.0/24", - "ip_version": 4, - "network_id": "e6031bc2-901a-4c66-82da-f4c32ed89406" - }, - { - "cidr": "10.56.4.0/22", - "ip_version": 4, - "network_id": "64239a54-dcc4-4b39-920b-b37c2144effa" - } - ] - } - self.check_service_client_function( - self.subnets_client.create_bulk_subnets, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SUBNETS, - bytes_body, - 201, - **kwargs) - - def test_create_subnet_with_str_body(self): - self._test_create_subnet() - - def test_create_subnet_with_bytes_body(self): - self._test_create_subnet(bytes_body=True) - - def test_update_subnet_with_str_body(self): - self._test_update_subnet() - - def test_update_subnet_with_bytes_body(self): - self._test_update_subnet(bytes_body=True) - - def test_show_subnet_with_str_body(self): - self._test_show_subnet() - - def test_show_subnet_with_bytes_body(self): - self._test_show_subnet(bytes_body=True) - - def test_list_subnets_with_str_body(self): - self._test_list_subnets() - - def test_list_subnets_with_bytes_body(self): - self._test_list_subnets(bytes_body=True) - - def test_delete_subnet(self): - self.check_service_client_function( - self.subnets_client.delete_subnet, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - subnet_id=self.FAKE_SUBNET_ID) - - def test_create_bulk_subnets_with_str_body(self): - self._test_create_bulk_subnets() - - def test_create_bulk_subnets_with_bytes_body(self): - self._test_create_bulk_subnets(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_tags_client.py b/tempest/tests/lib/services/network/test_tags_client.py deleted file mode 100644 index dbe50a045..000000000 --- a/tempest/tests/lib/services/network/test_tags_client.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.lib.services.network import tags_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTagsClient(base.BaseServiceTest): - - FAKE_TAGS = { - "tags": [ - "red", - "blue" - ] - } - - FAKE_RESOURCE_TYPE = 'network' - - FAKE_RESOURCE_ID = '7a8f904b-c1ed-4446-a87d-60440c02934b' - - def setUp(self): - super(TestTagsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = tags_client.TagsClient( - fake_auth, 'network', 'regionOne') - - def _test_update_all_tags(self, bytes_body=False): - self.check_service_client_function( - self.client.update_all_tags, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_TAGS, - bytes_body, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID, - tags=self.FAKE_TAGS) - - def _test_check_tag_existence(self, bytes_body=False): - self.check_service_client_function( - self.client.check_tag_existence, - 'tempest.lib.common.rest_client.RestClient.get', - {}, - bytes_body, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID, - tag=self.FAKE_TAGS['tags'][0], - status=204) - - def _test_create_tag(self, bytes_body=False): - self.check_service_client_function( - self.client.create_tag, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID, - tag=self.FAKE_TAGS['tags'][0], - status=201) - - def _test_list_tags(self, bytes_body=False): - self.check_service_client_function( - self.client.list_tags, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_TAGS, - bytes_body, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID) - - def test_update_all_tags_with_str_body(self): - self._test_update_all_tags() - - def test_update_all_tags_with_bytes_body(self): - self._test_update_all_tags(bytes_body=True) - - def test_delete_all_tags(self): - self.check_service_client_function( - self.client.delete_all_tags, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID, - status=204) - - def test_check_tag_existence_with_str_body(self): - self._test_check_tag_existence() - - def test_check_tag_existence_with_bytes_body(self): - self._test_check_tag_existence(bytes_body=True) - - def test_create_tag_with_str_body(self): - self._test_create_tag() - - def test_create_tag_with_bytes_body(self): - self._test_create_tag(bytes_body=True) - - def test_list_tags_with_str_body(self): - self._test_list_tags() - - def test_list_tags_with_bytes_body(self): - self._test_list_tags(bytes_body=True) - - def test_delete_tag(self): - self.check_service_client_function( - self.client.delete_tag, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID, - tag=self.FAKE_TAGS['tags'][0], - status=204) diff --git a/tempest/tests/lib/services/network/test_versions_client.py b/tempest/tests/lib/services/network/test_versions_client.py deleted file mode 100644 index 026dc6de2..000000000 --- a/tempest/tests/lib/services/network/test_versions_client.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2016 VMware, Inc. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.services.network import versions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNetworkVersionsClient(base.BaseServiceTest): - - FAKE_INIT_VERSION = { - "version": { - "id": "v2.0", - "links": [ - { - "href": "http://openstack.example.com/v2.0/", - "rel": "self" - }, - { - "href": "http://docs.openstack.org/", - "rel": "describedby", - "type": "text/html" - } - ], - "status": "CURRENT" - } - } - - FAKE_VERSIONS_INFO = { - "versions": [FAKE_INIT_VERSION["version"]] - } - - FAKE_VERSION_INFO = copy.deepcopy(FAKE_INIT_VERSION) - - FAKE_VERSION_INFO["version"]["media-types"] = [ - { - "base": "application/json", - "type": "application/vnd.openstack.network+json;version=2.0" - } - ] - - def setUp(self): - super(TestNetworkVersionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.versions_client = ( - versions_client.NetworkVersionsClient - (fake_auth, 'compute', 'regionOne')) - - def _test_versions_client(self, bytes_body=False): - self.check_service_client_function( - self.versions_client.list_versions, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSIONS_INFO, - bytes_body, - 200) - - def test_list_versions_client_with_str_body(self): - self._test_versions_client() - - def test_list_versions_client_with_bytes_body(self): - self._test_versions_client(bytes_body=True) diff --git a/tempest/tests/lib/services/test_clients.py b/tempest/tests/lib/services/test_clients.py deleted file mode 100644 index a837199c7..000000000 --- a/tempest/tests/lib/services/test_clients.py +++ /dev/null @@ -1,370 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -import types - -import fixtures -import mock -import testtools - -from tempest.lib import auth -from tempest.lib import exceptions -from tempest.lib.services import clients -from tempest.tests import base -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_credentials - - -has_attribute = testtools.matchers.MatchesPredicateWithParams( - lambda x, y: hasattr(x, y), '{0} does not have an attribute {1}') - - -class TestClientsFactory(base.TestCase): - - def setUp(self): - super(TestClientsFactory, self).setUp() - self.classes = [] - - def _setup_fake_module(self, class_names=None, extra_dict=None): - class_names = class_names or [] - fake_module = types.ModuleType('fake_service_client') - _dict = {} - # Add fake classes to the fake module - for name in class_names: - _dict[name] = type(name, (object,), {}) - # Store it for assertions - self.classes.append(_dict[name]) - if extra_dict: - _dict[extra_dict] = extra_dict - fake_module.__dict__.update(_dict) - fixture_importlib = self.useFixture(fixtures.MockPatch( - 'importlib.import_module', return_value=fake_module)) - return fixture_importlib.mock - - def test___init___one_class(self): - fake_partial = 'fake_partial' - partial_mock = self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory._get_partial_class', - return_value=fake_partial)).mock - class_names = ['FakeServiceClient1'] - mock_importlib = self._setup_fake_module(class_names=class_names) - auth_provider = fake_auth_provider.FakeAuthProvider() - params = {'k1': 'v1', 'k2': 'v2'} - factory = clients.ClientsFactory('fake_path', class_names, - auth_provider, **params) - # Assert module has been imported - mock_importlib.assert_called_once_with('fake_path') - # All attributes have been created - for client in class_names: - self.assertThat(factory, has_attribute(client)) - # Partial have been invoked correctly - partial_mock.assert_called_once_with( - self.classes[0], auth_provider, params) - # Get the clients - for name in class_names: - self.assertEqual(fake_partial, getattr(factory, name)) - - def test___init___two_classes(self): - fake_partial = 'fake_partial' - partial_mock = self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory._get_partial_class', - return_value=fake_partial)).mock - class_names = ['FakeServiceClient1', 'FakeServiceClient2'] - mock_importlib = self._setup_fake_module(class_names=class_names) - auth_provider = fake_auth_provider.FakeAuthProvider() - params = {'k1': 'v1', 'k2': 'v2'} - factory = clients.ClientsFactory('fake_path', class_names, - auth_provider, **params) - # Assert module has been imported - mock_importlib.assert_called_once_with('fake_path') - # All attributes have been created - for client in class_names: - self.assertThat(factory, has_attribute(client)) - # Partial have been invoked the right number of times - partial_mock.call_count = len(class_names) - # Get the clients - for name in class_names: - self.assertEqual(fake_partial, getattr(factory, name)) - - def test___init___no_module(self): - auth_provider = fake_auth_provider.FakeAuthProvider() - class_names = ['FakeServiceClient1', 'FakeServiceClient2'] - self.assertRaises(ImportError, clients.ClientsFactory, - 'fake_module', class_names, auth_provider) - - def test___init___not_a_class(self): - class_names = ['FakeServiceClient1', 'FakeServiceClient2'] - extended_class_names = class_names + ['not_really_a_class'] - self._setup_fake_module( - class_names=class_names, extra_dict='not_really_a_class') - auth_provider = fake_auth_provider.FakeAuthProvider() - expected_msg = '.*not_really_a_class.*str.*' - with testtools.ExpectedException(TypeError, expected_msg): - clients.ClientsFactory('fake_module', extended_class_names, - auth_provider) - - def test___init___class_not_found(self): - class_names = ['FakeServiceClient1', 'FakeServiceClient2'] - extended_class_names = class_names + ['not_really_a_class'] - self._setup_fake_module(class_names=class_names) - auth_provider = fake_auth_provider.FakeAuthProvider() - expected_msg = '.*not_really_a_class.*fake_service_client.*' - with testtools.ExpectedException(AttributeError, expected_msg): - clients.ClientsFactory('fake_module', extended_class_names, - auth_provider) - - def test__get_partial_class_no_later_kwargs(self): - expected_fake_client = 'not_really_a_client' - self._setup_fake_module(class_names=[]) - auth_provider = fake_auth_provider.FakeAuthProvider() - params = {'k1': 'v1', 'k2': 'v2'} - factory = clients.ClientsFactory( - 'fake_path', [], auth_provider, **params) - klass_mock = mock.Mock(return_value=expected_fake_client) - partial = factory._get_partial_class(klass_mock, auth_provider, params) - # Class has not be initialised yet - klass_mock.assert_not_called() - # Use partial and assert on parameters - client = partial() - self.assertEqual(expected_fake_client, client) - klass_mock.assert_called_once_with(auth_provider=auth_provider, - **params) - - def test__get_partial_class_later_kwargs(self): - expected_fake_client = 'not_really_a_client' - self._setup_fake_module(class_names=[]) - auth_provider = fake_auth_provider.FakeAuthProvider() - params = {'k1': 'v1', 'k2': 'v2'} - later_params = {'k2': 'v4', 'k3': 'v3'} - factory = clients.ClientsFactory( - 'fake_path', [], auth_provider, **params) - klass_mock = mock.Mock(return_value=expected_fake_client) - partial = factory._get_partial_class(klass_mock, auth_provider, params) - # Class has not be initialised yet - klass_mock.assert_not_called() - # Use partial and assert on parameters - client = partial(**later_params) - params.update(later_params) - self.assertEqual(expected_fake_client, client) - klass_mock.assert_called_once_with(auth_provider=auth_provider, - **params) - - def test__get_partial_class_with_alias(self): - expected_fake_client = 'not_really_a_client' - client_alias = 'fake_client' - self._setup_fake_module(class_names=[]) - auth_provider = fake_auth_provider.FakeAuthProvider() - params = {'k1': 'v1', 'k2': 'v2'} - later_params = {'k2': 'v4', 'k3': 'v3'} - factory = clients.ClientsFactory( - 'fake_path', [], auth_provider, **params) - klass_mock = mock.Mock(return_value=expected_fake_client) - partial = factory._get_partial_class(klass_mock, auth_provider, params) - # Class has not be initialised yet - klass_mock.assert_not_called() - # Use partial and assert on parameters - client = partial(alias=client_alias, **later_params) - params.update(later_params) - self.assertEqual(expected_fake_client, client) - klass_mock.assert_called_once_with(auth_provider=auth_provider, - **params) - self.assertThat(factory, has_attribute(client_alias)) - self.assertEqual(expected_fake_client, getattr(factory, client_alias)) - - -class TestServiceClients(base.TestCase): - - def setUp(self): - super(TestServiceClients, self).setUp() - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.tempest_modules', return_value={})) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients._tempest_internal_modules', - return_value=set(['fake_service1']))) - - def test___init___creds_v2_uri(self): - # Verify that no API request is made, since no mock - # is required to run the test successfully - creds = fake_credentials.FakeKeystoneV2Credentials() - uri = 'fake_uri' - _manager = clients.ServiceClients(creds, identity_uri=uri) - self.assertIsInstance(_manager.auth_provider, - auth.KeystoneV2AuthProvider) - - def test___init___creds_v3_uri(self): - # Verify that no API request is made, since no mock - # is required to run the test successfully - creds = fake_credentials.FakeKeystoneV3Credentials() - uri = 'fake_uri' - _manager = clients.ServiceClients(creds, identity_uri=uri) - self.assertIsInstance(_manager.auth_provider, - auth.KeystoneV3AuthProvider) - - def test___init___base_creds_uri(self): - creds = fake_credentials.FakeCredentials() - uri = 'fake_uri' - with testtools.ExpectedException(exceptions.InvalidCredentials): - clients.ServiceClients(creds, identity_uri=uri) - - def test___init___invalid_creds_uri(self): - creds = fake_credentials.FakeKeystoneV2Credentials() - delattr(creds, 'username') - uri = 'fake_uri' - with testtools.ExpectedException(exceptions.InvalidCredentials): - clients.ServiceClients(creds, identity_uri=uri) - - def test___init___creds_uri_none(self): - creds = fake_credentials.FakeKeystoneV2Credentials() - msg = ("Invalid Credentials\nDetails: ServiceClients requires a " - "non-empty") - with testtools.ExpectedException(exceptions.InvalidCredentials, - value_re=msg): - clients.ServiceClients(creds, None) - - def test___init___creds_uri_params(self): - creds = fake_credentials.FakeKeystoneV2Credentials() - expeted_params = {'fake_param1': 'fake_value1', - 'fake_param2': 'fake_value2'} - params = {'fake_service1': expeted_params} - uri = 'fake_uri' - _manager = clients.ServiceClients(creds, identity_uri=uri, - client_parameters=params) - self.assertIn('fake_service1', _manager.parameters) - for _key in expeted_params: - self.assertIn(_key, _manager.parameters['fake_service1'].keys()) - self.assertEqual(expeted_params[_key], - _manager.parameters['fake_service1'].get(_key)) - - def test___init___creds_uri_params_unknown_services(self): - creds = fake_credentials.FakeKeystoneV2Credentials() - fake_params = {'fake_param1': 'fake_value1'} - params = {'unknown_service1': fake_params, - 'unknown_service2': fake_params} - uri = 'fake_uri' - msg = "(?=.*{0})(?=.*{1})".format(*list(params.keys())) - with testtools.ExpectedException( - exceptions.UnknownServiceClient, value_re=msg): - clients.ServiceClients(creds, identity_uri=uri, - client_parameters=params) - - def _get_manager(self, init_region='fake_region'): - # Get a manager to invoke _setup_parameters on - creds = fake_credentials.FakeKeystoneV2Credentials() - return clients.ServiceClients(creds, identity_uri='fake_uri', - region=init_region) - - def test__setup_parameters_none_no_region(self): - kwargs = {} - _manager = self._get_manager(init_region=None) - _params = _manager._setup_parameters(kwargs) - self.assertNotIn('region', _params) - - def test__setup_parameters_none(self): - kwargs = {} - _manager = self._get_manager() - _params = _manager._setup_parameters(kwargs) - self.assertIn('region', _params) - self.assertEqual('fake_region', _params['region']) - - def test__setup_parameters_all(self): - expected_params = {'region': 'fake_region1', - 'catalog_type': 'fake_service2_mod', - 'fake_param1': 'fake_value1', - 'fake_param2': 'fake_value2'} - _manager = self._get_manager() - _params = _manager._setup_parameters(expected_params) - for _key in _params.keys(): - self.assertEqual(expected_params[_key], - _params[_key]) - - def test_register_service_client_module(self): - expected_params = {'fake_param1': 'fake_value1', - 'fake_param2': 'fake_value2'} - _manager = self._get_manager(init_region='fake_region_default') - # Mock after the _manager is setup to preserve the call count - factory_mock = self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory')).mock - _manager.register_service_client_module( - name='fake_module', - service_version='fake_service', - module_path='fake.path.to.module', - client_names=[], - **expected_params) - self.assertThat(_manager, has_attribute('fake_module')) - # Assert called once, without check for exact parameters - self.assertTrue(factory_mock.called) - self.assertEqual(1, factory_mock.call_count) - # Assert expected params are in with their values - actual_kwargs = factory_mock.call_args[1] - self.assertIn('region', actual_kwargs) - self.assertEqual('fake_region_default', actual_kwargs['region']) - for param in expected_params: - self.assertIn(param, actual_kwargs) - self.assertEqual(expected_params[param], actual_kwargs[param]) - # Assert the new service is registered - self.assertIn('fake_service', _manager._registered_services) - - def test_register_service_client_module_override_default(self): - new_region = 'new_region' - expected_params = {'fake_param1': 'fake_value1', - 'fake_param2': 'fake_value2', - 'region': new_region} - _manager = self._get_manager(init_region='fake_region_default') - # Mock after the _manager is setup to preserve the call count - factory_mock = self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory')).mock - _manager.register_service_client_module( - name='fake_module', - service_version='fake_service', - module_path='fake.path.to.module', - client_names=[], - **expected_params) - self.assertThat(_manager, has_attribute('fake_module')) - # Assert called once, without check for exact parameters - self.assertTrue(factory_mock.called) - self.assertEqual(1, factory_mock.call_count) - # Assert expected params are in with their values - actual_kwargs = factory_mock.call_args[1] - self.assertIn('region', actual_kwargs) - self.assertEqual(new_region, actual_kwargs['region']) - for param in expected_params: - self.assertIn(param, actual_kwargs) - self.assertEqual(expected_params[param], actual_kwargs[param]) - # Assert the new service is registered - self.assertIn('fake_service', _manager._registered_services) - - def test_register_service_client_module_duplicate_name(self): - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory')).mock - _manager = self._get_manager() - name_owner = 'this_is_a_string' - setattr(_manager, 'fake_module', name_owner) - expected_error = '.*' + name_owner - with testtools.ExpectedException( - exceptions.ServiceClientRegistrationException, expected_error): - _manager.register_service_client_module( - name='fake_module', module_path='fake.path.to.module', - service_version='fake_service', client_names=[]) - - def test_register_service_client_module_duplicate_service(self): - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory')).mock - _manager = self._get_manager() - duplicate_service = 'fake_service1' - expected_error = '.*' + duplicate_service - with testtools.ExpectedException( - exceptions.ServiceClientRegistrationException, expected_error): - _manager.register_service_client_module( - name='fake_module', module_path='fake.path.to.module', - service_version=duplicate_service, client_names=[]) diff --git a/tempest/tests/lib/services/volume/__init__.py b/tempest/tests/lib/services/volume/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/volume/v1/__init__.py b/tempest/tests/lib/services/volume/v1/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/volume/v1/test_encryption_types_client.py b/tempest/tests/lib/services/volume/v1/test_encryption_types_client.py deleted file mode 100644 index 585904e91..000000000 --- a/tempest/tests/lib/services/volume/v1/test_encryption_types_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v1 import encryption_types_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEncryptionTypesClient(base.BaseServiceTest): - FAKE_CREATE_ENCRYPTION_TYPE = { - "encryption": { - "id": "cbc36478b0bd8e67e89", - "name": "FakeEncryptionType", - "type": "fakeType", - "provider": "LuksEncryptor", - "cipher": "aes-xts-plain64", - "key_size": "512", - "control_location": "front-end" - } - } - - FAKE_INFO_ENCRYPTION_TYPE = { - "encryption": { - "name": "FakeEncryptionType", - "type": "fakeType", - "description": "test_description", - "volume_type": "fakeType", - "provider": "LuksEncryptor", - "cipher": "aes-xts-plain64", - "key_size": "512", - "control_location": "front-end" - } - } - - def setUp(self): - super(TestEncryptionTypesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = encryption_types_client.EncryptionTypesClient(fake_auth, - 'volume', - 'regionOne' - ) - - def _test_create_encryption(self, bytes_body=False): - self.check_service_client_function( - self.client.create_encryption_type, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ENCRYPTION_TYPE, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def _test_show_encryption_type(self, bytes_body=False): - self.check_service_client_function( - self.client.show_encryption_type, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_ENCRYPTION_TYPE, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def test_create_encryption_type_with_str_body(self): - self._test_create_encryption() - - def test_create_encryption_type_with_bytes_body(self): - self._test_create_encryption(bytes_body=True) - - def test_show_encryption_type_with_str_body(self): - self._test_show_encryption_type() - - def test_show_encryption_type_with_bytes_body(self): - self._test_show_encryption_type(bytes_body=True) - - def test_delete_encryption_type(self): - self.check_service_client_function( - self.client.delete_encryption_type, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - volume_type_id="cbc36478b0bd8e67e89", - status=202) diff --git a/tempest/tests/lib/services/volume/v1/test_quotas_client.py b/tempest/tests/lib/services/volume/v1/test_quotas_client.py deleted file mode 100644 index f9e76afe6..000000000 --- a/tempest/tests/lib/services/volume/v1/test_quotas_client.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v1 import quotas_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotasClient(base.BaseServiceTest): - FAKE_QUOTAS = { - "quota_set": { - "cores": 20, - "fixed_ips": -1, - "floating_ips": 10, - "id": "fake_tenant", - "injected_file_content_bytes": 10240, - "injected_file_path_bytes": 255, - "injected_files": 5, - "instances": 10, - "key_pairs": 100, - "metadata_items": 128, - "ram": 51200, - "security_group_rules": 20, - "security_groups": 10 - } - } - - FAKE_UPDATE_QUOTAS_REQUEST = { - "quota_set": { - "security_groups": 45 - } - } - - def setUp(self): - super(TestQuotasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = quotas_client.QuotasClient(fake_auth, - 'volume', - 'regionOne') - - def _test_show_default_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_QUOTAS, - bytes_body, tenant_id="fake_tenant") - - def _test_show_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.show_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_QUOTAS, - bytes_body, tenant_id="fake_tenant") - - def _test_update_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.update_quota_set, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_QUOTAS_REQUEST, - bytes_body, tenant_id="fake_tenant") - - def test_show_default_quota_set_with_str_body(self): - self._test_show_default_quota_set() - - def test_show_default_quota_set_with_bytes_body(self): - self._test_show_default_quota_set(bytes_body=True) - - def test_show_quota_set_with_str_body(self): - self._test_show_quota_set() - - def test_show_quota_set_with_bytes_body(self): - self._test_show_quota_set(bytes_body=True) - - def test_update_quota_set_with_str_body(self): - self._test_update_quota_set() - - def test_update_quota_set_with_bytes_body(self): - self._test_update_quota_set(bytes_body=True) - - def test_delete_quota_set(self): - self.check_service_client_function( - self.client.delete_quota_set, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - tenant_id="fake_tenant") diff --git a/tempest/tests/lib/services/volume/v1/test_snapshots_client.py b/tempest/tests/lib/services/volume/v1/test_snapshots_client.py deleted file mode 100644 index 49191e323..000000000 --- a/tempest/tests/lib/services/volume/v1/test_snapshots_client.py +++ /dev/null @@ -1,200 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v1 import snapshots_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSnapshotsClient(base.BaseServiceTest): - FAKE_CREATE_SNAPSHOT = { - "snapshot": { - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "force": True - } - } - - FAKE_UPDATE_SNAPSHOT_REQUEST = { - "metadata": { - "key": "v1" - } - } - - FAKE_INFO_SNAPSHOT = { - "snapshot": { - "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5", - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "status": "available", - "size": 30, - "created_at": "2012-02-29T03:50:07Z" - } - } - - FAKE_LIST_SNAPSHOTS = { - "snapshots": [ - { - "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5", - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "status": "available", - "size": 30, - "created_at": "2012-02-29T03:50:07Z", - "metadata": { - "contents": "junk" - } - }, - { - "id": "e479997c-650b-40a4-9dfe-77655818b0d2", - "display_name": "snap-002", - "display_description": "Weekly backup", - "volume_id": "76b8950a-8594-4e5b-8dce-0dfa9c696358", - "status": "available", - "size": 25, - "created_at": "2012-03-19T01:52:47Z", - "metadata": {} - } - ] - } - - def setUp(self): - super(TestSnapshotsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = snapshots_client.SnapshotsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_create_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.create_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SNAPSHOT, - bytes_body) - - def _test_show_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_SNAPSHOT, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_list_snapshots(self, bytes_body=False): - self.check_service_client_function( - self.client.list_snapshots, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_SNAPSHOTS, - bytes_body, - detail=True) - - def _test_create_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.create_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_INFO_SNAPSHOT, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5", - metadata={"key": "v1"}) - - def _test_update_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_show_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_update_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, snapshot_id="cbc36478b0bd8e67e89") - - def _test_update_snapshot_metadata_item(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot_metadata_item, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_INFO_SNAPSHOT, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def test_create_snapshot_with_str_body(self): - self._test_create_snapshot() - - def test_create_snapshot_with_bytes_body(self): - self._test_create_snapshot(bytes_body=True) - - def test_show_snapshot_with_str_body(self): - self._test_show_snapshot() - - def test_show_snapshot_with_bytes_body(self): - self._test_show_snapshot(bytes_body=True) - - def test_list_snapshots_with_str_body(self): - self._test_list_snapshots() - - def test_list_snapshots_with_bytes_body(self): - self._test_list_snapshots(bytes_body=True) - - def test_create_snapshot_metadata_with_str_body(self): - self._test_create_snapshot_metadata() - - def test_create_snapshot_metadata_with_bytes_body(self): - self._test_create_snapshot_metadata(bytes_body=True) - - def test_update_snapshot_with_str_body(self): - self._test_update_snapshot() - - def test_update_snapshot_with_bytes_body(self): - self._test_update_snapshot(bytes_body=True) - - def test_show_snapshot_metadata_with_str_body(self): - self._test_show_snapshot_metadata() - - def test_show_snapshot_metadata_with_bytes_body(self): - self._test_show_snapshot_metadata(bytes_body=True) - - def test_update_snapshot_metadata_with_str_body(self): - self._test_update_snapshot_metadata() - - def test_update_snapshot_metadata_with_bytes_body(self): - self._test_update_snapshot_metadata(bytes_body=True) - - def test_force_delete_snapshot(self): - self.check_service_client_function( - self.client.force_delete_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c", - status=202) - - def test_delete_snapshot(self): - self.check_service_client_function( - self.client.delete_snapshot, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c", - status=202) diff --git a/tempest/tests/lib/services/volume/v2/__init__.py b/tempest/tests/lib/services/volume/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/volume/v2/test_backups_client.py b/tempest/tests/lib/services/volume/v2/test_backups_client.py deleted file mode 100644 index 14e5fb0be..000000000 --- a/tempest/tests/lib/services/volume/v2/test_backups_client.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v2 import backups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestBackupsClient(base.BaseServiceTest): - - FAKE_BACKUP_LIST = { - "backups": [ - { - "id": "2ef47aee-8844-490c-804d-2a8efe561c65", - "links": [ - { - "href": "fake-url-1", - "rel": "self" - }, - { - "href": "fake-url-2", - "rel": "bookmark" - } - ], - "name": "backup001" - } - ] - } - - FAKE_BACKUP_LIST_WITH_DETAIL = { - "backups": [ - { - "availability_zone": "az1", - "container": "volumebackups", - "created_at": "2013-04-02T10:35:27.000000", - "description": None, - "fail_reason": None, - "id": "2ef47aee-8844-490c-804d-2a8efe561c65", - "links": [ - { - "href": "fake-url-1", - "rel": "self" - }, - { - "href": "fake-url-2", - "rel": "bookmark" - } - ], - "name": "backup001", - "object_count": 22, - "size": 1, - "status": "available", - "volume_id": "e5185058-943a-4cb4-96d9-72c184c337d6", - "is_incremental": True, - "has_dependent_backups": False - } - ] - } - - def setUp(self): - super(TestBackupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = backups_client.BackupsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_list_backups(self, detail=False, mock_args='backups', - bytes_body=False, **params): - if detail: - resp_body = self.FAKE_BACKUP_LIST_WITH_DETAIL - else: - resp_body = self.FAKE_BACKUP_LIST - self.check_service_client_function( - self.client.list_backups, - 'tempest.lib.common.rest_client.RestClient.get', - resp_body, - to_utf=bytes_body, - mock_args=[mock_args], - detail=detail, - **params) - - def test_list_backups_with_str_body(self): - self._test_list_backups() - - def test_list_backups_with_bytes_body(self): - self._test_list_backups(bytes_body=True) - - def test_list_backups_with_detail_with_str_body(self): - mock_args = "backups/detail" - self._test_list_backups(detail=True, mock_args=mock_args) - - def test_list_backups_with_detail_with_bytes_body(self): - mock_args = "backups/detail" - self._test_list_backups(detail=True, mock_args=mock_args, - bytes_body=True) - - def test_list_backups_with_params(self): - # Run the test separately for each param, to avoid assertion error - # resulting from randomized params order. - mock_args = 'backups?sort_key=name' - self._test_list_backups(mock_args=mock_args, sort_key='name') - - mock_args = 'backups/detail?limit=10' - self._test_list_backups(detail=True, mock_args=mock_args, - bytes_body=True, limit=10) diff --git a/tempest/tests/lib/services/volume/v2/test_capabilities_client.py b/tempest/tests/lib/services/volume/v2/test_capabilities_client.py deleted file mode 100644 index 3d3f1e119..000000000 --- a/tempest/tests/lib/services/volume/v2/test_capabilities_client.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v2 import capabilities_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestCapabilitiesClient(base.BaseServiceTest): - - FAKE_BACKEND_CAPABILITIES = { - "namespace": "OS::Storage::Capabilities::fake", - "vendor_name": "OpenStack", - "volume_backend_name": "lvmdriver-1", - "pool_name": "pool", - "driver_version": "2.0.0", - "storage_protocol": "iSCSI", - "display_name": "Capabilities of Cinder LVM driver", - "description": ( - "These are volume type options provided by Cinder LVM driver."), - "visibility": "public", - "replication_targets": [], - "properties": { - "compression": { - "title": "Compression", - "description": "Enables compression.", - "type": "boolean" - }, - "qos": { - "title": "QoS", - "description": "Enables QoS.", - "type": "boolean" - }, - "replication": { - "title": "Replication", - "description": "Enables replication.", - "type": "boolean" - }, - "thin_provisioning": { - "title": "Thin Provisioning", - "description": "Sets thin provisioning.", - "type": "boolean" - } - } - } - - def setUp(self): - super(TestCapabilitiesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = capabilities_client.CapabilitiesClient( - fake_auth, 'volume', 'regionOne') - - def _test_show_backend_capabilities(self, bytes_body=False): - self.check_service_client_function( - self.client.show_backend_capabilities, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_BACKEND_CAPABILITIES, - bytes_body, - host='lvmdriver-1') - - def test_show_backend_capabilities_with_str_body(self): - self._test_show_backend_capabilities() - - def test_show_backend_capabilities_with_bytes_body(self): - self._test_show_backend_capabilities(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py b/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py deleted file mode 100644 index d0290911e..000000000 --- a/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v2 import encryption_types_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEncryptionTypesClient(base.BaseServiceTest): - FAKE_CREATE_ENCRYPTION_TYPE = { - "encryption": { - "id": "cbc36478b0bd8e67e89", - "name": "FakeEncryptionType", - "type": "fakeType", - "provider": "LuksEncryptor", - "cipher": "aes-xts-plain64", - "key_size": "512", - "control_location": "front-end" - } - } - - FAKE_INFO_ENCRYPTION_TYPE = { - "encryption": { - "name": "FakeEncryptionType", - "type": "fakeType", - "description": "test_description", - "volume_type": "fakeType", - "provider": "LuksEncryptor", - "cipher": "aes-xts-plain64", - "key_size": "512", - "control_location": "front-end" - } - } - - def setUp(self): - super(TestEncryptionTypesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = encryption_types_client.EncryptionTypesClient(fake_auth, - 'volume', - 'regionOne' - ) - - def _test_create_encryption(self, bytes_body=False): - self.check_service_client_function( - self.client.create_encryption_type, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ENCRYPTION_TYPE, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def _test_show_encryption_type(self, bytes_body=False): - self.check_service_client_function( - self.client.show_encryption_type, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_ENCRYPTION_TYPE, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def test_create_encryption_type_with_str_body(self): - self._test_create_encryption() - - def test_create_encryption_type_with_bytes_body(self): - self._test_create_encryption(bytes_body=True) - - def test_show_encryption_type_with_str_body(self): - self._test_show_encryption_type() - - def test_show_encryption_type_with_bytes_body(self): - self._test_show_encryption_type(bytes_body=True) - - def test_delete_encryption_type(self): - self.check_service_client_function( - self.client.delete_encryption_type, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - volume_type_id="cbc36478b0bd8e67e89", - status=202) diff --git a/tempest/tests/lib/services/volume/v2/test_extensions_client.py b/tempest/tests/lib/services/volume/v2/test_extensions_client.py deleted file mode 100644 index c0ee42125..000000000 --- a/tempest/tests/lib/services/volume/v2/test_extensions_client.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v2 import extensions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestExtensionsClient(base.BaseServiceTest): - - FAKE_EXTENSION_LIST = { - "extensions": [ - { - "updated": "2012-03-12T00:00:00+00:00", - "name": "QuotaClasses", - "links": [], - "namespace": "fake-namespace-1", - "alias": "os-quota-class-sets", - "description": "Quota classes management support." - }, - { - "updated": "2013-05-29T00:00:00+00:00", - "name": "VolumeTransfer", - "links": [], - "namespace": "fake-namespace-2", - "alias": "os-volume-transfer", - "description": "Volume transfer management support." - }, - { - "updated": "2014-02-10T00:00:00+00:00", - "name": "VolumeManage", - "links": [], - "namespace": "fake-namespace-3", - "alias": "os-volume-manage", - "description": "Manage existing backend storage by Cinder." - } - ] - } - - def setUp(self): - super(TestExtensionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = extensions_client.ExtensionsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_list_extensions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_extensions, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_EXTENSION_LIST, - bytes_body) - - def test_list_extensions_with_str_body(self): - self._test_list_extensions() - - def test_list_extensions_with_bytes_body(self): - self._test_list_extensions(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_hosts_client.py b/tempest/tests/lib/services/volume/v2/test_hosts_client.py deleted file mode 100644 index e10791014..000000000 --- a/tempest/tests/lib/services/volume/v2/test_hosts_client.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v2 import hosts_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotasClient(base.BaseServiceTest): - FAKE_LIST_HOSTS = { - "hosts": [ - { - "service-status": "available", - "service": "cinder-scheduler", - "zone": "nova", - "service-state": "enabled", - "host_name": "fake-host", - "last-update": "2017-04-12T04:26:03.000000" - }, - { - "service-status": "available", - "service": "cinder-volume", - "zone": "nova", - "service-state": "enabled", - "host_name": "fake-host@rbd", - "last-update": "2017-04-12T04:26:07.000000" - } - ] - } - - FAKE_HOST_INFO = { - "host": [ - { - "resource": { - "volume_count": "2", - "total_volume_gb": "2", - "total_snapshot_gb": "0", - "project": "(total)", - "host": "fake-host", - "snapshot_count": "0" - } - }, - { - "resource": { - "volume_count": "2", - "total_volume_gb": "2", - "total_snapshot_gb": "0", - "project": "f21a9c86d7114bf99c711f4874d80474", - "host": "fake-host", - "snapshot_count": "0" - } - } - ] - } - - def setUp(self): - super(TestQuotasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = hosts_client.HostsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_list_hosts(self, bytes_body=False): - self.check_service_client_function( - self.client.list_hosts, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_HOSTS, bytes_body) - - def _test_show_host(self, bytes_body=False): - self.check_service_client_function( - self.client.show_host, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_HOST_INFO, bytes_body, host_name='fake-host') - - def test_list_hosts_with_str_body(self): - self._test_list_hosts() - - def test_list_hosts_with_bytes_body(self): - self._test_list_hosts(bytes_body=True) - - def test_show_host_with_str_body(self): - self._test_show_host() - - def test_show_host_with_bytes_body(self): - self._test_show_host(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_limits_client.py b/tempest/tests/lib/services/volume/v2/test_limits_client.py deleted file mode 100644 index 202054c02..000000000 --- a/tempest/tests/lib/services/volume/v2/test_limits_client.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v2 import limits_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestLimitsClient(base.BaseServiceTest): - - FAKE_LIMIT_INFO = { - "limits": { - "rate": [], - "absolute": { - "totalSnapshotsUsed": 0, - "maxTotalBackups": 10, - "maxTotalVolumeGigabytes": 1000, - "maxTotalSnapshots": 10, - "maxTotalBackupGigabytes": 1000, - "totalBackupGigabytesUsed": 0, - "maxTotalVolumes": 10, - "totalVolumesUsed": 0, - "totalBackupsUsed": 0, - "totalGigabytesUsed": 0 - } - } - } - - def setUp(self): - super(TestLimitsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = limits_client.LimitsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_show_limits(self, bytes_body=False): - self.check_service_client_function( - self.client.show_limits, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIMIT_INFO, - bytes_body) - - def test_show_limits_with_str_body(self): - self._test_show_limits() - - def test_show_limits_with_bytes_body(self): - self._test_show_limits(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_quota_classes_client.py b/tempest/tests/lib/services/volume/v2/test_quota_classes_client.py deleted file mode 100644 index e715fccc9..000000000 --- a/tempest/tests/lib/services/volume/v2/test_quota_classes_client.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib.services.volume.v2 import quota_classes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotaClassesClient(base.BaseServiceTest): - - FAKE_QUOTA_CLASS_SET = { - "id": "test", - "gigabytes": 2000, - "volumes": 200, - "snapshots": 50, - "backups": 20, - "backup_gigabytes": 1500, - "per_volume_gigabytes": 500, - } - - def setUp(self): - super(TestQuotaClassesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = quota_classes_client.QuotaClassesClient( - fake_auth, 'volume', 'regionOne') - - def _test_show_quota_class_set(self, bytes_body=False): - fake_body = {'quota_class_set': self.FAKE_QUOTA_CLASS_SET} - self.check_service_client_function( - self.client.show_quota_class_set, - 'tempest.lib.common.rest_client.RestClient.get', - fake_body, - bytes_body, - quota_class_id="test") - - def _test_update_quota_class_set(self, bytes_body=False): - fake_quota_class_set = copy.deepcopy(self.FAKE_QUOTA_CLASS_SET) - fake_quota_class_set.pop("id") - fake_body = {'quota_class_set': fake_quota_class_set} - self.check_service_client_function( - self.client.update_quota_class_set, - 'tempest.lib.common.rest_client.RestClient.put', - fake_body, - bytes_body, - quota_class_id="test") - - def test_show_quota_class_set_with_str_body(self): - self._test_show_quota_class_set() - - def test_show_quota_class_set_with_bytes_body(self): - self._test_show_quota_class_set(bytes_body=True) - - def test_update_quota_class_set_with_str_boy(self): - self._test_update_quota_class_set() - - def test_update_quota_class_set_with_bytes_body(self): - self._test_update_quota_class_set(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_quotas_client.py b/tempest/tests/lib/services/volume/v2/test_quotas_client.py deleted file mode 100644 index 6384350d2..000000000 --- a/tempest/tests/lib/services/volume/v2/test_quotas_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v2 import quotas_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotasClient(base.BaseServiceTest): - FAKE_QUOTAS = { - "quota_set": { - "gigabytes": 5, - "snapshots": 10, - "volumes": 20 - } - } - - FAKE_UPDATE_QUOTAS_REQUEST = { - "quota_set": { - "security_groups": 45 - } - } - - def setUp(self): - super(TestQuotasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = quotas_client.QuotasClient(fake_auth, - 'volume', - 'regionOne') - - def _test_show_default_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_QUOTAS, - bytes_body, tenant_id="fake_tenant") - - def _test_show_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.show_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_QUOTAS, - bytes_body, tenant_id="fake_tenant") - - def _test_update_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.update_quota_set, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_QUOTAS_REQUEST, - bytes_body, tenant_id="fake_tenant") - - def test_show_default_quota_set_with_str_body(self): - self._test_show_default_quota_set() - - def test_show_default_quota_set_with_bytes_body(self): - self._test_show_default_quota_set(bytes_body=True) - - def test_show_quota_set_with_str_body(self): - self._test_show_quota_set() - - def test_show_quota_set_with_bytes_body(self): - self._test_show_quota_set(bytes_body=True) - - def test_update_quota_set_with_str_body(self): - self._test_update_quota_set() - - def test_update_quota_set_with_bytes_body(self): - self._test_update_quota_set(bytes_body=True) - - def test_delete_quota_set(self): - self.check_service_client_function( - self.client.delete_quota_set, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - tenant_id="fake_tenant") diff --git a/tempest/tests/lib/services/volume/v2/test_scheduler_stats_client.py b/tempest/tests/lib/services/volume/v2/test_scheduler_stats_client.py deleted file mode 100644 index 8a5f25fd0..000000000 --- a/tempest/tests/lib/services/volume/v2/test_scheduler_stats_client.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v2 import scheduler_stats_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSchedulerStatsClient(base.BaseServiceTest): - FAKE_POOLS_LIST = { - "pools": [ - { - "name": "pool1", - "capabilities": { - "updated": "2014-10-28T00:00:00-00:00", - "total_capacity": 1024, - "free_capacity": 100, - "volume_backend_name": "pool1", - "reserved_percentage": 0, - "driver_version": "1.0.0", - "storage_protocol": "iSCSI", - "QoS_support": False - } - }, - { - "name": "pool2", - "capabilities": { - "updated": "2014-10-28T00:00:00-00:00", - "total_capacity": 512, - "free_capacity": 200, - "volume_backend_name": "pool2", - "reserved_percentage": 0, - "driver_version": "1.0.2", - "storage_protocol": "iSER", - "QoS_support": True - } - } - ] - } - - def setUp(self): - super(TestSchedulerStatsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = scheduler_stats_client.SchedulerStatsClient( - fake_auth, 'volume', 'regionOne') - - def _test_list_pools(self, bytes_body=False, detail=False): - resp_body = [] - if detail: - resp_body = self.FAKE_POOLS_LIST - else: - resp_body = {'pools': [{'name': pool['name']} - for pool in self.FAKE_POOLS_LIST['pools']]} - self.check_service_client_function( - self.client.list_pools, - 'tempest.lib.common.rest_client.RestClient.get', - resp_body, - bytes_body, - detail=detail) - - def test_list_pools_with_str_body(self): - self._test_list_pools() - - def test_list_pools_with_str_body_and_detail(self): - self._test_list_pools(detail=True) - - def test_list_pools_with_bytes_body(self): - self._test_list_pools(bytes_body=True) - - def test_list_pools_with_bytes_body_and_detail(self): - self._test_list_pools(bytes_body=True, detail=True) diff --git a/tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py b/tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py deleted file mode 100644 index 3fe8970a8..000000000 --- a/tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock - -from oslo_serialization import jsonutils as json - -from tempest.lib.services.volume.v2 import snapshot_manage_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSnapshotManageClient(base.BaseServiceTest): - - SNAPSHOT_MANAGE_REQUEST = { - "snapshot": { - "description": "snapshot-manage-description", - "metadata": None, - "ref": { - "source-name": "_snapshot-22b71da0-94f9-4aca-ad45-7522b3fa96bb" - }, - "name": "snapshot-managed", - "volume_id": "7c064b34-1e4b-40bd-93ca-4ac5a973661b" - } - } - - SNAPSHOT_MANAGE_RESPONSE = { - "snapshot": { - "status": "creating", - "description": "snapshot-manage-description", - "updated_at": None, - "volume_id": "32bafcc8-7109-42cd-8342-70d8de2bedef", - "id": "8fd6eb9d-0a82-456d-b1ec-dea4ac7f1ee2", - "size": 1, - "name": "snapshot-managed", - "created_at": "2017-07-11T10:07:58.000000", - "metadata": {} - } - } - - def setUp(self): - super(TestSnapshotManageClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = snapshot_manage_client.SnapshotManageClient(fake_auth, - 'volume', - 'regionOne') - - def _test_manage_snapshot(self, bytes_body=False): - payload = json.dumps(self.SNAPSHOT_MANAGE_REQUEST, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(snapshot_manage_client.json, - 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.manage_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - self.SNAPSHOT_MANAGE_RESPONSE, - to_utf=bytes_body, - status=202, - mock_args=['os-snapshot-manage', payload], - **self.SNAPSHOT_MANAGE_REQUEST['snapshot']) - - def test_manage_snapshot_with_str_body(self): - self._test_manage_snapshot() - - def test_manage_snapshot_with_bytes_body(self): - self._test_manage_snapshot(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_snapshots_client.py b/tempest/tests/lib/services/volume/v2/test_snapshots_client.py deleted file mode 100644 index c9f57a0d7..000000000 --- a/tempest/tests/lib/services/volume/v2/test_snapshots_client.py +++ /dev/null @@ -1,222 +0,0 @@ -# Copyright 2016 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v2 import snapshots_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSnapshotsClient(base.BaseServiceTest): - FAKE_CREATE_SNAPSHOT = { - "snapshot": { - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "force": True - } - } - - FAKE_UPDATE_SNAPSHOT_REQUEST = { - "metadata": { - "key": "v1" - } - } - - FAKE_INFO_SNAPSHOT = { - "snapshot": { - "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5", - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "status": "available", - "size": 30, - "created_at": "2012-02-29T03:50:07Z" - } - } - - FAKE_LIST_SNAPSHOTS = { - "snapshots": [ - { - "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5", - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "status": "available", - "size": 30, - "created_at": "2012-02-29T03:50:07Z", - "metadata": { - "contents": "junk" - } - }, - { - "id": "e479997c-650b-40a4-9dfe-77655818b0d2", - "display_name": "snap-002", - "display_description": "Weekly backup", - "volume_id": "76b8950a-8594-4e5b-8dce-0dfa9c696358", - "status": "available", - "size": 25, - "created_at": "2012-03-19T01:52:47Z", - "metadata": {} - } - ] - } - - FAKE_SNAPSHOT_METADATA_ITEM = { - "meta": { - "key1": "value1" - } - } - - def setUp(self): - super(TestSnapshotsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = snapshots_client.SnapshotsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_create_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.create_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SNAPSHOT, - bytes_body, - status=202) - - def _test_show_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_SNAPSHOT, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_list_snapshots(self, bytes_body=False): - self.check_service_client_function( - self.client.list_snapshots, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_SNAPSHOTS, - bytes_body, - detail=True) - - def _test_create_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.create_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_INFO_SNAPSHOT, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5", - metadata={"key": "v1"}) - - def _test_update_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_show_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_update_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, snapshot_id="cbc36478b0bd8e67e89") - - def _test_update_snapshot_metadata_item(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot_metadata_item, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_INFO_SNAPSHOT, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def _test_show_snapshot_metadata_item(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot_metadata_item, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SNAPSHOT_METADATA_ITEM, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5", - id="key1") - - def test_create_snapshot_with_str_body(self): - self._test_create_snapshot() - - def test_create_snapshot_with_bytes_body(self): - self._test_create_snapshot(bytes_body=True) - - def test_show_snapshot_with_str_body(self): - self._test_show_snapshot() - - def test_show_snapshot_with_bytes_body(self): - self._test_show_snapshot(bytes_body=True) - - def test_list_snapshots_with_str_body(self): - self._test_list_snapshots() - - def test_list_snapshots_with_bytes_body(self): - self._test_list_snapshots(bytes_body=True) - - def test_create_snapshot_metadata_with_str_body(self): - self._test_create_snapshot_metadata() - - def test_create_snapshot_metadata_with_bytes_body(self): - self._test_create_snapshot_metadata(bytes_body=True) - - def test_update_snapshot_with_str_body(self): - self._test_update_snapshot() - - def test_update_snapshot_with_bytes_body(self): - self._test_update_snapshot(bytes_body=True) - - def test_show_snapshot_metadata_with_str_body(self): - self._test_show_snapshot_metadata() - - def test_show_snapshot_metadata_with_bytes_body(self): - self._test_show_snapshot_metadata(bytes_body=True) - - def test_update_snapshot_metadata_with_str_body(self): - self._test_update_snapshot_metadata() - - def test_update_snapshot_metadata_with_bytes_body(self): - self._test_update_snapshot_metadata(bytes_body=True) - - def test_show_snapshot_metadata_item_with_str_body(self): - self._test_show_snapshot_metadata_item() - - def test_show_snapshot_metadata_item_with_bytes_body(self): - self._test_show_snapshot_metadata_item(bytes_body=True) - - def test_force_delete_snapshot(self): - self.check_service_client_function( - self.client.force_delete_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c", - status=202) - - def test_delete_snapshot(self): - self.check_service_client_function( - self.client.delete_snapshot, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c", - status=202) diff --git a/tempest/tests/lib/services/volume/v2/test_transfers_client.py b/tempest/tests/lib/services/volume/v2/test_transfers_client.py deleted file mode 100644 index 84f499283..000000000 --- a/tempest/tests/lib/services/volume/v2/test_transfers_client.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -import mock -from oslo_serialization import jsonutils as json - -from tempest.lib.services.volume.v2 import transfers_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTransfersClient(base.BaseServiceTest): - - FAKE_VOLUME_TRANSFER_ID = "0e89cdd1-6249-421b-96d8-25fac0623d42" - - FAKE_VOLUME_TRANSFER_INFO = { - "transfer": { - "id": FAKE_VOLUME_TRANSFER_ID, - "name": "fake-volume-transfer", - "volume_id": "47bf04ef-1ea5-4c5f-a375-430a086d6747", - "created_at": "2017-04-18T09:10:03.000000", - "links": [ - { - "href": "fake-url-1", - "rel": "self" - }, - { - "href": "fake-url-2", - "rel": "bookmark" - } - ] - } - } - - def setUp(self): - super(TestTransfersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = transfers_client.TransfersClient(fake_auth, - 'volume', - 'regionOne') - - def _test_create_volume_transfer(self, bytes_body=False): - resp_body = copy.deepcopy(self.FAKE_VOLUME_TRANSFER_INFO) - resp_body['transfer'].update({"auth_key": "fake-auth-key"}) - kwargs = {"name": "fake-volume-transfer", - "volume_id": "47bf04ef-1ea5-4c5f-a375-430a086d6747"} - payload = json.dumps({"transfer": kwargs}, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(transfers_client.json, 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.create_volume_transfer, - 'tempest.lib.common.rest_client.RestClient.post', - resp_body, - to_utf=bytes_body, - status=202, - mock_args=['os-volume-transfer', payload], - **kwargs) - - def _test_accept_volume_transfer(self, bytes_body=False): - resp_body = copy.deepcopy(self.FAKE_VOLUME_TRANSFER_INFO) - resp_body['transfer'].pop('created_at') - kwargs = {"auth_key": "fake-auth-key"} - payload = json.dumps({"accept": kwargs}, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(transfers_client.json, 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.accept_volume_transfer, - 'tempest.lib.common.rest_client.RestClient.post', - resp_body, - to_utf=bytes_body, - status=202, - mock_args=['os-volume-transfer/%s/accept' % - self.FAKE_VOLUME_TRANSFER_ID, payload], - transfer_id=self.FAKE_VOLUME_TRANSFER_ID, - **kwargs) - - def _test_show_volume_transfer(self, bytes_body=False): - resp_body = self.FAKE_VOLUME_TRANSFER_INFO - self.check_service_client_function( - self.client.show_volume_transfer, - 'tempest.lib.common.rest_client.RestClient.get', - resp_body, - to_utf=bytes_body, - transfer_id="0e89cdd1-6249-421b-96d8-25fac0623d42") - - def _test_list_volume_transfers(self, detail=False, bytes_body=False): - resp_body = copy.deepcopy(self.FAKE_VOLUME_TRANSFER_INFO) - if not detail: - resp_body['transfer'].pop('created_at') - resp_body = {"transfers": [resp_body['transfer']]} - self.check_service_client_function( - self.client.list_volume_transfers, - 'tempest.lib.common.rest_client.RestClient.get', - resp_body, - to_utf=bytes_body, - detail=detail) - - def test_create_volume_transfer_with_str_body(self): - self._test_create_volume_transfer() - - def test_create_volume_transfer_with_bytes_body(self): - self._test_create_volume_transfer(bytes_body=True) - - def test_accept_volume_transfer_with_str_body(self): - self._test_accept_volume_transfer() - - def test_accept_volume_transfer_with_bytes_body(self): - self._test_accept_volume_transfer(bytes_body=True) - - def test_show_volume_transfer_with_str_body(self): - self._test_show_volume_transfer() - - def test_show_volume_transfer_with_bytes_body(self): - self._test_show_volume_transfer(bytes_body=True) - - def test_list_volume_transfers_with_str_body(self): - self._test_list_volume_transfers() - - def test_list_volume_transfers_with_bytes_body(self): - self._test_list_volume_transfers(bytes_body=True) - - def test_list_volume_transfers_with_detail_with_str_body(self): - self._test_list_volume_transfers(detail=True) - - def test_list_volume_transfers_with_detail_with_bytes_body(self): - self._test_list_volume_transfers(detail=True, bytes_body=True) - - def test_delete_volume_transfer(self): - self.check_service_client_function( - self.client.delete_volume_transfer, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=202, - transfer_id="0e89cdd1-6249-421b-96d8-25fac0623d42") diff --git a/tempest/tests/lib/services/volume/v2/test_volume_manage_client.py b/tempest/tests/lib/services/volume/v2/test_volume_manage_client.py deleted file mode 100644 index ea4a9f996..000000000 --- a/tempest/tests/lib/services/volume/v2/test_volume_manage_client.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock - -from oslo_serialization import jsonutils as json - -from tempest.lib.services.volume.v2 import volume_manage_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVolumeManageClient(base.BaseServiceTest): - - VOLUME_MANAGE_REQUEST = { - "volume": { - "host": "controller1@rbd#rbd", - "name": "volume-managed", - "availability_zone": "nova", - "bootable": False, - "metadata": None, - "ref": { - "source-name": "volume-2ce6ca46-e6c1-4fe5-8268-3a1c536fcbf3" - }, - "volume_type": None, - "description": "volume-manage-description" - } - } - - VOLUME_MANAGE_RESPONSE = { - "volume": { - "migration_status": None, - "attachments": [], - "links": [ - { - "href": "fake-url-1", - "rel": "self" - }, - { - "href": "fake-url-2", - "rel": "bookmark" - } - ], - "availability_zone": "nova", - "os-vol-host-attr:host": "controller1@rbd#rbd", - "encrypted": False, - "updated_at": None, - "replication_status": None, - "snapshot_id": None, - "id": "c07cd4a4-b52b-4511-a176-fbaa2011a227", - "size": 0, - "user_id": "142d8663efce464c89811c63e45bd82e", - "os-vol-tenant-attr:tenant_id": "f21a9c86d7114bf99c711f4874d80474", - "os-vol-mig-status-attr:migstat": None, - "metadata": {}, - "status": "creating", - "description": "volume-manage-description", - "multiattach": False, - "source_volid": None, - "consistencygroup_id": None, - "os-vol-mig-status-attr:name_id": None, - "name": "volume-managed", - "bootable": "false", - "created_at": "2017-07-11T09:14:01.000000", - "volume_type": None - } - } - - def setUp(self): - super(TestVolumeManageClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = volume_manage_client.VolumeManageClient(fake_auth, - 'volume', - 'regionOne') - - def _test_manage_volume(self, bytes_body=False): - payload = json.dumps(self.VOLUME_MANAGE_REQUEST, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(volume_manage_client.json, - 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.manage_volume, - 'tempest.lib.common.rest_client.RestClient.post', - self.VOLUME_MANAGE_RESPONSE, - to_utf=bytes_body, - status=202, - mock_args=['os-volume-manage', payload], - **self.VOLUME_MANAGE_REQUEST['volume']) - - def test_manage_volume_with_str_body(self): - self._test_manage_volume() - - def test_manage_volume_with_bytes_body(self): - self._test_manage_volume(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_volumes_client.py b/tempest/tests/lib/services/volume/v2/test_volumes_client.py deleted file mode 100644 index e53e0a2a8..000000000 --- a/tempest/tests/lib/services/volume/v2/test_volumes_client.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v2 import volumes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVolumesClient(base.BaseServiceTest): - - FAKE_VOLUME_METADATA_ITEM = { - "meta": { - "key1": "value1" - } - } - - def setUp(self): - super(TestVolumesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = volumes_client.VolumesClient(fake_auth, - 'volume', - 'regionOne') - - def _test_retype_volume(self, bytes_body=False): - kwargs = { - "new_type": "dedup-tier-replication", - "migration_policy": "never" - } - - self.check_service_client_function( - self.client.retype_volume, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - to_utf=bytes_body, - status=202, - volume_id="a3be971b-8de5-4bdf-bdb8-3d8eb0fb69f8", - **kwargs - ) - - def _test_force_detach_volume(self, bytes_body=False): - kwargs = { - 'attachment_id': '6980e295-920f-412e-b189-05c50d605acd', - 'connector': { - 'initiator': 'iqn.2017-04.org.fake:01' - } - } - - self.check_service_client_function( - self.client.force_detach_volume, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - to_utf=bytes_body, - status=202, - volume_id="a3be971b-8de5-4bdf-bdb8-3d8eb0fb69f8", - **kwargs - ) - - def _test_show_volume_metadata_item(self, bytes_body=False): - self.check_service_client_function( - self.client.show_volume_metadata_item, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_VOLUME_METADATA_ITEM, - to_utf=bytes_body, - volume_id="a3be971b-8de5-4bdf-bdb8-3d8eb0fb69f8", - id="key1") - - def test_force_detach_volume_with_str_body(self): - self._test_force_detach_volume() - - def test_force_detach_volume_with_bytes_body(self): - self._test_force_detach_volume(bytes_body=True) - - def test_show_volume_metadata_item_with_str_body(self): - self._test_show_volume_metadata_item() - - def test_show_volume_metadata_item_with_bytes_body(self): - self._test_show_volume_metadata_item(bytes_body=True) - - def test_retype_volume_with_str_body(self): - self._test_retype_volume() - - def test_retype_volume_with_bytes_body(self): - self._test_retype_volume(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v3/__init__.py b/tempest/tests/lib/services/volume/v3/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/volume/v3/test_backups_client.py b/tempest/tests/lib/services/volume/v3/test_backups_client.py deleted file mode 100644 index f1ce98797..000000000 --- a/tempest/tests/lib/services/volume/v3/test_backups_client.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v3 import backups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestBackupsClient(base.BaseServiceTest): - - FAKE_BACKUP_UPDATE = { - "backup": { - "id": "4c65c15f-a5c5-464b-b92a-90e4c04636a7", - "name": "fake-backup-name", - "links": "fake-links" - } - } - - def setUp(self): - super(TestBackupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = backups_client.BackupsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_update_backup(self, bytes_body=False): - self.check_service_client_function( - self.client.update_backup, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_BACKUP_UPDATE, - bytes_body, - backup_id='4c65c15f-a5c5-464b-b92a-90e4c04636a7') - - def test_update_backup_with_str_body(self): - self._test_update_backup() - - def test_update_backup_with_bytes_body(self): - self._test_update_backup(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v3/test_group_types_client.py b/tempest/tests/lib/services/volume/v3/test_group_types_client.py deleted file mode 100644 index 0f456a26b..000000000 --- a/tempest/tests/lib/services/volume/v3/test_group_types_client.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v3 import group_types_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestGroupTypesClient(base.BaseServiceTest): - FAKE_CREATE_GROUP_TYPE = { - "group_type": { - "name": "group-type-001", - "description": "Test group type 1", - "group_specs": {}, - "is_public": True, - } - } - - FAKE_INFO_GROUP_TYPE = { - "group_type": { - "id": "0e701ab8-1bec-4b9f-b026-a7ba4af13578", - "name": "group-type-001", - "description": "Test group type 1", - "is_public": True, - "created_at": "20127-06-20T03:50:07Z", - "group_specs": {}, - } - } - - FAKE_LIST_GROUP_TYPES = { - "group_types": [ - { - "id": "0e701ab8-1bec-4b9f-b026-a7ba4af13578", - "name": "group-type-001", - "description": "Test group type 1", - "is_public": True, - "created_at": "2017-06-20T03:50:07Z", - "group_specs": {}, - }, - { - "id": "e479997c-650b-40a4-9dfe-77655818b0d2", - "name": "group-type-002", - "description": "Test group type 2", - "is_public": True, - "created_at": "2017-06-19T01:52:47Z", - "group_specs": {}, - }, - { - "id": "c5c4769e-213c-40a6-a568-8e797bb691d4", - "name": "group-type-003", - "description": "Test group type 3", - "is_public": True, - "created_at": "2017-06-18T06:34:32Z", - "group_specs": {}, - } - ] - } - - def setUp(self): - super(TestGroupTypesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = group_types_client.GroupTypesClient(fake_auth, - 'volume', - 'regionOne') - - def _test_create_group_type(self, bytes_body=False): - self.check_service_client_function( - self.client.create_group_type, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_GROUP_TYPE, - bytes_body, - status=202) - - def _test_show_group_type(self, bytes_body=False): - self.check_service_client_function( - self.client.show_group_type, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_GROUP_TYPE, - bytes_body, - group_type_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_list_group_types(self, bytes_body=False): - self.check_service_client_function( - self.client.list_group_types, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_GROUP_TYPES, - bytes_body) - - def test_create_group_type_with_str_body(self): - self._test_create_group_type() - - def test_create_group_type_with_bytes_body(self): - self._test_create_group_type(bytes_body=True) - - def test_delete_group_type(self): - self.check_service_client_function( - self.client.delete_group_type, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - group_type_id='0e58433f-d108-4bf3-a22c-34e6b71ef86b', - status=202) - - def test_show_group_type_with_str_body(self): - self._test_show_group_type() - - def test_show_group_type_with_bytes_body(self): - self._test_show_group_type(bytes_body=True) - - def test_list_group_types_with_str_body(self): - self._test_list_group_types() - - def test_list_group_types_with_bytes_body(self): - self._test_list_group_types(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v3/test_groups_client.py b/tempest/tests/lib/services/volume/v3/test_groups_client.py deleted file mode 100644 index 00db5b46a..000000000 --- a/tempest/tests/lib/services/volume/v3/test_groups_client.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v3 import groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestGroupsClient(base.BaseServiceTest): - FAKE_CREATE_GROUP = { - "group": { - "name": "group-001", - "description": "Test group 1", - "group_type": "0e58433f-d108-4bf3-a22c-34e6b71ef86b", - "volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"], - "availability_zone": "az1", - } - } - - FAKE_INFO_GROUP = { - "group": { - "id": "0e701ab8-1bec-4b9f-b026-a7ba4af13578", - "name": "group-001", - "description": "Test group 1", - "group_type": "0e58433f-d108-4bf3-a22c-34e6b71ef86b", - "volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"], - "status": "available", - "availability_zone": "az1", - "created_at": "20127-06-20T03:50:07Z" - } - } - - FAKE_LIST_GROUPS = { - "groups": [ - { - "id": "0e701ab8-1bec-4b9f-b026-a7ba4af13578", - "name": "group-001", - "description": "Test group 1", - "group_type": "0e58433f-d108-4bf3-a22c-34e6b71ef86b", - "volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"], - "status": "available", - "availability_zone": "az1", - "created_at": "2017-06-20T03:50:07Z", - }, - { - "id": "e479997c-650b-40a4-9dfe-77655818b0d2", - "name": "group-002", - "description": "Test group 2", - "group_snapshot_id": "79c9afdb-7e46-4d71-9249-1f022886963c", - "group_type": "0e58433f-d108-4bf3-a22c-34e6b71ef86b", - "volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"], - "status": "available", - "availability_zone": "az1", - "created_at": "2017-06-19T01:52:47Z", - }, - { - "id": "c5c4769e-213c-40a6-a568-8e797bb691d4", - "name": "group-003", - "description": "Test group 3", - "source_group_id": "e92f9dc7-0b20-492d-8ab2-3ad8fdac270e", - "group_type": "0e58433f-d108-4bf3-a22c-34e6b71ef86b", - "volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"], - "status": "available", - "availability_zone": "az1", - "created_at": "2017-06-18T06:34:32Z", - } - ] - } - - def setUp(self): - super(TestGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = groups_client.GroupsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_create_group(self, bytes_body=False): - self.check_service_client_function( - self.client.create_group, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_GROUP, - bytes_body, - status=202) - - def _test_show_group(self, bytes_body=False): - self.check_service_client_function( - self.client.show_group, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_GROUP, - bytes_body, - group_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_list_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_groups, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_GROUPS, - bytes_body, - detail=True) - - def test_create_group_with_str_body(self): - self._test_create_group() - - def test_create_group_with_bytes_body(self): - self._test_create_group(bytes_body=True) - - def test_show_group_with_str_body(self): - self._test_show_group() - - def test_show_group_with_bytes_body(self): - self._test_show_group(bytes_body=True) - - def test_list_groups_with_str_body(self): - self._test_list_groups() - - def test_list_groups_with_bytes_body(self): - self._test_list_groups(bytes_body=True) - - def test_delete_group(self): - self.check_service_client_function( - self.client.delete_group, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - group_id='0e701ab8-1bec-4b9f-b026-a7ba4af13578', - status=202) diff --git a/tempest/tests/lib/services/volume/v3/test_user_messages_client.py b/tempest/tests/lib/services/volume/v3/test_user_messages_client.py deleted file mode 100644 index 4aeed5f43..000000000 --- a/tempest/tests/lib/services/volume/v3/test_user_messages_client.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2016 Red Hat. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v3 import messages_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestUserMessagesClient(base.BaseServiceTest): - USER_MESSAGE_INFO = { - "created_at": "2016-11-21T06:16:34.000000", - "guaranteed_until": "2016-12-21T06:16:34.000000", - "user_message": "No storage could be allocated for this volume " - "request. You may be able to try another size or" - " volume type.", - "resource_uuid": "c570b406-bf0b-4067-9398-f0bb09a7d9d7", - "request_id": "req-8f68681e-9b6b-4009-b94c-ac0811595451", - "message_level": "ERROR", - "id": "9a7dafbd-a156-4540-8996-50e71b5dcadf", - "resource_type": "VOLUME", - "links": [ - {"href": "http://192.168.100.230:8776/v3/" - "a678cb65f701462ea2257245cd640829/messages/" - "9a7dafbd-a156-4540-8996-50e71b5dcadf", - "rel": "self"}, - {"href": "http://192.168.100.230:8776/" - "a678cb65f701462ea2257245cd640829/messages/" - "9a7dafbd-a156-4540-8996-50e71b5dcadf", - "rel": "bookmark"}] - } - FAKE_SHOW_USER_MESSAGE = { - "message": dict(event_id="000002", **USER_MESSAGE_INFO)} - - FAKE_LIST_USER_MESSAGES = { - "messages": [ - dict(event_id="000003", **USER_MESSAGE_INFO), - dict(event_id="000004", **USER_MESSAGE_INFO) - ] - } - - def setUp(self): - super(TestUserMessagesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = messages_client.MessagesClient(fake_auth, - 'volume', - 'regionOne') - - def _test_show_user_message(self, bytes_body=False): - self.check_service_client_function( - self.client.show_message, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SHOW_USER_MESSAGE, - bytes_body, - message_id="9a7dafbd-a156-4540-8996-50e71b5dcadf") - - def _test_list_user_message(self, bytes_body=False): - self.check_service_client_function( - self.client.list_messages, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_USER_MESSAGES, - bytes_body) - - def test_list_user_message_with_str_body(self): - self._test_list_user_message() - - def test_list_user_message_with_bytes_body(self): - self._test_list_user_message(bytes_body=True) - - def test_show_user_message_with_str_body(self): - self._test_show_user_message() - - def test_show_user_message_with_bytes_body(self): - self._test_show_user_message(bytes_body=True) - - def test_delete_user_message(self): - self.check_service_client_function( - self.client.delete_message, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - message_id="9a7dafbd-a156-4540-8996-50e71b5dcadf", - status=204) diff --git a/tempest/tests/lib/services/volume/v3/test_versions_client.py b/tempest/tests/lib/services/volume/v3/test_versions_client.py deleted file mode 100644 index 9627b9a2b..000000000 --- a/tempest/tests/lib/services/volume/v3/test_versions_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2017 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v3 import versions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVersionsClient(base.BaseServiceTest): - - FAKE_VERSIONS_INFO = { - "versions": [ - { - "status": "DEPRECATED", "updated": "2016-05-02T20:25:19Z", - "links": [ - {"href": "http://docs.openstack.org/", "type": "text/html", - "rel": "describedby"}, - {"href": "https://10.30.197.39:8776/v1/", "rel": "self"} - ], - "min_version": "", - "version": "", - "media-types": [ - {"base": "application/json", - "type": "application/vnd.openstack.volume+json;version=1"} - ], - "id": "v1.0" - }, - { - "status": "DEPRECATED", "updated": "2017-02-25T12:00:00Z", - "links": [ - {"href": "http://docs.openstack.org/", "type": "text/html", - "rel": "describedby"}, - {"href": "https://10.30.197.39:8776/v2/", "rel": "self"} - ], - "min_version": "", - "version": "", - "media-types": [ - {"base": "application/json", - "type": "application/vnd.openstack.volume+json;version=1"} - ], - "id": "v2.0" - }, - { - "status": "CURRENT", "updated": "2016-02-08T12:20:21Z", - "links": [ - {"href": "http://docs.openstack.org/", "type": "text/html", - "rel": "describedby"}, - {"href": "https://10.30.197.39:8776/v3/", "rel": "self"} - ], - "min_version": "3.0", - "version": "3.28", - "media-types": [ - {"base": "application/json", - "type": "application/vnd.openstack.volume+json;version=1"} - ], - "id": "v3.0" - } - ] - } - - def setUp(self): - super(TestVersionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = versions_client.VersionsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_list_versions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_versions, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSIONS_INFO, - bytes_body, - 300) - - def test_list_versions_with_str_body(self): - self._test_list_versions() - - def test_list_versions_with_bytes_body(self): - self._test_list_versions(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v3/test_volumes_client.py b/tempest/tests/lib/services/volume/v3/test_volumes_client.py deleted file mode 100644 index a515fd34a..000000000 --- a/tempest/tests/lib/services/volume/v3/test_volumes_client.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services.volume.v3 import volumes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVolumesClient(base.BaseServiceTest): - - FAKE_VOLUME_SUMMARY = { - "volume-summary": { - "total_size": 20, - "total_count": 5 - } - } - - def setUp(self): - super(TestVolumesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = volumes_client.VolumesClient(fake_auth, - 'volume', - 'regionOne') - - def _test_show_volume_summary(self, bytes_body=False): - self.check_service_client_function( - self.client.show_volume_summary, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_VOLUME_SUMMARY, - bytes_body) - - def test_show_volume_summary_with_str_body(self): - self._test_show_volume_summary() - - def test_show_volume_summary_with_bytes_body(self): - self._test_show_volume_summary(bytes_body=True) diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py deleted file mode 100644 index c3a792f41..000000000 --- a/tempest/tests/lib/test_auth.py +++ /dev/null @@ -1,915 +0,0 @@ -# Copyright 2014 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy -import datetime - -import fixtures -import testtools - -from tempest.lib import auth -from tempest.lib import exceptions -from tempest.lib.services.identity.v2 import token_client as v2_client -from tempest.lib.services.identity.v3 import token_client as v3_client -from tempest.tests import base -from tempest.tests.lib import fake_credentials -from tempest.tests.lib import fake_identity - - -def fake_get_credentials(fill_in=True, identity_version='v2', **kwargs): - return fake_credentials.FakeCredentials() - - -class BaseAuthTestsSetUp(base.TestCase): - _auth_provider_class = None - credentials = fake_credentials.FakeCredentials() - - def _auth(self, credentials, auth_url, **params): - """returns auth method according to keystone""" - return self._auth_provider_class(credentials, auth_url, **params) - - def setUp(self): - super(BaseAuthTestsSetUp, self).setUp() - self.patchobject(auth, 'get_credentials', fake_get_credentials) - self.auth_provider = self._auth(self.credentials, - fake_identity.FAKE_AUTH_URL) - - -class TestBaseAuthProvider(BaseAuthTestsSetUp): - """Tests for base AuthProvider - - This tests auth.AuthProvider class which is base for the other so we - obviously don't test not implemented method or the ones which strongly - depends on them. - """ - - class FakeAuthProviderImpl(auth.AuthProvider): - def _decorate_request(self): - pass - - def _fill_credentials(self): - pass - - def _get_auth(self): - pass - - def base_url(self): - pass - - def is_expired(self): - pass - - _auth_provider_class = FakeAuthProviderImpl - - def _auth(self, credentials, auth_url, **params): - """returns auth method according to keystone""" - return self._auth_provider_class(credentials, **params) - - def test_check_credentials_bad_type(self): - self.assertFalse(self.auth_provider.check_credentials([])) - - def test_auth_data_property_when_cache_exists(self): - self.auth_provider.cache = 'foo' - self.useFixture(fixtures.MockPatchObject(self.auth_provider, - 'is_expired', - return_value=False)) - self.assertEqual('foo', getattr(self.auth_provider, 'auth_data')) - - def test_delete_auth_data_property_through_deleter(self): - self.auth_provider.cache = 'foo' - del self.auth_provider.auth_data - self.assertIsNone(self.auth_provider.cache) - - def test_delete_auth_data_property_through_clear_auth(self): - self.auth_provider.cache = 'foo' - self.auth_provider.clear_auth() - self.assertIsNone(self.auth_provider.cache) - - def test_set_and_reset_alt_auth_data(self): - self.auth_provider.set_alt_auth_data('foo', 'bar') - self.assertEqual(self.auth_provider.alt_part, 'foo') - self.assertEqual(self.auth_provider.alt_auth_data, 'bar') - - self.auth_provider.reset_alt_auth_data() - self.assertIsNone(self.auth_provider.alt_part) - self.assertIsNone(self.auth_provider.alt_auth_data) - - def test_auth_class(self): - self.assertRaises(TypeError, - auth.AuthProvider, - fake_credentials.FakeCredentials) - - -class TestKeystoneV2AuthProvider(BaseAuthTestsSetUp): - _endpoints = fake_identity.IDENTITY_V2_RESPONSE['access']['serviceCatalog'] - _auth_provider_class = auth.KeystoneV2AuthProvider - credentials = fake_credentials.FakeKeystoneV2Credentials() - - def setUp(self): - super(TestKeystoneV2AuthProvider, self).setUp() - self.patchobject(v2_client.TokenClient, 'raw_request', - fake_identity._fake_v2_response) - self.target_url = 'test_api' - - def _get_fake_identity(self): - return fake_identity.IDENTITY_V2_RESPONSE['access'] - - def _get_fake_alt_identity(self): - return fake_identity.ALT_IDENTITY_V2_RESPONSE['access'] - - def _get_result_url_from_endpoint(self, ep, endpoint_type='publicURL', - replacement=None): - if replacement: - return ep[endpoint_type].replace('v2', replacement) - return ep[endpoint_type] - - def _get_token_from_fake_identity(self): - return fake_identity.TOKEN - - def _get_from_fake_identity(self, attr): - access = fake_identity.IDENTITY_V2_RESPONSE['access'] - if attr == 'user_id': - return access['user']['id'] - elif attr == 'tenant_id': - return access['token']['tenant']['id'] - - def _test_request_helper(self, filters, expected): - url, headers, body = self.auth_provider.auth_request('GET', - self.target_url, - filters=filters) - - self.assertEqual(expected['url'], url) - self.assertEqual(expected['token'], headers['X-Auth-Token']) - self.assertEqual(expected['body'], body) - - def _auth_data_with_expiry(self, date_as_string): - token, access = self.auth_provider.auth_data - access['token']['expires'] = date_as_string - return token, access - - def test_request(self): - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - - url = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1]) + '/' + self.target_url - - expected = { - 'body': None, - 'url': url, - 'token': self._get_token_from_fake_identity(), - } - self._test_request_helper(filters, expected) - - def test_request_with_alt_auth_cleans_alt(self): - """Test alternate auth data for headers - - Assert that when the alt data is provided for headers, after an - auth_request the data alt_data is cleaned-up. - """ - self.auth_provider.set_alt_auth_data( - 'headers', - (fake_identity.ALT_TOKEN, self._get_fake_alt_identity())) - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - self.auth_provider.auth_request('GET', self.target_url, - filters=filters) - - # Assert alt auth data is clear after it - self.assertIsNone(self.auth_provider.alt_part) - self.assertIsNone(self.auth_provider.alt_auth_data) - - def _test_request_with_identical_alt_auth(self, part): - """Test alternate but identical auth data for headers - - Assert that when the alt data is provided, but it's actually - identical, an exception is raised. - """ - self.auth_provider.set_alt_auth_data( - part, - (fake_identity.TOKEN, self._get_fake_identity())) - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - - self.assertRaises(exceptions.BadAltAuth, - self.auth_provider.auth_request, - 'GET', self.target_url, filters=filters) - - def test_request_with_identical_alt_auth_headers(self): - self._test_request_with_identical_alt_auth('headers') - - def test_request_with_identical_alt_auth_url(self): - self._test_request_with_identical_alt_auth('url') - - def test_request_with_identical_alt_auth_body(self): - self._test_request_with_identical_alt_auth('body') - - def test_request_with_alt_part_without_alt_data(self): - """Test empty alternate auth data - - Assert that when alt_part is defined, the corresponding original - request element is kept the same. - """ - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - self.auth_provider.set_alt_auth_data('headers', None) - - url, headers, body = self.auth_provider.auth_request('GET', - self.target_url, - filters=filters) - # The original headers where empty - self.assertNotEqual(url, self.target_url) - self.assertIsNone(headers) - self.assertIsNone(body) - - def _test_request_with_alt_part_without_alt_data_no_change(self, body): - """Test empty alternate auth data with no effect - - Assert that when alt_part is defined, no auth_data is provided, - and the corresponding original request element was not going to - be changed anyways, and exception is raised - """ - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - self.auth_provider.set_alt_auth_data('body', None) - - self.assertRaises(exceptions.BadAltAuth, - self.auth_provider.auth_request, - 'GET', self.target_url, filters=filters) - - def test_request_with_alt_part_without_alt_data_no_change_headers(self): - self._test_request_with_alt_part_without_alt_data_no_change('headers') - - def test_request_with_alt_part_without_alt_data_no_change_url(self): - self._test_request_with_alt_part_without_alt_data_no_change('url') - - def test_request_with_alt_part_without_alt_data_no_change_body(self): - self._test_request_with_alt_part_without_alt_data_no_change('body') - - def test_request_with_bad_service(self): - filters = { - 'service': 'BAD_SERVICE', - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - self.assertRaises(exceptions.EndpointNotFound, - self.auth_provider.auth_request, 'GET', - self.target_url, filters=filters) - - def test_request_without_service(self): - filters = { - 'service': None, - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - self.assertRaises(exceptions.EndpointNotFound, - self.auth_provider.auth_request, 'GET', - self.target_url, filters=filters) - - def test_check_credentials_missing_attribute(self): - for attr in ['username', 'password']: - cred = copy.copy(self.credentials) - del cred[attr] - self.assertFalse(self.auth_provider.check_credentials(cred)) - - def test_fill_credentials(self): - self.auth_provider.fill_credentials() - creds = self.auth_provider.credentials - for attr in ['user_id', 'tenant_id']: - self.assertEqual(self._get_from_fake_identity(attr), - getattr(creds, attr)) - - def _test_base_url_helper(self, expected_url, filters, - auth_data=None): - - url = self.auth_provider.base_url(filters, auth_data) - self.assertEqual(url, expected_url) - - def test_base_url(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1]) - self._test_base_url_helper(expected, self.filters) - - def test_base_url_to_get_admin_endpoint(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'adminURL', - 'region': 'FakeRegion' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1], endpoint_type='adminURL') - self._test_base_url_helper(expected, self.filters) - - def test_base_url_unknown_region(self): - """If the region is unknown, the first endpoint is returned.""" - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'AintNoBodyKnowThisRegion' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][0]) - self._test_base_url_helper(expected, self.filters) - - def test_base_url_with_non_existent_service(self): - self.filters = { - 'service': 'BAD_SERVICE', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - self.assertRaises(exceptions.EndpointNotFound, - self._test_base_url_helper, None, self.filters) - - def test_base_url_without_service(self): - self.filters = { - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - self.assertRaises(exceptions.EndpointNotFound, - self._test_base_url_helper, None, self.filters) - - def test_base_url_with_known_name(self): - """If name and service is known, return the endpoint.""" - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'name': 'nova' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1]) - self._test_base_url_helper(expected, self.filters) - - def test_base_url_with_known_name_and_unknown_servce(self): - """Test with Known Name and Unknown service - - If the name is known but the service is unknown, raise an exception. - """ - self.filters = { - 'service': 'AintNoBodyKnowThatService', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'name': 'AintNoBodyKnowThatName' - } - self.assertRaises(exceptions.EndpointNotFound, - self._test_base_url_helper, None, self.filters) - - def test_base_url_with_unknown_name_and_known_service(self): - """Test with Unknown Name and Known Service - - If the name is unknown, raise an exception. Note that filtering by - name is only successful service exists. - """ - - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'name': 'AintNoBodyKnowThatName' - } - self.assertRaises(exceptions.EndpointNotFound, - self._test_base_url_helper, None, self.filters) - - def test_base_url_without_name(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1]) - self._test_base_url_helper(expected, self.filters) - - def test_base_url_with_api_version_filter(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v12' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1], replacement='v12') - self._test_base_url_helper(expected, self.filters) - - def test_base_url_with_skip_path_filter(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'skip_path': True - } - expected = 'http://fake_url/' - self._test_base_url_helper(expected, self.filters) - - def test_base_url_with_unversioned_endpoint(self): - auth_data = { - 'serviceCatalog': [ - { - 'type': 'identity', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'publicURL': 'http://fake_url' - } - ] - } - ] - } - - filters = { - 'service': 'identity', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v2.0' - } - - expected = 'http://fake_url/v2.0' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - def test_base_url_with_extra_path_endpoint(self): - auth_data = { - 'serviceCatalog': [ - { - 'type': 'compute', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'publicURL': 'http://fake_url/some_path/v2.0' - } - ] - } - ] - } - - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v2.0' - } - - expected = 'http://fake_url/some_path/v2.0' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - def test_base_url_with_unversioned_extra_path_endpoint(self): - auth_data = { - 'serviceCatalog': [ - { - 'type': 'compute', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'publicURL': 'http://fake_url/some_path' - } - ] - } - ] - } - - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v2.0' - } - - expected = 'http://fake_url/some_path/v2.0' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - def test_token_not_expired(self): - expiry_data = datetime.datetime.utcnow() + datetime.timedelta(days=1) - self._verify_expiry(expiry_data=expiry_data, should_be_expired=False) - - def test_token_expired(self): - expiry_data = datetime.datetime.utcnow() - datetime.timedelta(hours=1) - self._verify_expiry(expiry_data=expiry_data, should_be_expired=True) - - def test_token_not_expired_to_be_renewed(self): - expiry_data = (datetime.datetime.utcnow() + - self.auth_provider.token_expiry_threshold / 2) - self._verify_expiry(expiry_data=expiry_data, should_be_expired=True) - - def _verify_expiry(self, expiry_data, should_be_expired): - for expiry_format in self.auth_provider.EXPIRY_DATE_FORMATS: - auth_data = self._auth_data_with_expiry( - expiry_data.strftime(expiry_format)) - self.assertEqual(self.auth_provider.is_expired(auth_data), - should_be_expired) - - def test_set_scope_all_valid(self): - for scope in self.auth_provider.SCOPES: - self.auth_provider.scope = scope - self.assertEqual(scope, self.auth_provider.scope) - - def test_set_scope_invalid(self): - with testtools.ExpectedException(exceptions.InvalidScope, - '.* invalid_scope .*'): - self.auth_provider.scope = 'invalid_scope' - - -class TestKeystoneV3AuthProvider(TestKeystoneV2AuthProvider): - _endpoints = fake_identity.IDENTITY_V3_RESPONSE['token']['catalog'] - _auth_provider_class = auth.KeystoneV3AuthProvider - credentials = fake_credentials.FakeKeystoneV3Credentials() - - def setUp(self): - super(TestKeystoneV3AuthProvider, self).setUp() - self.patchobject(v3_client.V3TokenClient, 'raw_request', - fake_identity._fake_v3_response) - - def _get_fake_identity(self): - return fake_identity.IDENTITY_V3_RESPONSE['token'] - - def _get_fake_alt_identity(self): - return fake_identity.ALT_IDENTITY_V3['token'] - - def _get_result_url_from_endpoint(self, ep, replacement=None): - if replacement: - return ep['url'].replace('v3', replacement) - return ep['url'] - - def _auth_data_with_expiry(self, date_as_string): - token, access = self.auth_provider.auth_data - access['expires_at'] = date_as_string - return token, access - - def _get_from_fake_identity(self, attr): - token = fake_identity.IDENTITY_V3_RESPONSE['token'] - if attr == 'user_id': - return token['user']['id'] - elif attr == 'project_id': - return token['project']['id'] - elif attr == 'user_domain_id': - return token['user']['domain']['id'] - elif attr == 'project_domain_id': - return token['project']['domain']['id'] - - def test_check_credentials_missing_attribute(self): - # reset credentials to fresh ones - self.credentials.reset() - for attr in ['username', 'password', 'user_domain_name', - 'project_domain_name']: - cred = copy.copy(self.credentials) - del cred[attr] - self.assertFalse(self.auth_provider.check_credentials(cred), - "Credentials should be invalid without %s" % attr) - - def test_check_domain_credentials_missing_attribute(self): - # reset credentials to fresh ones - self.credentials.reset() - domain_creds = fake_credentials.FakeKeystoneV3DomainCredentials() - for attr in ['username', 'password', 'user_domain_name']: - cred = copy.copy(domain_creds) - del cred[attr] - self.assertFalse(self.auth_provider.check_credentials(cred), - "Credentials should be invalid without %s" % attr) - - def test_fill_credentials(self): - self.auth_provider.fill_credentials() - creds = self.auth_provider.credentials - for attr in ['user_id', 'project_id', 'user_domain_id', - 'project_domain_id']: - self.assertEqual(self._get_from_fake_identity(attr), - getattr(creds, attr)) - - # Overwrites v2 test - def test_base_url_to_get_admin_endpoint(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'admin', - 'region': 'MiddleEarthRegion' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][2]) - self._test_base_url_helper(expected, self.filters) - - # Overwrites v2 test - def test_base_url_with_unversioned_endpoint(self): - auth_data = { - 'catalog': [ - { - 'type': 'identity', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'url': 'http://fake_url', - 'interface': 'public' - } - ] - } - ] - } - - filters = { - 'service': 'identity', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v3' - } - - expected = 'http://fake_url/v3' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - def test_base_url_with_extra_path_endpoint(self): - auth_data = { - 'catalog': [ - { - 'type': 'compute', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'url': 'http://fake_url/some_path/v2.0', - 'interface': 'public' - } - ] - } - ] - } - - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v2.0' - } - - expected = 'http://fake_url/some_path/v2.0' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - def test_base_url_with_unversioned_extra_path_endpoint(self): - auth_data = { - 'catalog': [ - { - 'type': 'compute', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'url': 'http://fake_url/some_path', - 'interface': 'public' - } - ] - } - ] - } - - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v2.0' - } - - expected = 'http://fake_url/some_path/v2.0' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - # Base URL test with scope only for V3 - def test_base_url_scope_project(self): - self.auth_provider.scope = 'project' - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1]) - self._test_base_url_helper(expected, self.filters) - - # Base URL test with scope only for V3 - def test_base_url_unscoped_identity(self): - self.auth_provider.scope = 'unscoped' - self.patchobject(v3_client.V3TokenClient, 'raw_request', - fake_identity._fake_v3_response_no_scope) - self.filters = { - 'service': 'identity', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - expected = fake_identity.FAKE_AUTH_URL - self._test_base_url_helper(expected, self.filters) - - # Base URL test with scope only for V3 - def test_base_url_unscoped_other(self): - self.auth_provider.scope = 'unscoped' - self.patchobject(v3_client.V3TokenClient, 'raw_request', - fake_identity._fake_v3_response_no_scope) - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - self.assertRaises(exceptions.EndpointNotFound, - self.auth_provider.base_url, - auth_data=self.auth_provider.auth_data, - filters=self.filters) - - def test_auth_parameters_with_scope_unset(self): - # No scope defaults to 'project' - all_creds = fake_credentials.FakeKeystoneV3AllCredentials() - self.auth_provider.credentials = all_creds - auth_params = self.auth_provider._auth_params() - self.assertNotIn('scope', auth_params.keys()) - for attr in all_creds.get_init_attributes(): - if attr.startswith('domain_'): - self.assertNotIn(attr, auth_params.keys()) - else: - self.assertIn(attr, auth_params.keys()) - self.assertEqual(getattr(all_creds, attr), auth_params[attr]) - - def test_auth_parameters_with_project_scope(self): - all_creds = fake_credentials.FakeKeystoneV3AllCredentials() - self.auth_provider.credentials = all_creds - self.auth_provider.scope = 'project' - auth_params = self.auth_provider._auth_params() - self.assertNotIn('scope', auth_params.keys()) - for attr in all_creds.get_init_attributes(): - if attr.startswith('domain_'): - self.assertNotIn(attr, auth_params.keys()) - else: - self.assertIn(attr, auth_params.keys()) - self.assertEqual(getattr(all_creds, attr), auth_params[attr]) - - def test_auth_parameters_with_domain_scope(self): - all_creds = fake_credentials.FakeKeystoneV3AllCredentials() - self.auth_provider.credentials = all_creds - self.auth_provider.scope = 'domain' - auth_params = self.auth_provider._auth_params() - self.assertNotIn('scope', auth_params.keys()) - for attr in all_creds.get_init_attributes(): - if attr.startswith('project_'): - self.assertNotIn(attr, auth_params.keys()) - else: - self.assertIn(attr, auth_params.keys()) - self.assertEqual(getattr(all_creds, attr), auth_params[attr]) - - def test_auth_parameters_unscoped(self): - all_creds = fake_credentials.FakeKeystoneV3AllCredentials() - self.auth_provider.credentials = all_creds - self.auth_provider.scope = 'unscoped' - auth_params = self.auth_provider._auth_params() - self.assertNotIn('scope', auth_params.keys()) - for attr in all_creds.get_init_attributes(): - if attr.startswith('project_') or attr.startswith('domain_'): - self.assertNotIn(attr, auth_params.keys()) - else: - self.assertIn(attr, auth_params.keys()) - self.assertEqual(getattr(all_creds, attr), auth_params[attr]) - - -class TestKeystoneV3Credentials(base.TestCase): - def testSetAttrUserDomain(self): - creds = auth.KeystoneV3Credentials() - creds.user_domain_name = 'user_domain' - creds.domain_name = 'domain' - self.assertEqual('user_domain', creds.user_domain_name) - creds = auth.KeystoneV3Credentials() - creds.domain_name = 'domain' - creds.user_domain_name = 'user_domain' - self.assertEqual('user_domain', creds.user_domain_name) - - def testSetAttrProjectDomain(self): - creds = auth.KeystoneV3Credentials() - creds.project_domain_name = 'project_domain' - creds.domain_name = 'domain' - self.assertEqual('project_domain', creds.user_domain_name) - creds = auth.KeystoneV3Credentials() - creds.domain_name = 'domain' - creds.project_domain_name = 'project_domain' - self.assertEqual('project_domain', creds.project_domain_name) - - def testProjectTenantNoCollision(self): - creds = auth.KeystoneV3Credentials(tenant_id='tenant') - self.assertEqual('tenant', creds.project_id) - creds = auth.KeystoneV3Credentials(project_id='project') - self.assertEqual('project', creds.tenant_id) - creds = auth.KeystoneV3Credentials(tenant_name='tenant') - self.assertEqual('tenant', creds.project_name) - creds = auth.KeystoneV3Credentials(project_name='project') - self.assertEqual('project', creds.tenant_name) - - def testProjectTenantCollision(self): - attrs = {'tenant_id': 'tenant', 'project_id': 'project'} - self.assertRaises( - exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs) - attrs = {'tenant_name': 'tenant', 'project_name': 'project'} - self.assertRaises( - exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs) - - -class TestReplaceVersion(base.TestCase): - def test_version_no_trailing_path(self): - self.assertEqual( - 'http://localhost:35357/v2.0', - auth.replace_version('http://localhost:35357/v3', 'v2.0')) - - def test_version_no_trailing_path_solidus(self): - self.assertEqual( - 'http://localhost:35357/v2.0/', - auth.replace_version('http://localhost:35357/v3/', 'v2.0')) - - def test_version_trailing_path(self): - self.assertEqual( - 'http://localhost:35357/v2.0/uuid', - auth.replace_version('http://localhost:35357/v3/uuid', 'v2.0')) - - def test_version_trailing_path_solidus(self): - self.assertEqual( - 'http://localhost:35357/v2.0/uuid/', - auth.replace_version('http://localhost:35357/v3/uuid/', 'v2.0')) - - def test_no_version_base(self): - self.assertEqual( - 'http://localhost:35357/v2.0', - auth.replace_version('http://localhost:35357', 'v2.0')) - - def test_no_version_base_solidus(self): - self.assertEqual( - 'http://localhost:35357/v2.0', - auth.replace_version('http://localhost:35357/', 'v2.0')) - - def test_no_version_path(self): - self.assertEqual( - 'http://localhost/identity/v2.0', - auth.replace_version('http://localhost/identity', 'v2.0')) - - def test_no_version_path_solidus(self): - self.assertEqual( - 'http://localhost/identity/v2.0', - auth.replace_version('http://localhost/identity/', 'v2.0')) - - def test_path_version(self): - self.assertEqual( - 'http://localhost/identity/v2.0', - auth.replace_version('http://localhost/identity/v3', 'v2.0')) - - def test_path_version_solidus(self): - self.assertEqual( - 'http://localhost/identity/v2.0/', - auth.replace_version('http://localhost/identity/v3/', 'v2.0')) - - def test_path_version_trailing_path(self): - self.assertEqual( - 'http://localhost/identity/v2.0/uuid', - auth.replace_version('http://localhost/identity/v3/uuid', 'v2.0')) - - def test_path_version_trailing_path_solidus(self): - self.assertEqual( - 'http://localhost/identity/v2.0/uuid/', - auth.replace_version('http://localhost/identity/v3/uuid/', 'v2.0')) - - -class TestKeystoneV3AuthProvider_DomainScope(BaseAuthTestsSetUp): - _endpoints = fake_identity.IDENTITY_V3_RESPONSE['token']['catalog'] - _auth_provider_class = auth.KeystoneV3AuthProvider - credentials = fake_credentials.FakeKeystoneV3Credentials() - - def setUp(self): - super(TestKeystoneV3AuthProvider_DomainScope, self).setUp() - self.patchobject(v3_client.V3TokenClient, 'raw_request', - fake_identity._fake_v3_response_domain_scope) - - def test_get_auth_with_domain_scope(self): - self.auth_provider.scope = 'domain' - _, auth_data = self.auth_provider.get_auth() - self.assertIn('domain', auth_data) - self.assertNotIn('project', auth_data) - - -class TestGetCredentials(base.TestCase): - - def test_invalid_identity_version(self): - with testtools.ExpectedException(exceptions.InvalidIdentityVersion, - '.* v1 .*'): - auth.get_credentials('http://localhost/identity/v3', - identity_version='v1') diff --git a/tempest/tests/lib/test_base.py b/tempest/tests/lib/test_base.py deleted file mode 100644 index 27cda1a2c..000000000 --- a/tempest/tests/lib/test_base.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2014 Mirantis Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import testtools - -from tempest.lib import base -from tempest.lib import exceptions - - -class TestAttr(base.BaseTestCase): - - def test_has_no_attrs(self): - self.assertEqual( - 'tempest.tests.lib.test_base.TestAttr.test_has_no_attrs', - self.id() - ) - - @testtools.testcase.attr('foo') - def test_has_one_attr(self): - self.assertEqual( - 'tempest.tests.lib.test_base.TestAttr.test_has_one_attr[foo]', - self.id() - ) - - @testtools.testcase.attr('foo') - @testtools.testcase.attr('bar') - def test_has_two_attrs(self): - self.assertEqual( - 'tempest.tests.lib.test_base.TestAttr.test_has_two_attrs[bar,foo]', - self.id(), - ) - - -class TestSetUpClass(base.BaseTestCase): - - @classmethod - def setUpClass(cls): # noqa - """Simulate absence of super() call.""" - - def setUp(self): - try: - # We expect here RuntimeError exception because 'setUpClass' - # has not called 'super'. - super(TestSetUpClass, self).setUp() - except RuntimeError: - pass - else: - raise exceptions.TempestException( - "If you see this, then expected exception was not raised.") - - def test_setup_class_raises_runtime_error(self): - """No-op test just to call setUp.""" diff --git a/tempest/tests/lib/test_credentials.py b/tempest/tests/lib/test_credentials.py deleted file mode 100644 index c910d6d6d..000000000 --- a/tempest/tests/lib/test_credentials.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import copy - -from tempest.lib import auth -from tempest.lib import exceptions -from tempest.lib.services.identity.v2 import token_client as v2_client -from tempest.lib.services.identity.v3 import token_client as v3_client -from tempest.tests import base -from tempest.tests.lib import fake_identity - - -class CredentialsTests(base.TestCase): - attributes = {} - credentials_class = auth.Credentials - - def _get_credentials(self, attributes=None): - if attributes is None: - attributes = self.attributes - return self.credentials_class(**attributes) - - def _check(self, credentials, credentials_class, filled): - # Check the right version of credentials has been returned - self.assertIsInstance(credentials, credentials_class) - # Check the id attributes are filled in - # NOTE(andreaf) project_* attributes are accepted as input but - # never set on the credentials object - attributes = [x for x in credentials.ATTRIBUTES if ( - '_id' in x and x != 'domain_id' and x != 'project_id')] - for attr in attributes: - if filled: - self.assertIsNotNone(getattr(credentials, attr)) - else: - self.assertIsNone(getattr(credentials, attr)) - - def test_create(self): - creds = self._get_credentials() - self.assertEqual(self.attributes, creds._initial) - - def test_create_invalid_attr(self): - self.assertRaises(exceptions.InvalidCredentials, - self._get_credentials, - attributes=dict(invalid='fake')) - - def test_is_valid(self): - creds = self._get_credentials() - self.assertRaises(NotImplementedError, creds.is_valid) - - -class KeystoneV2CredentialsTests(CredentialsTests): - attributes = { - 'username': 'fake_username', - 'password': 'fake_password', - 'tenant_name': 'fake_tenant_name' - } - - identity_response = fake_identity._fake_v2_response - credentials_class = auth.KeystoneV2Credentials - tokenclient_class = v2_client.TokenClient - identity_version = 'v2' - - def setUp(self): - super(KeystoneV2CredentialsTests, self).setUp() - self.patchobject(self.tokenclient_class, 'raw_request', - self.identity_response) - - def _verify_credentials(self, credentials_class, creds_dict, filled=True): - creds = auth.get_credentials(fake_identity.FAKE_AUTH_URL, - fill_in=filled, - identity_version=self.identity_version, - **creds_dict) - self._check(creds, credentials_class, filled) - - def test_get_credentials(self): - self._verify_credentials(credentials_class=self.credentials_class, - creds_dict=self.attributes) - - def test_get_credentials_not_filled(self): - self._verify_credentials(credentials_class=self.credentials_class, - creds_dict=self.attributes, - filled=False) - - def test_is_valid(self): - creds = self._get_credentials() - self.assertTrue(creds.is_valid()) - - def _test_is_not_valid(self, ignore_key): - creds = self._get_credentials() - for attr in self.attributes: - if attr == ignore_key: - continue - temp_attr = getattr(creds, attr) - delattr(creds, attr) - self.assertFalse(creds.is_valid(), - "Credentials should be invalid without %s" % attr) - setattr(creds, attr, temp_attr) - - def test_is_not_valid(self): - # NOTE(mtreinish): A KeystoneV2 credential object is valid without - # a tenant_name. So skip that check. See tempest.auth for the valid - # credential requirements - self._test_is_not_valid('tenant_name') - - def test_reset_all_attributes(self): - creds = self._get_credentials() - initial_creds = copy.deepcopy(creds) - set_attr = creds.__dict__.keys() - missing_attr = set(creds.ATTRIBUTES).difference(set_attr) - # Set all unset attributes, then reset - for attr in missing_attr: - setattr(creds, attr, 'fake' + attr) - creds.reset() - # Check reset credentials are same as initial ones - self.assertEqual(creds, initial_creds) - - def test_reset_single_attribute(self): - creds = self._get_credentials() - initial_creds = copy.deepcopy(creds) - set_attr = creds.__dict__.keys() - missing_attr = set(creds.ATTRIBUTES).difference(set_attr) - # Set one unset attributes, then reset - for attr in missing_attr: - setattr(creds, attr, 'fake' + attr) - creds.reset() - # Check reset credentials are same as initial ones - self.assertEqual(creds, initial_creds) - - -class KeystoneV3CredentialsTests(KeystoneV2CredentialsTests): - attributes = { - 'username': 'fake_username', - 'password': 'fake_password', - 'project_name': 'fake_project_name', - 'user_domain_name': 'fake_domain_name' - } - - credentials_class = auth.KeystoneV3Credentials - identity_response = fake_identity._fake_v3_response - tokenclient_class = v3_client.V3TokenClient - identity_version = 'v3' - - def test_is_not_valid(self): - # NOTE(mtreinish) For a Keystone V3 credential object a project name - # is not required to be valid, so we skip that check. See tempest.auth - # for the valid credential requirements - self._test_is_not_valid('project_name') - - def test_synced_attributes(self): - attributes = self.attributes - # Create V3 credentials with tenant instead of project, and user_domain - for attr in ['project_id', 'user_domain_id']: - attributes[attr] = 'fake_' + attr - creds = self._get_credentials(attributes) - self.assertEqual(creds.project_name, creds.tenant_name) - self.assertEqual(creds.project_id, creds.tenant_id) - self.assertEqual(creds.user_domain_name, creds.project_domain_name) - self.assertEqual(creds.user_domain_id, creds.project_domain_id) - # Replace user_domain with project_domain - del attributes['user_domain_name'] - del attributes['user_domain_id'] - del attributes['project_name'] - del attributes['project_id'] - for attr in ['project_domain_name', 'project_domain_id', - 'tenant_name', 'tenant_id']: - attributes[attr] = 'fake_' + attr - self.assertEqual(creds.tenant_name, creds.project_name) - self.assertEqual(creds.tenant_id, creds.project_id) - self.assertEqual(creds.project_domain_name, creds.user_domain_name) - self.assertEqual(creds.project_domain_id, creds.user_domain_id) diff --git a/tempest/tests/lib/test_decorators.py b/tempest/tests/lib/test_decorators.py deleted file mode 100644 index bbebcd3b2..000000000 --- a/tempest/tests/lib/test_decorators.py +++ /dev/null @@ -1,184 +0,0 @@ -# Copyright 2013 IBM Corp -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock -import testtools - -from tempest.lib import base as test -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.tests import base - - -class TestAttrDecorator(base.TestCase): - def _test_attr_helper(self, expected_attrs, **decorator_args): - @decorators.attr(**decorator_args) - def foo(): - pass - - # By our decorators.attr decorator the attribute __testtools_attrs - # will be set only for 'type' argument, so we test it first. - if 'type' in decorator_args: - # this is what testtools sets - self.assertEqual(getattr(foo, '__testtools_attrs'), - set(expected_attrs)) - - def test_attr_without_type(self): - self._test_attr_helper(expected_attrs='baz', bar='baz') - - def test_attr_decorator_with_list_type(self): - # if type is 'smoke' we'll get the original list of types - self._test_attr_helper(expected_attrs=['smoke', 'foo'], - type=['smoke', 'foo']) - - def test_attr_decorator_with_unknown_type(self): - self._test_attr_helper(expected_attrs=['foo'], type='foo') - - def test_attr_decorator_with_duplicated_type(self): - self._test_attr_helper(expected_attrs=['foo'], type=['foo', 'foo']) - - -class TestSkipBecauseDecorator(base.TestCase): - def _test_skip_because_helper(self, expected_to_skip=True, - **decorator_args): - class TestFoo(test.BaseTestCase): - _interface = 'json' - - @decorators.skip_because(**decorator_args) - def test_bar(self): - return 0 - - t = TestFoo('test_bar') - if expected_to_skip: - self.assertRaises(testtools.TestCase.skipException, t.test_bar) - else: - # assert that test_bar returned 0 - self.assertEqual(TestFoo('test_bar').test_bar(), 0) - - def test_skip_because_bug(self): - self._test_skip_because_helper(bug='12345') - - def test_skip_because_bug_and_condition_true(self): - self._test_skip_because_helper(bug='12348', condition=True) - - def test_skip_because_bug_and_condition_false(self): - self._test_skip_because_helper(expected_to_skip=False, - bug='12349', condition=False) - - def test_skip_because_bug_without_bug_never_skips(self): - """Never skip without a bug parameter.""" - self._test_skip_because_helper(expected_to_skip=False, - condition=True) - self._test_skip_because_helper(expected_to_skip=False) - - def test_skip_because_invalid_bug_number(self): - """Raise ValueError if with an invalid bug number""" - self.assertRaises(ValueError, self._test_skip_because_helper, - bug='critical_bug') - - -class TestIdempotentIdDecorator(base.TestCase): - def _test_helper(self, _id, **decorator_args): - @decorators.idempotent_id(_id) - def foo(): - """Docstring""" - pass - - return foo - - def _test_helper_without_doc(self, _id, **decorator_args): - @decorators.idempotent_id(_id) - def foo(): - pass - - return foo - - def test_positive(self): - _id = data_utils.rand_uuid() - foo = self._test_helper(_id) - self.assertIn('id-%s' % _id, getattr(foo, '__testtools_attrs')) - self.assertTrue(foo.__doc__.startswith('Test idempotent id: %s' % _id)) - - def test_positive_without_doc(self): - _id = data_utils.rand_uuid() - foo = self._test_helper_without_doc(_id) - self.assertTrue(foo.__doc__.startswith('Test idempotent id: %s' % _id)) - - def test_idempotent_id_not_str(self): - _id = 42 - self.assertRaises(TypeError, self._test_helper, _id) - - def test_idempotent_id_not_valid_uuid(self): - _id = '42' - self.assertRaises(ValueError, self._test_helper, _id) - - -class TestSkipUnlessAttrDecorator(base.TestCase): - def _test_skip_unless_attr(self, attr, expected_to_skip=True): - class TestFoo(test.BaseTestCase): - expected_attr = not expected_to_skip - - @decorators.skip_unless_attr(attr) - def test_foo(self): - pass - - t = TestFoo('test_foo') - if expected_to_skip: - self.assertRaises(testtools.TestCase.skipException, - t.test_foo) - else: - try: - t.test_foo() - except Exception: - raise testtools.TestCase.failureException() - - def test_skip_attr_does_not_exist(self): - self._test_skip_unless_attr('unexpected_attr') - - def test_skip_attr_false(self): - self._test_skip_unless_attr('expected_attr') - - def test_no_skip_for_attr_exist_and_true(self): - self._test_skip_unless_attr('expected_attr', expected_to_skip=False) - - -class TestRelatedBugDecorator(base.TestCase): - def test_relatedbug_when_no_exception(self): - f = mock.Mock() - sentinel = object() - - @decorators.related_bug(bug="1234", status_code=500) - def test_foo(self): - f(self) - - test_foo(sentinel) - f.assert_called_once_with(sentinel) - - def test_relatedbug_when_exception(self): - class MyException(Exception): - def __init__(self, status_code): - self.status_code = status_code - - def f(self): - raise MyException(status_code=500) - - @decorators.related_bug(bug="1234", status_code=500) - def test_foo(self): - f(self) - - with mock.patch.object(decorators.LOG, 'error') as m_error: - self.assertRaises(MyException, test_foo, object()) - - m_error.assert_called_once_with(mock.ANY, '1234', '1234') diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py deleted file mode 100644 index a16da1c15..000000000 --- a/tempest/tests/lib/test_ssh.py +++ /dev/null @@ -1,305 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from io import StringIO -import socket - -import mock -import six -import testtools - -from tempest.lib.common import ssh -from tempest.lib import exceptions -from tempest.tests import base -import tempest.tests.utils as utils - - -class TestSshClient(base.TestCase): - - SELECT_POLLIN = 1 - - @mock.patch('paramiko.RSAKey.from_private_key') - @mock.patch('six.StringIO') - def test_pkey_calls_paramiko_RSAKey(self, cs_mock, rsa_mock): - cs_mock.return_value = mock.sentinel.csio - pkey = 'mykey' - ssh.Client('localhost', 'root', pkey=pkey) - rsa_mock.assert_called_once_with(mock.sentinel.csio) - cs_mock.assert_called_once_with('mykey') - rsa_mock.reset_mock() - cs_mock.reset_mock() - pkey = mock.sentinel.pkey - # Shouldn't call out to load a file from RSAKey, since - # a sentinel isn't a basestring... - ssh.Client('localhost', 'root', pkey=pkey) - self.assertEqual(0, rsa_mock.call_count) - self.assertEqual(0, cs_mock.call_count) - - def _set_ssh_connection_mocks(self): - client_mock = mock.MagicMock() - client_mock.connect.return_value = True - return (self.patch('paramiko.SSHClient'), - self.patch('paramiko.AutoAddPolicy'), - client_mock) - - def test_get_ssh_connection(self): - c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks() - s_mock = self.patch('time.sleep') - - c_mock.return_value = client_mock - aa_mock.return_value = mock.sentinel.aa - - # Test normal case for successful connection on first try - client = ssh.Client('localhost', 'root', timeout=2) - client._get_ssh_connection(sleep=1) - - aa_mock.assert_called_once_with() - client_mock.set_missing_host_key_policy.assert_called_once_with( - mock.sentinel.aa) - expected_connect = [mock.call( - 'localhost', - port=22, - username='root', - pkey=None, - key_filename=None, - look_for_keys=False, - timeout=10.0, - password=None, - sock=None - )] - self.assertEqual(expected_connect, client_mock.connect.mock_calls) - self.assertEqual(0, s_mock.call_count) - - def test_get_ssh_connection_over_ssh(self): - c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks() - proxy_client_mock = mock.MagicMock() - proxy_client_mock.connect.return_value = True - s_mock = self.patch('time.sleep') - - c_mock.side_effect = [client_mock, proxy_client_mock] - aa_mock.return_value = mock.sentinel.aa - - proxy_client = ssh.Client('proxy-host', 'proxy-user', timeout=2) - client = ssh.Client('localhost', 'root', timeout=2, - proxy_client=proxy_client) - client._get_ssh_connection(sleep=1) - - aa_mock.assert_has_calls([mock.call(), mock.call()]) - proxy_client_mock.set_missing_host_key_policy.assert_called_once_with( - mock.sentinel.aa) - proxy_expected_connect = [mock.call( - 'proxy-host', - port=22, - username='proxy-user', - pkey=None, - key_filename=None, - look_for_keys=False, - timeout=10.0, - password=None, - sock=None - )] - self.assertEqual(proxy_expected_connect, - proxy_client_mock.connect.mock_calls) - client_mock.set_missing_host_key_policy.assert_called_once_with( - mock.sentinel.aa) - expected_connect = [mock.call( - 'localhost', - port=22, - username='root', - pkey=None, - key_filename=None, - look_for_keys=False, - timeout=10.0, - password=None, - sock=proxy_client_mock.get_transport().open_session() - )] - self.assertEqual(expected_connect, client_mock.connect.mock_calls) - self.assertEqual(0, s_mock.call_count) - - @mock.patch('time.sleep') - def test_get_ssh_connection_two_attemps(self, sleep_mock): - c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks() - - c_mock.return_value = client_mock - client_mock.connect.side_effect = [ - socket.error, - mock.MagicMock() - ] - - client = ssh.Client('localhost', 'root', timeout=1) - client._get_ssh_connection(sleep=1) - # We slept 2 seconds: because sleep is "1" and backoff is "1" too - sleep_mock.assert_called_once_with(2) - self.assertEqual(2, client_mock.connect.call_count) - - def test_get_ssh_connection_timeout(self): - c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks() - - timeout = 2 - time_mock = self.patch('time.time') - time_mock.side_effect = utils.generate_timeout_series(timeout + 1) - - c_mock.return_value = client_mock - client_mock.connect.side_effect = [ - socket.error, - socket.error, - socket.error, - ] - - client = ssh.Client('localhost', 'root', timeout=timeout) - # We need to mock LOG here because LOG.info() calls time.time() - # in order to preprend a timestamp. - with mock.patch.object(ssh, 'LOG'): - self.assertRaises(exceptions.SSHTimeout, - client._get_ssh_connection) - - # time.time() should be called twice, first to start the timer - # and then to compute the timedelta - self.assertEqual(2, time_mock.call_count) - - @mock.patch('select.POLLIN', SELECT_POLLIN, create=True) - def test_timeout_in_exec_command(self): - chan_mock, poll_mock, _ = self._set_mocks_for_select([0, 0, 0], True) - - # Test for a timeout condition immediately raised - client = ssh.Client('localhost', 'root', timeout=2) - with testtools.ExpectedException(exceptions.TimeoutException): - client.exec_command("test") - - chan_mock.fileno.assert_called_once_with() - chan_mock.exec_command.assert_called_once_with("test") - chan_mock.shutdown_write.assert_called_once_with() - - poll_mock.register.assert_called_once_with( - chan_mock, self.SELECT_POLLIN) - poll_mock.poll.assert_called_once_with(10) - - @mock.patch('select.POLLIN', SELECT_POLLIN, create=True) - def test_exec_command(self): - chan_mock, poll_mock, select_mock = ( - self._set_mocks_for_select([[1, 0, 0]], True)) - - chan_mock.recv_exit_status.return_value = 0 - chan_mock.recv.return_value = b'' - chan_mock.recv_stderr.return_value = b'' - - client = ssh.Client('localhost', 'root', timeout=2) - client.exec_command("test") - - chan_mock.fileno.assert_called_once_with() - chan_mock.exec_command.assert_called_once_with("test") - chan_mock.shutdown_write.assert_called_once_with() - - select_mock.assert_called_once_with() - poll_mock.register.assert_called_once_with( - chan_mock, self.SELECT_POLLIN) - poll_mock.poll.assert_called_once_with(10) - chan_mock.recv_ready.assert_called_once_with() - chan_mock.recv.assert_called_once_with(1024) - chan_mock.recv_stderr_ready.assert_called_once_with() - chan_mock.recv_stderr.assert_called_once_with(1024) - chan_mock.recv_exit_status.assert_called_once_with() - - def _set_mocks_for_select(self, poll_data, ito_value=False): - gsc_mock = self.patch('tempest.lib.common.ssh.Client.' - '_get_ssh_connection') - ito_mock = self.patch('tempest.lib.common.ssh.Client._is_timed_out') - csp_mock = self.patch( - 'tempest.lib.common.ssh.Client._can_system_poll') - csp_mock.return_value = True - - select_mock = self.patch('select.poll', create=True) - client_mock = mock.MagicMock() - tran_mock = mock.MagicMock() - chan_mock = mock.MagicMock() - poll_mock = mock.MagicMock() - - select_mock.return_value = poll_mock - gsc_mock.return_value = client_mock - ito_mock.return_value = ito_value - client_mock.get_transport.return_value = tran_mock - tran_mock.open_session().__enter__.return_value = chan_mock - if isinstance(poll_data[0], list): - poll_mock.poll.side_effect = poll_data - else: - poll_mock.poll.return_value = poll_data - - return chan_mock, poll_mock, select_mock - - _utf8_string = six.unichr(1071) - _utf8_bytes = _utf8_string.encode("utf-8") - - @mock.patch('select.POLLIN', SELECT_POLLIN, create=True) - def test_exec_good_command_output(self): - chan_mock, poll_mock, _ = self._set_mocks_for_select([1, 0, 0]) - closed_prop = mock.PropertyMock(return_value=True) - type(chan_mock).closed = closed_prop - - chan_mock.recv_exit_status.return_value = 0 - chan_mock.recv.side_effect = [self._utf8_bytes[0:1], - self._utf8_bytes[1:], b'R', b''] - chan_mock.recv_stderr.return_value = b'' - - client = ssh.Client('localhost', 'root', timeout=2) - out_data = client.exec_command("test") - self.assertEqual(self._utf8_string + 'R', out_data) - - @mock.patch('select.POLLIN', SELECT_POLLIN, create=True) - def test_exec_bad_command_output(self): - chan_mock, poll_mock, _ = self._set_mocks_for_select([1, 0, 0]) - closed_prop = mock.PropertyMock(return_value=True) - type(chan_mock).closed = closed_prop - - chan_mock.recv_exit_status.return_value = 1 - chan_mock.recv.return_value = b'' - chan_mock.recv_stderr.side_effect = [b'R', self._utf8_bytes[0:1], - self._utf8_bytes[1:], b''] - - client = ssh.Client('localhost', 'root', timeout=2) - exc = self.assertRaises(exceptions.SSHExecCommandFailed, - client.exec_command, "test") - self.assertIn('R' + self._utf8_string, six.text_type(exc)) - - def test_exec_command_no_select(self): - gsc_mock = self.patch('tempest.lib.common.ssh.Client.' - '_get_ssh_connection') - csp_mock = self.patch( - 'tempest.lib.common.ssh.Client._can_system_poll') - csp_mock.return_value = False - - select_mock = self.patch('select.poll', create=True) - client_mock = mock.MagicMock() - tran_mock = mock.MagicMock() - chan_mock = mock.MagicMock() - - # Test for proper reading of STDOUT and STDERROR - - gsc_mock.return_value = client_mock - client_mock.get_transport.return_value = tran_mock - tran_mock.open_session().__enter__.return_value = chan_mock - chan_mock.recv_exit_status.return_value = 0 - - std_out_mock = mock.MagicMock(StringIO) - std_err_mock = mock.MagicMock(StringIO) - chan_mock.makefile.return_value = std_out_mock - chan_mock.makefile_stderr.return_value = std_err_mock - - client = ssh.Client('localhost', 'root', timeout=2) - client.exec_command("test") - - chan_mock.makefile.assert_called_once_with('rb', 1024) - chan_mock.makefile_stderr.assert_called_once_with('rb', 1024) - std_out_mock.read.assert_called_once_with() - std_err_mock.read.assert_called_once_with() - self.assertFalse(select_mock.called) diff --git a/tempest/tests/lib/test_tempest_lib.py b/tempest/tests/lib/test_tempest_lib.py deleted file mode 100644 index 4d9f09989..000000000 --- a/tempest/tests/lib/test_tempest_lib.py +++ /dev/null @@ -1,26 +0,0 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -test_tempest.lib ----------------------------------- - -Tests for `tempest.lib` module. -""" - -from tempest.tests import base - - -class TestTempest_lib(base.TestCase): - - def test_something(self): - pass diff --git a/tempest/tests/services/__init__.py b/tempest/tests/services/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/services/object_storage/__init__.py b/tempest/tests/services/object_storage/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/services/object_storage/test_bulk_middleware_client.py b/tempest/tests/services/object_storage/test_bulk_middleware_client.py deleted file mode 100644 index 163b48e6f..000000000 --- a/tempest/tests/services/object_storage/test_bulk_middleware_client.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2017 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.services.object_storage import bulk_middleware_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestBulkMiddlewareClient(base.BaseServiceTest): - - def setUp(self): - super(TestBulkMiddlewareClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = bulk_middleware_client.BulkMiddlewareClient( - fake_auth, 'object-storage', 'regionOne') - - def test_upload_archive(self): - url = 'test_path?extract-archive=tar' - data = 'test_data' - self.check_service_client_function( - self.client.upload_archive, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - mock_args=[url, data, {}], - resp_as_string=True, - upload_path='test_path', data=data, archive_file_format='tar') - - def test_delete_bulk_data(self): - url = '?bulk-delete' - data = 'test_data' - self.check_service_client_function( - self.client.delete_bulk_data, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - mock_args=[url, {}, data], - resp_as_string=True, - data=data) - - def _test_delete_bulk_data_with_post(self, status): - url = '?bulk-delete' - data = 'test_data' - self.check_service_client_function( - self.client.delete_bulk_data_with_post, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - mock_args=[url, data, {}], - resp_as_string=True, - status=status, - data=data) - - def test_delete_bulk_data_with_post_200(self): - self._test_delete_bulk_data_with_post(200) - - def test_delete_bulk_data_with_post_204(self): - self._test_delete_bulk_data_with_post(204) diff --git a/tempest/tests/services/object_storage/test_capabilities_client.py b/tempest/tests/services/object_storage/test_capabilities_client.py deleted file mode 100644 index 5279bf474..000000000 --- a/tempest/tests/services/object_storage/test_capabilities_client.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2016 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.services.object_storage import capabilities_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestCapabilitiesClient(base.BaseServiceTest): - - def setUp(self): - super(TestCapabilitiesClient, self).setUp() - self.fake_auth = fake_auth_provider.FakeAuthProvider() - self.url = self.fake_auth.base_url(None) - self.client = capabilities_client.CapabilitiesClient( - self.fake_auth, 'swift', 'region1') - - def _test_list_capabilities(self, bytes_body=False): - resp = { - "swift": { - "version": "1.11.0" - }, - "slo": { - "max_manifest_segments": 1000, - "max_manifest_size": 2097152, - "min_segment_size": 1 - }, - "staticweb": {}, - "tempurl": {} - } - self.check_service_client_function( - self.client.list_capabilities, - 'tempest.lib.common.rest_client.RestClient.get', - resp, - bytes_body) - - def test_list_capabilities_with_str_body(self): - self._test_list_capabilities() - - def test_list_capabilities_with_bytes_body(self): - self._test_list_capabilities(True) diff --git a/tempest/tests/services/object_storage/test_object_client.py b/tempest/tests/services/object_storage/test_object_client.py deleted file mode 100644 index 748614c7e..000000000 --- a/tempest/tests/services/object_storage/test_object_client.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2016 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -import mock - -from tempest.lib import exceptions -from tempest.services.object_storage import object_client -from tempest.tests import base -from tempest.tests.lib import fake_auth_provider - - -class TestObjectClient(base.TestCase): - - def setUp(self): - super(TestObjectClient, self).setUp() - self.fake_auth = fake_auth_provider.FakeAuthProvider() - self.url = self.fake_auth.base_url(None) - self.object_client = object_client.ObjectClient(self.fake_auth, - 'swift', 'region1') - - @mock.patch.object(object_client, 'create_connection') - def test_create_object_continue_no_data(self, mock_poc): - self._validate_create_object_continue(None, mock_poc) - - @mock.patch.object(object_client, 'create_connection') - def test_create_object_continue_with_data(self, mock_poc): - self._validate_create_object_continue('hello', mock_poc) - - @mock.patch.object(object_client, 'create_connection') - def test_create_continue_with_no_continue_received(self, mock_poc): - self._validate_create_object_continue('hello', mock_poc, - initial_status=201) - - def _validate_create_object_continue(self, req_data, - mock_poc, initial_status=100): - - expected_hdrs = { - 'X-Auth-Token': self.fake_auth.get_token(), - 'content-length': 0 if req_data is None else len(req_data), - 'Expect': '100-continue'} - - # Setup the Mocks prior to invoking the object creation - mock_resp_cls = mock.Mock() - mock_resp_cls._read_status.return_value = ("1", initial_status, "OK") - - mock_poc.return_value.response_class.return_value = mock_resp_cls - - # This is the final expected return value - mock_poc.return_value.getresponse.return_value.status = 201 - mock_poc.return_value.getresponse.return_value.reason = 'OK' - - # Call method to PUT object using expect:100-continue - cnt = "container1" - obj = "object1" - path = "/%s/%s" % (cnt, obj) - - # If the expected initial status is not 100, then an exception - # should be thrown and the connection closed - if initial_status is 100: - status, reason = \ - self.object_client.create_object_continue(cnt, obj, req_data) - else: - self.assertRaises(exceptions.UnexpectedResponseCode, - self.object_client.create_object_continue, cnt, - obj, req_data) - mock_poc.return_value.close.assert_called_once_with() - - # Verify that putrequest is called 1 time with the appropriate values - mock_poc.return_value.putrequest.assert_called_once_with('PUT', path) - - # Verify that headers were written, including "Expect:100-continue" - calls = [] - - for header, value in expected_hdrs.items(): - calls.append(mock.call(header, value)) - - mock_poc.return_value.putheader.assert_has_calls(calls, False) - mock_poc.return_value.endheaders.assert_called_once_with() - - # The following steps are only taken if the initial status is 100 - if initial_status is 100: - # Verify that the method returned what it was supposed to - self.assertEqual(status, 201) - - # Verify that _safe_read was called once to remove the CRLF - # after the 100 response - mock_rc = mock_poc.return_value.response_class.return_value - mock_rc._safe_read.assert_called_once_with(2) - - # Verify the actual data was written via send - mock_poc.return_value.send.assert_called_once_with(req_data) - - # Verify that the getresponse method was called to receive - # the final - mock_poc.return_value.getresponse.assert_called_once_with() diff --git a/tempest/tests/test_base_test.py b/tempest/tests/test_base_test.py deleted file mode 100644 index 6c6f612e2..000000000 --- a/tempest/tests/test_base_test.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright 2016 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import mock - -from tempest import clients -from tempest.common import credentials_factory as credentials -from tempest import config -from tempest.lib.common import fixed_network -from tempest import test -from tempest.tests import base -from tempest.tests import fake_config - - -class TestBaseTestCase(base.TestCase): - def setUp(self): - super(TestBaseTestCase, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.fixed_network_name = 'fixed-net' - config.CONF.compute.fixed_network_name = self.fixed_network_name - config.CONF.service_available.neutron = True - - @mock.patch.object(test.BaseTestCase, 'get_client_manager') - @mock.patch.object(test.BaseTestCase, '_get_credentials_provider') - @mock.patch.object(fixed_network, 'get_tenant_network') - def test_get_tenant_network(self, mock_gtn, mock_gprov, mock_gcm): - net_client = mock.Mock() - mock_prov = mock.Mock() - mock_gcm.return_value.compute_networks_client = net_client - mock_gprov.return_value = mock_prov - - test.BaseTestCase.get_tenant_network() - - mock_gcm.assert_called_once_with(credential_type='primary') - mock_gprov.assert_called_once_with() - mock_gtn.assert_called_once_with(mock_prov, net_client, - self.fixed_network_name) - - @mock.patch.object(test.BaseTestCase, 'get_client_manager') - @mock.patch.object(test.BaseTestCase, '_get_credentials_provider') - @mock.patch.object(fixed_network, 'get_tenant_network') - @mock.patch.object(test.BaseTestCase, 'get_identity_version') - @mock.patch.object(credentials, 'is_admin_available') - @mock.patch.object(clients, 'Manager') - def test_get_tenant_network_with_nova_net(self, mock_man, mock_iaa, - mock_giv, mock_gtn, mock_gcp, - mock_gcm): - config.CONF.service_available.neutron = False - mock_prov = mock.Mock() - mock_admin_man = mock.Mock() - mock_iaa.return_value = True - mock_gcp.return_value = mock_prov - mock_man.return_value = mock_admin_man - - test.BaseTestCase.get_tenant_network() - - mock_man.assert_called_once_with( - mock_prov.get_admin_creds.return_value.credentials) - mock_iaa.assert_called_once_with( - identity_version=mock_giv.return_value) - mock_gcp.assert_called_once_with() - mock_gtn.assert_called_once_with( - mock_prov, mock_admin_man.compute_networks_client, - self.fixed_network_name) - - @mock.patch.object(test.BaseTestCase, 'get_client_manager') - @mock.patch.object(test.BaseTestCase, '_get_credentials_provider') - @mock.patch.object(fixed_network, 'get_tenant_network') - def test_get_tenant_network_with_alt_creds(self, mock_gtn, mock_gprov, - mock_gcm): - net_client = mock.Mock() - mock_prov = mock.Mock() - mock_gcm.return_value.compute_networks_client = net_client - mock_gprov.return_value = mock_prov - - test.BaseTestCase.get_tenant_network(credentials_type='alt') - - mock_gcm.assert_called_once_with(credential_type='alt') - mock_gprov.assert_called_once_with() - mock_gtn.assert_called_once_with(mock_prov, net_client, - self.fixed_network_name) - - @mock.patch.object(test.BaseTestCase, 'get_client_manager') - @mock.patch.object(test.BaseTestCase, '_get_credentials_provider') - @mock.patch.object(fixed_network, 'get_tenant_network') - def test_get_tenant_network_with_role_creds(self, mock_gtn, mock_gprov, - mock_gcm): - net_client = mock.Mock() - mock_prov = mock.Mock() - mock_gcm.return_value.compute_networks_client = net_client - mock_gprov.return_value = mock_prov - creds = ['foo_type', 'role1'] - - test.BaseTestCase.get_tenant_network(credentials_type=creds) - - mock_gcm.assert_called_once_with(roles=['role1']) - mock_gprov.assert_called_once_with() - mock_gtn.assert_called_once_with(mock_prov, net_client, - self.fixed_network_name) diff --git a/tempest/tests/test_config.py b/tempest/tests/test_config.py deleted file mode 100644 index 2808a9cf9..000000000 --- a/tempest/tests/test_config.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - -import testtools - -from tempest import config -from tempest.lib import exceptions -from tempest.tests import base -from tempest.tests import fake_config - - -class TestServiceClientConfig(base.TestCase): - - expected_common_params = set(['disable_ssl_certificate_validation', - 'ca_certs', 'trace_requests']) - expected_extra_params = set(['service', 'endpoint_type', 'region', - 'build_timeout', 'build_interval']) - - def setUp(self): - super(TestServiceClientConfig, self).setUp() - self.useFixture(fake_config.ServiceClientsConfigFixture()) - self.patchobject(config, 'CONF', - fake_config.ServiceClientsFakePrivate()) - self.CONF = config.CONF - - def test_service_client_config_no_service(self): - params = config.service_client_config() - for param_name in self.expected_common_params: - self.assertIn(param_name, params) - for param_name in self.expected_extra_params: - self.assertNotIn(param_name, params) - self.assertEqual( - self.CONF.identity.disable_ssl_certificate_validation, - params['disable_ssl_certificate_validation']) - self.assertEqual(self.CONF.identity.ca_certificates_file, - params['ca_certs']) - self.assertEqual(self.CONF.debug.trace_requests, - params['trace_requests']) - - def test_service_client_config_service_all(self): - params = config.service_client_config( - service_client_name='fake-service1') - for param_name in self.expected_common_params: - self.assertIn(param_name, params) - for param_name in self.expected_extra_params: - self.assertIn(param_name, params) - self.assertEqual(self.CONF.fake_service1.catalog_type, - params['service']) - self.assertEqual(self.CONF.fake_service1.endpoint_type, - params['endpoint_type']) - self.assertEqual(self.CONF.fake_service1.region, params['region']) - self.assertEqual(self.CONF.fake_service1.build_timeout, - params['build_timeout']) - self.assertEqual(self.CONF.fake_service1.build_interval, - params['build_interval']) - - def test_service_client_config_service_minimal(self): - params = config.service_client_config( - service_client_name='fake-service2') - for param_name in self.expected_common_params: - self.assertIn(param_name, params) - for param_name in self.expected_extra_params: - self.assertIn(param_name, params) - self.assertEqual(self.CONF.fake_service2.catalog_type, - params['service']) - self.assertEqual(self.CONF.fake_service2.endpoint_type, - params['endpoint_type']) - self.assertEqual(self.CONF.identity.region, params['region']) - self.assertEqual(self.CONF.compute.build_timeout, - params['build_timeout']) - self.assertEqual(self.CONF.compute.build_interval, - params['build_interval']) - - def test_service_client_config_service_unknown(self): - unknown_service = 'unknown_service' - with testtools.ExpectedException(exceptions.UnknownServiceClient, - '.*' + unknown_service + '.*'): - config.service_client_config(service_client_name=unknown_service) diff --git a/tempest/tests/test_decorators.py b/tempest/tests/test_decorators.py deleted file mode 100644 index 2fc84dc6e..000000000 --- a/tempest/tests/test_decorators.py +++ /dev/null @@ -1,265 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures -from oslo_config import cfg -import testtools - -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest import test -from tempest.tests import base -from tempest.tests import fake_config - - -class BaseDecoratorsTest(base.TestCase): - def setUp(self): - super(BaseDecoratorsTest, self).setUp() - self.config_fixture = self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - - -class TestIdempotentIdDecorator(BaseDecoratorsTest): - - def _test_helper(self, _id, **decorator_args): - @test.idempotent_id(_id) - def foo(): - """Docstring""" - pass - - return foo - - def _test_helper_without_doc(self, _id, **decorator_args): - @test.idempotent_id(_id) - def foo(): - pass - - return foo - - def test_positive(self): - _id = data_utils.rand_uuid() - foo = self._test_helper(_id) - self.assertIn('id-%s' % _id, getattr(foo, '__testtools_attrs')) - self.assertTrue(foo.__doc__.startswith('Test idempotent id: %s' % _id)) - - def test_positive_without_doc(self): - _id = data_utils.rand_uuid() - foo = self._test_helper_without_doc(_id) - self.assertTrue(foo.__doc__.startswith('Test idempotent id: %s' % _id)) - - def test_idempotent_id_not_str(self): - _id = 42 - self.assertRaises(TypeError, self._test_helper, _id) - - def test_idempotent_id_not_valid_uuid(self): - _id = '42' - self.assertRaises(ValueError, self._test_helper, _id) - - -class TestServicesDecorator(BaseDecoratorsTest): - def _test_services_helper(self, *decorator_args): - class TestFoo(test.BaseTestCase): - @test.services(*decorator_args) - def test_bar(self): - return 0 - - t = TestFoo('test_bar') - self.assertEqual(set(decorator_args), getattr(t.test_bar, - '__testtools_attrs')) - self.assertEqual(t.test_bar(), 0) - - def test_services_decorator_with_single_service(self): - self._test_services_helper('compute') - - def test_services_decorator_with_multiple_services(self): - self._test_services_helper('compute', 'network') - - def test_services_decorator_with_duplicated_service(self): - self._test_services_helper('compute', 'compute') - - def test_services_decorator_with_invalid_service(self): - self.assertRaises(test.InvalidServiceTag, - self._test_services_helper, 'compute', - 'bad_service') - - def test_services_decorator_with_service_valid_and_unavailable(self): - self.useFixture(fixtures.MockPatchObject(test.CONF.service_available, - 'cinder', False)) - self.assertRaises(testtools.TestCase.skipException, - self._test_services_helper, 'compute', - 'volume') - - def test_services_list(self): - service_list = test.get_service_list() - for service in service_list: - try: - self._test_services_helper(service) - except test.InvalidServiceTag: - self.fail('%s is not listed in the valid service tag list' - % service) - except KeyError: - # NOTE(mtreinish): This condition is to test for an entry in - # the outer decorator list but not in the service_list dict. - # However, because we're looping over the service_list dict - # it's unlikely we'll trigger this. So manual review is still - # need for the list in the outer decorator. - self.fail('%s is in the list of valid service tags but there ' - 'is no corresponding entry in the dict returned from' - ' get_service_list()' % service) - except testtools.TestCase.skipException: - # Test didn't raise an exception because of an incorrect list - # entry so move onto the next entry - continue - - -class TestRequiresExtDecorator(BaseDecoratorsTest): - def setUp(self): - super(TestRequiresExtDecorator, self).setUp() - cfg.CONF.set_default('api_extensions', ['enabled_ext', 'another_ext'], - 'compute-feature-enabled') - - def _test_requires_ext_helper(self, expected_to_skip=True, - **decorator_args): - class TestFoo(test.BaseTestCase): - @test.requires_ext(**decorator_args) - def test_bar(self): - return 0 - - t = TestFoo('test_bar') - if expected_to_skip: - self.assertRaises(testtools.TestCase.skipException, t.test_bar) - else: - try: - self.assertEqual(t.test_bar(), 0) - except testtools.TestCase.skipException: - # We caught a skipException but we didn't expect to skip - # this test so raise a hard test failure instead. - raise testtools.TestCase.failureException( - "Not supposed to skip") - - def test_requires_ext_decorator(self): - self._test_requires_ext_helper(expected_to_skip=False, - extension='enabled_ext', - service='compute') - - def test_requires_ext_decorator_disabled_ext(self): - self._test_requires_ext_helper(extension='disabled_ext', - service='compute') - - def test_requires_ext_decorator_with_all_ext_enabled(self): - cfg.CONF.set_default('api_extensions', ['all'], - group='compute-feature-enabled') - self._test_requires_ext_helper(expected_to_skip=False, - extension='random_ext', - service='compute') - - def test_requires_ext_decorator_bad_service(self): - self.assertRaises(KeyError, - self._test_requires_ext_helper, - extension='enabled_ext', - service='bad_service') - - -class TestConfigDecorators(BaseDecoratorsTest): - def setUp(self): - super(TestConfigDecorators, self).setUp() - cfg.CONF.set_default('nova', True, 'service_available') - cfg.CONF.set_default('glance', False, 'service_available') - - def _assert_skip_message(self, func, skip_msg): - try: - func() - self.fail() - except testtools.TestCase.skipException as skip_exc: - self.assertEqual(skip_exc.args[0], skip_msg) - - def _test_skip_unless_config(self, expected_to_skip=True, *decorator_args): - - class TestFoo(test.BaseTestCase): - @config.skip_unless_config(*decorator_args) - def test_bar(self): - return 0 - - t = TestFoo('test_bar') - if expected_to_skip: - self.assertRaises(testtools.TestCase.skipException, t.test_bar) - if (len(decorator_args) >= 3): - # decorator_args[2]: skip message specified - self._assert_skip_message(t.test_bar, decorator_args[2]) - else: - try: - self.assertEqual(t.test_bar(), 0) - except testtools.TestCase.skipException: - # We caught a skipException but we didn't expect to skip - # this test so raise a hard test failure instead. - raise testtools.TestCase.failureException( - "Not supposed to skip") - - def _test_skip_if_config(self, expected_to_skip=True, - *decorator_args): - - class TestFoo(test.BaseTestCase): - @config.skip_if_config(*decorator_args) - def test_bar(self): - return 0 - - t = TestFoo('test_bar') - if expected_to_skip: - self.assertRaises(testtools.TestCase.skipException, t.test_bar) - if (len(decorator_args) >= 3): - # decorator_args[2]: skip message specified - self._assert_skip_message(t.test_bar, decorator_args[2]) - else: - try: - self.assertEqual(t.test_bar(), 0) - except testtools.TestCase.skipException: - # We caught a skipException but we didn't expect to skip - # this test so raise a hard test failure instead. - raise testtools.TestCase.failureException( - "Not supposed to skip") - - def test_skip_unless_no_group(self): - self._test_skip_unless_config(True, 'fake_group', 'an_option') - - def test_skip_unless_no_option(self): - self._test_skip_unless_config(True, 'service_available', - 'not_an_option') - - def test_skip_unless_false_option(self): - self._test_skip_unless_config(True, 'service_available', 'glance') - - def test_skip_unless_false_option_msg(self): - self._test_skip_unless_config(True, 'service_available', 'glance', - 'skip message') - - def test_skip_unless_true_option(self): - self._test_skip_unless_config(False, - 'service_available', 'nova') - - def test_skip_if_no_group(self): - self._test_skip_if_config(False, 'fake_group', 'an_option') - - def test_skip_if_no_option(self): - self._test_skip_if_config(False, 'service_available', 'not_an_option') - - def test_skip_if_false_option(self): - self._test_skip_if_config(False, 'service_available', 'glance') - - def test_skip_if_true_option(self): - self._test_skip_if_config(True, 'service_available', 'nova') - - def test_skip_if_true_option_msg(self): - self._test_skip_if_config(True, 'service_available', 'nova', - 'skip message') diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py deleted file mode 100644 index f005c219f..000000000 --- a/tempest/tests/test_hacking.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2014 Matthew Treinish -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.hacking import checks -from tempest.tests import base - - -class HackingTestCase(base.TestCase): - """Test class for hacking rule - - This class tests the hacking checks in tempest.hacking.checks by passing - strings to the check methods like the pep8/flake8 parser would. The parser - loops over each line in the file and then passes the parameters to the - check method. The parameter names in the check method dictate what type of - object is passed to the check method. The parameter types are:: - - logical_line: A processed line with the following modifications: - - Multi-line statements converted to a single line. - - Stripped left and right. - - Contents of strings replaced with "xxx" of same length. - - Comments removed. - physical_line: Raw line of text from the input file. - lines: a list of the raw lines from the input file - tokens: the tokens that contribute to this logical line - line_number: line number in the input file - total_lines: number of lines in the input file - blank_lines: blank lines before this one - indent_char: indentation character in this file (" " or "\t") - indent_level: indentation (with tabs expanded to multiples of 8) - previous_indent_level: indentation on previous line - previous_logical: previous logical line - filename: Path of the file being run through pep8 - - When running a test on a check method the return will be False/None if - there is no violation in the sample input. If there is an error a tuple is - returned with a position in the line, and a message. So to check the result - just assertTrue if the check is expected to fail and assertFalse if it - should pass. - """ - def test_no_setup_teardown_class_for_tests(self): - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls):", './tempest/tests/fake_test.py')) - self.assertIsNone(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls): # noqa", './tempest/tests/fake_test.py')) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls):", './tempest/api/fake_test.py')) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls):", './tempest/scenario/fake_test.py')) - self.assertFalse(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls):", './tempest/test.py')) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls):", './tempest/tests/fake_test.py')) - self.assertIsNone(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls): # noqa", './tempest/tests/fake_test.py')) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls):", './tempest/api/fake_test.py')) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls):", './tempest/scenario/fake_test.py')) - self.assertFalse(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls):", './tempest/test.py')) - - def test_import_no_clients_in_api_and_scenario_tests(self): - for client in checks.PYTHON_CLIENTS: - string = "import " + client + "client" - self.assertTrue( - checks.import_no_clients_in_api_and_scenario_tests( - string, './tempest/api/fake_test.py')) - self.assertTrue( - checks.import_no_clients_in_api_and_scenario_tests( - string, './tempest/scenario/fake_test.py')) - self.assertFalse( - checks.import_no_clients_in_api_and_scenario_tests( - string, './tempest/test.py')) - - def test_scenario_tests_need_service_tags(self): - self.assertFalse(checks.scenario_tests_need_service_tags( - 'def test_fake:', './tempest/scenario/test_fake.py', - "@test.services('compute')")) - self.assertFalse(checks.scenario_tests_need_service_tags( - 'def test_fake_test:', './tempest/api/compute/test_fake.py', - "@test.services('image')")) - self.assertFalse(checks.scenario_tests_need_service_tags( - 'def test_fake:', './tempest/scenario/orchestration/test_fake.py', - "@test.services('compute')")) - self.assertTrue(checks.scenario_tests_need_service_tags( - 'def test_fake_test:', './tempest/scenario/test_fake.py', - '\n')) - self.assertTrue(checks.scenario_tests_need_service_tags( - 'def test_fake:', './tempest/scenario/orchestration/test_fake.py', - "\n")) - - def test_no_vi_headers(self): - # NOTE(mtreinish) The lines parameter is used only for finding the - # line location in the file. So these tests just pass a list of an - # arbitrary length to use for verifying the check function. - self.assertTrue(checks.no_vi_headers( - '# vim: tabstop=4 shiftwidth=4 softtabstop=4', 1, range(250))) - self.assertTrue(checks.no_vi_headers( - '# vim: tabstop=4 shiftwidth=4 softtabstop=4', 249, range(250))) - self.assertFalse(checks.no_vi_headers( - '# vim: tabstop=4 shiftwidth=4 softtabstop=4', 149, range(250))) - - def test_service_tags_not_in_module_path(self): - self.assertTrue(checks.service_tags_not_in_module_path( - "@test.services('compute')", './tempest/api/compute/fake_test.py')) - self.assertFalse(checks.service_tags_not_in_module_path( - "@test.services('compute')", - './tempest/scenario/compute/fake_test.py')) - self.assertFalse(checks.service_tags_not_in_module_path( - "@test.services('compute')", './tempest/api/image/fake_test.py')) - - def test_no_hyphen_at_end_of_rand_name(self): - self.assertIsNone(checks.no_hyphen_at_end_of_rand_name( - 'data_utils.rand_name("fake-resource")', './tempest/test_foo.py')) - self.assertEqual(2, len(list(checks.no_hyphen_at_end_of_rand_name( - 'data_utils.rand_name("fake-resource-")', './tempest/test_foo.py') - ))) - - def test_no_mutable_default_args(self): - self.assertEqual(1, len(list(checks.no_mutable_default_args( - " def function1(para={}):")))) - - self.assertEqual(1, len(list(checks.no_mutable_default_args( - "def function2(para1, para2, para3=[])")))) - - self.assertEqual(0, len(list(checks.no_mutable_default_args( - "defined = []")))) - - self.assertEqual(0, len(list(checks.no_mutable_default_args( - "defined, undefined = [], {}")))) - - def test_no_testtools_skip_decorator(self): - self.assertEqual(1, len(list(checks.no_testtools_skip_decorator( - " @testtools.skip('Bug xxx')")))) - self.assertEqual(0, len(list(checks.no_testtools_skip_decorator( - " @testtools.skipUnless(CONF.something, 'msg')")))) - self.assertEqual(0, len(list(checks.no_testtools_skip_decorator( - " @testtools.skipIf(CONF.something, 'msg')")))) - - def test_dont_import_local_tempest_code_into_lib(self): - self.assertEqual(0, len(list(checks.dont_import_local_tempest_into_lib( - "from tempest.common import waiters", - './tempest/common/compute.py')))) - self.assertEqual(0, len(list(checks.dont_import_local_tempest_into_lib( - "from tempest import config", - './tempest/common/compute.py')))) - self.assertEqual(0, len(list(checks.dont_import_local_tempest_into_lib( - "import tempest.exception", - './tempest/common/compute.py')))) - self.assertEqual(1, len(list(checks.dont_import_local_tempest_into_lib( - "from tempest.common import waiters", - './tempest/lib/common/compute.py')))) - self.assertEqual(1, len(list(checks.dont_import_local_tempest_into_lib( - "from tempest import config", - './tempest/lib/common/compute.py')))) - self.assertEqual(1, len(list(checks.dont_import_local_tempest_into_lib( - "import tempest.exception", - './tempest/lib/common/compute.py')))) - - def test_dont_use_config_in_tempest_lib(self): - self.assertFalse(list(checks.dont_use_config_in_tempest_lib( - 'from tempest import config', './tempest/common/compute.py'))) - self.assertFalse(list(checks.dont_use_config_in_tempest_lib( - 'from oslo_concurrency import lockutils', - './tempest/lib/auth.py'))) - self.assertTrue(list(checks.dont_use_config_in_tempest_lib( - 'from tempest import config', './tempest/lib/auth.py'))) - self.assertTrue(list(checks.dont_use_config_in_tempest_lib( - 'from oslo_config import cfg', './tempest/lib/decorators.py'))) - self.assertTrue(list(checks.dont_use_config_in_tempest_lib( - 'import tempest.config', './tempest/lib/common/rest_client.py'))) diff --git a/tempest/tests/test_list_tests.py b/tempest/tests/test_list_tests.py deleted file mode 100644 index a23887965..000000000 --- a/tempest/tests/test_list_tests.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import os -import re -import subprocess - -import six - -from tempest.tests import base - - -class TestTestList(base.TestCase): - - def test_testr_list_tests_no_errors(self): - # Remove unit test discover path from env to test tempest tests - test_env = os.environ.copy() - test_env.pop('OS_TEST_PATH') - import_failures = [] - p = subprocess.Popen(['testr', 'list-tests'], stdout=subprocess.PIPE, - env=test_env) - ids, err = p.communicate() - self.assertEqual(0, p.returncode, - "test discovery failed, one or more files cause an " - "error on import %s" % ids) - ids = six.text_type(ids).split('\n') - for test_id in ids: - if re.match('(\w+\.){3}\w+', test_id): - if not test_id.startswith('tempest.'): - parts = test_id.partition('tempest') - fail_id = parts[1] + parts[2] - import_failures.append(fail_id) - error_message = ("The following tests have import failures and aren't" - " being run with test filters %s" % import_failures) - self.assertFalse(import_failures, error_message) diff --git a/tempest/tests/test_microversions.py b/tempest/tests/test_microversions.py deleted file mode 100644 index 173accbd5..000000000 --- a/tempest/tests/test_microversions.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright 2015 NEC Corporation. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from oslo_config import cfg -import testtools - -from tempest.api.compute import base as compute_base -from tempest import config -from tempest.lib import exceptions -from tempest.tests import base -from tempest.tests import fake_config - - -class VersionTestNoneTolatest(compute_base.BaseV2ComputeTest): - min_microversion = None - max_microversion = 'latest' - - -class VersionTestNoneTo2_2(compute_base.BaseV2ComputeTest): - min_microversion = None - max_microversion = '2.2' - - -class VersionTest2_3ToLatest(compute_base.BaseV2ComputeTest): - min_microversion = '2.3' - max_microversion = 'latest' - - -class VersionTest2_5To2_10(compute_base.BaseV2ComputeTest): - min_microversion = '2.5' - max_microversion = '2.10' - - -class VersionTest2_10To2_10(compute_base.BaseV2ComputeTest): - min_microversion = '2.10' - max_microversion = '2.10' - - -class InvalidVersionTest(compute_base.BaseV2ComputeTest): - min_microversion = '2.11' - max_microversion = '2.1' - - -class TestMicroversionsTestsClass(base.TestCase): - - def setUp(self): - super(TestMicroversionsTestsClass, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - - def _test_version(self, cfg_min, cfg_max, - expected_pass_tests, - expected_skip_tests): - cfg.CONF.set_default('min_microversion', - cfg_min, group='compute') - cfg.CONF.set_default('max_microversion', - cfg_max, group='compute') - try: - for test_class in expected_pass_tests: - test_class.skip_checks() - for test_class in expected_skip_tests: - self.assertRaises(testtools.TestCase.skipException, - test_class.skip_checks) - except testtools.TestCase.skipException as e: - raise testtools.TestCase.failureException(e.message) - - def test_config_version_none_none(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2] - expected_skip_tests = [VersionTest2_3ToLatest, VersionTest2_5To2_10, - VersionTest2_10To2_10] - self._test_version(None, None, - expected_pass_tests, - expected_skip_tests) - - def test_config_version_none_23(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2, - VersionTest2_3ToLatest] - expected_skip_tests = [VersionTest2_5To2_10, VersionTest2_10To2_10] - self._test_version(None, '2.3', - expected_pass_tests, - expected_skip_tests) - - def test_config_version_22_latest(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2, - VersionTest2_3ToLatest, VersionTest2_5To2_10, - VersionTest2_10To2_10] - expected_skip_tests = [] - self._test_version('2.2', 'latest', - expected_pass_tests, - expected_skip_tests) - - def test_config_version_22_23(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2, - VersionTest2_3ToLatest] - expected_skip_tests = [VersionTest2_5To2_10, VersionTest2_10To2_10] - self._test_version('2.2', '2.3', - expected_pass_tests, - expected_skip_tests) - - def test_config_version_210_210(self): - expected_pass_tests = [VersionTestNoneTolatest, - VersionTest2_3ToLatest, - VersionTest2_5To2_10, - VersionTest2_10To2_10] - expected_skip_tests = [VersionTestNoneTo2_2] - self._test_version('2.10', '2.10', - expected_pass_tests, - expected_skip_tests) - - def test_config_version_none_latest(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2, - VersionTest2_3ToLatest, VersionTest2_5To2_10, - VersionTest2_10To2_10] - expected_skip_tests = [] - self._test_version(None, 'latest', - expected_pass_tests, - expected_skip_tests) - - def test_config_version_latest_latest(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTest2_3ToLatest] - expected_skip_tests = [VersionTestNoneTo2_2, VersionTest2_5To2_10, - VersionTest2_10To2_10] - self._test_version('latest', 'latest', - expected_pass_tests, - expected_skip_tests) - - def test_config_invalid_version(self): - cfg.CONF.set_default('min_microversion', - '2.5', group='compute') - cfg.CONF.set_default('max_microversion', - '2.1', group='compute') - self.assertRaises(exceptions.InvalidAPIVersionRange, - VersionTestNoneTolatest.skip_checks) - - def test_config_version_invalid_test_version(self): - cfg.CONF.set_default('min_microversion', - None, group='compute') - cfg.CONF.set_default('max_microversion', - '2.13', group='compute') - self.assertRaises(exceptions.InvalidAPIVersionRange, - InvalidVersionTest.skip_checks) diff --git a/tempest/tests/test_tempest_plugin.py b/tempest/tests/test_tempest_plugin.py deleted file mode 100644 index 13e249937..000000000 --- a/tempest/tests/test_tempest_plugin.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (c) 2015 Deutsche Telekom AG -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.services import clients -from tempest.test_discover import plugins -from tempest.tests import base -from tempest.tests import fake_tempest_plugin as fake_plugin - - -class TestPluginDiscovery(base.TestCase): - def test_load_tests_with_one_plugin(self): - # we can't mock stevedore since it's a singleton and already executed - # during test discovery. So basically this test covers the plugin loop - # and the abstract plugin interface. - manager = plugins.TempestTestPluginManager() - fake_obj = fake_plugin.FakeStevedoreObj() - manager.ext_plugins = [fake_obj] - result = manager.get_plugin_load_tests_tuple() - - self.assertEqual(fake_plugin.FakePlugin.expected_load_test, - result[fake_obj.name]) - - def test_load_tests_with_two_plugins(self): - manager = plugins.TempestTestPluginManager() - obj1 = fake_plugin.FakeStevedoreObj('fake01') - obj2 = fake_plugin.FakeStevedoreObj('fake02') - manager.ext_plugins = [obj1, obj2] - result = manager.get_plugin_load_tests_tuple() - - self.assertEqual(fake_plugin.FakePlugin.expected_load_test, - result['fake01']) - self.assertEqual(fake_plugin.FakePlugin.expected_load_test, - result['fake02']) - - def test__register_service_clients_with_one_plugin(self): - registry = clients.ClientsRegistry() - manager = plugins.TempestTestPluginManager() - fake_obj = fake_plugin.FakeStevedoreObj() - manager.ext_plugins = [fake_obj] - manager._register_service_clients() - expected_result = fake_plugin.FakePlugin.expected_service_clients - registered_clients = registry.get_service_clients() - self.assertIn(fake_obj.name, registered_clients) - self.assertEqual(expected_result, registered_clients[fake_obj.name]) - - def test__get_service_clients_with_two_plugins(self): - registry = clients.ClientsRegistry() - manager = plugins.TempestTestPluginManager() - obj1 = fake_plugin.FakeStevedoreObj('fake01') - obj2 = fake_plugin.FakeStevedoreObj('fake02') - manager.ext_plugins = [obj1, obj2] - manager._register_service_clients() - expected_result = fake_plugin.FakePlugin.expected_service_clients - registered_clients = registry.get_service_clients() - self.assertIn('fake01', registered_clients) - self.assertIn('fake02', registered_clients) - self.assertEqual(expected_result, registered_clients['fake01']) - self.assertEqual(expected_result, registered_clients['fake02']) - - def test__register_service_clients_one_plugin_no_service_clients(self): - registry = clients.ClientsRegistry() - manager = plugins.TempestTestPluginManager() - fake_obj = fake_plugin.FakeStevedoreObjNoServiceClients() - manager.ext_plugins = [fake_obj] - manager._register_service_clients() - registered_clients = registry.get_service_clients() - self.assertNotIn(fake_obj.name, registered_clients) diff --git a/tempest/tests/utils.py b/tempest/tests/utils.py deleted file mode 100644 index 9c3049dc7..000000000 --- a/tempest/tests/utils.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# - - -def generate_timeout_series(timeout): - """Generate a series of times that exceeds the given timeout. - - Yields a series of fake time.time() floating point numbers - such that the difference between each pair in the series just - exceeds the timeout value that is passed in. Useful for - mocking time.time() in methods that otherwise wait for timeout - seconds. - """ - iteration = 0 - while True: - iteration += 1 - yield (iteration * timeout) + iteration diff --git a/tempest/version.py b/tempest/version.py deleted file mode 100644 index bc9f65137..000000000 --- a/tempest/version.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not -# use this file except in compliance with the License. You may obtain a copy of -# the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations under -# the License. - - -import pbr.version - -version_info = pbr.version.VersionInfo('tempest') diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 6a5ea0300..000000000 --- a/test-requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 -# needed for doc build -sphinx>=1.6.2 # BSD -openstackdocstheme>=1.11.0 # Apache-2.0 -reno!=2.3.1,>=1.8.0 # Apache-2.0 -mock>=2.0 # BSD -coverage!=4.4,>=4.0 # Apache-2.0 -oslotest>=1.10.0 # Apache-2.0 -flake8-import-order==0.11 # LGPLv3 diff --git a/tools/check_logs.py b/tools/check_logs.py deleted file mode 100755 index fc21f755d..000000000 --- a/tools/check_logs.py +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2013 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import argparse -import gzip -import os -import re -import sys - -import six -import six.moves.urllib.request as urlreq -import yaml - -# DEVSTACK_GATE_GRENADE is either unset if grenade is not running -# or a string describing what type of grenade run to perform. -is_grenade = os.environ.get('DEVSTACK_GATE_GRENADE') is not None -dump_all_errors = True - -# As logs are made clean, remove from this set -allowed_dirty = set([ - 'c-api', - 'ceilometer-acentral', - 'ceilometer-acompute', - 'ceilometer-alarm-evaluator', - 'ceilometer-anotification', - 'ceilometer-api', - 'ceilometer-collector', - 'c-vol', - 'g-api', - 'h-api', - 'h-eng', - 'ir-cond', - 'n-api', - 'n-cpu', - 'n-net', - 'q-agt', - 'q-dhcp', - 'q-lbaas', - 'q-meta', - 'q-metering', - 'q-svc', - 's-proxy']) - - -def process_files(file_specs, url_specs, whitelists): - regexp = re.compile(r"^.* (ERROR|CRITICAL|TRACE) .*\[.*\-.*\]") - logs_with_errors = [] - for (name, filename) in file_specs: - whitelist = whitelists.get(name, []) - with open(filename) as content: - if scan_content(name, content, regexp, whitelist): - logs_with_errors.append(name) - for (name, url) in url_specs: - whitelist = whitelists.get(name, []) - req = urlreq.Request(url) - req.add_header('Accept-Encoding', 'gzip') - page = urlreq.urlopen(req) - buf = six.StringIO(page.read()) - f = gzip.GzipFile(fileobj=buf) - if scan_content(name, f.read().splitlines(), regexp, whitelist): - logs_with_errors.append(name) - return logs_with_errors - - -def scan_content(name, content, regexp, whitelist): - had_errors = False - for line in content: - if not line.startswith("Stderr:") and regexp.match(line): - whitelisted = False - for w in whitelist: - pat = ".*%s.*%s.*" % (w['module'].replace('.', '\\.'), - w['message']) - if re.match(pat, line): - whitelisted = True - break - if not whitelisted or dump_all_errors: - if not whitelisted: - had_errors = True - return had_errors - - -def collect_url_logs(url): - page = urlreq.urlopen(url) - content = page.read() - logs = re.findall('(screen-[\w-]+\.txt\.gz)', content) - return logs - - -def main(opts): - if opts.directory and opts.url or not (opts.directory or opts.url): - print("Must provide exactly one of -d or -u") - return 1 - print("Checking logs...") - WHITELIST_FILE = os.path.join( - os.path.abspath(os.path.dirname(os.path.dirname(__file__))), - "etc", "whitelist.yaml") - - file_matcher = re.compile(r".*screen-([\w-]+)\.log") - files = [] - if opts.directory: - d = opts.directory - for f in os.listdir(d): - files.append(os.path.join(d, f)) - files_to_process = [] - for f in files: - m = file_matcher.match(f) - if m: - files_to_process.append((m.group(1), f)) - - url_matcher = re.compile(r".*screen-([\w-]+)\.txt\.gz") - urls = [] - if opts.url: - for logfile in collect_url_logs(opts.url): - urls.append("%s/%s" % (opts.url, logfile)) - urls_to_process = [] - for u in urls: - m = url_matcher.match(u) - if m: - urls_to_process.append((m.group(1), u)) - - whitelists = {} - with open(WHITELIST_FILE) as stream: - loaded = yaml.safe_load(stream) - if loaded: - for (name, l) in six.iteritems(loaded): - for w in l: - assert 'module' in w, 'no module in %s' % name - assert 'message' in w, 'no message in %s' % name - whitelists = loaded - logs_with_errors = process_files(files_to_process, urls_to_process, - whitelists) - - failed = False - if logs_with_errors: - log_files = set(logs_with_errors) - for log in log_files: - msg = '%s log file has errors' % log - if log not in allowed_dirty: - msg += ' and is not allowed to have them' - failed = True - print(msg) - print("\nPlease check the respective log files to see the errors") - if failed: - if is_grenade: - print("Currently not failing grenade runs with errors") - return 0 - return 1 - print("ok") - return 0 - -usage = """ -Find non-white-listed log errors in log files from a devstack-gate run. -Log files will be searched for ERROR or CRITICAL messages. If any -error messages do not match any of the whitelist entries contained in -etc/whitelist.yaml, those messages will be printed to the console and -failure will be returned. A file directory containing logs or a url to the -log files of an OpenStack gate job can be provided. - -The whitelist yaml looks like: - -log-name: - - module: "a.b.c" - message: "regexp" - - module: "a.b.c" - message: "regexp" - -repeated for each log file with a whitelist. -""" - -parser = argparse.ArgumentParser(description=usage) -parser.add_argument('-d', '--directory', - help="Directory containing log files") -parser.add_argument('-u', '--url', - help="url containing logs from an OpenStack gate job") - -if __name__ == "__main__": - try: - sys.exit(main(parser.parse_args())) - except Exception as e: - print("Failure in script: %s" % e) - # Don't fail if there is a problem with the script. - sys.exit(0) diff --git a/tools/find_stack_traces.py b/tools/find_stack_traces.py deleted file mode 100755 index 1f2b88b44..000000000 --- a/tools/find_stack_traces.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2013 IBM Corp. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import gzip -import pprint -import re -import sys - -import six -import six.moves.urllib.request as urlreq - - -pp = pprint.PrettyPrinter() - -NOVA_TIMESTAMP = r"\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d" - -NOVA_REGEX = r"(?P%s) (?P\d+ )?(?P(ERROR|TRACE)) " \ - "(?P[\w\.]+) (?P.*)" % (NOVA_TIMESTAMP) - - -class StackTrace(object): - timestamp = None - pid = None - level = "" - module = "" - msg = "" - - def __init__(self, timestamp=None, pid=None, level="", module="", - msg=""): - self.timestamp = timestamp - self.pid = pid - self.level = level - self.module = module - self.msg = msg - - def append(self, msg): - self.msg = self.msg + msg - - def is_same(self, data): - return (data['timestamp'] == self.timestamp and - data['level'] == self.level) - - def not_none(self): - return self.timestamp is not None - - def __str__(self): - buff = "<%s %s %s>\n" % (self.timestamp, self.level, self.module) - for line in self.msg.splitlines(): - buff = buff + line + "\n" - return buff - - -def hunt_for_stacktrace(url): - """Return TRACE or ERROR lines out of logs.""" - req = urlreq.Request(url) - req.add_header('Accept-Encoding', 'gzip') - page = urlreq.urlopen(req) - buf = six.StringIO(page.read()) - f = gzip.GzipFile(fileobj=buf) - content = f.read() - - traces = [] - trace = StackTrace() - for line in content.splitlines(): - m = re.match(NOVA_REGEX, line) - if m: - data = m.groupdict() - if trace.not_none() and trace.is_same(data): - trace.append(data['msg'] + "\n") - else: - trace = StackTrace( - timestamp=data.get('timestamp'), - pid=data.get('pid'), - level=data.get('level'), - module=data.get('module'), - msg=data.get('msg')) - - else: - if trace.not_none(): - traces.append(trace) - trace = StackTrace() - - # once more at the end to pick up any stragglers - if trace.not_none(): - traces.append(trace) - - return traces - - -def log_url(url, log): - return "%s/%s" % (url, log) - - -def collect_logs(url): - page = urlreq.urlopen(url) - content = page.read() - logs = re.findall('(screen-[\w-]+\.txt\.gz)', content) - return logs - - -def usage(): - print(""" -Usage: find_stack_traces.py - -Hunts for stack traces in a devstack run. Must provide it a base log url -from a tempest devstack run. Should start with http and end with /logs/. - -Returns a report listing stack traces out of the various files where -they are found. -""") - sys.exit(0) - - -def print_stats(items, fname, verbose=False): - errors = len([x for x in items if x.level == "ERROR"]) - traces = len([x for x in items if x.level == "TRACE"]) - print("%d ERRORS found in %s" % (errors, fname)) - print("%d TRACES found in %s" % (traces, fname)) - - if verbose: - for item in items: - print(item) - print("\n\n") - - -def main(): - if len(sys.argv) == 2: - url = sys.argv[1] - loglist = collect_logs(url) - - # probably wrong base url - if not loglist: - usage() - - for log in loglist: - logurl = log_url(url, log) - traces = hunt_for_stacktrace(logurl) - - if traces: - print_stats(traces, log, verbose=True) - - else: - usage() - -if __name__ == '__main__': - main() diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py deleted file mode 100644 index 99df0d120..000000000 --- a/tools/generate-tempest-plugins-list.py +++ /dev/null @@ -1,89 +0,0 @@ -#! /usr/bin/env python - -# Copyright 2016 Hewlett Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# This script is intended to be run as part of a periodic proposal bot -# job in OpenStack infrastructure. -# -# In order to function correctly, the environment in which the -# script runs must have -# * network access to the review.openstack.org Gerrit API -# working directory -# * network access to https://git.openstack.org/cgit - -import json -import re - -try: - # For Python 3.0 and later - from urllib.error import HTTPError as HTTPError - import urllib.request as urllib -except ImportError: - # Fall back to Python 2's urllib2 - import urllib2 as urllib - from urllib2 import HTTPError as HTTPError - - -url = 'https://review.openstack.org/projects/' - -# This is what a project looks like -''' - "openstack-attic/akanda": { - "id": "openstack-attic%2Fakanda", - "state": "READ_ONLY" - }, -''' - - -def is_in_openstack_namespace(proj): - return proj.startswith('openstack/') - -# Rather than returning a 404 for a nonexistent file, cgit delivers a -# 0-byte response to a GET request. It also does not provide a -# Content-Length in a HEAD response, so the way we tell if a file exists -# is to check the length of the entire GET response body. - - -def has_tempest_plugin(proj): - try: - r = urllib.urlopen( - "https://git.openstack.org/cgit/%s/plain/setup.cfg" % proj) - except HTTPError as err: - if err.code == 404: - return False - p = re.compile('^tempest\.test_plugins', re.M) - if p.findall(r.read().decode('utf-8')): - return True - else: - False - -r = urllib.urlopen(url) -# Gerrit prepends 4 garbage octets to the JSON, in order to counter -# cross-site scripting attacks. Therefore we must discard it so the -# json library won't choke. -projects = sorted(filter(is_in_openstack_namespace, json.loads(r.read()[4:]))) - -# Retrieve projects having no deb, ui or spec namespace as those namespaces -# do not contains tempest plugins. -projects_list = [i for i in projects if not (i.startswith('openstack/deb-') or - i.endswith('-ui') or - i.endswith('-specs'))] - -found_plugins = list(filter(has_tempest_plugin, projects_list)) - -# Every element of the found_plugins list begins with "openstack/". -# We drop those initial 10 octets when printing the list. -for project in found_plugins: - print(project[10:]) diff --git a/tools/generate-tempest-plugins-list.sh b/tools/generate-tempest-plugins-list.sh deleted file mode 100755 index e6aad8695..000000000 --- a/tools/generate-tempest-plugins-list.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2016 Hewlett Packard Enterprise Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# This script is intended to be run as a periodic proposal bot job -# in OpenStack infrastructure, though you can run it as a one-off. -# -# In order to function correctly, the environment in which the -# script runs must have -# * a writable doc/source directory relative to the current -# working directory -# AND ( ( -# * git -# * all git repos meant to be searched for plugins cloned and -# at the desired level of up-to-datedness -# * the environment variable git_dir pointing to the location -# * of said git repositories -# ) OR ( -# * network access to the review.openstack.org Gerrit API -# working directory -# * network access to https://git.openstack.org/cgit -# )) -# -# If a file named data/tempest-plugins-registry.header or -# data/tempest-plugins-registry.footer is found relative to the -# current working directory, it will be prepended or appended to -# the generated reStructuredText plugins table respectively. - -set -ex - -( -declare -A plugins - -if [[ -r data/tempest-plugins-registry.header ]]; then - cat data/tempest-plugins-registry.header -fi - -sorted_plugins=$(python tools/generate-tempest-plugins-list.py) - -for k in ${sorted_plugins}; do - project=${k:0:28} - giturl="git://git.openstack.org/openstack/${k:0:26}" - printf "|%-28s|%-73s|\n" "${project}" "${giturl}" - printf "+----------------------------+-------------------------------------------------------------------------+\n" -done - -if [[ -r data/tempest-plugins-registry.footer ]]; then - cat data/tempest-plugins-registry.footer -fi -) > doc/source/plugin-registry.rst - -if [[ -n ${1} ]]; then - cp doc/source/plugin-registry.rst ${1}/doc/source/plugin-registry.rst -fi diff --git a/tools/skip_tracker.py b/tools/skip_tracker.py deleted file mode 100755 index 44f5874db..000000000 --- a/tools/skip_tracker.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -""" -Track test skips via launchpadlib API and raise alerts if a bug -is fixed but a skip is still in the Tempest test code -""" - -from tempest.lib.cmd import skip_tracker - - -if __name__ == '__main__': - print("DEPRECATED: `skip_tracker.py` is already deprecated, " - "use `skip-tracker` command instead.") - skip_tracker.main() diff --git a/tools/tempest-plugin-sanity.sh b/tools/tempest-plugin-sanity.sh deleted file mode 100644 index a4f706e01..000000000 --- a/tools/tempest-plugin-sanity.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2017 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -# This script is intended to check the sanity of tempest plugins against -# tempest master. -# What it does: -# * Creates the virtualenv -# * Install tempest -# * Retrive the project lists having tempest plugin if project name is -# given. -# * For each project in a list, It does: -# * Clone the Project -# * Install the Project and also installs dependencies from -# test-requirements.txt. -# * Create Tempest workspace -# * List tempest plugins -# * List tempest plugins tests -# * Uninstall the project and its dependencies -# * Again Install tempest -# * Again repeat the step from cloning project -# -# If one of the step fails, The script will exit with failure. - -if [ "$1" == "-h" ]; then - echo -e "This script performs the sanity of tempest plugins to find -configuration and dependency issues with the tempest.\n -Usage: sh ./tools/tempest-plugin-sanity.sh [Run sanity on tempest plugins]" - exit 0 -fi - -set -ex - -# retrieve a list of projects having tempest plugins -PROJECT_LIST="$(python tools/generate-tempest-plugins-list.py)" -# List of projects having tempest plugin stale or unmaintained from long time -BLACKLIST="trio2o" - -# Function to clone project using zuul-cloner or from git -function clone_project() { - if [ -e /usr/zuul-env/bin/zuul-cloner ]; then - /usr/zuul-env/bin/zuul-cloner --cache-dir /opt/git \ - git://git.openstack.org \ - openstack/"$1" - - elif [ -e /usr/bin/git ]; then - /usr/bin/git clone git://git.openstack.org/openstack/"$1" \ - openstack/"$1" - - fi -} - -# Create virtualenv to perform sanity operation -SANITY_DIR=$(pwd) -virtualenv "$SANITY_DIR"/.venv -export TVENV="$SANITY_DIR/tools/with_venv.sh" -cd "$SANITY_DIR" - -# Install tempest in a venv -"$TVENV" pip install . - -# Function to install project -function install_project() { - "$TVENV" pip install "$SANITY_DIR"/openstack/"$1" - # Check for test-requirements.txt file in a project then install it. - if [ -e "$SANITY_DIR"/openstack/"$1"/test-requirements.txt ]; then - "$TVENV" pip install -r "$SANITY_DIR"/openstack/"$1"/test-requirements.txt - fi -} - -# Function to perform sanity checking on Tempest plugin -function tempest_sanity() { - "$TVENV" tempest init "$SANITY_DIR"/tempest_sanity - cd "$SANITY_DIR"/tempest_sanity - "$TVENV" tempest list-plugins - "$TVENV" tempest run -l - # Delete tempest workspace - "$TVENV" tempest workspace remove --name tempest_sanity --rmdir - cd "$SANITY_DIR" -} - -# Function to uninstall project -function uninstall_project() { - "$TVENV" pip uninstall -y "$SANITY_DIR"/openstack/"$1" - # Check for *requirements.txt file in a project then uninstall it. - if [ -e "$SANITY_DIR"/openstack/"$1"/*requirements.txt ]; then - "$TVENV" pip uninstall -y -r "$SANITY_DIR"/openstack/"$1"/*requirements.txt - fi - # Remove the project directory after sanity run - rm -fr "$SANITY_DIR"/openstack/"$1" -} - -# Function to run sanity check on each project -function plugin_sanity_check() { - clone_project "$1" && install_project "$1" && tempest_sanity "$1" \ - && uninstall_project "$1" && "$TVENV" pip install . -} - -# Log status -passed_plugin='' -failed_plugin='' -# Perform sanity on all tempest plugin projects -for project in $PROJECT_LIST; do - # Remove blacklisted tempest plugins - if ! [[ `echo $BLACKLIST | grep -c $project ` -gt 0 ]]; then - plugin_sanity_check $project && passed_plugin+=", $project" || \ - failed_plugin+=", $project" - fi -done diff --git a/tools/tox_install.sh b/tools/tox_install.sh deleted file mode 100755 index 43468e450..000000000 --- a/tools/tox_install.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -# Client constraint file contains this client version pin that is in conflict -# with installing the client from source. We should remove the version pin in -# the constraints file before applying it for from-source installation. - -CONSTRAINTS_FILE=$1 -shift 1 - -set -e - -# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get -# published to logs.openstack.org for easy debugging. -localfile="$VIRTUAL_ENV/log/upper-constraints.txt" - -if [[ $CONSTRAINTS_FILE != http* ]]; then - CONSTRAINTS_FILE=file://$CONSTRAINTS_FILE -fi -# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep -curl $CONSTRAINTS_FILE --insecure --progress-bar --output $localfile - -pip install -c$localfile openstack-requirements - -# This is the main purpose of the script: Allow local installation of -# the current repo. It is listed in constraints file and thus any -# install will be constrained and we need to unconstrain it. -edit-constraints $localfile -- $CLIENT_NAME - -pip install -c$localfile -U $* -exit $? diff --git a/tools/with_venv.sh b/tools/with_venv.sh deleted file mode 100755 index 408b5f132..000000000 --- a/tools/with_venv.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -TOOLS_PATH=${TOOLS_PATH:-$(dirname $0)/../} -VENV_PATH=${VENV_PATH:-${TOOLS_PATH}} -VENV_DIR=${VENV_DIR:-/.venv} -VENV=${VENV:-${VENV_PATH}/${VENV_DIR}} -source ${VENV}/bin/activate && "$@" diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 6f37d00e5..000000000 --- a/tox.ini +++ /dev/null @@ -1,193 +0,0 @@ -[tox] -envlist = pep8,py35,py27,pip-check-reqs -minversion = 2.3.1 -skipsdist = True - -[tempestenv] -sitepackages = False -setenv = - VIRTUAL_ENV={envdir} - OS_TEST_PATH=./tempest/test_discover - BRANCH_NAME=master - CLIENT_NAME=tempest -deps = - -r{toxinidir}/requirements.txt - -[testenv] -setenv = - VIRTUAL_ENV={envdir} - OS_TEST_PATH=./tempest/tests - PYTHONWARNINGS=default::DeprecationWarning - BRANCH_NAME=master - CLIENT_NAME=tempest -passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH OS_TEST_PATH TEMPEST_CONFIG TEMPEST_CONFIG_DIR http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY ZUUL_CACHE_DIR REQUIREMENTS_PIP_LOCATION GENERATE_TEMPEST_PLUGIN_LIST -usedevelop = True -install_command = - {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} -whitelist_externals = * -deps = - -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = - find . -type f -name "*.pyc" -delete - ostestr {posargs} - -[testenv:genconfig] -commands = oslo-config-generator --config-file tempest/cmd/config-generator.tempest.conf - -[testenv:cover] -commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}' - -[testenv:all] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -# 'all' includes slow tests -setenv = - {[tempestenv]setenv} - OS_TEST_TIMEOUT={env:OS_TEST_TIMEOUT:1200} -deps = {[tempestenv]deps} -commands = - find . -type f -name "*.pyc" -delete - tempest run --regex {posargs} - -[testenv:ostestr] -sitepackages = {[tempestenv]sitepackages} -# 'all' includes slow tests -setenv = - {[tempestenv]setenv} - OS_TEST_TIMEOUT={env:OS_TEST_TIMEOUT:1200} -deps = {[tempestenv]deps} -commands = - find . -type f -name "*.pyc" -delete - ostestr {posargs} - -[testenv:all-plugin] -sitepackages = True -# 'all' includes slow tests -setenv = - {[tempestenv]setenv} - OS_TEST_TIMEOUT={env:OS_TEST_TIMEOUT:1200} -deps = {[tempestenv]deps} -commands = - find . -type f -name "*.pyc" -delete - tempest run --regex {posargs} - -[testenv:full] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -# The regex below is used to select which tests to run and exclude the slow tag: -# See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610 -commands = - find . -type f -name "*.pyc" -delete - tempest run --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.api)' {posargs} - tempest run --combine --serial --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.scenario)' {posargs} - -[testenv:full-serial] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -# The regex below is used to select which tests to run and exclude the slow tag: -# See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610 -commands = - find . -type f -name "*.pyc" -delete - tempest run --serial --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' {posargs} - -[testenv:scenario] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -# The regex below is used to select all scenario tests -commands = - find . -type f -name "*.pyc" -delete - tempest run --serial --regex '(^tempest\.scenario)' {posargs} - -[testenv:smoke] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -commands = - find . -type f -name "*.pyc" -delete - tempest run --regex '\[.*\bsmoke\b.*\]' {posargs} - -[testenv:smoke-serial] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -# This is still serial because neutron doesn't work with parallel. See: -# https://bugs.launchpad.net/tempest/+bug/1216076 so the neutron smoke -# job would fail if we moved it to parallel. -commands = - find . -type f -name "*.pyc" -delete - tempest run --serial --regex '\[.*\bsmoke\b.*\]' {posargs} - -[testenv:venv] -commands = {posargs} - -[testenv:venv-tempest] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -commands = {posargs} - -[testenv:docs] -commands = - python setup.py build_sphinx {posargs} - -[testenv:pep8] -commands = - flake8 {posargs} - check-uuid - -[testenv:uuidgen] -commands = - check-uuid --fix - -[hacking] -local-check-factory = tempest.hacking.checks.factory -import_exceptions = tempest.services - -[flake8] -# E125 is a won't fix until https://github.com/jcrocholl/pep8/issues/126 is resolved. For further detail see https://review.openstack.org/#/c/36788/ -# E123 skipped because it is ignored by default in the default pep8 -# E129 skipped because it is too limiting when combined with other rules -ignore = E125,E123,E129 -show-source = True -exclude = .git,.venv,.tox,dist,doc,*egg -enable-extensions = H106,H203,H904 -import-order-style = pep8 - -[testenv:releasenotes] -commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html - -[testenv:pip-check-reqs] -# Do not install test-requirements as that will pollute the virtualenv for -# determining missing packages. -# This also means that pip-check-reqs must be installed separately, outside -# of the requirements.txt files -deps = pip_check_reqs - -r{toxinidir}/requirements.txt -commands= - pip-extra-reqs -d --ignore-file=tempest/tests/* tempest - pip-missing-reqs -d --ignore-file=tempest/tests/* tempest - - -[testenv:bindep] -# Do not install any requirements. We want this to be fast and work even if -# system dependencies are missing, since it's used to tell you what system -# dependencies are missing! This also means that bindep must be installed -# separately, outside of the requirements files. -deps = bindep -commands = bindep test - -[testenv:plugin-sanity-check] -# perform tempest plugin sanity -whitelist_externals = bash -commands = - bash tools/tempest-plugin-sanity.sh